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 int default_action_direction_graphic = element_info[i].graphic[act];
810 int default_action_direction_crumbled = element_info[i].crumbled[act];
812 /* no graphic for current action -- use default direction graphic */
813 /* !!! maybe it's better to use default _action_ graphic here !!! */
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_direction_graphic[dir]);
821 if (default_action_direction_crumbled == -1)
822 default_action_direction_crumbled = default_action_direction_graphic;
824 if (default_action_direction_crumbled == -1)
825 default_action_direction_crumbled =
826 (act_remove ? default_remove_graphic :
828 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
829 default_direction_crumbled[dir]);
832 if (element_info[i].direction_graphic[act][dir] == -1)
833 element_info[i].direction_graphic[act][dir] =
834 default_action_direction_graphic;
836 if (element_info[i].direction_crumbled[act][dir] == -1)
837 element_info[i].direction_crumbled[act][dir] =
838 element_info[i].direction_graphic[act][dir];
840 if (element_info[i].direction_crumbled[act][dir] == -1)
841 element_info[i].direction_crumbled[act][dir] =
842 default_action_direction_crumbled;
846 /* no graphic for this specific action -- use default action graphic */
847 if (element_info[i].graphic[act] == -1)
848 element_info[i].graphic[act] =
849 (act_remove ? default_remove_graphic :
850 act_turning ? element_info[i].graphic[ACTION_TURNING] :
851 default_action_graphic);
853 if (element_info[i].crumbled[act] == -1)
854 element_info[i].crumbled[act] = element_info[i].graphic[act];
856 if (element_info[i].crumbled[act] == -1)
857 element_info[i].crumbled[act] =
858 (act_remove ? default_remove_graphic :
859 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
860 default_action_crumbled);
866 /* set animation mode to "none" for each graphic with only 1 frame */
867 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
869 for (act = 0; act < NUM_ACTIONS; act++)
871 int graphic = element_info[i].graphic[act];
872 int crumbled = element_info[i].crumbled[act];
874 if (graphic_info[graphic].anim_frames == 1)
875 graphic_info[graphic].anim_mode = ANIM_NONE;
876 if (graphic_info[crumbled].anim_frames == 1)
877 graphic_info[crumbled].anim_mode = ANIM_NONE;
879 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
881 graphic = element_info[i].direction_graphic[act][dir];
882 crumbled = element_info[i].direction_crumbled[act][dir];
884 if (graphic_info[graphic].anim_frames == 1)
885 graphic_info[graphic].anim_mode = ANIM_NONE;
886 if (graphic_info[crumbled].anim_frames == 1)
887 graphic_info[crumbled].anim_mode = ANIM_NONE;
897 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
898 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
900 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
901 element_info[i].token_name, i);
907 void InitElementSpecialGraphicInfo()
909 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
910 int num_property_mappings = getImageListPropertyMappingSize();
913 /* always start with reliable default values */
914 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
915 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
916 element_info[i].special_graphic[j] =
917 element_info[i].graphic[ACTION_DEFAULT];
919 /* initialize special element/graphic mapping from static configuration */
920 for (i = 0; element_to_special_graphic[i].element > -1; i++)
922 int element = element_to_special_graphic[i].element;
923 int special = element_to_special_graphic[i].special;
924 int graphic = element_to_special_graphic[i].graphic;
925 int base_graphic = el2baseimg(element);
926 boolean base_redefined =
927 getImageListEntryFromImageID(base_graphic)->redefined;
928 boolean special_redefined =
929 getImageListEntryFromImageID(graphic)->redefined;
931 /* if the base graphic ("emerald", for example) has been redefined,
932 but not the special graphic ("emerald.EDITOR", for example), do not
933 use an existing (in this case considered obsolete) special graphic
934 anymore, but use the automatically created (down-scaled) graphic */
935 if (base_redefined && !special_redefined)
938 element_info[element].special_graphic[special] = graphic;
941 /* initialize special element/graphic mapping from dynamic configuration */
942 for (i = 0; i < num_property_mappings; i++)
944 int element = property_mapping[i].base_index;
945 int special = property_mapping[i].ext3_index;
946 int graphic = property_mapping[i].artwork_index;
948 if (element >= MAX_NUM_ELEMENTS)
951 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
952 element_info[element].special_graphic[special] = graphic;
956 /* now set all undefined/invalid graphics to default */
957 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
958 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
959 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
960 element_info[i].special_graphic[j] =
961 element_info[i].graphic[ACTION_DEFAULT];
965 static int get_element_from_token(char *token)
969 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 if (strcmp(element_info[i].token_name, token) == 0)
976 static int get_scaled_graphic_width(int graphic)
978 int original_width = getOriginalImageWidthFromImageID(graphic);
979 int scale_up_factor = graphic_info[graphic].scale_up_factor;
981 return original_width * scale_up_factor;
984 static int get_scaled_graphic_height(int graphic)
986 int original_height = getOriginalImageHeightFromImageID(graphic);
987 int scale_up_factor = graphic_info[graphic].scale_up_factor;
989 return original_height * scale_up_factor;
992 static void set_graphic_parameters(int graphic, int graphic_copy_from)
994 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
995 char **parameter_raw = image->parameter;
996 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
997 int parameter[NUM_GFX_ARGS];
998 int anim_frames_per_row = 1, anim_frames_per_col = 1;
999 int anim_frames_per_line = 1;
1002 /* get integer values from string parameters */
1003 for (i = 0; i < NUM_GFX_ARGS; i++)
1006 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
1007 image_config_suffix[i].type);
1009 if (image_config_suffix[i].type == TYPE_TOKEN)
1010 parameter[i] = get_element_from_token(parameter_raw[i]);
1013 graphic_info[graphic].bitmap = src_bitmap;
1015 /* start with reliable default values */
1016 graphic_info[graphic].src_x = 0;
1017 graphic_info[graphic].src_y = 0;
1018 graphic_info[graphic].width = TILEX;
1019 graphic_info[graphic].height = TILEY;
1020 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1021 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1022 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1023 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1024 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1025 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1026 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1027 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1028 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1029 graphic_info[graphic].anim_delay_fixed = 0;
1030 graphic_info[graphic].anim_delay_random = 0;
1031 graphic_info[graphic].post_delay_fixed = 0;
1032 graphic_info[graphic].post_delay_random = 0;
1034 /* optional x and y tile position of animation frame sequence */
1035 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1036 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1037 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1038 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1040 /* optional x and y pixel position of animation frame sequence */
1041 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1042 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1043 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1044 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1046 /* optional width and height of each animation frame */
1047 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1048 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1049 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1050 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1052 /* optional zoom factor for scaling up the image to a larger size */
1053 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1055 if (graphic_info[graphic].scale_up_factor < 1)
1056 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1060 /* get final bitmap size (with scaling, but without small images) */
1061 int src_bitmap_width = get_scaled_graphic_width(graphic);
1062 int src_bitmap_height = get_scaled_graphic_height(graphic);
1064 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1065 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1068 /* correct x or y offset dependent of vertical or horizontal frame order */
1069 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1071 graphic_info[graphic].offset_y =
1072 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1073 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1074 anim_frames_per_line = anim_frames_per_col;
1076 else /* frames are ordered horizontally */
1078 graphic_info[graphic].offset_x =
1079 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1080 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1081 anim_frames_per_line = anim_frames_per_row;
1084 /* optionally, the x and y offset of frames can be specified directly */
1085 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1086 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1087 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1088 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1090 /* optionally, moving animations may have separate start and end graphics */
1091 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1093 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1094 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1096 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1097 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1098 graphic_info[graphic].offset2_y =
1099 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1100 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1101 else /* frames are ordered horizontally */
1102 graphic_info[graphic].offset2_x =
1103 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1104 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1106 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1107 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1108 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1109 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1110 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1112 /* optionally, the second movement tile can be specified as start tile */
1113 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1114 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1116 /* automatically determine correct number of frames, if not defined */
1117 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1118 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1119 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1120 graphic_info[graphic].anim_frames = anim_frames_per_row;
1121 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1122 graphic_info[graphic].anim_frames = anim_frames_per_col;
1124 graphic_info[graphic].anim_frames = 1;
1126 graphic_info[graphic].anim_frames_per_line =
1127 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1128 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1130 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1131 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1132 graphic_info[graphic].anim_delay = 1;
1134 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1136 if (graphic_info[graphic].anim_frames == 1)
1137 graphic_info[graphic].anim_mode = ANIM_NONE;
1140 /* automatically determine correct start frame, if not defined */
1141 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1142 graphic_info[graphic].anim_start_frame = 0;
1143 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1144 graphic_info[graphic].anim_start_frame =
1145 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1147 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1149 /* animation synchronized with global frame counter, not move position */
1150 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1152 /* optional element for cloning crumble graphics */
1153 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1154 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1156 /* optional element for cloning digging graphics */
1157 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1158 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1160 /* optional border size for "crumbling" diggable graphics */
1161 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1162 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1164 /* this is only used for player "boring" and "sleeping" actions */
1165 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1166 graphic_info[graphic].anim_delay_fixed =
1167 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1168 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1169 graphic_info[graphic].anim_delay_random =
1170 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1171 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1172 graphic_info[graphic].post_delay_fixed =
1173 parameter[GFX_ARG_POST_DELAY_FIXED];
1174 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1175 graphic_info[graphic].post_delay_random =
1176 parameter[GFX_ARG_POST_DELAY_RANDOM];
1178 /* this is only used for toon animations */
1179 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1180 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1182 /* this is only used for drawing font characters */
1183 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1184 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1186 /* this is only used for drawing envelope graphics */
1187 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1190 static void InitGraphicInfo()
1192 int fallback_graphic = IMG_CHAR_EXCLAM;
1193 int num_images = getImageListSize();
1196 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1197 static boolean clipmasks_initialized = FALSE;
1199 XGCValues clip_gc_values;
1200 unsigned long clip_gc_valuemask;
1201 GC copy_clipmask_gc = None;
1204 checked_free(graphic_info);
1206 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1209 printf("::: graphic_info: %d entries\n", num_images);
1212 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1213 if (clipmasks_initialized)
1215 for (i = 0; i < num_images; i++)
1217 if (graphic_info[i].clip_mask)
1218 XFreePixmap(display, graphic_info[i].clip_mask);
1219 if (graphic_info[i].clip_gc)
1220 XFreeGC(display, graphic_info[i].clip_gc);
1222 graphic_info[i].clip_mask = None;
1223 graphic_info[i].clip_gc = None;
1228 for (i = 0; i < num_images; i++)
1232 int first_frame, last_frame;
1233 int src_bitmap_width, src_bitmap_height;
1236 printf("::: image: '%s' [%d]\n", image->token, i);
1240 printf("::: image # %d: '%s' ['%s']\n",
1242 getTokenFromImageID(i));
1245 set_graphic_parameters(i, i);
1247 /* now check if no animation frames are outside of the loaded image */
1249 if (graphic_info[i].bitmap == NULL)
1250 continue; /* skip check for optional images that are undefined */
1252 /* get final bitmap size (with scaling, but without small images) */
1253 src_bitmap_width = get_scaled_graphic_width(i);
1254 src_bitmap_height = get_scaled_graphic_height(i);
1257 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1258 if (src_x < 0 || src_y < 0 ||
1259 src_x + TILEX > src_bitmap_width ||
1260 src_y + TILEY > src_bitmap_height)
1262 Error(ERR_RETURN_LINE, "-");
1263 Error(ERR_RETURN, "warning: error found in config file:");
1264 Error(ERR_RETURN, "- config file: '%s'",
1265 getImageConfigFilename());
1266 Error(ERR_RETURN, "- config token: '%s'",
1267 getTokenFromImageID(i));
1268 Error(ERR_RETURN, "- image file: '%s'",
1269 src_bitmap->source_filename);
1271 "error: first animation frame out of bounds (%d, %d)",
1273 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1276 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1279 if (i == fallback_graphic)
1280 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1282 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1283 Error(ERR_RETURN_LINE, "-");
1285 set_graphic_parameters(i, fallback_graphic);
1288 last_frame = graphic_info[i].anim_frames - 1;
1289 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1290 if (src_x < 0 || src_y < 0 ||
1291 src_x + TILEX > src_bitmap_width ||
1292 src_y + TILEY > src_bitmap_height)
1294 Error(ERR_RETURN_LINE, "-");
1295 Error(ERR_RETURN, "warning: error found in config file:");
1296 Error(ERR_RETURN, "- config file: '%s'",
1297 getImageConfigFilename());
1298 Error(ERR_RETURN, "- config token: '%s'",
1299 getTokenFromImageID(i));
1300 Error(ERR_RETURN, "- image file: '%s'",
1301 src_bitmap->source_filename);
1303 "error: last animation frame (%d) out of bounds (%d, %d)",
1304 last_frame, src_x, src_y);
1305 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1307 if (i == fallback_graphic)
1308 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1310 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1311 Error(ERR_RETURN_LINE, "-");
1313 set_graphic_parameters(i, fallback_graphic);
1316 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1317 /* currently we only need a tile clip mask from the first frame */
1318 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1320 if (copy_clipmask_gc == None)
1322 clip_gc_values.graphics_exposures = False;
1323 clip_gc_valuemask = GCGraphicsExposures;
1324 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1325 clip_gc_valuemask, &clip_gc_values);
1328 graphic_info[i].clip_mask =
1329 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1331 src_pixmap = src_bitmap->clip_mask;
1332 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1333 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1335 clip_gc_values.graphics_exposures = False;
1336 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1337 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1339 graphic_info[i].clip_gc =
1340 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1344 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1345 if (copy_clipmask_gc)
1346 XFreeGC(display, copy_clipmask_gc);
1348 clipmasks_initialized = TRUE;
1352 static void InitElementSoundInfo()
1354 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1355 int num_property_mappings = getSoundListPropertyMappingSize();
1358 /* set values to -1 to identify later as "uninitialized" values */
1359 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1360 for (act = 0; act < NUM_ACTIONS; act++)
1361 element_info[i].sound[act] = -1;
1363 /* initialize element/sound mapping from static configuration */
1364 for (i = 0; element_to_sound[i].element > -1; i++)
1366 int element = element_to_sound[i].element;
1367 int action = element_to_sound[i].action;
1368 int sound = element_to_sound[i].sound;
1369 boolean is_class = element_to_sound[i].is_class;
1372 action = ACTION_DEFAULT;
1375 element_info[element].sound[action] = sound;
1377 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1378 if (strcmp(element_info[j].class_name,
1379 element_info[element].class_name) == 0)
1380 element_info[j].sound[action] = sound;
1383 /* initialize element class/sound mapping from dynamic configuration */
1384 for (i = 0; i < num_property_mappings; i++)
1386 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1387 int action = property_mapping[i].ext1_index;
1388 int sound = property_mapping[i].artwork_index;
1390 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1394 action = ACTION_DEFAULT;
1396 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1397 if (strcmp(element_info[j].class_name,
1398 element_info[element_class].class_name) == 0)
1399 element_info[j].sound[action] = sound;
1402 /* initialize element/sound mapping from dynamic configuration */
1403 for (i = 0; i < num_property_mappings; i++)
1405 int element = property_mapping[i].base_index;
1406 int action = property_mapping[i].ext1_index;
1407 int sound = property_mapping[i].artwork_index;
1409 if (element >= MAX_NUM_ELEMENTS)
1413 action = ACTION_DEFAULT;
1415 element_info[element].sound[action] = sound;
1418 /* now set all '-1' values to element specific default values */
1419 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1421 for (act = 0; act < NUM_ACTIONS; act++)
1423 /* generic default action sound (defined by "[default]" directive) */
1424 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1426 /* look for special default action sound (classic game specific) */
1427 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1428 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1429 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1430 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1431 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1432 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1434 /* !!! there's no such thing as a "default action sound" !!! */
1436 /* look for element specific default sound (independent from action) */
1437 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1438 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1442 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1443 /* !!! make this better !!! */
1444 if (i == EL_EMPTY_SPACE)
1445 default_action_sound = element_info[EL_DEFAULT].sound[act];
1448 /* no sound for this specific action -- use default action sound */
1449 if (element_info[i].sound[act] == -1)
1450 element_info[i].sound[act] = default_action_sound;
1455 static void InitGameModeSoundInfo()
1459 /* set values to -1 to identify later as "uninitialized" values */
1460 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1463 /* initialize gamemode/sound mapping from static configuration */
1464 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1466 int gamemode = gamemode_to_sound[i].gamemode;
1467 int sound = gamemode_to_sound[i].sound;
1470 gamemode = GAME_MODE_DEFAULT;
1472 menu.sound[gamemode] = sound;
1475 /* now set all '-1' values to levelset specific default values */
1476 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1477 if (menu.sound[i] == -1)
1478 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1482 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1483 if (menu.sound[i] != -1)
1484 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1488 static void set_sound_parameters(int sound, char **parameter_raw)
1490 int parameter[NUM_SND_ARGS];
1493 /* get integer values from string parameters */
1494 for (i = 0; i < NUM_SND_ARGS; i++)
1496 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1497 sound_config_suffix[i].type);
1499 /* explicit loop mode setting in configuration overrides default value */
1500 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1501 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1503 /* sound volume to change the original volume when loading the sound file */
1504 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1506 /* sound priority to give certain sounds a higher or lower priority */
1507 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1510 static void InitSoundInfo()
1513 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1514 int num_property_mappings = getSoundListPropertyMappingSize();
1516 int *sound_effect_properties;
1517 int num_sounds = getSoundListSize();
1520 checked_free(sound_info);
1522 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1523 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1525 /* initialize sound effect for all elements to "no sound" */
1526 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1527 for (j = 0; j < NUM_ACTIONS; j++)
1528 element_info[i].sound[j] = SND_UNDEFINED;
1530 for (i = 0; i < num_sounds; i++)
1532 struct FileInfo *sound = getSoundListEntry(i);
1533 int len_effect_text = strlen(sound->token);
1535 sound_effect_properties[i] = ACTION_OTHER;
1536 sound_info[i].loop = FALSE; /* default: play sound only once */
1539 printf("::: sound %d: '%s'\n", i, sound->token);
1542 /* determine all loop sounds and identify certain sound classes */
1544 for (j = 0; element_action_info[j].suffix; j++)
1546 int len_action_text = strlen(element_action_info[j].suffix);
1548 if (len_action_text < len_effect_text &&
1549 strcmp(&sound->token[len_effect_text - len_action_text],
1550 element_action_info[j].suffix) == 0)
1552 sound_effect_properties[i] = element_action_info[j].value;
1553 sound_info[i].loop = element_action_info[j].is_loop_sound;
1560 if (strcmp(sound->token, "custom_42") == 0)
1561 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1564 /* associate elements and some selected sound actions */
1566 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1568 if (element_info[j].class_name)
1570 int len_class_text = strlen(element_info[j].class_name);
1572 if (len_class_text + 1 < len_effect_text &&
1573 strncmp(sound->token,
1574 element_info[j].class_name, len_class_text) == 0 &&
1575 sound->token[len_class_text] == '.')
1577 int sound_action_value = sound_effect_properties[i];
1579 element_info[j].sound[sound_action_value] = i;
1584 set_sound_parameters(i, sound->parameter);
1587 free(sound_effect_properties);
1590 /* !!! now handled in InitElementSoundInfo() !!! */
1591 /* initialize element/sound mapping from dynamic configuration */
1592 for (i = 0; i < num_property_mappings; i++)
1594 int element = property_mapping[i].base_index;
1595 int action = property_mapping[i].ext1_index;
1596 int sound = property_mapping[i].artwork_index;
1599 action = ACTION_DEFAULT;
1601 printf("::: %d: %d, %d, %d ['%s']\n",
1602 i, element, action, sound, element_info[element].token_name);
1604 element_info[element].sound[action] = sound;
1611 int element = EL_CUSTOM_11;
1614 while (element_action_info[j].suffix)
1616 printf("element %d, sound action '%s' == %d\n",
1617 element, element_action_info[j].suffix,
1618 element_info[element].sound[j]);
1623 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1629 int element = EL_SAND;
1630 int sound_action = ACTION_DIGGING;
1633 while (element_action_info[j].suffix)
1635 if (element_action_info[j].value == sound_action)
1636 printf("element %d, sound action '%s' == %d\n",
1637 element, element_action_info[j].suffix,
1638 element_info[element].sound[sound_action]);
1645 static void InitGameModeMusicInfo()
1647 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1648 int num_property_mappings = getMusicListPropertyMappingSize();
1649 int default_levelset_music = -1;
1652 /* set values to -1 to identify later as "uninitialized" values */
1653 for (i = 0; i < MAX_LEVELS; i++)
1654 levelset.music[i] = -1;
1655 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1658 /* initialize gamemode/music mapping from static configuration */
1659 for (i = 0; gamemode_to_music[i].music > -1; i++)
1661 int gamemode = gamemode_to_music[i].gamemode;
1662 int music = gamemode_to_music[i].music;
1665 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1669 gamemode = GAME_MODE_DEFAULT;
1671 menu.music[gamemode] = music;
1674 /* initialize gamemode/music mapping from dynamic configuration */
1675 for (i = 0; i < num_property_mappings; i++)
1677 int prefix = property_mapping[i].base_index;
1678 int gamemode = property_mapping[i].ext1_index;
1679 int level = property_mapping[i].ext2_index;
1680 int music = property_mapping[i].artwork_index;
1683 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1684 prefix, gamemode, level, music);
1687 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1691 gamemode = GAME_MODE_DEFAULT;
1693 /* level specific music only allowed for in-game music */
1694 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1695 gamemode = GAME_MODE_PLAYING;
1700 default_levelset_music = music;
1703 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1704 levelset.music[level] = music;
1705 if (gamemode != GAME_MODE_PLAYING)
1706 menu.music[gamemode] = music;
1709 /* now set all '-1' values to menu specific default values */
1710 /* (undefined values of "levelset.music[]" might stay at "-1" to
1711 allow dynamic selection of music files from music directory!) */
1712 for (i = 0; i < MAX_LEVELS; i++)
1713 if (levelset.music[i] == -1)
1714 levelset.music[i] = default_levelset_music;
1715 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1716 if (menu.music[i] == -1)
1717 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1721 for (i = 0; i < MAX_LEVELS; i++)
1722 if (levelset.music[i] != -1)
1723 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1724 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1725 if (menu.music[i] != -1)
1726 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1730 static void set_music_parameters(int music, char **parameter_raw)
1732 int parameter[NUM_MUS_ARGS];
1735 /* get integer values from string parameters */
1736 for (i = 0; i < NUM_MUS_ARGS; i++)
1738 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1739 music_config_suffix[i].type);
1741 /* explicit loop mode setting in configuration overrides default value */
1742 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1743 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1746 static void InitMusicInfo()
1748 int num_music = getMusicListSize();
1751 checked_free(music_info);
1753 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1755 for (i = 0; i < num_music; i++)
1757 struct FileInfo *music = getMusicListEntry(i);
1758 int len_music_text = strlen(music->token);
1760 music_info[i].loop = TRUE; /* default: play music in loop mode */
1762 /* determine all loop music */
1764 for (j = 0; music_prefix_info[j].prefix; j++)
1766 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1768 if (len_prefix_text < len_music_text &&
1769 strncmp(music->token,
1770 music_prefix_info[j].prefix, len_prefix_text) == 0)
1772 music_info[i].loop = music_prefix_info[j].is_loop_music;
1778 set_music_parameters(i, music->parameter);
1782 static void ReinitializeGraphics()
1784 InitGraphicInfo(); /* graphic properties mapping */
1785 InitElementGraphicInfo(); /* element game graphic mapping */
1786 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1788 InitElementSmallImages(); /* scale images to all needed sizes */
1789 InitFontGraphicInfo(); /* initialize text drawing functions */
1791 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1793 SetMainBackgroundImage(IMG_BACKGROUND);
1794 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1800 static void ReinitializeSounds()
1802 InitSoundInfo(); /* sound properties mapping */
1803 InitElementSoundInfo(); /* element game sound mapping */
1804 InitGameModeSoundInfo(); /* game mode sound mapping */
1806 InitPlayLevelSound(); /* internal game sound settings */
1809 static void ReinitializeMusic()
1811 InitMusicInfo(); /* music properties mapping */
1812 InitGameModeMusicInfo(); /* game mode music mapping */
1815 static int get_special_property_bit(int element, int property_bit_nr)
1817 struct PropertyBitInfo
1823 static struct PropertyBitInfo pb_can_move_into_acid[] =
1825 /* the player may be able fall into acid when gravity is activated */
1830 { EL_SP_MURPHY, 0 },
1831 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1833 /* all element that can move may be able to also move into acid */
1836 { EL_BUG_RIGHT, 1 },
1839 { EL_SPACESHIP, 2 },
1840 { EL_SPACESHIP_LEFT, 2 },
1841 { EL_SPACESHIP_RIGHT, 2 },
1842 { EL_SPACESHIP_UP, 2 },
1843 { EL_SPACESHIP_DOWN, 2 },
1844 { EL_BD_BUTTERFLY, 3 },
1845 { EL_BD_BUTTERFLY_LEFT, 3 },
1846 { EL_BD_BUTTERFLY_RIGHT, 3 },
1847 { EL_BD_BUTTERFLY_UP, 3 },
1848 { EL_BD_BUTTERFLY_DOWN, 3 },
1849 { EL_BD_FIREFLY, 4 },
1850 { EL_BD_FIREFLY_LEFT, 4 },
1851 { EL_BD_FIREFLY_RIGHT, 4 },
1852 { EL_BD_FIREFLY_UP, 4 },
1853 { EL_BD_FIREFLY_DOWN, 4 },
1855 { EL_DARK_YAMYAM, 6 },
1858 { EL_PACMAN_LEFT, 8 },
1859 { EL_PACMAN_RIGHT, 8 },
1860 { EL_PACMAN_UP, 8 },
1861 { EL_PACMAN_DOWN, 8 },
1863 { EL_MOLE_LEFT, 9 },
1864 { EL_MOLE_RIGHT, 9 },
1866 { EL_MOLE_DOWN, 9 },
1870 { EL_SATELLITE, 13 },
1871 { EL_SP_SNIKSNAK, 14 },
1872 { EL_SP_ELECTRON, 15 },
1879 static struct PropertyBitInfo pb_dont_collide_with[] =
1881 { EL_SP_SNIKSNAK, 0 },
1882 { EL_SP_ELECTRON, 1 },
1890 struct PropertyBitInfo *pb_info;
1893 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1894 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1899 struct PropertyBitInfo *pb_info = NULL;
1902 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1903 if (pb_definition[i].bit_nr == property_bit_nr)
1904 pb_info = pb_definition[i].pb_info;
1906 if (pb_info == NULL)
1909 for (i = 0; pb_info[i].element != -1; i++)
1910 if (pb_info[i].element == element)
1911 return pb_info[i].bit_nr;
1917 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1918 boolean property_value)
1920 int bit_nr = get_special_property_bit(element, property_bit_nr);
1925 *bitfield |= (1 << bit_nr);
1927 *bitfield &= ~(1 << bit_nr);
1931 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1933 int bit_nr = get_special_property_bit(element, property_bit_nr);
1936 return ((*bitfield & (1 << bit_nr)) != 0);
1943 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1945 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1949 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1952 level->can_move_into_acid_bits |= (1 << bit_nr);
1956 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1958 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1961 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1967 void InitElementPropertiesStatic()
1969 static int ep_diggable[] =
1974 EL_SP_BUGGY_BASE_ACTIVATING,
1977 EL_INVISIBLE_SAND_ACTIVE,
1980 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1981 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1985 EL_SP_BUGGY_BASE_ACTIVE,
1991 static int ep_collectible_only[] =
2012 EL_DYNABOMB_INCREASE_NUMBER,
2013 EL_DYNABOMB_INCREASE_SIZE,
2014 EL_DYNABOMB_INCREASE_POWER,
2033 static int ep_dont_run_into[] =
2035 /* same elements as in 'ep_dont_touch' */
2041 /* same elements as in 'ep_dont_collide_with' */
2053 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2057 EL_SP_BUGGY_BASE_ACTIVE,
2063 static int ep_dont_collide_with[] =
2065 /* same elements as in 'ep_dont_touch' */
2081 static int ep_dont_touch[] =
2090 static int ep_indestructible[] =
2094 EL_ACID_POOL_TOPLEFT,
2095 EL_ACID_POOL_TOPRIGHT,
2096 EL_ACID_POOL_BOTTOMLEFT,
2097 EL_ACID_POOL_BOTTOM,
2098 EL_ACID_POOL_BOTTOMRIGHT,
2099 EL_SP_HARDWARE_GRAY,
2100 EL_SP_HARDWARE_GREEN,
2101 EL_SP_HARDWARE_BLUE,
2103 EL_SP_HARDWARE_YELLOW,
2104 EL_SP_HARDWARE_BASE_1,
2105 EL_SP_HARDWARE_BASE_2,
2106 EL_SP_HARDWARE_BASE_3,
2107 EL_SP_HARDWARE_BASE_4,
2108 EL_SP_HARDWARE_BASE_5,
2109 EL_SP_HARDWARE_BASE_6,
2110 EL_INVISIBLE_STEELWALL,
2111 EL_INVISIBLE_STEELWALL_ACTIVE,
2112 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2113 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2114 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2115 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2116 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2117 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2118 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2119 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2120 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2121 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2122 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2123 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2125 EL_LIGHT_SWITCH_ACTIVE,
2126 EL_SIGN_EXCLAMATION,
2127 EL_SIGN_RADIOACTIVITY,
2138 EL_STEELWALL_SLIPPERY,
2161 EL_SWITCHGATE_OPENING,
2162 EL_SWITCHGATE_CLOSED,
2163 EL_SWITCHGATE_CLOSING,
2165 EL_SWITCHGATE_SWITCH_UP,
2166 EL_SWITCHGATE_SWITCH_DOWN,
2169 EL_TIMEGATE_OPENING,
2171 EL_TIMEGATE_CLOSING,
2174 EL_TIMEGATE_SWITCH_ACTIVE,
2179 EL_TUBE_VERTICAL_LEFT,
2180 EL_TUBE_VERTICAL_RIGHT,
2181 EL_TUBE_HORIZONTAL_UP,
2182 EL_TUBE_HORIZONTAL_DOWN,
2190 static int ep_slippery[] =
2204 EL_ROBOT_WHEEL_ACTIVE,
2210 EL_ACID_POOL_TOPLEFT,
2211 EL_ACID_POOL_TOPRIGHT,
2221 EL_STEELWALL_SLIPPERY,
2224 EL_EMC_WALL_SLIPPERY_1,
2225 EL_EMC_WALL_SLIPPERY_2,
2226 EL_EMC_WALL_SLIPPERY_3,
2227 EL_EMC_WALL_SLIPPERY_4,
2231 static int ep_can_change[] =
2236 static int ep_can_move[] =
2238 /* same elements as in 'pb_can_move_into_acid' */
2260 static int ep_can_fall[] =
2275 EL_BD_MAGIC_WALL_FULL,
2288 static int ep_can_smash_player[] =
2313 static int ep_can_smash_enemies[] =
2321 static int ep_can_smash_everything[] =
2329 static int ep_explodes_by_fire[] =
2331 /* same elements as in 'ep_explodes_impact' */
2336 /* same elements as in 'ep_explodes_smashed' */
2345 EL_DYNABOMB_PLAYER_1_ACTIVE,
2346 EL_DYNABOMB_PLAYER_2_ACTIVE,
2347 EL_DYNABOMB_PLAYER_3_ACTIVE,
2348 EL_DYNABOMB_PLAYER_4_ACTIVE,
2349 EL_DYNABOMB_INCREASE_NUMBER,
2350 EL_DYNABOMB_INCREASE_SIZE,
2351 EL_DYNABOMB_INCREASE_POWER,
2352 EL_SP_DISK_RED_ACTIVE,
2365 static int ep_explodes_smashed[] =
2367 /* same elements as in 'ep_explodes_impact' */
2380 static int ep_explodes_impact[] =
2388 static int ep_walkable_over[] =
2392 EL_SOKOBAN_FIELD_EMPTY,
2410 static int ep_walkable_inside[] =
2415 EL_TUBE_VERTICAL_LEFT,
2416 EL_TUBE_VERTICAL_RIGHT,
2417 EL_TUBE_HORIZONTAL_UP,
2418 EL_TUBE_HORIZONTAL_DOWN,
2426 static int ep_walkable_under[] =
2431 static int ep_passable_over[] =
2454 static int ep_passable_inside[] =
2460 EL_SP_PORT_HORIZONTAL,
2461 EL_SP_PORT_VERTICAL,
2463 EL_SP_GRAVITY_PORT_LEFT,
2464 EL_SP_GRAVITY_PORT_RIGHT,
2465 EL_SP_GRAVITY_PORT_UP,
2466 EL_SP_GRAVITY_PORT_DOWN,
2467 EL_SP_GRAVITY_ON_PORT_LEFT,
2468 EL_SP_GRAVITY_ON_PORT_RIGHT,
2469 EL_SP_GRAVITY_ON_PORT_UP,
2470 EL_SP_GRAVITY_ON_PORT_DOWN,
2471 EL_SP_GRAVITY_OFF_PORT_LEFT,
2472 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2473 EL_SP_GRAVITY_OFF_PORT_UP,
2474 EL_SP_GRAVITY_OFF_PORT_DOWN,
2478 static int ep_passable_under[] =
2483 static int ep_droppable[] =
2488 static int ep_explodes_1x1_old[] =
2493 static int ep_pushable[] =
2505 EL_SOKOBAN_FIELD_FULL,
2513 static int ep_explodes_cross_old[] =
2518 static int ep_protected[] =
2520 /* same elements as in 'ep_walkable_inside' */
2524 EL_TUBE_VERTICAL_LEFT,
2525 EL_TUBE_VERTICAL_RIGHT,
2526 EL_TUBE_HORIZONTAL_UP,
2527 EL_TUBE_HORIZONTAL_DOWN,
2533 /* same elements as in 'ep_passable_over' */
2553 /* same elements as in 'ep_passable_inside' */
2558 EL_SP_PORT_HORIZONTAL,
2559 EL_SP_PORT_VERTICAL,
2561 EL_SP_GRAVITY_PORT_LEFT,
2562 EL_SP_GRAVITY_PORT_RIGHT,
2563 EL_SP_GRAVITY_PORT_UP,
2564 EL_SP_GRAVITY_PORT_DOWN,
2565 EL_SP_GRAVITY_ON_PORT_LEFT,
2566 EL_SP_GRAVITY_ON_PORT_RIGHT,
2567 EL_SP_GRAVITY_ON_PORT_UP,
2568 EL_SP_GRAVITY_ON_PORT_DOWN,
2569 EL_SP_GRAVITY_OFF_PORT_LEFT,
2570 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2571 EL_SP_GRAVITY_OFF_PORT_UP,
2572 EL_SP_GRAVITY_OFF_PORT_DOWN,
2576 static int ep_throwable[] =
2581 static int ep_can_explode[] =
2583 /* same elements as in 'ep_explodes_impact' */
2588 /* same elements as in 'ep_explodes_smashed' */
2594 /* elements that can explode by explosion or by dragonfire */
2597 EL_DYNABOMB_PLAYER_1_ACTIVE,
2598 EL_DYNABOMB_PLAYER_2_ACTIVE,
2599 EL_DYNABOMB_PLAYER_3_ACTIVE,
2600 EL_DYNABOMB_PLAYER_4_ACTIVE,
2601 EL_DYNABOMB_INCREASE_NUMBER,
2602 EL_DYNABOMB_INCREASE_SIZE,
2603 EL_DYNABOMB_INCREASE_POWER,
2604 EL_SP_DISK_RED_ACTIVE,
2612 /* elements that can explode only by explosion */
2617 static int ep_gravity_reachable[] =
2623 EL_INVISIBLE_SAND_ACTIVE,
2628 EL_SP_PORT_HORIZONTAL,
2629 EL_SP_PORT_VERTICAL,
2631 EL_SP_GRAVITY_PORT_LEFT,
2632 EL_SP_GRAVITY_PORT_RIGHT,
2633 EL_SP_GRAVITY_PORT_UP,
2634 EL_SP_GRAVITY_PORT_DOWN,
2635 EL_SP_GRAVITY_ON_PORT_LEFT,
2636 EL_SP_GRAVITY_ON_PORT_RIGHT,
2637 EL_SP_GRAVITY_ON_PORT_UP,
2638 EL_SP_GRAVITY_ON_PORT_DOWN,
2639 EL_SP_GRAVITY_OFF_PORT_LEFT,
2640 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2641 EL_SP_GRAVITY_OFF_PORT_UP,
2642 EL_SP_GRAVITY_OFF_PORT_DOWN,
2647 static int ep_player[] =
2654 EL_SOKOBAN_FIELD_PLAYER,
2659 static int ep_can_pass_magic_wall[] =
2672 static int ep_switchable[] =
2676 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2677 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2678 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2679 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2680 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2681 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2682 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2683 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2684 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2685 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2686 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2687 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2688 EL_SWITCHGATE_SWITCH_UP,
2689 EL_SWITCHGATE_SWITCH_DOWN,
2691 EL_LIGHT_SWITCH_ACTIVE,
2693 EL_BALLOON_SWITCH_LEFT,
2694 EL_BALLOON_SWITCH_RIGHT,
2695 EL_BALLOON_SWITCH_UP,
2696 EL_BALLOON_SWITCH_DOWN,
2697 EL_BALLOON_SWITCH_ANY,
2700 EL_EMC_MAGIC_BALL_SWITCH,
2704 static int ep_bd_element[] =
2737 static int ep_sp_element[] =
2739 /* should always be valid */
2742 /* standard classic Supaplex elements */
2749 EL_SP_HARDWARE_GRAY,
2757 EL_SP_GRAVITY_PORT_RIGHT,
2758 EL_SP_GRAVITY_PORT_DOWN,
2759 EL_SP_GRAVITY_PORT_LEFT,
2760 EL_SP_GRAVITY_PORT_UP,
2765 EL_SP_PORT_VERTICAL,
2766 EL_SP_PORT_HORIZONTAL,
2772 EL_SP_HARDWARE_BASE_1,
2773 EL_SP_HARDWARE_GREEN,
2774 EL_SP_HARDWARE_BLUE,
2776 EL_SP_HARDWARE_YELLOW,
2777 EL_SP_HARDWARE_BASE_2,
2778 EL_SP_HARDWARE_BASE_3,
2779 EL_SP_HARDWARE_BASE_4,
2780 EL_SP_HARDWARE_BASE_5,
2781 EL_SP_HARDWARE_BASE_6,
2785 /* additional elements that appeared in newer Supaplex levels */
2788 /* additional gravity port elements (not switching, but setting gravity) */
2789 EL_SP_GRAVITY_ON_PORT_LEFT,
2790 EL_SP_GRAVITY_ON_PORT_RIGHT,
2791 EL_SP_GRAVITY_ON_PORT_UP,
2792 EL_SP_GRAVITY_ON_PORT_DOWN,
2793 EL_SP_GRAVITY_OFF_PORT_LEFT,
2794 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2795 EL_SP_GRAVITY_OFF_PORT_UP,
2796 EL_SP_GRAVITY_OFF_PORT_DOWN,
2798 /* more than one Murphy in a level results in an inactive clone */
2801 /* runtime Supaplex elements */
2802 EL_SP_DISK_RED_ACTIVE,
2803 EL_SP_TERMINAL_ACTIVE,
2804 EL_SP_BUGGY_BASE_ACTIVATING,
2805 EL_SP_BUGGY_BASE_ACTIVE,
2811 static int ep_sb_element[] =
2816 EL_SOKOBAN_FIELD_EMPTY,
2817 EL_SOKOBAN_FIELD_FULL,
2818 EL_SOKOBAN_FIELD_PLAYER,
2823 EL_INVISIBLE_STEELWALL,
2827 static int ep_gem[] =
2838 static int ep_food_dark_yamyam[] =
2865 static int ep_food_penguin[] =
2878 static int ep_food_pig[] =
2889 static int ep_historic_wall[] =
2914 EL_EXPANDABLE_WALL_HORIZONTAL,
2915 EL_EXPANDABLE_WALL_VERTICAL,
2916 EL_EXPANDABLE_WALL_ANY,
2917 EL_EXPANDABLE_WALL_GROWING,
2924 EL_SP_HARDWARE_GRAY,
2925 EL_SP_HARDWARE_GREEN,
2926 EL_SP_HARDWARE_BLUE,
2928 EL_SP_HARDWARE_YELLOW,
2929 EL_SP_HARDWARE_BASE_1,
2930 EL_SP_HARDWARE_BASE_2,
2931 EL_SP_HARDWARE_BASE_3,
2932 EL_SP_HARDWARE_BASE_4,
2933 EL_SP_HARDWARE_BASE_5,
2934 EL_SP_HARDWARE_BASE_6,
2936 EL_SP_TERMINAL_ACTIVE,
2939 EL_INVISIBLE_STEELWALL,
2940 EL_INVISIBLE_STEELWALL_ACTIVE,
2942 EL_INVISIBLE_WALL_ACTIVE,
2943 EL_STEELWALL_SLIPPERY,
2959 static int ep_historic_solid[] =
2963 EL_EXPANDABLE_WALL_HORIZONTAL,
2964 EL_EXPANDABLE_WALL_VERTICAL,
2965 EL_EXPANDABLE_WALL_ANY,
2978 EL_QUICKSAND_FILLING,
2979 EL_QUICKSAND_EMPTYING,
2981 EL_MAGIC_WALL_ACTIVE,
2982 EL_MAGIC_WALL_EMPTYING,
2983 EL_MAGIC_WALL_FILLING,
2987 EL_BD_MAGIC_WALL_ACTIVE,
2988 EL_BD_MAGIC_WALL_EMPTYING,
2989 EL_BD_MAGIC_WALL_FULL,
2990 EL_BD_MAGIC_WALL_FILLING,
2991 EL_BD_MAGIC_WALL_DEAD,
3000 EL_SP_TERMINAL_ACTIVE,
3004 EL_INVISIBLE_WALL_ACTIVE,
3005 EL_SWITCHGATE_SWITCH_UP,
3006 EL_SWITCHGATE_SWITCH_DOWN,
3008 EL_TIMEGATE_SWITCH_ACTIVE,
3020 /* the following elements are a direct copy of "indestructible" elements,
3021 except "EL_ACID", which is "indestructible", but not "solid"! */
3026 EL_ACID_POOL_TOPLEFT,
3027 EL_ACID_POOL_TOPRIGHT,
3028 EL_ACID_POOL_BOTTOMLEFT,
3029 EL_ACID_POOL_BOTTOM,
3030 EL_ACID_POOL_BOTTOMRIGHT,
3031 EL_SP_HARDWARE_GRAY,
3032 EL_SP_HARDWARE_GREEN,
3033 EL_SP_HARDWARE_BLUE,
3035 EL_SP_HARDWARE_YELLOW,
3036 EL_SP_HARDWARE_BASE_1,
3037 EL_SP_HARDWARE_BASE_2,
3038 EL_SP_HARDWARE_BASE_3,
3039 EL_SP_HARDWARE_BASE_4,
3040 EL_SP_HARDWARE_BASE_5,
3041 EL_SP_HARDWARE_BASE_6,
3042 EL_INVISIBLE_STEELWALL,
3043 EL_INVISIBLE_STEELWALL_ACTIVE,
3044 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3045 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3046 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3047 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3048 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3049 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3050 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3051 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3052 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3053 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3054 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3055 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3057 EL_LIGHT_SWITCH_ACTIVE,
3058 EL_SIGN_EXCLAMATION,
3059 EL_SIGN_RADIOACTIVITY,
3070 EL_STEELWALL_SLIPPERY,
3093 EL_SWITCHGATE_OPENING,
3094 EL_SWITCHGATE_CLOSED,
3095 EL_SWITCHGATE_CLOSING,
3097 EL_TIMEGATE_OPENING,
3099 EL_TIMEGATE_CLOSING,
3103 EL_TUBE_VERTICAL_LEFT,
3104 EL_TUBE_VERTICAL_RIGHT,
3105 EL_TUBE_HORIZONTAL_UP,
3106 EL_TUBE_HORIZONTAL_DOWN,
3114 static int ep_classic_enemy[] =
3130 static int ep_belt[] =
3132 EL_CONVEYOR_BELT_1_LEFT,
3133 EL_CONVEYOR_BELT_1_MIDDLE,
3134 EL_CONVEYOR_BELT_1_RIGHT,
3135 EL_CONVEYOR_BELT_2_LEFT,
3136 EL_CONVEYOR_BELT_2_MIDDLE,
3137 EL_CONVEYOR_BELT_2_RIGHT,
3138 EL_CONVEYOR_BELT_3_LEFT,
3139 EL_CONVEYOR_BELT_3_MIDDLE,
3140 EL_CONVEYOR_BELT_3_RIGHT,
3141 EL_CONVEYOR_BELT_4_LEFT,
3142 EL_CONVEYOR_BELT_4_MIDDLE,
3143 EL_CONVEYOR_BELT_4_RIGHT,
3147 static int ep_belt_active[] =
3149 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3150 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3151 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3152 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3153 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3154 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3155 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3156 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3157 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3158 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3159 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3160 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3164 static int ep_belt_switch[] =
3166 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3167 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3168 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3169 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3170 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3171 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3172 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3173 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3174 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3175 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3176 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3177 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3181 static int ep_tube[] =
3188 EL_TUBE_HORIZONTAL_UP,
3189 EL_TUBE_HORIZONTAL_DOWN,
3191 EL_TUBE_VERTICAL_LEFT,
3192 EL_TUBE_VERTICAL_RIGHT,
3197 static int ep_keygate[] =
3226 static int ep_amoeboid[] =
3236 static int ep_amoebalive[] =
3245 static int ep_has_content[] =
3255 static int ep_can_turn_each_move[] =
3257 /* !!! do something with this one !!! */
3261 static int ep_can_grow[] =
3273 static int ep_active_bomb[] =
3276 EL_DYNABOMB_PLAYER_1_ACTIVE,
3277 EL_DYNABOMB_PLAYER_2_ACTIVE,
3278 EL_DYNABOMB_PLAYER_3_ACTIVE,
3279 EL_DYNABOMB_PLAYER_4_ACTIVE,
3280 EL_SP_DISK_RED_ACTIVE,
3284 static int ep_inactive[] =
3333 EL_INVISIBLE_STEELWALL,
3341 EL_WALL_EMERALD_YELLOW,
3342 EL_DYNABOMB_INCREASE_NUMBER,
3343 EL_DYNABOMB_INCREASE_SIZE,
3344 EL_DYNABOMB_INCREASE_POWER,
3348 EL_SOKOBAN_FIELD_EMPTY,
3349 EL_SOKOBAN_FIELD_FULL,
3350 EL_WALL_EMERALD_RED,
3351 EL_WALL_EMERALD_PURPLE,
3352 EL_ACID_POOL_TOPLEFT,
3353 EL_ACID_POOL_TOPRIGHT,
3354 EL_ACID_POOL_BOTTOMLEFT,
3355 EL_ACID_POOL_BOTTOM,
3356 EL_ACID_POOL_BOTTOMRIGHT,
3360 EL_BD_MAGIC_WALL_DEAD,
3361 EL_AMOEBA_TO_DIAMOND,
3369 EL_SP_GRAVITY_PORT_RIGHT,
3370 EL_SP_GRAVITY_PORT_DOWN,
3371 EL_SP_GRAVITY_PORT_LEFT,
3372 EL_SP_GRAVITY_PORT_UP,
3373 EL_SP_PORT_HORIZONTAL,
3374 EL_SP_PORT_VERTICAL,
3385 EL_SP_HARDWARE_GRAY,
3386 EL_SP_HARDWARE_GREEN,
3387 EL_SP_HARDWARE_BLUE,
3389 EL_SP_HARDWARE_YELLOW,
3390 EL_SP_HARDWARE_BASE_1,
3391 EL_SP_HARDWARE_BASE_2,
3392 EL_SP_HARDWARE_BASE_3,
3393 EL_SP_HARDWARE_BASE_4,
3394 EL_SP_HARDWARE_BASE_5,
3395 EL_SP_HARDWARE_BASE_6,
3396 EL_SP_GRAVITY_ON_PORT_LEFT,
3397 EL_SP_GRAVITY_ON_PORT_RIGHT,
3398 EL_SP_GRAVITY_ON_PORT_UP,
3399 EL_SP_GRAVITY_ON_PORT_DOWN,
3400 EL_SP_GRAVITY_OFF_PORT_LEFT,
3401 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3402 EL_SP_GRAVITY_OFF_PORT_UP,
3403 EL_SP_GRAVITY_OFF_PORT_DOWN,
3404 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3405 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3406 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3407 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3408 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3409 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3410 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3411 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3412 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3413 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3414 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3415 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3416 EL_SIGN_EXCLAMATION,
3417 EL_SIGN_RADIOACTIVITY,
3428 EL_STEELWALL_SLIPPERY,
3433 EL_EMC_WALL_SLIPPERY_1,
3434 EL_EMC_WALL_SLIPPERY_2,
3435 EL_EMC_WALL_SLIPPERY_3,
3436 EL_EMC_WALL_SLIPPERY_4,
3456 static int ep_em_slippery_wall[] =
3461 static int ep_gfx_crumbled[] =
3474 } element_properties[] =
3476 { ep_diggable, EP_DIGGABLE },
3477 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3478 { ep_dont_run_into, EP_DONT_RUN_INTO },
3479 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3480 { ep_dont_touch, EP_DONT_TOUCH },
3481 { ep_indestructible, EP_INDESTRUCTIBLE },
3482 { ep_slippery, EP_SLIPPERY },
3483 { ep_can_change, EP_CAN_CHANGE },
3484 { ep_can_move, EP_CAN_MOVE },
3485 { ep_can_fall, EP_CAN_FALL },
3486 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3487 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3488 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3489 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3490 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3491 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3492 { ep_walkable_over, EP_WALKABLE_OVER },
3493 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3494 { ep_walkable_under, EP_WALKABLE_UNDER },
3495 { ep_passable_over, EP_PASSABLE_OVER },
3496 { ep_passable_inside, EP_PASSABLE_INSIDE },
3497 { ep_passable_under, EP_PASSABLE_UNDER },
3498 { ep_droppable, EP_DROPPABLE },
3499 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3500 { ep_pushable, EP_PUSHABLE },
3501 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3502 { ep_protected, EP_PROTECTED },
3503 { ep_throwable, EP_THROWABLE },
3504 { ep_can_explode, EP_CAN_EXPLODE },
3505 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3507 { ep_player, EP_PLAYER },
3508 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3509 { ep_switchable, EP_SWITCHABLE },
3510 { ep_bd_element, EP_BD_ELEMENT },
3511 { ep_sp_element, EP_SP_ELEMENT },
3512 { ep_sb_element, EP_SB_ELEMENT },
3514 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3515 { ep_food_penguin, EP_FOOD_PENGUIN },
3516 { ep_food_pig, EP_FOOD_PIG },
3517 { ep_historic_wall, EP_HISTORIC_WALL },
3518 { ep_historic_solid, EP_HISTORIC_SOLID },
3519 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3520 { ep_belt, EP_BELT },
3521 { ep_belt_active, EP_BELT_ACTIVE },
3522 { ep_belt_switch, EP_BELT_SWITCH },
3523 { ep_tube, EP_TUBE },
3524 { ep_keygate, EP_KEYGATE },
3525 { ep_amoeboid, EP_AMOEBOID },
3526 { ep_amoebalive, EP_AMOEBALIVE },
3527 { ep_has_content, EP_HAS_CONTENT },
3528 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3529 { ep_can_grow, EP_CAN_GROW },
3530 { ep_active_bomb, EP_ACTIVE_BOMB },
3531 { ep_inactive, EP_INACTIVE },
3533 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3535 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3540 static int copy_properties[][5] =
3544 EL_BUG_LEFT, EL_BUG_RIGHT,
3545 EL_BUG_UP, EL_BUG_DOWN
3549 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3550 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3554 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3555 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3559 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3560 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3564 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3565 EL_PACMAN_UP, EL_PACMAN_DOWN
3569 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3570 EL_MOLE_UP, EL_MOLE_DOWN
3580 /* always start with reliable default values (element has no properties) */
3581 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3582 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3583 SET_PROPERTY(i, j, FALSE);
3585 /* set all base element properties from above array definitions */
3586 for (i = 0; element_properties[i].elements != NULL; i++)
3587 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3588 SET_PROPERTY((element_properties[i].elements)[j],
3589 element_properties[i].property, TRUE);
3591 /* copy properties to some elements that are only stored in level file */
3592 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3593 for (j = 0; copy_properties[j][0] != -1; j++)
3594 if (HAS_PROPERTY(copy_properties[j][0], i))
3595 for (k = 1; k <= 4; k++)
3596 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3599 void InitElementPropertiesEngine(int engine_version)
3602 static int active_properties[] =
3607 EP_DONT_COLLIDE_WITH,
3611 EP_CAN_PASS_MAGIC_WALL,
3616 EP_EXPLODES_BY_FIRE,
3629 EP_EM_SLIPPERY_WALL,
3633 static int no_wall_properties[] =
3636 EP_COLLECTIBLE_ONLY,
3638 EP_DONT_COLLIDE_WITH,
3641 EP_CAN_SMASH_PLAYER,
3642 EP_CAN_SMASH_ENEMIES,
3643 EP_CAN_SMASH_EVERYTHING,
3648 EP_FOOD_DARK_YAMYAM,
3665 InitElementPropertiesStatic();
3668 /* important: after initialization in InitElementPropertiesStatic(), the
3669 elements are not again initialized to a default value; therefore all
3670 changes have to make sure that they leave the element with a defined
3671 property (which means that conditional property changes must be set to
3672 a reliable default value before) */
3674 /* set all special, combined or engine dependent element properties */
3675 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3678 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3679 SET_PROPERTY(i, j, FALSE);
3682 /* ---------- INACTIVE ------------------------------------------------- */
3683 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3685 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3686 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3687 IS_WALKABLE_INSIDE(i) ||
3688 IS_WALKABLE_UNDER(i)));
3690 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3691 IS_PASSABLE_INSIDE(i) ||
3692 IS_PASSABLE_UNDER(i)));
3694 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3695 IS_PASSABLE_OVER(i)));
3697 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3698 IS_PASSABLE_INSIDE(i)));
3700 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3701 IS_PASSABLE_UNDER(i)));
3703 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3706 /* ---------- COLLECTIBLE ---------------------------------------------- */
3707 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3711 /* ---------- SNAPPABLE ------------------------------------------------ */
3712 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3713 IS_COLLECTIBLE(i) ||
3717 /* ---------- WALL ----------------------------------------------------- */
3718 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3720 for (j = 0; no_wall_properties[j] != -1; j++)
3721 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3722 i >= EL_FIRST_RUNTIME_UNREAL)
3723 SET_PROPERTY(i, EP_WALL, FALSE);
3725 if (IS_HISTORIC_WALL(i))
3726 SET_PROPERTY(i, EP_WALL, TRUE);
3728 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3729 if (engine_version < VERSION_IDENT(2,2,0,0))
3730 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3732 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3734 !IS_COLLECTIBLE(i)));
3737 /* ---------- PROTECTED ------------------------------------------------ */
3738 if (IS_ACCESSIBLE_INSIDE(i))
3739 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3742 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3744 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3745 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3747 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3748 IS_INDESTRUCTIBLE(i)));
3750 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3752 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3753 else if (engine_version < VERSION_IDENT(2,2,0,0))
3754 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3757 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3762 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3763 !IS_WALKABLE_OVER(i) &&
3764 !IS_WALKABLE_UNDER(i)));
3766 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3771 if (IS_CUSTOM_ELEMENT(i))
3773 /* these are additional properties which are initially false when set */
3775 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3777 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3778 if (DONT_COLLIDE_WITH(i))
3779 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3781 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3782 if (CAN_SMASH_EVERYTHING(i))
3783 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3784 if (CAN_SMASH_ENEMIES(i))
3785 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3788 /* ---------- CAN_SMASH ------------------------------------------------ */
3789 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3790 CAN_SMASH_ENEMIES(i) ||
3791 CAN_SMASH_EVERYTHING(i)));
3794 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3795 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3796 CAN_EXPLODE_SMASHED(i) ||
3797 CAN_EXPLODE_IMPACT(i)));
3801 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3803 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3804 !CAN_EXPLODE_CROSS(i)));
3806 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3807 !CAN_EXPLODE_1X1(i) &&
3808 !CAN_EXPLODE_CROSS(i)));
3812 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3813 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3814 EXPLODES_BY_FIRE(i)));
3816 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3817 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3818 EXPLODES_SMASHED(i)));
3820 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3821 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3822 EXPLODES_IMPACT(i)));
3824 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3825 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3827 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3828 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3829 i == EL_BLACK_ORB));
3831 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3832 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3834 IS_CUSTOM_ELEMENT(i)));
3836 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3837 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3838 i == EL_SP_ELECTRON));
3840 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3841 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3842 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3843 getMoveIntoAcidProperty(&level, i));
3845 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3846 if (MAYBE_DONT_COLLIDE_WITH(i))
3847 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3848 getDontCollideWithProperty(&level, i));
3850 /* ---------- SP_PORT -------------------------------------------------- */
3851 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3852 IS_PASSABLE_INSIDE(i)));
3854 /* ---------- CAN_CHANGE ----------------------------------------------- */
3855 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3856 for (j = 0; j < element_info[i].num_change_pages; j++)
3857 if (element_info[i].change_page[j].can_change)
3858 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3860 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3862 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3863 element_info[i].crumbled[ACTION_DEFAULT] !=
3864 element_info[i].graphic[ACTION_DEFAULT]);
3866 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3867 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3868 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3873 /* determine inactive elements (used for engine main loop optimization) */
3874 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3876 boolean active = FALSE;
3878 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3880 if (HAS_PROPERTY(i, j))
3886 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3891 /* dynamically adjust element properties according to game engine version */
3893 static int ep_em_slippery_wall[] =
3898 EL_EXPANDABLE_WALL_HORIZONTAL,
3899 EL_EXPANDABLE_WALL_VERTICAL,
3900 EL_EXPANDABLE_WALL_ANY,
3904 /* special EM style gems behaviour */
3905 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3906 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3907 level.em_slippery_gems);
3909 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3910 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3911 (level.em_slippery_gems &&
3912 engine_version > VERSION_IDENT(2,0,1,0)));
3916 /* set default push delay values (corrected since version 3.0.7-1) */
3917 if (engine_version < VERSION_IDENT(3,0,7,1))
3919 game.default_push_delay_fixed = 2;
3920 game.default_push_delay_random = 8;
3924 game.default_push_delay_fixed = 8;
3925 game.default_push_delay_random = 8;
3928 /* set uninitialized push delay values of custom elements in older levels */
3929 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3931 int element = EL_CUSTOM_START + i;
3933 if (element_info[element].push_delay_fixed == -1)
3934 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3935 if (element_info[element].push_delay_random == -1)
3936 element_info[element].push_delay_random = game.default_push_delay_random;
3939 /* set some other uninitialized values of custom elements in older levels */
3940 if (engine_version < VERSION_IDENT(3,1,0,0))
3942 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3944 int element = EL_CUSTOM_START + i;
3946 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3948 element_info[element].explosion_delay = 17;
3949 element_info[element].ignition_delay = 8;
3954 /* set element properties that were handled incorrectly in older levels */
3955 if (engine_version < VERSION_IDENT(3,1,0,0))
3957 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3958 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3964 /* this is needed because some graphics depend on element properties */
3965 if (game_status == GAME_MODE_PLAYING)
3966 InitElementGraphicInfo();
3969 static void InitGlobal()
3973 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3975 /* check if element_name_info entry defined for each element in "main.h" */
3976 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3977 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3979 element_info[i].token_name = element_name_info[i].token_name;
3980 element_info[i].class_name = element_name_info[i].class_name;
3981 element_info[i].editor_description=element_name_info[i].editor_description;
3984 global.autoplay_leveldir = NULL;
3985 global.convert_leveldir = NULL;
3987 global.frames_per_second = 0;
3988 global.fps_slowdown = FALSE;
3989 global.fps_slowdown_factor = 1;
3992 void Execute_Command(char *command)
3996 if (strcmp(command, "print graphicsinfo.conf") == 0)
3998 printf("# You can configure additional/alternative image files here.\n");
3999 printf("# (The entries below are default and therefore commented out.)\n");
4001 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4003 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4006 for (i = 0; image_config[i].token != NULL; i++)
4007 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4008 image_config[i].value));
4012 else if (strcmp(command, "print soundsinfo.conf") == 0)
4014 printf("# You can configure additional/alternative sound files here.\n");
4015 printf("# (The entries below are default and therefore commented out.)\n");
4017 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4019 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4022 for (i = 0; sound_config[i].token != NULL; i++)
4023 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4024 sound_config[i].value));
4028 else if (strcmp(command, "print musicinfo.conf") == 0)
4030 printf("# You can configure additional/alternative music files here.\n");
4031 printf("# (The entries below are default and therefore commented out.)\n");
4033 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4035 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4038 for (i = 0; music_config[i].token != NULL; i++)
4039 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4040 music_config[i].value));
4044 else if (strcmp(command, "print editorsetup.conf") == 0)
4046 printf("# You can configure your personal editor element list here.\n");
4047 printf("# (The entries below are default and therefore commented out.)\n");
4050 PrintEditorElementList();
4054 else if (strcmp(command, "print helpanim.conf") == 0)
4056 printf("# You can configure different element help animations here.\n");
4057 printf("# (The entries below are default and therefore commented out.)\n");
4060 for (i = 0; helpanim_config[i].token != NULL; i++)
4062 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4063 helpanim_config[i].value));
4065 if (strcmp(helpanim_config[i].token, "end") == 0)
4071 else if (strcmp(command, "print helptext.conf") == 0)
4073 printf("# You can configure different element help text here.\n");
4074 printf("# (The entries below are default and therefore commented out.)\n");
4077 for (i = 0; helptext_config[i].token != NULL; i++)
4078 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4079 helptext_config[i].value));
4083 else if (strncmp(command, "dump level ", 11) == 0)
4085 char *filename = &command[11];
4087 if (access(filename, F_OK) != 0)
4088 Error(ERR_EXIT, "cannot open file '%s'", filename);
4090 LoadLevelFromFilename(&level, filename);
4095 else if (strncmp(command, "dump tape ", 10) == 0)
4097 char *filename = &command[10];
4099 if (access(filename, F_OK) != 0)
4100 Error(ERR_EXIT, "cannot open file '%s'", filename);
4102 LoadTapeFromFilename(filename);
4107 else if (strncmp(command, "autoplay ", 9) == 0)
4109 char *str_copy = getStringCopy(&command[9]);
4110 char *str_ptr = strchr(str_copy, ' ');
4112 global.autoplay_leveldir = str_copy;
4113 global.autoplay_level_nr = -1;
4115 if (str_ptr != NULL)
4117 *str_ptr++ = '\0'; /* terminate leveldir string */
4118 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4121 else if (strncmp(command, "convert ", 8) == 0)
4123 char *str_copy = getStringCopy(&command[8]);
4124 char *str_ptr = strchr(str_copy, ' ');
4126 global.convert_leveldir = str_copy;
4127 global.convert_level_nr = -1;
4129 if (str_ptr != NULL)
4131 *str_ptr++ = '\0'; /* terminate leveldir string */
4132 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4137 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4141 static void InitSetup()
4143 LoadSetup(); /* global setup info */
4145 /* set some options from setup file */
4147 if (setup.options.verbose)
4148 options.verbose = TRUE;
4151 static void InitPlayerInfo()
4155 /* choose default local player */
4156 local_player = &stored_player[0];
4158 for (i = 0; i < MAX_PLAYERS; i++)
4159 stored_player[i].connected = FALSE;
4161 local_player->connected = TRUE;
4164 static void InitArtworkInfo()
4169 static char *get_string_in_brackets(char *string)
4171 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4173 sprintf(string_in_brackets, "[%s]", string);
4175 return string_in_brackets;
4178 static char *get_level_id_suffix(int id_nr)
4180 char *id_suffix = checked_malloc(1 + 3 + 1);
4182 if (id_nr < 0 || id_nr > 999)
4185 sprintf(id_suffix, ".%03d", id_nr);
4191 static char *get_element_class_token(int element)
4193 char *element_class_name = element_info[element].class_name;
4194 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4196 sprintf(element_class_token, "[%s]", element_class_name);
4198 return element_class_token;
4201 static char *get_action_class_token(int action)
4203 char *action_class_name = &element_action_info[action].suffix[1];
4204 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4206 sprintf(action_class_token, "[%s]", action_class_name);
4208 return action_class_token;
4212 static void InitArtworkConfig()
4214 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4215 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4216 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4217 static char *action_id_suffix[NUM_ACTIONS + 1];
4218 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4219 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4220 static char *level_id_suffix[MAX_LEVELS + 1];
4221 static char *dummy[1] = { NULL };
4222 static char *ignore_generic_tokens[] =
4228 static char **ignore_image_tokens;
4229 static char **ignore_sound_tokens;
4230 static char **ignore_music_tokens;
4231 int num_ignore_generic_tokens;
4232 int num_ignore_image_tokens;
4233 int num_ignore_sound_tokens;
4234 int num_ignore_music_tokens;
4237 /* dynamically determine list of generic tokens to be ignored */
4238 num_ignore_generic_tokens = 0;
4239 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4240 num_ignore_generic_tokens++;
4242 /* dynamically determine list of image tokens to be ignored */
4243 num_ignore_image_tokens = num_ignore_generic_tokens;
4244 for (i = 0; image_config_vars[i].token != NULL; i++)
4245 num_ignore_image_tokens++;
4246 ignore_image_tokens =
4247 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4248 for (i = 0; i < num_ignore_generic_tokens; i++)
4249 ignore_image_tokens[i] = ignore_generic_tokens[i];
4250 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4251 ignore_image_tokens[num_ignore_generic_tokens + i] =
4252 image_config_vars[i].token;
4253 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4255 /* dynamically determine list of sound tokens to be ignored */
4256 num_ignore_sound_tokens = num_ignore_generic_tokens;
4257 ignore_sound_tokens =
4258 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4259 for (i = 0; i < num_ignore_generic_tokens; i++)
4260 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4261 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4263 /* dynamically determine list of music tokens to be ignored */
4264 num_ignore_music_tokens = num_ignore_generic_tokens;
4265 ignore_music_tokens =
4266 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4267 for (i = 0; i < num_ignore_generic_tokens; i++)
4268 ignore_music_tokens[i] = ignore_generic_tokens[i];
4269 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4271 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4272 image_id_prefix[i] = element_info[i].token_name;
4273 for (i = 0; i < NUM_FONTS; i++)
4274 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4275 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4277 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4278 sound_id_prefix[i] = element_info[i].token_name;
4279 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4280 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4281 get_string_in_brackets(element_info[i].class_name);
4282 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4284 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4285 music_id_prefix[i] = music_prefix_info[i].prefix;
4286 music_id_prefix[MAX_LEVELS] = NULL;
4288 for (i = 0; i < NUM_ACTIONS; i++)
4289 action_id_suffix[i] = element_action_info[i].suffix;
4290 action_id_suffix[NUM_ACTIONS] = NULL;
4292 for (i = 0; i < NUM_DIRECTIONS; i++)
4293 direction_id_suffix[i] = element_direction_info[i].suffix;
4294 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4296 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4297 special_id_suffix[i] = special_suffix_info[i].suffix;
4298 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4300 for (i = 0; i < MAX_LEVELS; i++)
4301 level_id_suffix[i] = get_level_id_suffix(i);
4302 level_id_suffix[MAX_LEVELS] = NULL;
4304 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4305 image_id_prefix, action_id_suffix, direction_id_suffix,
4306 special_id_suffix, ignore_image_tokens);
4307 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4308 sound_id_prefix, action_id_suffix, dummy,
4309 special_id_suffix, ignore_sound_tokens);
4310 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4311 music_id_prefix, special_id_suffix, level_id_suffix,
4312 dummy, ignore_music_tokens);
4315 static void InitMixer()
4323 char *filename_font_initial = NULL;
4324 Bitmap *bitmap_font_initial = NULL;
4327 /* determine settings for initial font (for displaying startup messages) */
4328 for (i = 0; image_config[i].token != NULL; i++)
4330 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4332 char font_token[128];
4335 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4336 len_font_token = strlen(font_token);
4338 if (strcmp(image_config[i].token, font_token) == 0)
4339 filename_font_initial = image_config[i].value;
4340 else if (strlen(image_config[i].token) > len_font_token &&
4341 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4343 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4344 font_initial[j].src_x = atoi(image_config[i].value);
4345 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4346 font_initial[j].src_y = atoi(image_config[i].value);
4347 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4348 font_initial[j].width = atoi(image_config[i].value);
4349 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4350 font_initial[j].height = atoi(image_config[i].value);
4355 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4357 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4358 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4361 if (filename_font_initial == NULL) /* should not happen */
4362 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4364 /* create additional image buffers for double-buffering */
4365 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4366 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4368 /* initialize screen properties */
4369 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4372 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4373 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4374 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4376 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4378 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4379 font_initial[j].bitmap = bitmap_font_initial;
4381 InitFontGraphicInfo();
4383 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4384 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4386 DrawInitText("Loading graphics:", 120, FC_GREEN);
4388 InitTileClipmasks();
4391 void InitGfxBackground()
4395 drawto = backbuffer;
4396 fieldbuffer = bitmap_db_field;
4397 SetDrawtoField(DRAW_BACKBUFFER);
4399 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4400 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4401 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4402 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4404 for (x = 0; x < MAX_BUF_XSIZE; x++)
4405 for (y = 0; y < MAX_BUF_YSIZE; y++)
4408 redraw_mask = REDRAW_ALL;
4411 static void InitLevelInfo()
4413 LoadLevelInfo(); /* global level info */
4414 LoadLevelSetup_LastSeries(); /* last played series info */
4415 LoadLevelSetup_SeriesInfo(); /* last played level info */
4418 void InitLevelArtworkInfo()
4420 LoadLevelArtworkInfo();
4423 static void InitImages()
4426 setLevelArtworkDir(artwork.gfx_first);
4430 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4431 leveldir_current->identifier,
4432 artwork.gfx_current_identifier,
4433 artwork.gfx_current->identifier,
4434 leveldir_current->graphics_set,
4435 leveldir_current->graphics_path);
4438 ReloadCustomImages();
4440 LoadCustomElementDescriptions();
4441 LoadSpecialMenuDesignSettings();
4443 ReinitializeGraphics();
4446 static void InitSound(char *identifier)
4448 if (identifier == NULL)
4449 identifier = artwork.snd_current->identifier;
4452 /* set artwork path to send it to the sound server process */
4453 setLevelArtworkDir(artwork.snd_first);
4456 InitReloadCustomSounds(identifier);
4457 ReinitializeSounds();
4460 static void InitMusic(char *identifier)
4462 if (identifier == NULL)
4463 identifier = artwork.mus_current->identifier;
4466 /* set artwork path to send it to the sound server process */
4467 setLevelArtworkDir(artwork.mus_first);
4470 InitReloadCustomMusic(identifier);
4471 ReinitializeMusic();
4474 void InitNetworkServer()
4476 #if defined(NETWORK_AVALIABLE)
4480 if (!options.network)
4483 #if defined(NETWORK_AVALIABLE)
4484 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4486 if (!ConnectToServer(options.server_host, options.server_port))
4487 Error(ERR_EXIT, "cannot connect to network game server");
4489 SendToServer_PlayerName(setup.player_name);
4490 SendToServer_ProtocolVersion();
4493 SendToServer_NrWanted(nr_wanted);
4497 static char *getNewArtworkIdentifier(int type)
4499 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4500 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4501 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4502 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4503 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4504 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4505 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4506 char *leveldir_identifier = leveldir_current->identifier;
4508 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4509 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4511 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4513 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4514 char *artwork_current_identifier;
4515 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4517 /* leveldir_current may be invalid (level group, parent link) */
4518 if (!validLevelSeries(leveldir_current))
4521 /* 1st step: determine artwork set to be activated in descending order:
4522 --------------------------------------------------------------------
4523 1. setup artwork (when configured to override everything else)
4524 2. artwork set configured in "levelinfo.conf" of current level set
4525 (artwork in level directory will have priority when loading later)
4526 3. artwork in level directory (stored in artwork sub-directory)
4527 4. setup artwork (currently configured in setup menu) */
4529 if (setup_override_artwork)
4530 artwork_current_identifier = setup_artwork_set;
4531 else if (leveldir_artwork_set != NULL)
4532 artwork_current_identifier = leveldir_artwork_set;
4533 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4534 artwork_current_identifier = leveldir_identifier;
4536 artwork_current_identifier = setup_artwork_set;
4539 /* 2nd step: check if it is really needed to reload artwork set
4540 ------------------------------------------------------------ */
4543 if (type == ARTWORK_TYPE_GRAPHICS)
4544 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4545 artwork_new_identifier,
4546 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4547 artwork_current_identifier,
4548 leveldir_current->graphics_set,
4549 leveldir_current->identifier);
4552 /* ---------- reload if level set and also artwork set has changed ------- */
4553 if (leveldir_current_identifier[type] != leveldir_identifier &&
4554 (last_has_level_artwork_set[type] || has_level_artwork_set))
4555 artwork_new_identifier = artwork_current_identifier;
4557 leveldir_current_identifier[type] = leveldir_identifier;
4558 last_has_level_artwork_set[type] = has_level_artwork_set;
4561 if (type == ARTWORK_TYPE_GRAPHICS)
4562 printf("::: 1: '%s'\n", artwork_new_identifier);
4565 /* ---------- reload if "override artwork" setting has changed ----------- */
4566 if (last_override_level_artwork[type] != setup_override_artwork)
4567 artwork_new_identifier = artwork_current_identifier;
4569 last_override_level_artwork[type] = setup_override_artwork;
4572 if (type == ARTWORK_TYPE_GRAPHICS)
4573 printf("::: 2: '%s'\n", artwork_new_identifier);
4576 /* ---------- reload if current artwork identifier has changed ----------- */
4577 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4578 artwork_current_identifier) != 0)
4579 artwork_new_identifier = artwork_current_identifier;
4581 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4584 if (type == ARTWORK_TYPE_GRAPHICS)
4585 printf("::: 3: '%s'\n", artwork_new_identifier);
4588 /* ---------- do not reload directly after starting ---------------------- */
4589 if (!initialized[type])
4590 artwork_new_identifier = NULL;
4592 initialized[type] = TRUE;
4595 if (type == ARTWORK_TYPE_GRAPHICS)
4596 printf("::: 4: '%s'\n", artwork_new_identifier);
4600 if (type == ARTWORK_TYPE_GRAPHICS)
4601 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4602 artwork.gfx_current_identifier, artwork_current_identifier,
4603 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4604 artwork_new_identifier);
4607 return artwork_new_identifier;
4610 void ReloadCustomArtwork(int force_reload)
4612 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4613 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4614 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4615 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4616 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4617 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4618 boolean redraw_screen = FALSE;
4620 if (gfx_new_identifier != NULL || force_reload_gfx)
4623 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4624 artwork.gfx_current_identifier,
4626 artwork.gfx_current->identifier,
4627 leveldir_current->graphics_set);
4630 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4635 printf("... '%s'\n",
4636 leveldir_current->graphics_set);
4639 FreeTileClipmasks();
4640 InitTileClipmasks();
4642 redraw_screen = TRUE;
4645 if (snd_new_identifier != NULL || force_reload_snd)
4647 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4649 InitSound(snd_new_identifier);
4651 redraw_screen = TRUE;
4654 if (mus_new_identifier != NULL || force_reload_mus)
4656 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4658 InitMusic(mus_new_identifier);
4660 redraw_screen = TRUE;
4665 InitGfxBackground();
4667 /* force redraw of (open or closed) door graphics */
4668 SetDoorState(DOOR_OPEN_ALL);
4669 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4673 void KeyboardAutoRepeatOffUnlessAutoplay()
4675 if (global.autoplay_leveldir == NULL)
4676 KeyboardAutoRepeatOff();
4680 /* ========================================================================= */
4682 /* ========================================================================= */
4686 InitGlobal(); /* initialize some global variables */
4688 if (options.execute_command)
4689 Execute_Command(options.execute_command);
4691 if (options.serveronly)
4693 #if defined(PLATFORM_UNIX)
4694 NetworkServer(options.server_port, options.serveronly);
4696 Error(ERR_WARN, "networking only supported in Unix version");
4698 exit(0); /* never reached */
4704 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4705 InitArtworkConfig(); /* needed before forking sound child process */
4710 InitRND(NEW_RANDOMIZE);
4711 InitSimpleRND(NEW_RANDOMIZE);
4716 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4719 InitEventFilter(FilterMouseMotionEvents);
4721 InitElementPropertiesStatic();
4722 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4727 InitLevelArtworkInfo();
4729 InitImages(); /* needs to know current level directory */
4730 InitSound(NULL); /* needs to know current level directory */
4731 InitMusic(NULL); /* needs to know current level directory */
4733 InitGfxBackground();
4735 if (global.autoplay_leveldir)
4740 else if (global.convert_leveldir)
4746 game_status = GAME_MODE_MAIN;
4754 InitNetworkServer();
4757 void CloseAllAndExit(int exit_value)
4762 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4769 FreeTileClipmasks();
4771 #if defined(TARGET_SDL)
4772 if (network_server) /* terminate network server */
4773 SDL_KillThread(server_thread);
4776 CloseVideoDisplay();
4777 ClosePlatformDependentStuff();