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 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static void InitTileClipmasks()
46 #if defined(TARGET_X11)
47 XGCValues clip_gc_values;
48 unsigned long clip_gc_valuemask;
50 #if defined(TARGET_X11_NATIVE)
60 tile_needs_clipping[] =
62 { GFX_SPIELER1_UP, 4 },
63 { GFX_SPIELER1_DOWN, 4 },
64 { GFX_SPIELER1_LEFT, 4 },
65 { GFX_SPIELER1_RIGHT, 4 },
66 { GFX_SPIELER1_PUSH_LEFT, 4 },
67 { GFX_SPIELER1_PUSH_RIGHT, 4 },
68 { GFX_SPIELER2_UP, 4 },
69 { GFX_SPIELER2_DOWN, 4 },
70 { GFX_SPIELER2_LEFT, 4 },
71 { GFX_SPIELER2_RIGHT, 4 },
72 { GFX_SPIELER2_PUSH_LEFT, 4 },
73 { GFX_SPIELER2_PUSH_RIGHT, 4 },
74 { GFX_SPIELER3_UP, 4 },
75 { GFX_SPIELER3_DOWN, 4 },
76 { GFX_SPIELER3_LEFT, 4 },
77 { GFX_SPIELER3_RIGHT, 4 },
78 { GFX_SPIELER3_PUSH_LEFT, 4 },
79 { GFX_SPIELER3_PUSH_RIGHT, 4 },
80 { GFX_SPIELER4_UP, 4 },
81 { GFX_SPIELER4_DOWN, 4 },
82 { GFX_SPIELER4_LEFT, 4 },
83 { GFX_SPIELER4_RIGHT, 4 },
84 { GFX_SPIELER4_PUSH_LEFT, 4 },
85 { GFX_SPIELER4_PUSH_RIGHT, 4 },
87 { GFX_MURPHY_GO_LEFT, 3 },
88 { GFX_MURPHY_GO_RIGHT, 3 },
89 { GFX_MURPHY_SNAP_UP, 1 },
90 { GFX_MURPHY_SNAP_DOWN, 1 },
91 { GFX_MURPHY_SNAP_RIGHT, 1 },
92 { GFX_MURPHY_SNAP_LEFT, 1 },
93 { GFX_MURPHY_PUSH_RIGHT, 1 },
94 { GFX_MURPHY_PUSH_LEFT, 1 },
99 { GFX_SOKOBAN_OBJEKT, 1 },
100 { GFX_FUNKELN_BLAU, 3 },
101 { GFX_FUNKELN_WEISS, 3 },
102 { GFX2_SHIELD_PASSIVE, 3 },
103 { GFX2_SHIELD_ACTIVE, 3 },
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
113 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114 for (i = 0; i < NUM_TILES; i++)
115 tile_clipmask[i] = None;
117 #if defined(TARGET_X11)
118 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119 often very slow when preparing a masked XCopyArea() for big Pixmaps.
120 To prevent this, create small (tile-sized) mask Pixmaps which will then
121 be set much faster with XSetClipOrigin() and speed things up a lot. */
123 clip_gc_values.graphics_exposures = False;
124 clip_gc_valuemask = GCGraphicsExposures;
125 tile_clip_gc = XCreateGC(display, window->drawable,
126 clip_gc_valuemask, &clip_gc_values);
129 for (i = 0; i < NUM_BITMAPS; i++)
131 if (pix[i]->clip_mask)
133 clip_gc_values.graphics_exposures = False;
134 clip_gc_values.clip_mask = pix[i]->clip_mask;
135 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137 clip_gc_valuemask, &clip_gc_values);
142 #if defined(TARGET_X11_NATIVE)
145 /* create graphic context structures needed for clipping */
146 clip_gc_values.graphics_exposures = False;
147 clip_gc_valuemask = GCGraphicsExposures;
148 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149 clip_gc_valuemask, &clip_gc_values);
151 /* create only those clipping Pixmaps we really need */
152 for (i = 0; tile_needs_clipping[i].start >= 0; i++)
156 for (j = 0; j < tile_needs_clipping[i].count; j++)
158 int tile = tile_needs_clipping[i].start + j;
164 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165 src_pixmap = src_bitmap->clip_mask;
167 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
170 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171 src_x, src_y, TILEX, TILEY, 0, 0);
175 XFreeGC(display, copy_clipmask_gc);
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
183 void FreeTileClipmasks()
186 #if defined(TARGET_X11)
189 for (i = 0; i < NUM_TILES; i++)
191 if (tile_clipmask[i] != None)
193 XFreePixmap(display, tile_clipmask[i]);
194 tile_clipmask[i] = None;
199 XFreeGC(display, tile_clip_gc);
203 for (i = 0; i < NUM_BITMAPS; i++)
205 if (pix[i] != NULL && pix[i]->stored_clip_gc)
207 XFreeGC(display, pix[i]->stored_clip_gc);
208 pix[i]->stored_clip_gc = None;
213 #endif /* TARGET_X11 */
219 FreeLevelEditorGadgets();
228 static boolean gadgets_initialized = FALSE;
230 if (gadgets_initialized)
233 CreateLevelEditorGadgets();
237 CreateScreenGadgets();
239 gadgets_initialized = TRUE;
242 inline void InitElementSmallImagesScaledUp(int graphic)
244 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
247 void InitElementSmallImages()
249 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250 int num_property_mappings = getImageListPropertyMappingSize();
253 /* initialize normal images from static configuration */
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
257 /* initialize special images from static configuration */
258 for (i = 0; element_to_special_graphic[i].element > -1; i++)
259 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 /* initialize images from dynamic configuration (may be elements or other) */
263 for (i = 0; i < num_property_mappings; i++)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
266 /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
267 /* !!! ALSO, non-element graphics might need scaling-up !!! */
268 for (i = 0; i < num_property_mappings; i++)
269 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
270 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
276 InitElementSmallImagesScaledUp(i);
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_EM(Bitmap **em_bitmap)
284 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
285 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
289 static int getFontBitmapID(int font_nr)
293 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
297 else if (game_status == GAME_MODE_PLAYING)
298 special = GFX_SPECIAL_ARG_DOOR;
301 return font_info[font_nr].special_bitmap_id[special];
306 void InitFontGraphicInfo()
308 static struct FontBitmapInfo *font_bitmap_info = NULL;
309 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
310 int num_property_mappings = getImageListPropertyMappingSize();
311 int num_font_bitmaps = NUM_FONTS;
314 if (graphic_info == NULL) /* still at startup phase */
316 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
321 /* ---------- initialize font graphic definitions ---------- */
323 /* always start with reliable default values (normal font graphics) */
325 for (i = 0; i < NUM_FONTS; i++)
326 font_info[i].graphic = IMG_FONT_INITIAL_1;
328 for (i = 0; i < NUM_FONTS; i++)
329 font_info[i].graphic = FONT_INITIAL_1;
332 /* initialize normal font/graphic mapping from static configuration */
333 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
335 int font_nr = font_to_graphic[i].font_nr;
336 int special = font_to_graphic[i].special;
337 int graphic = font_to_graphic[i].graphic;
342 font_info[font_nr].graphic = graphic;
345 /* always start with reliable default values (special font graphics) */
346 for (i = 0; i < NUM_FONTS; i++)
348 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
350 font_info[i].special_graphic[j] = font_info[i].graphic;
351 font_info[i].special_bitmap_id[j] = i;
355 /* initialize special font/graphic mapping from static configuration */
356 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
358 int font_nr = font_to_graphic[i].font_nr;
359 int special = font_to_graphic[i].special;
360 int graphic = font_to_graphic[i].graphic;
362 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
364 font_info[font_nr].special_graphic[special] = graphic;
365 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
370 /* initialize special element/graphic mapping from dynamic configuration */
371 for (i = 0; i < num_property_mappings; i++)
373 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
374 int special = property_mapping[i].ext3_index;
375 int graphic = property_mapping[i].artwork_index;
380 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
382 font_info[font_nr].special_graphic[special] = graphic;
383 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
388 /* ---------- initialize font bitmap array ---------- */
390 if (font_bitmap_info != NULL)
391 FreeFontInfo(font_bitmap_info);
394 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
396 /* ---------- initialize font bitmap definitions ---------- */
398 for (i = 0; i < NUM_FONTS; i++)
400 if (i < NUM_INITIAL_FONTS)
402 font_bitmap_info[i] = font_initial[i];
406 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
408 int font_bitmap_id = font_info[i].special_bitmap_id[j];
409 int graphic = font_info[i].special_graphic[j];
411 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
412 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
414 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
415 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
418 /* copy font relevant information from graphics information */
419 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
420 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
421 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
422 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
423 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
424 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
425 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
427 font_bitmap_info[font_bitmap_id].num_chars =
428 graphic_info[graphic].anim_frames;
429 font_bitmap_info[font_bitmap_id].num_chars_per_line =
430 graphic_info[graphic].anim_frames_per_line;
434 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
437 void InitElementGraphicInfo()
439 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
440 int num_property_mappings = getImageListPropertyMappingSize();
443 if (graphic_info == NULL) /* still at startup phase */
446 /* set values to -1 to identify later as "uninitialized" values */
447 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
449 for (act = 0; act < NUM_ACTIONS; act++)
451 element_info[i].graphic[act] = -1;
452 element_info[i].crumbled[act] = -1;
454 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
456 element_info[i].direction_graphic[act][dir] = -1;
457 element_info[i].direction_crumbled[act][dir] = -1;
462 /* initialize normal element/graphic mapping from static configuration */
463 for (i = 0; element_to_graphic[i].element > -1; i++)
465 int element = element_to_graphic[i].element;
466 int action = element_to_graphic[i].action;
467 int direction = element_to_graphic[i].direction;
468 boolean crumbled = element_to_graphic[i].crumbled;
469 int graphic = element_to_graphic[i].graphic;
470 int base_graphic = el2baseimg(element);
472 if (graphic_info[graphic].bitmap == NULL)
475 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
478 boolean base_redefined =
479 getImageListEntryFromImageID(base_graphic)->redefined;
480 boolean act_dir_redefined =
481 getImageListEntryFromImageID(graphic)->redefined;
483 /* if the base graphic ("emerald", for example) has been redefined,
484 but not the action graphic ("emerald.falling", for example), do not
485 use an existing (in this case considered obsolete) action graphic
486 anymore, but use the automatically determined default graphic */
487 if (base_redefined && !act_dir_redefined)
492 action = ACTION_DEFAULT;
497 element_info[element].direction_crumbled[action][direction] = graphic;
499 element_info[element].crumbled[action] = graphic;
504 element_info[element].direction_graphic[action][direction] = graphic;
506 element_info[element].graphic[action] = graphic;
510 /* initialize normal element/graphic mapping from dynamic configuration */
511 for (i = 0; i < num_property_mappings; i++)
513 int element = property_mapping[i].base_index;
514 int action = property_mapping[i].ext1_index;
515 int direction = property_mapping[i].ext2_index;
516 int special = property_mapping[i].ext3_index;
517 int graphic = property_mapping[i].artwork_index;
518 boolean crumbled = FALSE;
520 if (special == GFX_SPECIAL_ARG_CRUMBLED)
526 if (graphic_info[graphic].bitmap == NULL)
529 if (element >= MAX_NUM_ELEMENTS || special != -1)
533 action = ACTION_DEFAULT;
538 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
539 element_info[element].direction_crumbled[action][dir] = -1;
542 element_info[element].direction_crumbled[action][direction] = graphic;
544 element_info[element].crumbled[action] = graphic;
549 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
550 element_info[element].direction_graphic[action][dir] = -1;
553 element_info[element].direction_graphic[action][direction] = graphic;
555 element_info[element].graphic[action] = graphic;
559 /* now copy all graphics that are defined to be cloned from other graphics */
560 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
562 int graphic = element_info[i].graphic[ACTION_DEFAULT];
563 int crumbled_like, diggable_like;
568 crumbled_like = graphic_info[graphic].crumbled_like;
569 diggable_like = graphic_info[graphic].diggable_like;
571 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
573 for (act = 0; act < NUM_ACTIONS; act++)
574 element_info[i].crumbled[act] =
575 element_info[crumbled_like].crumbled[act];
576 for (act = 0; act < NUM_ACTIONS; act++)
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_crumbled[act][dir] =
579 element_info[crumbled_like].direction_crumbled[act][dir];
582 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
584 element_info[i].graphic[ACTION_DIGGING] =
585 element_info[diggable_like].graphic[ACTION_DIGGING];
586 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
587 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
588 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
593 /* set hardcoded definitions for some runtime elements without graphic */
594 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
598 /* now set all undefined/invalid graphics to -1 to set to default after it */
599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601 for (act = 0; act < NUM_ACTIONS; act++)
605 graphic = element_info[i].graphic[act];
606 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
607 element_info[i].graphic[act] = -1;
609 graphic = element_info[i].crumbled[act];
610 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
611 element_info[i].crumbled[act] = -1;
613 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
615 graphic = element_info[i].direction_graphic[act][dir];
616 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
617 element_info[i].direction_graphic[act][dir] = -1;
619 graphic = element_info[i].direction_crumbled[act][dir];
620 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
621 element_info[i].direction_crumbled[act][dir] = -1;
628 /* adjust graphics with 2nd tile for movement according to direction
629 (do this before correcting '-1' values to minimize calculations) */
630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
632 for (act = 0; act < NUM_ACTIONS; act++)
634 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
636 int graphic = element_info[i].direction_graphic[act][dir];
637 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
639 if (act == ACTION_FALLING) /* special case */
640 graphic = element_info[i].graphic[act];
643 graphic_info[graphic].double_movement &&
644 graphic_info[graphic].swap_double_tiles != 0)
646 struct GraphicInfo *g = &graphic_info[graphic];
647 int src_x_front = g->src_x;
648 int src_y_front = g->src_y;
649 int src_x_back = g->src_x + g->offset2_x;
650 int src_y_back = g->src_y + g->offset2_y;
651 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
653 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
654 src_y_front < src_y_back);
656 boolean second_tile_is_back =
657 ((move_dir == MV_BIT_LEFT && front_is_left_or_upper) ||
658 (move_dir == MV_BIT_UP && front_is_left_or_upper));
659 boolean second_tile_is_front =
660 ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
661 (move_dir == MV_BIT_DOWN && front_is_left_or_upper));
662 boolean second_tile_should_be_front =
663 (g->second_tile_is_start == 0);
664 boolean second_tile_should_be_back =
665 (g->second_tile_is_start == 1);
667 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
668 boolean swap_movement_tiles_autodetected =
669 (!frames_are_ordered_diagonally &&
670 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
671 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
672 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
673 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
677 printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
678 i, element_info[i].token_name,
679 element_action_info[act].suffix, move_dir,
680 g->swap_double_tiles,
681 swap_movement_tiles_never,
682 swap_movement_tiles_always,
683 swap_movement_tiles_autodetected,
684 swap_movement_tiles);
687 /* swap frontside and backside graphic tile coordinates, if needed */
688 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
690 /* get current (wrong) backside tile coordinates */
691 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
694 /* set frontside tile coordinates to backside tile coordinates */
695 g->src_x = src_x_back;
696 g->src_y = src_y_back;
698 /* invert tile offset to point to new backside tile coordinates */
702 /* do not swap front and backside tiles again after correction */
703 g->swap_double_tiles = 0;
706 printf(" CORRECTED\n");
715 /* now set all '-1' values to element specific default values */
716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
719 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
720 int default_direction_graphic[NUM_DIRECTIONS];
721 int default_direction_crumbled[NUM_DIRECTIONS];
723 if (default_graphic == -1)
724 default_graphic = IMG_UNKNOWN;
726 if (default_crumbled == -1)
727 default_crumbled = default_graphic;
729 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
730 if (default_crumbled == -1)
731 default_crumbled = IMG_EMPTY;
734 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
736 default_direction_graphic[dir] =
737 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
738 default_direction_crumbled[dir] =
739 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
741 if (default_direction_graphic[dir] == -1)
742 default_direction_graphic[dir] = default_graphic;
744 if (default_direction_crumbled[dir] == -1)
745 default_direction_crumbled[dir] = default_direction_graphic[dir];
747 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
748 if (default_direction_crumbled[dir] == -1)
749 default_direction_crumbled[dir] = default_crumbled;
753 for (act = 0; act < NUM_ACTIONS; act++)
755 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
756 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
757 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
758 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
759 act == ACTION_TURNING_FROM_RIGHT ||
760 act == ACTION_TURNING_FROM_UP ||
761 act == ACTION_TURNING_FROM_DOWN);
763 /* generic default action graphic (defined by "[default]" directive) */
764 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
765 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
766 int default_remove_graphic = IMG_EMPTY;
768 if (act_remove && default_action_graphic != -1)
769 default_remove_graphic = default_action_graphic;
771 /* look for special default action graphic (classic game specific) */
772 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
773 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
774 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
775 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
776 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
777 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
779 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
780 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
781 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
782 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
783 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
784 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
787 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
788 /* !!! make this better !!! */
789 if (i == EL_EMPTY_SPACE)
791 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
792 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
796 if (default_action_graphic == -1)
797 default_action_graphic = default_graphic;
799 if (default_action_crumbled == -1)
800 default_action_crumbled = default_action_graphic;
802 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
803 if (default_action_crumbled == -1)
804 default_action_crumbled = default_crumbled;
807 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
809 /* use action graphic as the default direction graphic, if undefined */
810 int default_action_direction_graphic = element_info[i].graphic[act];
811 int default_action_direction_crumbled = element_info[i].crumbled[act];
813 /* no graphic for current action -- use default direction graphic */
814 if (default_action_direction_graphic == -1)
815 default_action_direction_graphic =
816 (act_remove ? default_remove_graphic :
818 element_info[i].direction_graphic[ACTION_TURNING][dir] :
819 default_action_graphic != default_graphic ?
820 default_action_graphic :
821 default_direction_graphic[dir]);
823 if (element_info[i].direction_graphic[act][dir] == -1)
824 element_info[i].direction_graphic[act][dir] =
825 default_action_direction_graphic;
828 if (default_action_direction_crumbled == -1)
829 default_action_direction_crumbled =
830 element_info[i].direction_graphic[act][dir];
832 if (default_action_direction_crumbled == -1)
833 default_action_direction_crumbled =
834 (act_remove ? default_remove_graphic :
836 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
837 default_action_crumbled != default_crumbled ?
838 default_action_crumbled :
839 default_direction_crumbled[dir]);
842 if (element_info[i].direction_crumbled[act][dir] == -1)
843 element_info[i].direction_crumbled[act][dir] =
844 default_action_direction_crumbled;
847 if (i == EL_EMC_GRASS &&
848 act == ACTION_DIGGING &&
850 printf("::: direction_crumbled == %d, %d, %d\n",
851 element_info[i].direction_crumbled[act][dir],
852 default_action_direction_crumbled,
853 element_info[i].crumbled[act]);
857 /* no graphic for this specific action -- use default action graphic */
858 if (element_info[i].graphic[act] == -1)
859 element_info[i].graphic[act] =
860 (act_remove ? default_remove_graphic :
861 act_turning ? element_info[i].graphic[ACTION_TURNING] :
862 default_action_graphic);
864 if (element_info[i].crumbled[act] == -1)
865 element_info[i].crumbled[act] = element_info[i].graphic[act];
867 if (element_info[i].crumbled[act] == -1)
868 element_info[i].crumbled[act] =
869 (act_remove ? default_remove_graphic :
870 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
871 default_action_crumbled);
877 /* set animation mode to "none" for each graphic with only 1 frame */
878 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
880 for (act = 0; act < NUM_ACTIONS; act++)
882 int graphic = element_info[i].graphic[act];
883 int crumbled = element_info[i].crumbled[act];
885 if (graphic_info[graphic].anim_frames == 1)
886 graphic_info[graphic].anim_mode = ANIM_NONE;
887 if (graphic_info[crumbled].anim_frames == 1)
888 graphic_info[crumbled].anim_mode = ANIM_NONE;
890 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
892 graphic = element_info[i].direction_graphic[act][dir];
893 crumbled = element_info[i].direction_crumbled[act][dir];
895 if (graphic_info[graphic].anim_frames == 1)
896 graphic_info[graphic].anim_mode = ANIM_NONE;
897 if (graphic_info[crumbled].anim_frames == 1)
898 graphic_info[crumbled].anim_mode = ANIM_NONE;
908 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
911 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
912 element_info[i].token_name, i);
918 void InitElementSpecialGraphicInfo()
920 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
921 int num_property_mappings = getImageListPropertyMappingSize();
924 /* always start with reliable default values */
925 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
926 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
927 element_info[i].special_graphic[j] =
928 element_info[i].graphic[ACTION_DEFAULT];
930 /* initialize special element/graphic mapping from static configuration */
931 for (i = 0; element_to_special_graphic[i].element > -1; i++)
933 int element = element_to_special_graphic[i].element;
934 int special = element_to_special_graphic[i].special;
935 int graphic = element_to_special_graphic[i].graphic;
936 int base_graphic = el2baseimg(element);
937 boolean base_redefined =
938 getImageListEntryFromImageID(base_graphic)->redefined;
939 boolean special_redefined =
940 getImageListEntryFromImageID(graphic)->redefined;
942 /* if the base graphic ("emerald", for example) has been redefined,
943 but not the special graphic ("emerald.EDITOR", for example), do not
944 use an existing (in this case considered obsolete) special graphic
945 anymore, but use the automatically created (down-scaled) graphic */
946 if (base_redefined && !special_redefined)
949 element_info[element].special_graphic[special] = graphic;
952 /* initialize special element/graphic mapping from dynamic configuration */
953 for (i = 0; i < num_property_mappings; i++)
955 int element = property_mapping[i].base_index;
956 int special = property_mapping[i].ext3_index;
957 int graphic = property_mapping[i].artwork_index;
959 if (element >= MAX_NUM_ELEMENTS)
962 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
963 element_info[element].special_graphic[special] = graphic;
967 /* now set all undefined/invalid graphics to default */
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
969 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
970 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
971 element_info[i].special_graphic[j] =
972 element_info[i].graphic[ACTION_DEFAULT];
976 static int get_element_from_token(char *token)
980 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
981 if (strcmp(element_info[i].token_name, token) == 0)
987 static int get_scaled_graphic_width(int graphic)
989 int original_width = getOriginalImageWidthFromImageID(graphic);
990 int scale_up_factor = graphic_info[graphic].scale_up_factor;
992 return original_width * scale_up_factor;
995 static int get_scaled_graphic_height(int graphic)
997 int original_height = getOriginalImageHeightFromImageID(graphic);
998 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1000 return original_height * scale_up_factor;
1003 static void set_graphic_parameters(int graphic, int graphic_copy_from)
1005 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
1006 char **parameter_raw = image->parameter;
1007 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
1008 int parameter[NUM_GFX_ARGS];
1009 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1010 int anim_frames_per_line = 1;
1016 /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
1017 /* if fallback to default artwork is done, also use the default parameters */
1018 if (image->fallback_to_default)
1021 printf("::: FALLBACK for %d\n", graphic_copy_from);
1024 parameter_raw = image->default_parameter;
1029 /* !!! ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
1030 /* (better try to set a "fallback -> use default parameters" flag) */
1033 int len_source_filename = strlen(src_bitmap->source_filename);
1034 int len_default_filename = strlen(image->default_filename);
1035 int pos_basename = len_source_filename - len_default_filename;
1036 char *source_basename = &src_bitmap->source_filename[pos_basename];
1039 printf("::: src_bitmap->source_filename -> '%s'\n",
1040 src_bitmap->source_filename);
1041 printf("::: image->default_filename -> '%s'\n",
1042 image->default_filename);
1043 printf("::: image->filename -> '%s'\n",
1047 /* check if there was a fallback to the default artwork file */
1048 if (strcmp(image->filename, image->default_filename) != 0 &&
1049 pos_basename >= 0 &&
1050 strcmp(source_basename, image->default_filename) == 0)
1051 parameter_raw = image->default_parameter;
1056 /* get integer values from string parameters */
1057 for (i = 0; i < NUM_GFX_ARGS; i++)
1060 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
1061 image_config_suffix[i].type);
1063 if (image_config_suffix[i].type == TYPE_TOKEN)
1064 parameter[i] = get_element_from_token(parameter_raw[i]);
1067 graphic_info[graphic].bitmap = src_bitmap;
1069 /* start with reliable default values */
1070 graphic_info[graphic].src_x = 0;
1071 graphic_info[graphic].src_y = 0;
1072 graphic_info[graphic].width = TILEX;
1073 graphic_info[graphic].height = TILEY;
1074 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1075 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1076 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1077 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1078 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1079 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1080 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1081 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1082 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1083 graphic_info[graphic].anim_delay_fixed = 0;
1084 graphic_info[graphic].anim_delay_random = 0;
1085 graphic_info[graphic].post_delay_fixed = 0;
1086 graphic_info[graphic].post_delay_random = 0;
1088 /* optional x and y tile position of animation frame sequence */
1089 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1090 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1091 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1092 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1094 /* optional x and y pixel position of animation frame sequence */
1095 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1096 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1097 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1098 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1100 /* optional width and height of each animation frame */
1101 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1102 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1103 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1104 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1106 /* optional zoom factor for scaling up the image to a larger size */
1107 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1108 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1109 if (graphic_info[graphic].scale_up_factor < 1)
1110 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1114 /* get final bitmap size (with scaling, but without small images) */
1115 int src_bitmap_width = get_scaled_graphic_width(graphic);
1116 int src_bitmap_height = get_scaled_graphic_height(graphic);
1118 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1119 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1122 /* correct x or y offset dependent of vertical or horizontal frame order */
1123 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1125 graphic_info[graphic].offset_y =
1126 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1127 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1128 anim_frames_per_line = anim_frames_per_col;
1130 else /* frames are ordered horizontally */
1132 graphic_info[graphic].offset_x =
1133 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1134 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1135 anim_frames_per_line = anim_frames_per_row;
1138 /* optionally, the x and y offset of frames can be specified directly */
1139 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1141 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1142 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1144 /* optionally, moving animations may have separate start and end graphics */
1145 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1147 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1148 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1150 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1151 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1152 graphic_info[graphic].offset2_y =
1153 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1154 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1155 else /* frames are ordered horizontally */
1156 graphic_info[graphic].offset2_x =
1157 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1158 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1160 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1161 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1162 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1163 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1164 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1166 /* optionally, the second movement tile can be specified as start tile */
1167 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1168 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1170 /* automatically determine correct number of frames, if not defined */
1171 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1172 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1173 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1174 graphic_info[graphic].anim_frames = anim_frames_per_row;
1175 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1176 graphic_info[graphic].anim_frames = anim_frames_per_col;
1178 graphic_info[graphic].anim_frames = 1;
1180 graphic_info[graphic].anim_frames_per_line =
1181 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1182 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1184 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1185 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1186 graphic_info[graphic].anim_delay = 1;
1188 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1190 if (graphic_info[graphic].anim_frames == 1)
1191 graphic_info[graphic].anim_mode = ANIM_NONE;
1194 /* automatically determine correct start frame, if not defined */
1195 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1196 graphic_info[graphic].anim_start_frame = 0;
1197 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1198 graphic_info[graphic].anim_start_frame =
1199 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1201 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1203 /* animation synchronized with global frame counter, not move position */
1204 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1206 /* optional element for cloning crumble graphics */
1207 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1208 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1210 /* optional element for cloning digging graphics */
1211 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1212 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1214 /* optional border size for "crumbling" diggable graphics */
1215 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1216 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1218 /* this is only used for player "boring" and "sleeping" actions */
1219 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1220 graphic_info[graphic].anim_delay_fixed =
1221 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1222 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1223 graphic_info[graphic].anim_delay_random =
1224 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1225 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1226 graphic_info[graphic].post_delay_fixed =
1227 parameter[GFX_ARG_POST_DELAY_FIXED];
1228 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1229 graphic_info[graphic].post_delay_random =
1230 parameter[GFX_ARG_POST_DELAY_RANDOM];
1232 /* this is only used for toon animations */
1233 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1234 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1236 /* this is only used for drawing font characters */
1237 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1238 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1240 /* this is only used for drawing envelope graphics */
1241 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1244 static void InitGraphicInfo()
1246 int fallback_graphic = IMG_CHAR_EXCLAM;
1247 int num_images = getImageListSize();
1250 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1251 static boolean clipmasks_initialized = FALSE;
1253 XGCValues clip_gc_values;
1254 unsigned long clip_gc_valuemask;
1255 GC copy_clipmask_gc = None;
1258 checked_free(graphic_info);
1260 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1263 printf("::: graphic_info: %d entries\n", num_images);
1266 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1267 if (clipmasks_initialized)
1269 for (i = 0; i < num_images; i++)
1271 if (graphic_info[i].clip_mask)
1272 XFreePixmap(display, graphic_info[i].clip_mask);
1273 if (graphic_info[i].clip_gc)
1274 XFreeGC(display, graphic_info[i].clip_gc);
1276 graphic_info[i].clip_mask = None;
1277 graphic_info[i].clip_gc = None;
1282 for (i = 0; i < num_images; i++)
1286 int first_frame, last_frame;
1287 int src_bitmap_width, src_bitmap_height;
1290 printf("::: image: '%s' [%d]\n", image->token, i);
1294 printf("::: image # %d: '%s' ['%s']\n",
1296 getTokenFromImageID(i));
1299 set_graphic_parameters(i, i);
1301 /* now check if no animation frames are outside of the loaded image */
1303 if (graphic_info[i].bitmap == NULL)
1304 continue; /* skip check for optional images that are undefined */
1306 /* get final bitmap size (with scaling, but without small images) */
1307 src_bitmap_width = get_scaled_graphic_width(i);
1308 src_bitmap_height = get_scaled_graphic_height(i);
1311 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1312 if (src_x < 0 || src_y < 0 ||
1313 src_x + TILEX > src_bitmap_width ||
1314 src_y + TILEY > src_bitmap_height)
1316 Error(ERR_RETURN_LINE, "-");
1317 Error(ERR_RETURN, "warning: error found in config file:");
1318 Error(ERR_RETURN, "- config file: '%s'",
1319 getImageConfigFilename());
1320 Error(ERR_RETURN, "- config token: '%s'",
1321 getTokenFromImageID(i));
1322 Error(ERR_RETURN, "- image file: '%s'",
1323 src_bitmap->source_filename);
1325 "error: first animation frame out of bounds (%d, %d)",
1327 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1330 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1333 if (i == fallback_graphic)
1334 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1336 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1337 Error(ERR_RETURN_LINE, "-");
1339 set_graphic_parameters(i, fallback_graphic);
1342 last_frame = graphic_info[i].anim_frames - 1;
1343 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1344 if (src_x < 0 || src_y < 0 ||
1345 src_x + TILEX > src_bitmap_width ||
1346 src_y + TILEY > src_bitmap_height)
1348 Error(ERR_RETURN_LINE, "-");
1349 Error(ERR_RETURN, "warning: error found in config file:");
1350 Error(ERR_RETURN, "- config file: '%s'",
1351 getImageConfigFilename());
1352 Error(ERR_RETURN, "- config token: '%s'",
1353 getTokenFromImageID(i));
1354 Error(ERR_RETURN, "- image file: '%s'",
1355 src_bitmap->source_filename);
1357 "error: last animation frame (%d) out of bounds (%d, %d)",
1358 last_frame, src_x, src_y);
1359 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1361 if (i == fallback_graphic)
1362 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1364 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1365 Error(ERR_RETURN_LINE, "-");
1367 set_graphic_parameters(i, fallback_graphic);
1370 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1371 /* currently we only need a tile clip mask from the first frame */
1372 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1374 if (copy_clipmask_gc == None)
1376 clip_gc_values.graphics_exposures = False;
1377 clip_gc_valuemask = GCGraphicsExposures;
1378 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1379 clip_gc_valuemask, &clip_gc_values);
1382 graphic_info[i].clip_mask =
1383 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1385 src_pixmap = src_bitmap->clip_mask;
1386 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1387 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1389 clip_gc_values.graphics_exposures = False;
1390 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1391 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1393 graphic_info[i].clip_gc =
1394 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1398 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1399 if (copy_clipmask_gc)
1400 XFreeGC(display, copy_clipmask_gc);
1402 clipmasks_initialized = TRUE;
1406 static void InitElementSoundInfo()
1408 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1409 int num_property_mappings = getSoundListPropertyMappingSize();
1412 /* set values to -1 to identify later as "uninitialized" values */
1413 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1414 for (act = 0; act < NUM_ACTIONS; act++)
1415 element_info[i].sound[act] = -1;
1417 /* initialize element/sound mapping from static configuration */
1418 for (i = 0; element_to_sound[i].element > -1; i++)
1420 int element = element_to_sound[i].element;
1421 int action = element_to_sound[i].action;
1422 int sound = element_to_sound[i].sound;
1423 boolean is_class = element_to_sound[i].is_class;
1426 action = ACTION_DEFAULT;
1429 element_info[element].sound[action] = sound;
1431 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1432 if (strcmp(element_info[j].class_name,
1433 element_info[element].class_name) == 0)
1434 element_info[j].sound[action] = sound;
1437 /* initialize element class/sound mapping from dynamic configuration */
1438 for (i = 0; i < num_property_mappings; i++)
1440 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1441 int action = property_mapping[i].ext1_index;
1442 int sound = property_mapping[i].artwork_index;
1444 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1448 action = ACTION_DEFAULT;
1450 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1451 if (strcmp(element_info[j].class_name,
1452 element_info[element_class].class_name) == 0)
1453 element_info[j].sound[action] = sound;
1456 /* initialize element/sound mapping from dynamic configuration */
1457 for (i = 0; i < num_property_mappings; i++)
1459 int element = property_mapping[i].base_index;
1460 int action = property_mapping[i].ext1_index;
1461 int sound = property_mapping[i].artwork_index;
1463 if (element >= MAX_NUM_ELEMENTS)
1467 action = ACTION_DEFAULT;
1469 element_info[element].sound[action] = sound;
1472 /* now set all '-1' values to element specific default values */
1473 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1475 for (act = 0; act < NUM_ACTIONS; act++)
1477 /* generic default action sound (defined by "[default]" directive) */
1478 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1480 /* look for special default action sound (classic game specific) */
1481 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1482 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1483 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1484 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1485 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1486 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1488 /* !!! there's no such thing as a "default action sound" !!! */
1490 /* look for element specific default sound (independent from action) */
1491 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1492 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1496 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1497 /* !!! make this better !!! */
1498 if (i == EL_EMPTY_SPACE)
1499 default_action_sound = element_info[EL_DEFAULT].sound[act];
1502 /* no sound for this specific action -- use default action sound */
1503 if (element_info[i].sound[act] == -1)
1504 element_info[i].sound[act] = default_action_sound;
1509 static void InitGameModeSoundInfo()
1513 /* set values to -1 to identify later as "uninitialized" values */
1514 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1517 /* initialize gamemode/sound mapping from static configuration */
1518 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1520 int gamemode = gamemode_to_sound[i].gamemode;
1521 int sound = gamemode_to_sound[i].sound;
1524 gamemode = GAME_MODE_DEFAULT;
1526 menu.sound[gamemode] = sound;
1529 /* now set all '-1' values to levelset specific default values */
1530 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1531 if (menu.sound[i] == -1)
1532 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1536 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1537 if (menu.sound[i] != -1)
1538 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1542 static void set_sound_parameters(int sound, char **parameter_raw)
1544 int parameter[NUM_SND_ARGS];
1547 /* get integer values from string parameters */
1548 for (i = 0; i < NUM_SND_ARGS; i++)
1550 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1551 sound_config_suffix[i].type);
1553 /* explicit loop mode setting in configuration overrides default value */
1554 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1555 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1557 /* sound volume to change the original volume when loading the sound file */
1558 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1560 /* sound priority to give certain sounds a higher or lower priority */
1561 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1564 static void InitSoundInfo()
1567 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1568 int num_property_mappings = getSoundListPropertyMappingSize();
1570 int *sound_effect_properties;
1571 int num_sounds = getSoundListSize();
1574 checked_free(sound_info);
1576 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1577 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1579 /* initialize sound effect for all elements to "no sound" */
1580 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1581 for (j = 0; j < NUM_ACTIONS; j++)
1582 element_info[i].sound[j] = SND_UNDEFINED;
1584 for (i = 0; i < num_sounds; i++)
1586 struct FileInfo *sound = getSoundListEntry(i);
1587 int len_effect_text = strlen(sound->token);
1589 sound_effect_properties[i] = ACTION_OTHER;
1590 sound_info[i].loop = FALSE; /* default: play sound only once */
1593 printf("::: sound %d: '%s'\n", i, sound->token);
1596 /* determine all loop sounds and identify certain sound classes */
1598 for (j = 0; element_action_info[j].suffix; j++)
1600 int len_action_text = strlen(element_action_info[j].suffix);
1602 if (len_action_text < len_effect_text &&
1603 strcmp(&sound->token[len_effect_text - len_action_text],
1604 element_action_info[j].suffix) == 0)
1606 sound_effect_properties[i] = element_action_info[j].value;
1607 sound_info[i].loop = element_action_info[j].is_loop_sound;
1614 if (strcmp(sound->token, "custom_42") == 0)
1615 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1618 /* associate elements and some selected sound actions */
1620 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1622 if (element_info[j].class_name)
1624 int len_class_text = strlen(element_info[j].class_name);
1626 if (len_class_text + 1 < len_effect_text &&
1627 strncmp(sound->token,
1628 element_info[j].class_name, len_class_text) == 0 &&
1629 sound->token[len_class_text] == '.')
1631 int sound_action_value = sound_effect_properties[i];
1633 element_info[j].sound[sound_action_value] = i;
1638 set_sound_parameters(i, sound->parameter);
1641 free(sound_effect_properties);
1644 /* !!! now handled in InitElementSoundInfo() !!! */
1645 /* initialize element/sound mapping from dynamic configuration */
1646 for (i = 0; i < num_property_mappings; i++)
1648 int element = property_mapping[i].base_index;
1649 int action = property_mapping[i].ext1_index;
1650 int sound = property_mapping[i].artwork_index;
1653 action = ACTION_DEFAULT;
1655 printf("::: %d: %d, %d, %d ['%s']\n",
1656 i, element, action, sound, element_info[element].token_name);
1658 element_info[element].sound[action] = sound;
1665 int element = EL_CUSTOM_11;
1668 while (element_action_info[j].suffix)
1670 printf("element %d, sound action '%s' == %d\n",
1671 element, element_action_info[j].suffix,
1672 element_info[element].sound[j]);
1677 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1683 int element = EL_SAND;
1684 int sound_action = ACTION_DIGGING;
1687 while (element_action_info[j].suffix)
1689 if (element_action_info[j].value == sound_action)
1690 printf("element %d, sound action '%s' == %d\n",
1691 element, element_action_info[j].suffix,
1692 element_info[element].sound[sound_action]);
1699 static void InitGameModeMusicInfo()
1701 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1702 int num_property_mappings = getMusicListPropertyMappingSize();
1703 int default_levelset_music = -1;
1706 /* set values to -1 to identify later as "uninitialized" values */
1707 for (i = 0; i < MAX_LEVELS; i++)
1708 levelset.music[i] = -1;
1709 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1712 /* initialize gamemode/music mapping from static configuration */
1713 for (i = 0; gamemode_to_music[i].music > -1; i++)
1715 int gamemode = gamemode_to_music[i].gamemode;
1716 int music = gamemode_to_music[i].music;
1719 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1723 gamemode = GAME_MODE_DEFAULT;
1725 menu.music[gamemode] = music;
1728 /* initialize gamemode/music mapping from dynamic configuration */
1729 for (i = 0; i < num_property_mappings; i++)
1731 int prefix = property_mapping[i].base_index;
1732 int gamemode = property_mapping[i].ext1_index;
1733 int level = property_mapping[i].ext2_index;
1734 int music = property_mapping[i].artwork_index;
1737 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1738 prefix, gamemode, level, music);
1741 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1745 gamemode = GAME_MODE_DEFAULT;
1747 /* level specific music only allowed for in-game music */
1748 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1749 gamemode = GAME_MODE_PLAYING;
1754 default_levelset_music = music;
1757 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1758 levelset.music[level] = music;
1759 if (gamemode != GAME_MODE_PLAYING)
1760 menu.music[gamemode] = music;
1763 /* now set all '-1' values to menu specific default values */
1764 /* (undefined values of "levelset.music[]" might stay at "-1" to
1765 allow dynamic selection of music files from music directory!) */
1766 for (i = 0; i < MAX_LEVELS; i++)
1767 if (levelset.music[i] == -1)
1768 levelset.music[i] = default_levelset_music;
1769 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1770 if (menu.music[i] == -1)
1771 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1775 for (i = 0; i < MAX_LEVELS; i++)
1776 if (levelset.music[i] != -1)
1777 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1778 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1779 if (menu.music[i] != -1)
1780 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1784 static void set_music_parameters(int music, char **parameter_raw)
1786 int parameter[NUM_MUS_ARGS];
1789 /* get integer values from string parameters */
1790 for (i = 0; i < NUM_MUS_ARGS; i++)
1792 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1793 music_config_suffix[i].type);
1795 /* explicit loop mode setting in configuration overrides default value */
1796 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1797 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1800 static void InitMusicInfo()
1802 int num_music = getMusicListSize();
1805 checked_free(music_info);
1807 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1809 for (i = 0; i < num_music; i++)
1811 struct FileInfo *music = getMusicListEntry(i);
1812 int len_music_text = strlen(music->token);
1814 music_info[i].loop = TRUE; /* default: play music in loop mode */
1816 /* determine all loop music */
1818 for (j = 0; music_prefix_info[j].prefix; j++)
1820 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1822 if (len_prefix_text < len_music_text &&
1823 strncmp(music->token,
1824 music_prefix_info[j].prefix, len_prefix_text) == 0)
1826 music_info[i].loop = music_prefix_info[j].is_loop_music;
1832 set_music_parameters(i, music->parameter);
1836 static void ReinitializeGraphics()
1838 InitGraphicInfo(); /* graphic properties mapping */
1839 InitElementGraphicInfo(); /* element game graphic mapping */
1840 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1842 InitElementSmallImages(); /* scale images to all needed sizes */
1843 InitFontGraphicInfo(); /* initialize text drawing functions */
1845 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1847 SetMainBackgroundImage(IMG_BACKGROUND);
1848 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1854 static void ReinitializeSounds()
1856 InitSoundInfo(); /* sound properties mapping */
1857 InitElementSoundInfo(); /* element game sound mapping */
1858 InitGameModeSoundInfo(); /* game mode sound mapping */
1860 InitPlayLevelSound(); /* internal game sound settings */
1863 static void ReinitializeMusic()
1865 InitMusicInfo(); /* music properties mapping */
1866 InitGameModeMusicInfo(); /* game mode music mapping */
1869 static int get_special_property_bit(int element, int property_bit_nr)
1871 struct PropertyBitInfo
1877 static struct PropertyBitInfo pb_can_move_into_acid[] =
1879 /* the player may be able fall into acid when gravity is activated */
1884 { EL_SP_MURPHY, 0 },
1885 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1887 /* all element that can move may be able to also move into acid */
1890 { EL_BUG_RIGHT, 1 },
1893 { EL_SPACESHIP, 2 },
1894 { EL_SPACESHIP_LEFT, 2 },
1895 { EL_SPACESHIP_RIGHT, 2 },
1896 { EL_SPACESHIP_UP, 2 },
1897 { EL_SPACESHIP_DOWN, 2 },
1898 { EL_BD_BUTTERFLY, 3 },
1899 { EL_BD_BUTTERFLY_LEFT, 3 },
1900 { EL_BD_BUTTERFLY_RIGHT, 3 },
1901 { EL_BD_BUTTERFLY_UP, 3 },
1902 { EL_BD_BUTTERFLY_DOWN, 3 },
1903 { EL_BD_FIREFLY, 4 },
1904 { EL_BD_FIREFLY_LEFT, 4 },
1905 { EL_BD_FIREFLY_RIGHT, 4 },
1906 { EL_BD_FIREFLY_UP, 4 },
1907 { EL_BD_FIREFLY_DOWN, 4 },
1909 { EL_DARK_YAMYAM, 6 },
1912 { EL_PACMAN_LEFT, 8 },
1913 { EL_PACMAN_RIGHT, 8 },
1914 { EL_PACMAN_UP, 8 },
1915 { EL_PACMAN_DOWN, 8 },
1917 { EL_MOLE_LEFT, 9 },
1918 { EL_MOLE_RIGHT, 9 },
1920 { EL_MOLE_DOWN, 9 },
1924 { EL_SATELLITE, 13 },
1925 { EL_SP_SNIKSNAK, 14 },
1926 { EL_SP_ELECTRON, 15 },
1933 static struct PropertyBitInfo pb_dont_collide_with[] =
1935 { EL_SP_SNIKSNAK, 0 },
1936 { EL_SP_ELECTRON, 1 },
1944 struct PropertyBitInfo *pb_info;
1947 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1948 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1953 struct PropertyBitInfo *pb_info = NULL;
1956 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1957 if (pb_definition[i].bit_nr == property_bit_nr)
1958 pb_info = pb_definition[i].pb_info;
1960 if (pb_info == NULL)
1963 for (i = 0; pb_info[i].element != -1; i++)
1964 if (pb_info[i].element == element)
1965 return pb_info[i].bit_nr;
1971 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1972 boolean property_value)
1974 int bit_nr = get_special_property_bit(element, property_bit_nr);
1979 *bitfield |= (1 << bit_nr);
1981 *bitfield &= ~(1 << bit_nr);
1985 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1987 int bit_nr = get_special_property_bit(element, property_bit_nr);
1990 return ((*bitfield & (1 << bit_nr)) != 0);
1997 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1999 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
2003 level->can_move_into_acid_bits &= ~(1 << bit_nr);
2006 level->can_move_into_acid_bits |= (1 << bit_nr);
2010 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
2012 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
2015 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
2021 void InitElementPropertiesStatic()
2023 static int ep_diggable[] =
2028 EL_SP_BUGGY_BASE_ACTIVATING,
2031 EL_INVISIBLE_SAND_ACTIVE,
2034 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2035 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2039 EL_SP_BUGGY_BASE_ACTIVE,
2045 static int ep_collectible_only[] =
2066 EL_DYNABOMB_INCREASE_NUMBER,
2067 EL_DYNABOMB_INCREASE_SIZE,
2068 EL_DYNABOMB_INCREASE_POWER,
2087 static int ep_dont_run_into[] =
2089 /* same elements as in 'ep_dont_touch' */
2095 /* same elements as in 'ep_dont_collide_with' */
2107 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2111 EL_SP_BUGGY_BASE_ACTIVE,
2117 static int ep_dont_collide_with[] =
2119 /* same elements as in 'ep_dont_touch' */
2135 static int ep_dont_touch[] =
2144 static int ep_indestructible[] =
2148 EL_ACID_POOL_TOPLEFT,
2149 EL_ACID_POOL_TOPRIGHT,
2150 EL_ACID_POOL_BOTTOMLEFT,
2151 EL_ACID_POOL_BOTTOM,
2152 EL_ACID_POOL_BOTTOMRIGHT,
2153 EL_SP_HARDWARE_GRAY,
2154 EL_SP_HARDWARE_GREEN,
2155 EL_SP_HARDWARE_BLUE,
2157 EL_SP_HARDWARE_YELLOW,
2158 EL_SP_HARDWARE_BASE_1,
2159 EL_SP_HARDWARE_BASE_2,
2160 EL_SP_HARDWARE_BASE_3,
2161 EL_SP_HARDWARE_BASE_4,
2162 EL_SP_HARDWARE_BASE_5,
2163 EL_SP_HARDWARE_BASE_6,
2164 EL_INVISIBLE_STEELWALL,
2165 EL_INVISIBLE_STEELWALL_ACTIVE,
2166 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2167 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2168 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2169 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2170 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2171 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2172 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2173 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2174 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2175 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2176 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2177 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2179 EL_LIGHT_SWITCH_ACTIVE,
2180 EL_SIGN_EXCLAMATION,
2181 EL_SIGN_RADIOACTIVITY,
2192 EL_STEELWALL_SLIPPERY,
2223 EL_SWITCHGATE_OPENING,
2224 EL_SWITCHGATE_CLOSED,
2225 EL_SWITCHGATE_CLOSING,
2227 EL_SWITCHGATE_SWITCH_UP,
2228 EL_SWITCHGATE_SWITCH_DOWN,
2231 EL_TIMEGATE_OPENING,
2233 EL_TIMEGATE_CLOSING,
2236 EL_TIMEGATE_SWITCH_ACTIVE,
2241 EL_TUBE_VERTICAL_LEFT,
2242 EL_TUBE_VERTICAL_RIGHT,
2243 EL_TUBE_HORIZONTAL_UP,
2244 EL_TUBE_HORIZONTAL_DOWN,
2252 static int ep_slippery[] =
2266 EL_ROBOT_WHEEL_ACTIVE,
2272 EL_ACID_POOL_TOPLEFT,
2273 EL_ACID_POOL_TOPRIGHT,
2283 EL_STEELWALL_SLIPPERY,
2286 EL_EMC_WALL_SLIPPERY_1,
2287 EL_EMC_WALL_SLIPPERY_2,
2288 EL_EMC_WALL_SLIPPERY_3,
2289 EL_EMC_WALL_SLIPPERY_4,
2293 static int ep_can_change[] =
2298 static int ep_can_move[] =
2300 /* same elements as in 'pb_can_move_into_acid' */
2322 static int ep_can_fall[] =
2337 EL_BD_MAGIC_WALL_FULL,
2350 static int ep_can_smash_player[] =
2375 static int ep_can_smash_enemies[] =
2383 static int ep_can_smash_everything[] =
2391 static int ep_explodes_by_fire[] =
2393 /* same elements as in 'ep_explodes_impact' */
2398 /* same elements as in 'ep_explodes_smashed' */
2407 EL_DYNABOMB_PLAYER_1_ACTIVE,
2408 EL_DYNABOMB_PLAYER_2_ACTIVE,
2409 EL_DYNABOMB_PLAYER_3_ACTIVE,
2410 EL_DYNABOMB_PLAYER_4_ACTIVE,
2411 EL_DYNABOMB_INCREASE_NUMBER,
2412 EL_DYNABOMB_INCREASE_SIZE,
2413 EL_DYNABOMB_INCREASE_POWER,
2414 EL_SP_DISK_RED_ACTIVE,
2427 static int ep_explodes_smashed[] =
2429 /* same elements as in 'ep_explodes_impact' */
2442 static int ep_explodes_impact[] =
2450 static int ep_walkable_over[] =
2454 EL_SOKOBAN_FIELD_EMPTY,
2472 static int ep_walkable_inside[] =
2477 EL_TUBE_VERTICAL_LEFT,
2478 EL_TUBE_VERTICAL_RIGHT,
2479 EL_TUBE_HORIZONTAL_UP,
2480 EL_TUBE_HORIZONTAL_DOWN,
2488 static int ep_walkable_under[] =
2493 static int ep_passable_over[] =
2516 static int ep_passable_inside[] =
2522 EL_SP_PORT_HORIZONTAL,
2523 EL_SP_PORT_VERTICAL,
2525 EL_SP_GRAVITY_PORT_LEFT,
2526 EL_SP_GRAVITY_PORT_RIGHT,
2527 EL_SP_GRAVITY_PORT_UP,
2528 EL_SP_GRAVITY_PORT_DOWN,
2529 EL_SP_GRAVITY_ON_PORT_LEFT,
2530 EL_SP_GRAVITY_ON_PORT_RIGHT,
2531 EL_SP_GRAVITY_ON_PORT_UP,
2532 EL_SP_GRAVITY_ON_PORT_DOWN,
2533 EL_SP_GRAVITY_OFF_PORT_LEFT,
2534 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2535 EL_SP_GRAVITY_OFF_PORT_UP,
2536 EL_SP_GRAVITY_OFF_PORT_DOWN,
2540 static int ep_passable_under[] =
2545 static int ep_droppable[] =
2550 static int ep_explodes_1x1_old[] =
2555 static int ep_pushable[] =
2567 EL_SOKOBAN_FIELD_FULL,
2575 static int ep_explodes_cross_old[] =
2580 static int ep_protected[] =
2582 /* same elements as in 'ep_walkable_inside' */
2586 EL_TUBE_VERTICAL_LEFT,
2587 EL_TUBE_VERTICAL_RIGHT,
2588 EL_TUBE_HORIZONTAL_UP,
2589 EL_TUBE_HORIZONTAL_DOWN,
2595 /* same elements as in 'ep_passable_over' */
2615 /* same elements as in 'ep_passable_inside' */
2620 EL_SP_PORT_HORIZONTAL,
2621 EL_SP_PORT_VERTICAL,
2623 EL_SP_GRAVITY_PORT_LEFT,
2624 EL_SP_GRAVITY_PORT_RIGHT,
2625 EL_SP_GRAVITY_PORT_UP,
2626 EL_SP_GRAVITY_PORT_DOWN,
2627 EL_SP_GRAVITY_ON_PORT_LEFT,
2628 EL_SP_GRAVITY_ON_PORT_RIGHT,
2629 EL_SP_GRAVITY_ON_PORT_UP,
2630 EL_SP_GRAVITY_ON_PORT_DOWN,
2631 EL_SP_GRAVITY_OFF_PORT_LEFT,
2632 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2633 EL_SP_GRAVITY_OFF_PORT_UP,
2634 EL_SP_GRAVITY_OFF_PORT_DOWN,
2638 static int ep_throwable[] =
2643 static int ep_can_explode[] =
2645 /* same elements as in 'ep_explodes_impact' */
2650 /* same elements as in 'ep_explodes_smashed' */
2656 /* elements that can explode by explosion or by dragonfire */
2659 EL_DYNABOMB_PLAYER_1_ACTIVE,
2660 EL_DYNABOMB_PLAYER_2_ACTIVE,
2661 EL_DYNABOMB_PLAYER_3_ACTIVE,
2662 EL_DYNABOMB_PLAYER_4_ACTIVE,
2663 EL_DYNABOMB_INCREASE_NUMBER,
2664 EL_DYNABOMB_INCREASE_SIZE,
2665 EL_DYNABOMB_INCREASE_POWER,
2666 EL_SP_DISK_RED_ACTIVE,
2674 /* elements that can explode only by explosion */
2679 static int ep_gravity_reachable[] =
2685 EL_INVISIBLE_SAND_ACTIVE,
2690 EL_SP_PORT_HORIZONTAL,
2691 EL_SP_PORT_VERTICAL,
2693 EL_SP_GRAVITY_PORT_LEFT,
2694 EL_SP_GRAVITY_PORT_RIGHT,
2695 EL_SP_GRAVITY_PORT_UP,
2696 EL_SP_GRAVITY_PORT_DOWN,
2697 EL_SP_GRAVITY_ON_PORT_LEFT,
2698 EL_SP_GRAVITY_ON_PORT_RIGHT,
2699 EL_SP_GRAVITY_ON_PORT_UP,
2700 EL_SP_GRAVITY_ON_PORT_DOWN,
2701 EL_SP_GRAVITY_OFF_PORT_LEFT,
2702 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2703 EL_SP_GRAVITY_OFF_PORT_UP,
2704 EL_SP_GRAVITY_OFF_PORT_DOWN,
2709 static int ep_player[] =
2716 EL_SOKOBAN_FIELD_PLAYER,
2721 static int ep_can_pass_magic_wall[] =
2734 static int ep_switchable[] =
2738 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2739 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2740 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2741 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2742 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2743 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2744 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2745 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2746 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2747 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2748 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2749 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2750 EL_SWITCHGATE_SWITCH_UP,
2751 EL_SWITCHGATE_SWITCH_DOWN,
2753 EL_LIGHT_SWITCH_ACTIVE,
2755 EL_BALLOON_SWITCH_LEFT,
2756 EL_BALLOON_SWITCH_RIGHT,
2757 EL_BALLOON_SWITCH_UP,
2758 EL_BALLOON_SWITCH_DOWN,
2759 EL_BALLOON_SWITCH_ANY,
2762 EL_EMC_MAGIC_BALL_SWITCH,
2766 static int ep_bd_element[] =
2799 static int ep_sp_element[] =
2801 /* should always be valid */
2804 /* standard classic Supaplex elements */
2811 EL_SP_HARDWARE_GRAY,
2819 EL_SP_GRAVITY_PORT_RIGHT,
2820 EL_SP_GRAVITY_PORT_DOWN,
2821 EL_SP_GRAVITY_PORT_LEFT,
2822 EL_SP_GRAVITY_PORT_UP,
2827 EL_SP_PORT_VERTICAL,
2828 EL_SP_PORT_HORIZONTAL,
2834 EL_SP_HARDWARE_BASE_1,
2835 EL_SP_HARDWARE_GREEN,
2836 EL_SP_HARDWARE_BLUE,
2838 EL_SP_HARDWARE_YELLOW,
2839 EL_SP_HARDWARE_BASE_2,
2840 EL_SP_HARDWARE_BASE_3,
2841 EL_SP_HARDWARE_BASE_4,
2842 EL_SP_HARDWARE_BASE_5,
2843 EL_SP_HARDWARE_BASE_6,
2847 /* additional elements that appeared in newer Supaplex levels */
2850 /* additional gravity port elements (not switching, but setting gravity) */
2851 EL_SP_GRAVITY_ON_PORT_LEFT,
2852 EL_SP_GRAVITY_ON_PORT_RIGHT,
2853 EL_SP_GRAVITY_ON_PORT_UP,
2854 EL_SP_GRAVITY_ON_PORT_DOWN,
2855 EL_SP_GRAVITY_OFF_PORT_LEFT,
2856 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2857 EL_SP_GRAVITY_OFF_PORT_UP,
2858 EL_SP_GRAVITY_OFF_PORT_DOWN,
2860 /* more than one Murphy in a level results in an inactive clone */
2863 /* runtime Supaplex elements */
2864 EL_SP_DISK_RED_ACTIVE,
2865 EL_SP_TERMINAL_ACTIVE,
2866 EL_SP_BUGGY_BASE_ACTIVATING,
2867 EL_SP_BUGGY_BASE_ACTIVE,
2873 static int ep_sb_element[] =
2878 EL_SOKOBAN_FIELD_EMPTY,
2879 EL_SOKOBAN_FIELD_FULL,
2880 EL_SOKOBAN_FIELD_PLAYER,
2885 EL_INVISIBLE_STEELWALL,
2889 static int ep_gem[] =
2900 static int ep_food_dark_yamyam[] =
2927 static int ep_food_penguin[] =
2940 static int ep_food_pig[] =
2951 static int ep_historic_wall[] =
2976 EL_EXPANDABLE_WALL_HORIZONTAL,
2977 EL_EXPANDABLE_WALL_VERTICAL,
2978 EL_EXPANDABLE_WALL_ANY,
2979 EL_EXPANDABLE_WALL_GROWING,
2986 EL_SP_HARDWARE_GRAY,
2987 EL_SP_HARDWARE_GREEN,
2988 EL_SP_HARDWARE_BLUE,
2990 EL_SP_HARDWARE_YELLOW,
2991 EL_SP_HARDWARE_BASE_1,
2992 EL_SP_HARDWARE_BASE_2,
2993 EL_SP_HARDWARE_BASE_3,
2994 EL_SP_HARDWARE_BASE_4,
2995 EL_SP_HARDWARE_BASE_5,
2996 EL_SP_HARDWARE_BASE_6,
2998 EL_SP_TERMINAL_ACTIVE,
3001 EL_INVISIBLE_STEELWALL,
3002 EL_INVISIBLE_STEELWALL_ACTIVE,
3004 EL_INVISIBLE_WALL_ACTIVE,
3005 EL_STEELWALL_SLIPPERY,
3021 static int ep_historic_solid[] =
3025 EL_EXPANDABLE_WALL_HORIZONTAL,
3026 EL_EXPANDABLE_WALL_VERTICAL,
3027 EL_EXPANDABLE_WALL_ANY,
3040 EL_QUICKSAND_FILLING,
3041 EL_QUICKSAND_EMPTYING,
3043 EL_MAGIC_WALL_ACTIVE,
3044 EL_MAGIC_WALL_EMPTYING,
3045 EL_MAGIC_WALL_FILLING,
3049 EL_BD_MAGIC_WALL_ACTIVE,
3050 EL_BD_MAGIC_WALL_EMPTYING,
3051 EL_BD_MAGIC_WALL_FULL,
3052 EL_BD_MAGIC_WALL_FILLING,
3053 EL_BD_MAGIC_WALL_DEAD,
3062 EL_SP_TERMINAL_ACTIVE,
3066 EL_INVISIBLE_WALL_ACTIVE,
3067 EL_SWITCHGATE_SWITCH_UP,
3068 EL_SWITCHGATE_SWITCH_DOWN,
3070 EL_TIMEGATE_SWITCH_ACTIVE,
3082 /* the following elements are a direct copy of "indestructible" elements,
3083 except "EL_ACID", which is "indestructible", but not "solid"! */
3088 EL_ACID_POOL_TOPLEFT,
3089 EL_ACID_POOL_TOPRIGHT,
3090 EL_ACID_POOL_BOTTOMLEFT,
3091 EL_ACID_POOL_BOTTOM,
3092 EL_ACID_POOL_BOTTOMRIGHT,
3093 EL_SP_HARDWARE_GRAY,
3094 EL_SP_HARDWARE_GREEN,
3095 EL_SP_HARDWARE_BLUE,
3097 EL_SP_HARDWARE_YELLOW,
3098 EL_SP_HARDWARE_BASE_1,
3099 EL_SP_HARDWARE_BASE_2,
3100 EL_SP_HARDWARE_BASE_3,
3101 EL_SP_HARDWARE_BASE_4,
3102 EL_SP_HARDWARE_BASE_5,
3103 EL_SP_HARDWARE_BASE_6,
3104 EL_INVISIBLE_STEELWALL,
3105 EL_INVISIBLE_STEELWALL_ACTIVE,
3106 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3107 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3108 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3109 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3110 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3111 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3112 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3113 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3114 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3115 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3116 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3117 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3119 EL_LIGHT_SWITCH_ACTIVE,
3120 EL_SIGN_EXCLAMATION,
3121 EL_SIGN_RADIOACTIVITY,
3132 EL_STEELWALL_SLIPPERY,
3155 EL_SWITCHGATE_OPENING,
3156 EL_SWITCHGATE_CLOSED,
3157 EL_SWITCHGATE_CLOSING,
3159 EL_TIMEGATE_OPENING,
3161 EL_TIMEGATE_CLOSING,
3165 EL_TUBE_VERTICAL_LEFT,
3166 EL_TUBE_VERTICAL_RIGHT,
3167 EL_TUBE_HORIZONTAL_UP,
3168 EL_TUBE_HORIZONTAL_DOWN,
3176 static int ep_classic_enemy[] =
3192 static int ep_belt[] =
3194 EL_CONVEYOR_BELT_1_LEFT,
3195 EL_CONVEYOR_BELT_1_MIDDLE,
3196 EL_CONVEYOR_BELT_1_RIGHT,
3197 EL_CONVEYOR_BELT_2_LEFT,
3198 EL_CONVEYOR_BELT_2_MIDDLE,
3199 EL_CONVEYOR_BELT_2_RIGHT,
3200 EL_CONVEYOR_BELT_3_LEFT,
3201 EL_CONVEYOR_BELT_3_MIDDLE,
3202 EL_CONVEYOR_BELT_3_RIGHT,
3203 EL_CONVEYOR_BELT_4_LEFT,
3204 EL_CONVEYOR_BELT_4_MIDDLE,
3205 EL_CONVEYOR_BELT_4_RIGHT,
3209 static int ep_belt_active[] =
3211 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3212 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3213 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3214 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3215 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3216 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3217 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3218 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3219 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3220 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3221 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3222 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3226 static int ep_belt_switch[] =
3228 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3229 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3230 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3231 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3232 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3233 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3234 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3235 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3236 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3237 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3238 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3239 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3243 static int ep_tube[] =
3250 EL_TUBE_HORIZONTAL_UP,
3251 EL_TUBE_HORIZONTAL_DOWN,
3253 EL_TUBE_VERTICAL_LEFT,
3254 EL_TUBE_VERTICAL_RIGHT,
3259 static int ep_keygate[] =
3288 static int ep_amoeboid[] =
3298 static int ep_amoebalive[] =
3307 static int ep_has_content[] =
3317 static int ep_can_turn_each_move[] =
3319 /* !!! do something with this one !!! */
3323 static int ep_can_grow[] =
3335 static int ep_active_bomb[] =
3338 EL_DYNABOMB_PLAYER_1_ACTIVE,
3339 EL_DYNABOMB_PLAYER_2_ACTIVE,
3340 EL_DYNABOMB_PLAYER_3_ACTIVE,
3341 EL_DYNABOMB_PLAYER_4_ACTIVE,
3342 EL_SP_DISK_RED_ACTIVE,
3346 static int ep_inactive[] =
3395 EL_INVISIBLE_STEELWALL,
3403 EL_WALL_EMERALD_YELLOW,
3404 EL_DYNABOMB_INCREASE_NUMBER,
3405 EL_DYNABOMB_INCREASE_SIZE,
3406 EL_DYNABOMB_INCREASE_POWER,
3410 EL_SOKOBAN_FIELD_EMPTY,
3411 EL_SOKOBAN_FIELD_FULL,
3412 EL_WALL_EMERALD_RED,
3413 EL_WALL_EMERALD_PURPLE,
3414 EL_ACID_POOL_TOPLEFT,
3415 EL_ACID_POOL_TOPRIGHT,
3416 EL_ACID_POOL_BOTTOMLEFT,
3417 EL_ACID_POOL_BOTTOM,
3418 EL_ACID_POOL_BOTTOMRIGHT,
3422 EL_BD_MAGIC_WALL_DEAD,
3423 EL_AMOEBA_TO_DIAMOND,
3431 EL_SP_GRAVITY_PORT_RIGHT,
3432 EL_SP_GRAVITY_PORT_DOWN,
3433 EL_SP_GRAVITY_PORT_LEFT,
3434 EL_SP_GRAVITY_PORT_UP,
3435 EL_SP_PORT_HORIZONTAL,
3436 EL_SP_PORT_VERTICAL,
3447 EL_SP_HARDWARE_GRAY,
3448 EL_SP_HARDWARE_GREEN,
3449 EL_SP_HARDWARE_BLUE,
3451 EL_SP_HARDWARE_YELLOW,
3452 EL_SP_HARDWARE_BASE_1,
3453 EL_SP_HARDWARE_BASE_2,
3454 EL_SP_HARDWARE_BASE_3,
3455 EL_SP_HARDWARE_BASE_4,
3456 EL_SP_HARDWARE_BASE_5,
3457 EL_SP_HARDWARE_BASE_6,
3458 EL_SP_GRAVITY_ON_PORT_LEFT,
3459 EL_SP_GRAVITY_ON_PORT_RIGHT,
3460 EL_SP_GRAVITY_ON_PORT_UP,
3461 EL_SP_GRAVITY_ON_PORT_DOWN,
3462 EL_SP_GRAVITY_OFF_PORT_LEFT,
3463 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3464 EL_SP_GRAVITY_OFF_PORT_UP,
3465 EL_SP_GRAVITY_OFF_PORT_DOWN,
3466 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3467 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3468 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3469 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3470 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3471 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3472 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3473 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3474 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3475 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3476 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3477 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3478 EL_SIGN_EXCLAMATION,
3479 EL_SIGN_RADIOACTIVITY,
3490 EL_STEELWALL_SLIPPERY,
3495 EL_EMC_WALL_SLIPPERY_1,
3496 EL_EMC_WALL_SLIPPERY_2,
3497 EL_EMC_WALL_SLIPPERY_3,
3498 EL_EMC_WALL_SLIPPERY_4,
3518 static int ep_em_slippery_wall[] =
3523 static int ep_gfx_crumbled[] =
3536 } element_properties[] =
3538 { ep_diggable, EP_DIGGABLE },
3539 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3540 { ep_dont_run_into, EP_DONT_RUN_INTO },
3541 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3542 { ep_dont_touch, EP_DONT_TOUCH },
3543 { ep_indestructible, EP_INDESTRUCTIBLE },
3544 { ep_slippery, EP_SLIPPERY },
3545 { ep_can_change, EP_CAN_CHANGE },
3546 { ep_can_move, EP_CAN_MOVE },
3547 { ep_can_fall, EP_CAN_FALL },
3548 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3549 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3550 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3551 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3552 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3553 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3554 { ep_walkable_over, EP_WALKABLE_OVER },
3555 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3556 { ep_walkable_under, EP_WALKABLE_UNDER },
3557 { ep_passable_over, EP_PASSABLE_OVER },
3558 { ep_passable_inside, EP_PASSABLE_INSIDE },
3559 { ep_passable_under, EP_PASSABLE_UNDER },
3560 { ep_droppable, EP_DROPPABLE },
3561 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3562 { ep_pushable, EP_PUSHABLE },
3563 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3564 { ep_protected, EP_PROTECTED },
3565 { ep_throwable, EP_THROWABLE },
3566 { ep_can_explode, EP_CAN_EXPLODE },
3567 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3569 { ep_player, EP_PLAYER },
3570 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3571 { ep_switchable, EP_SWITCHABLE },
3572 { ep_bd_element, EP_BD_ELEMENT },
3573 { ep_sp_element, EP_SP_ELEMENT },
3574 { ep_sb_element, EP_SB_ELEMENT },
3576 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3577 { ep_food_penguin, EP_FOOD_PENGUIN },
3578 { ep_food_pig, EP_FOOD_PIG },
3579 { ep_historic_wall, EP_HISTORIC_WALL },
3580 { ep_historic_solid, EP_HISTORIC_SOLID },
3581 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3582 { ep_belt, EP_BELT },
3583 { ep_belt_active, EP_BELT_ACTIVE },
3584 { ep_belt_switch, EP_BELT_SWITCH },
3585 { ep_tube, EP_TUBE },
3586 { ep_keygate, EP_KEYGATE },
3587 { ep_amoeboid, EP_AMOEBOID },
3588 { ep_amoebalive, EP_AMOEBALIVE },
3589 { ep_has_content, EP_HAS_CONTENT },
3590 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3591 { ep_can_grow, EP_CAN_GROW },
3592 { ep_active_bomb, EP_ACTIVE_BOMB },
3593 { ep_inactive, EP_INACTIVE },
3595 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3597 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3602 static int copy_properties[][5] =
3606 EL_BUG_LEFT, EL_BUG_RIGHT,
3607 EL_BUG_UP, EL_BUG_DOWN
3611 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3612 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3616 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3617 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3621 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3622 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3626 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3627 EL_PACMAN_UP, EL_PACMAN_DOWN
3631 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3632 EL_MOLE_UP, EL_MOLE_DOWN
3642 /* always start with reliable default values (element has no properties) */
3643 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3644 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3645 SET_PROPERTY(i, j, FALSE);
3647 /* set all base element properties from above array definitions */
3648 for (i = 0; element_properties[i].elements != NULL; i++)
3649 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3650 SET_PROPERTY((element_properties[i].elements)[j],
3651 element_properties[i].property, TRUE);
3653 /* copy properties to some elements that are only stored in level file */
3654 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3655 for (j = 0; copy_properties[j][0] != -1; j++)
3656 if (HAS_PROPERTY(copy_properties[j][0], i))
3657 for (k = 1; k <= 4; k++)
3658 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3661 void InitElementPropertiesEngine(int engine_version)
3664 static int active_properties[] =
3669 EP_DONT_COLLIDE_WITH,
3673 EP_CAN_PASS_MAGIC_WALL,
3678 EP_EXPLODES_BY_FIRE,
3691 EP_EM_SLIPPERY_WALL,
3695 static int no_wall_properties[] =
3698 EP_COLLECTIBLE_ONLY,
3700 EP_DONT_COLLIDE_WITH,
3703 EP_CAN_SMASH_PLAYER,
3704 EP_CAN_SMASH_ENEMIES,
3705 EP_CAN_SMASH_EVERYTHING,
3710 EP_FOOD_DARK_YAMYAM,
3727 InitElementPropertiesStatic();
3730 /* important: after initialization in InitElementPropertiesStatic(), the
3731 elements are not again initialized to a default value; therefore all
3732 changes have to make sure that they leave the element with a defined
3733 property (which means that conditional property changes must be set to
3734 a reliable default value before) */
3736 /* set all special, combined or engine dependent element properties */
3737 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3740 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3741 SET_PROPERTY(i, j, FALSE);
3744 /* ---------- INACTIVE ------------------------------------------------- */
3745 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3747 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3748 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3749 IS_WALKABLE_INSIDE(i) ||
3750 IS_WALKABLE_UNDER(i)));
3752 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3753 IS_PASSABLE_INSIDE(i) ||
3754 IS_PASSABLE_UNDER(i)));
3756 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3757 IS_PASSABLE_OVER(i)));
3759 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3760 IS_PASSABLE_INSIDE(i)));
3762 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3763 IS_PASSABLE_UNDER(i)));
3765 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3768 /* ---------- COLLECTIBLE ---------------------------------------------- */
3769 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3773 /* ---------- SNAPPABLE ------------------------------------------------ */
3774 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3775 IS_COLLECTIBLE(i) ||
3779 /* ---------- WALL ----------------------------------------------------- */
3780 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3782 for (j = 0; no_wall_properties[j] != -1; j++)
3783 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3784 i >= EL_FIRST_RUNTIME_UNREAL)
3785 SET_PROPERTY(i, EP_WALL, FALSE);
3787 if (IS_HISTORIC_WALL(i))
3788 SET_PROPERTY(i, EP_WALL, TRUE);
3790 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3791 if (engine_version < VERSION_IDENT(2,2,0,0))
3792 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3794 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3796 !IS_COLLECTIBLE(i)));
3799 /* ---------- PROTECTED ------------------------------------------------ */
3800 if (IS_ACCESSIBLE_INSIDE(i))
3801 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3804 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3806 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3807 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3809 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3810 IS_INDESTRUCTIBLE(i)));
3812 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3814 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3815 else if (engine_version < VERSION_IDENT(2,2,0,0))
3816 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3819 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3824 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3825 !IS_WALKABLE_OVER(i) &&
3826 !IS_WALKABLE_UNDER(i)));
3828 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3833 if (IS_CUSTOM_ELEMENT(i))
3835 /* these are additional properties which are initially false when set */
3837 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3839 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3840 if (DONT_COLLIDE_WITH(i))
3841 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3843 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3844 if (CAN_SMASH_EVERYTHING(i))
3845 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3846 if (CAN_SMASH_ENEMIES(i))
3847 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3850 /* ---------- CAN_SMASH ------------------------------------------------ */
3851 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3852 CAN_SMASH_ENEMIES(i) ||
3853 CAN_SMASH_EVERYTHING(i)));
3856 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3857 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3858 CAN_EXPLODE_SMASHED(i) ||
3859 CAN_EXPLODE_IMPACT(i)));
3863 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3865 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3866 !CAN_EXPLODE_CROSS(i)));
3868 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3869 !CAN_EXPLODE_1X1(i) &&
3870 !CAN_EXPLODE_CROSS(i)));
3874 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3875 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3876 EXPLODES_BY_FIRE(i)));
3878 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3879 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3880 EXPLODES_SMASHED(i)));
3882 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3883 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3884 EXPLODES_IMPACT(i)));
3886 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3887 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3889 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3890 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3891 i == EL_BLACK_ORB));
3893 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3894 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3896 IS_CUSTOM_ELEMENT(i)));
3898 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3899 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3900 i == EL_SP_ELECTRON));
3902 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3903 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3904 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3905 getMoveIntoAcidProperty(&level, i));
3907 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3908 if (MAYBE_DONT_COLLIDE_WITH(i))
3909 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3910 getDontCollideWithProperty(&level, i));
3912 /* ---------- SP_PORT -------------------------------------------------- */
3913 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3914 IS_PASSABLE_INSIDE(i)));
3916 /* ---------- CAN_CHANGE ----------------------------------------------- */
3917 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3918 for (j = 0; j < element_info[i].num_change_pages; j++)
3919 if (element_info[i].change_page[j].can_change)
3920 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3922 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3924 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3925 element_info[i].crumbled[ACTION_DEFAULT] !=
3926 element_info[i].graphic[ACTION_DEFAULT]);
3928 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3929 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3930 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3935 /* determine inactive elements (used for engine main loop optimization) */
3936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3938 boolean active = FALSE;
3940 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3942 if (HAS_PROPERTY(i, j))
3948 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3953 /* dynamically adjust element properties according to game engine version */
3955 static int ep_em_slippery_wall[] =
3960 EL_EXPANDABLE_WALL_HORIZONTAL,
3961 EL_EXPANDABLE_WALL_VERTICAL,
3962 EL_EXPANDABLE_WALL_ANY,
3966 /* special EM style gems behaviour */
3967 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3968 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3969 level.em_slippery_gems);
3971 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3972 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3973 (level.em_slippery_gems &&
3974 engine_version > VERSION_IDENT(2,0,1,0)));
3978 /* set default push delay values (corrected since version 3.0.7-1) */
3979 if (engine_version < VERSION_IDENT(3,0,7,1))
3981 game.default_push_delay_fixed = 2;
3982 game.default_push_delay_random = 8;
3986 game.default_push_delay_fixed = 8;
3987 game.default_push_delay_random = 8;
3990 /* set uninitialized push delay values of custom elements in older levels */
3991 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3993 int element = EL_CUSTOM_START + i;
3995 if (element_info[element].push_delay_fixed == -1)
3996 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3997 if (element_info[element].push_delay_random == -1)
3998 element_info[element].push_delay_random = game.default_push_delay_random;
4001 /* set some other uninitialized values of custom elements in older levels */
4002 if (engine_version < VERSION_IDENT(3,1,0,0))
4004 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4006 int element = EL_CUSTOM_START + i;
4008 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4010 element_info[element].explosion_delay = 17;
4011 element_info[element].ignition_delay = 8;
4016 /* set element properties that were handled incorrectly in older levels */
4017 if (engine_version < VERSION_IDENT(3,1,0,0))
4019 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4020 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4026 /* this is needed because some graphics depend on element properties */
4027 if (game_status == GAME_MODE_PLAYING)
4028 InitElementGraphicInfo();
4031 static void InitGlobal()
4035 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4037 /* check if element_name_info entry defined for each element in "main.h" */
4038 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4039 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4041 element_info[i].token_name = element_name_info[i].token_name;
4042 element_info[i].class_name = element_name_info[i].class_name;
4043 element_info[i].editor_description=element_name_info[i].editor_description;
4046 global.autoplay_leveldir = NULL;
4047 global.convert_leveldir = NULL;
4049 global.frames_per_second = 0;
4050 global.fps_slowdown = FALSE;
4051 global.fps_slowdown_factor = 1;
4054 void Execute_Command(char *command)
4058 if (strcmp(command, "print graphicsinfo.conf") == 0)
4060 printf("# You can configure additional/alternative image files here.\n");
4061 printf("# (The entries below are default and therefore commented out.)\n");
4063 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4065 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4068 for (i = 0; image_config[i].token != NULL; i++)
4069 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4070 image_config[i].value));
4074 else if (strcmp(command, "print soundsinfo.conf") == 0)
4076 printf("# You can configure additional/alternative sound files here.\n");
4077 printf("# (The entries below are default and therefore commented out.)\n");
4079 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4081 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4084 for (i = 0; sound_config[i].token != NULL; i++)
4085 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4086 sound_config[i].value));
4090 else if (strcmp(command, "print musicinfo.conf") == 0)
4092 printf("# You can configure additional/alternative music files here.\n");
4093 printf("# (The entries below are default and therefore commented out.)\n");
4095 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4097 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4100 for (i = 0; music_config[i].token != NULL; i++)
4101 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4102 music_config[i].value));
4106 else if (strcmp(command, "print editorsetup.conf") == 0)
4108 printf("# You can configure your personal editor element list here.\n");
4109 printf("# (The entries below are default and therefore commented out.)\n");
4112 PrintEditorElementList();
4116 else if (strcmp(command, "print helpanim.conf") == 0)
4118 printf("# You can configure different element help animations here.\n");
4119 printf("# (The entries below are default and therefore commented out.)\n");
4122 for (i = 0; helpanim_config[i].token != NULL; i++)
4124 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4125 helpanim_config[i].value));
4127 if (strcmp(helpanim_config[i].token, "end") == 0)
4133 else if (strcmp(command, "print helptext.conf") == 0)
4135 printf("# You can configure different element help text here.\n");
4136 printf("# (The entries below are default and therefore commented out.)\n");
4139 for (i = 0; helptext_config[i].token != NULL; i++)
4140 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4141 helptext_config[i].value));
4145 else if (strncmp(command, "dump level ", 11) == 0)
4147 char *filename = &command[11];
4149 if (access(filename, F_OK) != 0)
4150 Error(ERR_EXIT, "cannot open file '%s'", filename);
4152 LoadLevelFromFilename(&level, filename);
4157 else if (strncmp(command, "dump tape ", 10) == 0)
4159 char *filename = &command[10];
4161 if (access(filename, F_OK) != 0)
4162 Error(ERR_EXIT, "cannot open file '%s'", filename);
4164 LoadTapeFromFilename(filename);
4169 else if (strncmp(command, "autoplay ", 9) == 0)
4171 char *str_copy = getStringCopy(&command[9]);
4172 char *str_ptr = strchr(str_copy, ' ');
4174 global.autoplay_leveldir = str_copy;
4175 global.autoplay_level_nr = -1;
4177 if (str_ptr != NULL)
4179 *str_ptr++ = '\0'; /* terminate leveldir string */
4180 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4183 else if (strncmp(command, "convert ", 8) == 0)
4185 char *str_copy = getStringCopy(&command[8]);
4186 char *str_ptr = strchr(str_copy, ' ');
4188 global.convert_leveldir = str_copy;
4189 global.convert_level_nr = -1;
4191 if (str_ptr != NULL)
4193 *str_ptr++ = '\0'; /* terminate leveldir string */
4194 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4199 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4203 static void InitSetup()
4205 LoadSetup(); /* global setup info */
4207 /* set some options from setup file */
4209 if (setup.options.verbose)
4210 options.verbose = TRUE;
4213 static void InitPlayerInfo()
4217 /* choose default local player */
4218 local_player = &stored_player[0];
4220 for (i = 0; i < MAX_PLAYERS; i++)
4221 stored_player[i].connected = FALSE;
4223 local_player->connected = TRUE;
4226 static void InitArtworkInfo()
4231 static char *get_string_in_brackets(char *string)
4233 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4235 sprintf(string_in_brackets, "[%s]", string);
4237 return string_in_brackets;
4240 static char *get_level_id_suffix(int id_nr)
4242 char *id_suffix = checked_malloc(1 + 3 + 1);
4244 if (id_nr < 0 || id_nr > 999)
4247 sprintf(id_suffix, ".%03d", id_nr);
4253 static char *get_element_class_token(int element)
4255 char *element_class_name = element_info[element].class_name;
4256 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4258 sprintf(element_class_token, "[%s]", element_class_name);
4260 return element_class_token;
4263 static char *get_action_class_token(int action)
4265 char *action_class_name = &element_action_info[action].suffix[1];
4266 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4268 sprintf(action_class_token, "[%s]", action_class_name);
4270 return action_class_token;
4274 static void InitArtworkConfig()
4276 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4277 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4278 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4279 static char *action_id_suffix[NUM_ACTIONS + 1];
4280 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4281 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4282 static char *level_id_suffix[MAX_LEVELS + 1];
4283 static char *dummy[1] = { NULL };
4284 static char *ignore_generic_tokens[] =
4290 static char **ignore_image_tokens;
4291 static char **ignore_sound_tokens;
4292 static char **ignore_music_tokens;
4293 int num_ignore_generic_tokens;
4294 int num_ignore_image_tokens;
4295 int num_ignore_sound_tokens;
4296 int num_ignore_music_tokens;
4299 /* dynamically determine list of generic tokens to be ignored */
4300 num_ignore_generic_tokens = 0;
4301 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4302 num_ignore_generic_tokens++;
4304 /* dynamically determine list of image tokens to be ignored */
4305 num_ignore_image_tokens = num_ignore_generic_tokens;
4306 for (i = 0; image_config_vars[i].token != NULL; i++)
4307 num_ignore_image_tokens++;
4308 ignore_image_tokens =
4309 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4310 for (i = 0; i < num_ignore_generic_tokens; i++)
4311 ignore_image_tokens[i] = ignore_generic_tokens[i];
4312 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4313 ignore_image_tokens[num_ignore_generic_tokens + i] =
4314 image_config_vars[i].token;
4315 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4317 /* dynamically determine list of sound tokens to be ignored */
4318 num_ignore_sound_tokens = num_ignore_generic_tokens;
4319 ignore_sound_tokens =
4320 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4321 for (i = 0; i < num_ignore_generic_tokens; i++)
4322 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4323 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4325 /* dynamically determine list of music tokens to be ignored */
4326 num_ignore_music_tokens = num_ignore_generic_tokens;
4327 ignore_music_tokens =
4328 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4329 for (i = 0; i < num_ignore_generic_tokens; i++)
4330 ignore_music_tokens[i] = ignore_generic_tokens[i];
4331 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4333 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4334 image_id_prefix[i] = element_info[i].token_name;
4335 for (i = 0; i < NUM_FONTS; i++)
4336 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4337 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4339 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4340 sound_id_prefix[i] = element_info[i].token_name;
4341 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4342 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4343 get_string_in_brackets(element_info[i].class_name);
4344 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4346 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4347 music_id_prefix[i] = music_prefix_info[i].prefix;
4348 music_id_prefix[MAX_LEVELS] = NULL;
4350 for (i = 0; i < NUM_ACTIONS; i++)
4351 action_id_suffix[i] = element_action_info[i].suffix;
4352 action_id_suffix[NUM_ACTIONS] = NULL;
4354 for (i = 0; i < NUM_DIRECTIONS; i++)
4355 direction_id_suffix[i] = element_direction_info[i].suffix;
4356 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4358 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4359 special_id_suffix[i] = special_suffix_info[i].suffix;
4360 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4362 for (i = 0; i < MAX_LEVELS; i++)
4363 level_id_suffix[i] = get_level_id_suffix(i);
4364 level_id_suffix[MAX_LEVELS] = NULL;
4366 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4367 image_id_prefix, action_id_suffix, direction_id_suffix,
4368 special_id_suffix, ignore_image_tokens);
4369 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4370 sound_id_prefix, action_id_suffix, dummy,
4371 special_id_suffix, ignore_sound_tokens);
4372 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4373 music_id_prefix, special_id_suffix, level_id_suffix,
4374 dummy, ignore_music_tokens);
4377 static void InitMixer()
4385 char *filename_font_initial = NULL;
4386 Bitmap *bitmap_font_initial = NULL;
4389 /* determine settings for initial font (for displaying startup messages) */
4390 for (i = 0; image_config[i].token != NULL; i++)
4392 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4394 char font_token[128];
4397 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4398 len_font_token = strlen(font_token);
4400 if (strcmp(image_config[i].token, font_token) == 0)
4401 filename_font_initial = image_config[i].value;
4402 else if (strlen(image_config[i].token) > len_font_token &&
4403 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4405 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4406 font_initial[j].src_x = atoi(image_config[i].value);
4407 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4408 font_initial[j].src_y = atoi(image_config[i].value);
4409 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4410 font_initial[j].width = atoi(image_config[i].value);
4411 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4412 font_initial[j].height = atoi(image_config[i].value);
4417 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4419 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4420 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4423 if (filename_font_initial == NULL) /* should not happen */
4424 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4426 /* create additional image buffers for double-buffering */
4427 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4428 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4430 /* initialize screen properties */
4431 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4432 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4434 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4435 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4436 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4438 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4440 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4441 font_initial[j].bitmap = bitmap_font_initial;
4443 InitFontGraphicInfo();
4445 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4446 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4448 DrawInitText("Loading graphics:", 120, FC_GREEN);
4450 InitTileClipmasks();
4453 void InitGfxBackground()
4457 drawto = backbuffer;
4458 fieldbuffer = bitmap_db_field;
4459 SetDrawtoField(DRAW_BACKBUFFER);
4461 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4462 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4463 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4464 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4466 for (x = 0; x < MAX_BUF_XSIZE; x++)
4467 for (y = 0; y < MAX_BUF_YSIZE; y++)
4470 redraw_mask = REDRAW_ALL;
4473 static void InitLevelInfo()
4475 LoadLevelInfo(); /* global level info */
4476 LoadLevelSetup_LastSeries(); /* last played series info */
4477 LoadLevelSetup_SeriesInfo(); /* last played level info */
4480 void InitLevelArtworkInfo()
4482 LoadLevelArtworkInfo();
4485 static void InitImages()
4488 setLevelArtworkDir(artwork.gfx_first);
4492 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4493 leveldir_current->identifier,
4494 artwork.gfx_current_identifier,
4495 artwork.gfx_current->identifier,
4496 leveldir_current->graphics_set,
4497 leveldir_current->graphics_path);
4500 ReloadCustomImages();
4502 LoadCustomElementDescriptions();
4503 LoadSpecialMenuDesignSettings();
4505 ReinitializeGraphics();
4508 static void InitSound(char *identifier)
4510 if (identifier == NULL)
4511 identifier = artwork.snd_current->identifier;
4514 /* set artwork path to send it to the sound server process */
4515 setLevelArtworkDir(artwork.snd_first);
4518 InitReloadCustomSounds(identifier);
4519 ReinitializeSounds();
4522 static void InitMusic(char *identifier)
4524 if (identifier == NULL)
4525 identifier = artwork.mus_current->identifier;
4528 /* set artwork path to send it to the sound server process */
4529 setLevelArtworkDir(artwork.mus_first);
4532 InitReloadCustomMusic(identifier);
4533 ReinitializeMusic();
4536 void InitNetworkServer()
4538 #if defined(NETWORK_AVALIABLE)
4542 if (!options.network)
4545 #if defined(NETWORK_AVALIABLE)
4546 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4548 if (!ConnectToServer(options.server_host, options.server_port))
4549 Error(ERR_EXIT, "cannot connect to network game server");
4551 SendToServer_PlayerName(setup.player_name);
4552 SendToServer_ProtocolVersion();
4555 SendToServer_NrWanted(nr_wanted);
4559 static char *getNewArtworkIdentifier(int type)
4561 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4562 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4563 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4564 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4565 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4566 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4567 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4568 char *leveldir_identifier = leveldir_current->identifier;
4570 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4571 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4573 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4575 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4576 char *artwork_current_identifier;
4577 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4579 /* leveldir_current may be invalid (level group, parent link) */
4580 if (!validLevelSeries(leveldir_current))
4583 /* 1st step: determine artwork set to be activated in descending order:
4584 --------------------------------------------------------------------
4585 1. setup artwork (when configured to override everything else)
4586 2. artwork set configured in "levelinfo.conf" of current level set
4587 (artwork in level directory will have priority when loading later)
4588 3. artwork in level directory (stored in artwork sub-directory)
4589 4. setup artwork (currently configured in setup menu) */
4591 if (setup_override_artwork)
4592 artwork_current_identifier = setup_artwork_set;
4593 else if (leveldir_artwork_set != NULL)
4594 artwork_current_identifier = leveldir_artwork_set;
4595 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4596 artwork_current_identifier = leveldir_identifier;
4598 artwork_current_identifier = setup_artwork_set;
4601 /* 2nd step: check if it is really needed to reload artwork set
4602 ------------------------------------------------------------ */
4605 if (type == ARTWORK_TYPE_GRAPHICS)
4606 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4607 artwork_new_identifier,
4608 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4609 artwork_current_identifier,
4610 leveldir_current->graphics_set,
4611 leveldir_current->identifier);
4614 /* ---------- reload if level set and also artwork set has changed ------- */
4615 if (leveldir_current_identifier[type] != leveldir_identifier &&
4616 (last_has_level_artwork_set[type] || has_level_artwork_set))
4617 artwork_new_identifier = artwork_current_identifier;
4619 leveldir_current_identifier[type] = leveldir_identifier;
4620 last_has_level_artwork_set[type] = has_level_artwork_set;
4623 if (type == ARTWORK_TYPE_GRAPHICS)
4624 printf("::: 1: '%s'\n", artwork_new_identifier);
4627 /* ---------- reload if "override artwork" setting has changed ----------- */
4628 if (last_override_level_artwork[type] != setup_override_artwork)
4629 artwork_new_identifier = artwork_current_identifier;
4631 last_override_level_artwork[type] = setup_override_artwork;
4634 if (type == ARTWORK_TYPE_GRAPHICS)
4635 printf("::: 2: '%s'\n", artwork_new_identifier);
4638 /* ---------- reload if current artwork identifier has changed ----------- */
4639 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4640 artwork_current_identifier) != 0)
4641 artwork_new_identifier = artwork_current_identifier;
4643 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4646 if (type == ARTWORK_TYPE_GRAPHICS)
4647 printf("::: 3: '%s'\n", artwork_new_identifier);
4650 /* ---------- do not reload directly after starting ---------------------- */
4651 if (!initialized[type])
4652 artwork_new_identifier = NULL;
4654 initialized[type] = TRUE;
4657 if (type == ARTWORK_TYPE_GRAPHICS)
4658 printf("::: 4: '%s'\n", artwork_new_identifier);
4662 if (type == ARTWORK_TYPE_GRAPHICS)
4663 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4664 artwork.gfx_current_identifier, artwork_current_identifier,
4665 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4666 artwork_new_identifier);
4669 return artwork_new_identifier;
4672 void ReloadCustomArtwork(int force_reload)
4674 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4675 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4676 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4677 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4678 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4679 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4680 boolean redraw_screen = FALSE;
4682 if (gfx_new_identifier != NULL || force_reload_gfx)
4685 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4686 artwork.gfx_current_identifier,
4688 artwork.gfx_current->identifier,
4689 leveldir_current->graphics_set);
4692 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4697 printf("... '%s'\n",
4698 leveldir_current->graphics_set);
4701 FreeTileClipmasks();
4702 InitTileClipmasks();
4704 redraw_screen = TRUE;
4707 if (snd_new_identifier != NULL || force_reload_snd)
4709 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4711 InitSound(snd_new_identifier);
4713 redraw_screen = TRUE;
4716 if (mus_new_identifier != NULL || force_reload_mus)
4718 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4720 InitMusic(mus_new_identifier);
4722 redraw_screen = TRUE;
4727 InitGfxBackground();
4729 /* force redraw of (open or closed) door graphics */
4730 SetDoorState(DOOR_OPEN_ALL);
4731 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4735 void KeyboardAutoRepeatOffUnlessAutoplay()
4737 if (global.autoplay_leveldir == NULL)
4738 KeyboardAutoRepeatOff();
4742 /* ========================================================================= */
4744 /* ========================================================================= */
4748 InitGlobal(); /* initialize some global variables */
4750 if (options.execute_command)
4751 Execute_Command(options.execute_command);
4753 if (options.serveronly)
4755 #if defined(PLATFORM_UNIX)
4756 NetworkServer(options.server_port, options.serveronly);
4758 Error(ERR_WARN, "networking only supported in Unix version");
4761 exit(0); /* never reached, server loops forever */
4767 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4768 InitArtworkConfig(); /* needed before forking sound child process */
4773 InitRND(NEW_RANDOMIZE);
4774 InitSimpleRND(NEW_RANDOMIZE);
4779 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4782 InitEventFilter(FilterMouseMotionEvents);
4784 InitElementPropertiesStatic();
4785 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4790 InitLevelArtworkInfo();
4792 InitImages(); /* needs to know current level directory */
4793 InitSound(NULL); /* needs to know current level directory */
4794 InitMusic(NULL); /* needs to know current level directory */
4796 InitGfxBackground();
4798 if (global.autoplay_leveldir)
4803 else if (global.convert_leveldir)
4809 game_status = GAME_MODE_MAIN;
4817 InitNetworkServer();
4820 void CloseAllAndExit(int exit_value)
4825 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4832 FreeTileClipmasks();
4834 #if defined(TARGET_SDL)
4835 if (network_server) /* terminate network server */
4836 SDL_KillThread(server_thread);
4839 CloseVideoDisplay();
4840 ClosePlatformDependentStuff();