1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static void InitTileClipmasks()
46 #if defined(TARGET_X11)
47 XGCValues clip_gc_values;
48 unsigned long clip_gc_valuemask;
50 #if defined(TARGET_X11_NATIVE)
60 tile_needs_clipping[] =
62 { GFX_SPIELER1_UP, 4 },
63 { GFX_SPIELER1_DOWN, 4 },
64 { GFX_SPIELER1_LEFT, 4 },
65 { GFX_SPIELER1_RIGHT, 4 },
66 { GFX_SPIELER1_PUSH_LEFT, 4 },
67 { GFX_SPIELER1_PUSH_RIGHT, 4 },
68 { GFX_SPIELER2_UP, 4 },
69 { GFX_SPIELER2_DOWN, 4 },
70 { GFX_SPIELER2_LEFT, 4 },
71 { GFX_SPIELER2_RIGHT, 4 },
72 { GFX_SPIELER2_PUSH_LEFT, 4 },
73 { GFX_SPIELER2_PUSH_RIGHT, 4 },
74 { GFX_SPIELER3_UP, 4 },
75 { GFX_SPIELER3_DOWN, 4 },
76 { GFX_SPIELER3_LEFT, 4 },
77 { GFX_SPIELER3_RIGHT, 4 },
78 { GFX_SPIELER3_PUSH_LEFT, 4 },
79 { GFX_SPIELER3_PUSH_RIGHT, 4 },
80 { GFX_SPIELER4_UP, 4 },
81 { GFX_SPIELER4_DOWN, 4 },
82 { GFX_SPIELER4_LEFT, 4 },
83 { GFX_SPIELER4_RIGHT, 4 },
84 { GFX_SPIELER4_PUSH_LEFT, 4 },
85 { GFX_SPIELER4_PUSH_RIGHT, 4 },
87 { GFX_MURPHY_GO_LEFT, 3 },
88 { GFX_MURPHY_GO_RIGHT, 3 },
89 { GFX_MURPHY_SNAP_UP, 1 },
90 { GFX_MURPHY_SNAP_DOWN, 1 },
91 { GFX_MURPHY_SNAP_RIGHT, 1 },
92 { GFX_MURPHY_SNAP_LEFT, 1 },
93 { GFX_MURPHY_PUSH_RIGHT, 1 },
94 { GFX_MURPHY_PUSH_LEFT, 1 },
99 { GFX_SOKOBAN_OBJEKT, 1 },
100 { GFX_FUNKELN_BLAU, 3 },
101 { GFX_FUNKELN_WEISS, 3 },
102 { GFX2_SHIELD_PASSIVE, 3 },
103 { GFX2_SHIELD_ACTIVE, 3 },
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
113 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114 for (i = 0; i < NUM_TILES; i++)
115 tile_clipmask[i] = None;
117 #if defined(TARGET_X11)
118 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119 often very slow when preparing a masked XCopyArea() for big Pixmaps.
120 To prevent this, create small (tile-sized) mask Pixmaps which will then
121 be set much faster with XSetClipOrigin() and speed things up a lot. */
123 clip_gc_values.graphics_exposures = False;
124 clip_gc_valuemask = GCGraphicsExposures;
125 tile_clip_gc = XCreateGC(display, window->drawable,
126 clip_gc_valuemask, &clip_gc_values);
129 for (i = 0; i < NUM_BITMAPS; i++)
131 if (pix[i]->clip_mask)
133 clip_gc_values.graphics_exposures = False;
134 clip_gc_values.clip_mask = pix[i]->clip_mask;
135 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137 clip_gc_valuemask, &clip_gc_values);
142 #if defined(TARGET_X11_NATIVE)
145 /* create graphic context structures needed for clipping */
146 clip_gc_values.graphics_exposures = False;
147 clip_gc_valuemask = GCGraphicsExposures;
148 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149 clip_gc_valuemask, &clip_gc_values);
151 /* create only those clipping Pixmaps we really need */
152 for (i = 0; tile_needs_clipping[i].start >= 0; i++)
156 for (j = 0; j < tile_needs_clipping[i].count; j++)
158 int tile = tile_needs_clipping[i].start + j;
164 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165 src_pixmap = src_bitmap->clip_mask;
167 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
170 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171 src_x, src_y, TILEX, TILEY, 0, 0);
175 XFreeGC(display, copy_clipmask_gc);
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
183 void FreeTileClipmasks()
186 #if defined(TARGET_X11)
189 for (i = 0; i < NUM_TILES; i++)
191 if (tile_clipmask[i] != None)
193 XFreePixmap(display, tile_clipmask[i]);
194 tile_clipmask[i] = None;
199 XFreeGC(display, tile_clip_gc);
203 for (i = 0; i < NUM_BITMAPS; i++)
205 if (pix[i] != NULL && pix[i]->stored_clip_gc)
207 XFreeGC(display, pix[i]->stored_clip_gc);
208 pix[i]->stored_clip_gc = None;
213 #endif /* TARGET_X11 */
219 FreeLevelEditorGadgets();
228 static boolean gadgets_initialized = FALSE;
230 if (gadgets_initialized)
233 CreateLevelEditorGadgets();
237 CreateScreenGadgets();
239 gadgets_initialized = TRUE;
242 inline void InitElementSmallImagesScaledUp(int graphic)
244 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
247 void InitElementSmallImages()
249 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250 int num_property_mappings = getImageListPropertyMappingSize();
253 /* initialize normal images from static configuration */
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
257 /* initialize special images from static configuration */
258 for (i = 0; element_to_special_graphic[i].element > -1; i++)
259 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 /* initialize images from dynamic configuration (may be elements or other) */
263 for (i = 0; i < num_property_mappings; i++)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
266 /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
267 /* !!! ALSO, non-element graphics might need scaling-up !!! */
268 for (i = 0; i < num_property_mappings; i++)
269 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
270 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
276 InitElementSmallImagesScaledUp(i);
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_EM(Bitmap **em_bitmap)
284 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
285 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
289 static int getFontBitmapID(int font_nr)
293 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
297 else if (game_status == GAME_MODE_PLAYING)
298 special = GFX_SPECIAL_ARG_DOOR;
301 return font_info[font_nr].special_bitmap_id[special];
306 void InitFontGraphicInfo()
308 static struct FontBitmapInfo *font_bitmap_info = NULL;
309 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
310 int num_property_mappings = getImageListPropertyMappingSize();
311 int num_font_bitmaps = NUM_FONTS;
314 if (graphic_info == NULL) /* still at startup phase */
316 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
321 /* ---------- initialize font graphic definitions ---------- */
323 /* always start with reliable default values (normal font graphics) */
325 for (i = 0; i < NUM_FONTS; i++)
326 font_info[i].graphic = IMG_FONT_INITIAL_1;
328 for (i = 0; i < NUM_FONTS; i++)
329 font_info[i].graphic = FONT_INITIAL_1;
332 /* initialize normal font/graphic mapping from static configuration */
333 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
335 int font_nr = font_to_graphic[i].font_nr;
336 int special = font_to_graphic[i].special;
337 int graphic = font_to_graphic[i].graphic;
342 font_info[font_nr].graphic = graphic;
345 /* always start with reliable default values (special font graphics) */
346 for (i = 0; i < NUM_FONTS; i++)
348 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
350 font_info[i].special_graphic[j] = font_info[i].graphic;
351 font_info[i].special_bitmap_id[j] = i;
355 /* initialize special font/graphic mapping from static configuration */
356 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
358 int font_nr = font_to_graphic[i].font_nr;
359 int special = font_to_graphic[i].special;
360 int graphic = font_to_graphic[i].graphic;
362 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
364 font_info[font_nr].special_graphic[special] = graphic;
365 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
370 /* initialize special element/graphic mapping from dynamic configuration */
371 for (i = 0; i < num_property_mappings; i++)
373 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
374 int special = property_mapping[i].ext3_index;
375 int graphic = property_mapping[i].artwork_index;
380 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
382 font_info[font_nr].special_graphic[special] = graphic;
383 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
388 /* ---------- initialize font bitmap array ---------- */
390 if (font_bitmap_info != NULL)
391 FreeFontInfo(font_bitmap_info);
394 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
396 /* ---------- initialize font bitmap definitions ---------- */
398 for (i = 0; i < NUM_FONTS; i++)
400 if (i < NUM_INITIAL_FONTS)
402 font_bitmap_info[i] = font_initial[i];
406 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
408 int font_bitmap_id = font_info[i].special_bitmap_id[j];
409 int graphic = font_info[i].special_graphic[j];
411 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
412 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
414 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
415 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
418 /* copy font relevant information from graphics information */
419 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
420 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
421 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
422 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
423 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
424 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
425 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
427 font_bitmap_info[font_bitmap_id].num_chars =
428 graphic_info[graphic].anim_frames;
429 font_bitmap_info[font_bitmap_id].num_chars_per_line =
430 graphic_info[graphic].anim_frames_per_line;
434 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
437 void InitElementGraphicInfo()
439 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
440 int num_property_mappings = getImageListPropertyMappingSize();
443 if (graphic_info == NULL) /* still at startup phase */
446 /* set values to -1 to identify later as "uninitialized" values */
447 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
449 for (act = 0; act < NUM_ACTIONS; act++)
451 element_info[i].graphic[act] = -1;
452 element_info[i].crumbled[act] = -1;
454 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
456 element_info[i].direction_graphic[act][dir] = -1;
457 element_info[i].direction_crumbled[act][dir] = -1;
462 /* initialize normal element/graphic mapping from static configuration */
463 for (i = 0; element_to_graphic[i].element > -1; i++)
465 int element = element_to_graphic[i].element;
466 int action = element_to_graphic[i].action;
467 int direction = element_to_graphic[i].direction;
468 boolean crumbled = element_to_graphic[i].crumbled;
469 int graphic = element_to_graphic[i].graphic;
470 int base_graphic = el2baseimg(element);
472 if (graphic_info[graphic].bitmap == NULL)
475 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
478 boolean base_redefined =
479 getImageListEntryFromImageID(base_graphic)->redefined;
480 boolean act_dir_redefined =
481 getImageListEntryFromImageID(graphic)->redefined;
483 /* if the base graphic ("emerald", for example) has been redefined,
484 but not the action graphic ("emerald.falling", for example), do not
485 use an existing (in this case considered obsolete) action graphic
486 anymore, but use the automatically determined default graphic */
487 if (base_redefined && !act_dir_redefined)
492 action = ACTION_DEFAULT;
497 element_info[element].direction_crumbled[action][direction] = graphic;
499 element_info[element].crumbled[action] = graphic;
504 element_info[element].direction_graphic[action][direction] = graphic;
506 element_info[element].graphic[action] = graphic;
510 /* initialize normal element/graphic mapping from dynamic configuration */
511 for (i = 0; i < num_property_mappings; i++)
513 int element = property_mapping[i].base_index;
514 int action = property_mapping[i].ext1_index;
515 int direction = property_mapping[i].ext2_index;
516 int special = property_mapping[i].ext3_index;
517 int graphic = property_mapping[i].artwork_index;
518 boolean crumbled = FALSE;
520 if (special == GFX_SPECIAL_ARG_CRUMBLED)
526 if (graphic_info[graphic].bitmap == NULL)
529 if (element >= MAX_NUM_ELEMENTS || special != -1)
533 action = ACTION_DEFAULT;
538 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
539 element_info[element].direction_crumbled[action][dir] = -1;
542 element_info[element].direction_crumbled[action][direction] = graphic;
544 element_info[element].crumbled[action] = graphic;
549 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
550 element_info[element].direction_graphic[action][dir] = -1;
553 element_info[element].direction_graphic[action][direction] = graphic;
555 element_info[element].graphic[action] = graphic;
559 /* now copy all graphics that are defined to be cloned from other graphics */
560 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
562 int graphic = element_info[i].graphic[ACTION_DEFAULT];
563 int crumbled_like, diggable_like;
568 crumbled_like = graphic_info[graphic].crumbled_like;
569 diggable_like = graphic_info[graphic].diggable_like;
571 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
573 for (act = 0; act < NUM_ACTIONS; act++)
574 element_info[i].crumbled[act] =
575 element_info[crumbled_like].crumbled[act];
576 for (act = 0; act < NUM_ACTIONS; act++)
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_crumbled[act][dir] =
579 element_info[crumbled_like].direction_crumbled[act][dir];
582 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
584 element_info[i].graphic[ACTION_DIGGING] =
585 element_info[diggable_like].graphic[ACTION_DIGGING];
586 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
587 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
588 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
593 /* set hardcoded definitions for some runtime elements without graphic */
594 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
598 /* now set all undefined/invalid graphics to -1 to set to default after it */
599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601 for (act = 0; act < NUM_ACTIONS; act++)
605 graphic = element_info[i].graphic[act];
606 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
607 element_info[i].graphic[act] = -1;
609 graphic = element_info[i].crumbled[act];
610 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
611 element_info[i].crumbled[act] = -1;
613 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
615 graphic = element_info[i].direction_graphic[act][dir];
616 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
617 element_info[i].direction_graphic[act][dir] = -1;
619 graphic = element_info[i].direction_crumbled[act][dir];
620 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
621 element_info[i].direction_crumbled[act][dir] = -1;
628 /* adjust graphics with 2nd tile for movement according to direction
629 (do this before correcting '-1' values to minimize calculations) */
630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
632 for (act = 0; act < NUM_ACTIONS; act++)
634 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
636 int graphic = element_info[i].direction_graphic[act][dir];
637 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
639 if (act == ACTION_FALLING) /* special case */
640 graphic = element_info[i].graphic[act];
643 graphic_info[graphic].double_movement &&
644 graphic_info[graphic].swap_double_tiles != 0)
646 struct GraphicInfo *g = &graphic_info[graphic];
647 int src_x_front = g->src_x;
648 int src_y_front = g->src_y;
649 int src_x_back = g->src_x + g->offset2_x;
650 int src_y_back = g->src_y + g->offset2_y;
651 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
653 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
654 src_y_front < src_y_back);
656 boolean second_tile_is_back =
657 ((move_dir == MV_BIT_LEFT && front_is_left_or_upper) ||
658 (move_dir == MV_BIT_UP && front_is_left_or_upper));
659 boolean second_tile_is_front =
660 ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
661 (move_dir == MV_BIT_DOWN && front_is_left_or_upper));
662 boolean second_tile_should_be_front =
663 (g->second_tile_is_start == 0);
664 boolean second_tile_should_be_back =
665 (g->second_tile_is_start == 1);
667 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
668 boolean swap_movement_tiles_autodetected =
669 (!frames_are_ordered_diagonally &&
670 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
671 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
672 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
673 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
677 printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
678 i, element_info[i].token_name,
679 element_action_info[act].suffix, move_dir,
680 g->swap_double_tiles,
681 swap_movement_tiles_never,
682 swap_movement_tiles_always,
683 swap_movement_tiles_autodetected,
684 swap_movement_tiles);
687 /* swap frontside and backside graphic tile coordinates, if needed */
688 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
690 /* get current (wrong) backside tile coordinates */
691 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
694 /* set frontside tile coordinates to backside tile coordinates */
695 g->src_x = src_x_back;
696 g->src_y = src_y_back;
698 /* invert tile offset to point to new backside tile coordinates */
702 /* do not swap front and backside tiles again after correction */
703 g->swap_double_tiles = 0;
706 printf(" CORRECTED\n");
715 /* now set all '-1' values to element specific default values */
716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
719 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
720 int default_direction_graphic[NUM_DIRECTIONS];
721 int default_direction_crumbled[NUM_DIRECTIONS];
723 if (default_graphic == -1)
724 default_graphic = IMG_UNKNOWN;
726 if (default_crumbled == -1)
727 default_crumbled = default_graphic;
729 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
730 if (default_crumbled == -1)
731 default_crumbled = IMG_EMPTY;
734 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
736 default_direction_graphic[dir] =
737 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
738 default_direction_crumbled[dir] =
739 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
741 if (default_direction_graphic[dir] == -1)
742 default_direction_graphic[dir] = default_graphic;
744 if (default_direction_crumbled[dir] == -1)
745 default_direction_crumbled[dir] = default_direction_graphic[dir];
747 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
748 if (default_direction_crumbled[dir] == -1)
749 default_direction_crumbled[dir] = default_crumbled;
753 for (act = 0; act < NUM_ACTIONS; act++)
755 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
756 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
757 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
758 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
759 act == ACTION_TURNING_FROM_RIGHT ||
760 act == ACTION_TURNING_FROM_UP ||
761 act == ACTION_TURNING_FROM_DOWN);
763 /* generic default action graphic (defined by "[default]" directive) */
764 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
765 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
766 int default_remove_graphic = IMG_EMPTY;
768 if (act_remove && default_action_graphic != -1)
769 default_remove_graphic = default_action_graphic;
771 /* look for special default action graphic (classic game specific) */
772 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
773 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
774 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
775 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
776 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
777 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
779 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
780 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
781 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
782 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
783 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
784 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
787 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
788 /* !!! make this better !!! */
789 if (i == EL_EMPTY_SPACE)
791 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
792 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
796 if (default_action_graphic == -1)
797 default_action_graphic = default_graphic;
799 if (default_action_crumbled == -1)
800 default_action_crumbled = default_action_graphic;
802 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
803 if (default_action_crumbled == -1)
804 default_action_crumbled = default_crumbled;
807 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
809 /* use action graphic as the default direction graphic, if undefined */
810 int default_action_direction_graphic = element_info[i].graphic[act];
811 int default_action_direction_crumbled = element_info[i].crumbled[act];
813 /* no graphic for current action -- use default direction graphic */
814 if (default_action_direction_graphic == -1)
815 default_action_direction_graphic =
816 (act_remove ? default_remove_graphic :
818 element_info[i].direction_graphic[ACTION_TURNING][dir] :
819 default_action_graphic != default_graphic ?
820 default_action_graphic :
821 default_direction_graphic[dir]);
823 if (element_info[i].direction_graphic[act][dir] == -1)
824 element_info[i].direction_graphic[act][dir] =
825 default_action_direction_graphic;
828 if (default_action_direction_crumbled == -1)
829 default_action_direction_crumbled =
830 element_info[i].direction_graphic[act][dir];
832 if (default_action_direction_crumbled == -1)
833 default_action_direction_crumbled =
834 (act_remove ? default_remove_graphic :
836 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
837 default_action_crumbled != default_crumbled ?
838 default_action_crumbled :
839 default_direction_crumbled[dir]);
842 if (element_info[i].direction_crumbled[act][dir] == -1)
843 element_info[i].direction_crumbled[act][dir] =
844 default_action_direction_crumbled;
847 if (i == EL_EMC_GRASS &&
848 act == ACTION_DIGGING &&
850 printf("::: direction_crumbled == %d, %d, %d\n",
851 element_info[i].direction_crumbled[act][dir],
852 default_action_direction_crumbled,
853 element_info[i].crumbled[act]);
857 /* no graphic for this specific action -- use default action graphic */
858 if (element_info[i].graphic[act] == -1)
859 element_info[i].graphic[act] =
860 (act_remove ? default_remove_graphic :
861 act_turning ? element_info[i].graphic[ACTION_TURNING] :
862 default_action_graphic);
864 if (element_info[i].crumbled[act] == -1)
865 element_info[i].crumbled[act] = element_info[i].graphic[act];
867 if (element_info[i].crumbled[act] == -1)
868 element_info[i].crumbled[act] =
869 (act_remove ? default_remove_graphic :
870 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
871 default_action_crumbled);
877 /* set animation mode to "none" for each graphic with only 1 frame */
878 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
880 for (act = 0; act < NUM_ACTIONS; act++)
882 int graphic = element_info[i].graphic[act];
883 int crumbled = element_info[i].crumbled[act];
885 if (graphic_info[graphic].anim_frames == 1)
886 graphic_info[graphic].anim_mode = ANIM_NONE;
887 if (graphic_info[crumbled].anim_frames == 1)
888 graphic_info[crumbled].anim_mode = ANIM_NONE;
890 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
892 graphic = element_info[i].direction_graphic[act][dir];
893 crumbled = element_info[i].direction_crumbled[act][dir];
895 if (graphic_info[graphic].anim_frames == 1)
896 graphic_info[graphic].anim_mode = ANIM_NONE;
897 if (graphic_info[crumbled].anim_frames == 1)
898 graphic_info[crumbled].anim_mode = ANIM_NONE;
908 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
911 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
912 element_info[i].token_name, i);
918 void InitElementSpecialGraphicInfo()
920 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
921 int num_property_mappings = getImageListPropertyMappingSize();
924 /* always start with reliable default values */
925 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
926 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
927 element_info[i].special_graphic[j] =
928 element_info[i].graphic[ACTION_DEFAULT];
930 /* initialize special element/graphic mapping from static configuration */
931 for (i = 0; element_to_special_graphic[i].element > -1; i++)
933 int element = element_to_special_graphic[i].element;
934 int special = element_to_special_graphic[i].special;
935 int graphic = element_to_special_graphic[i].graphic;
936 int base_graphic = el2baseimg(element);
937 boolean base_redefined =
938 getImageListEntryFromImageID(base_graphic)->redefined;
939 boolean special_redefined =
940 getImageListEntryFromImageID(graphic)->redefined;
942 /* if the base graphic ("emerald", for example) has been redefined,
943 but not the special graphic ("emerald.EDITOR", for example), do not
944 use an existing (in this case considered obsolete) special graphic
945 anymore, but use the automatically created (down-scaled) graphic */
946 if (base_redefined && !special_redefined)
949 element_info[element].special_graphic[special] = graphic;
952 /* initialize special element/graphic mapping from dynamic configuration */
953 for (i = 0; i < num_property_mappings; i++)
955 int element = property_mapping[i].base_index;
956 int special = property_mapping[i].ext3_index;
957 int graphic = property_mapping[i].artwork_index;
959 if (element >= MAX_NUM_ELEMENTS)
962 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
963 element_info[element].special_graphic[special] = graphic;
967 /* now set all undefined/invalid graphics to default */
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
969 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
970 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
971 element_info[i].special_graphic[j] =
972 element_info[i].graphic[ACTION_DEFAULT];
976 static int get_element_from_token(char *token)
980 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
981 if (strcmp(element_info[i].token_name, token) == 0)
987 static int get_scaled_graphic_width(int graphic)
989 int original_width = getOriginalImageWidthFromImageID(graphic);
990 int scale_up_factor = graphic_info[graphic].scale_up_factor;
992 return original_width * scale_up_factor;
995 static int get_scaled_graphic_height(int graphic)
997 int original_height = getOriginalImageHeightFromImageID(graphic);
998 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1000 return original_height * scale_up_factor;
1003 static void set_graphic_parameters(int graphic, int graphic_copy_from)
1005 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
1006 char **parameter_raw = image->parameter;
1007 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
1008 int parameter[NUM_GFX_ARGS];
1009 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1010 int anim_frames_per_line = 1;
1013 /* get integer values from string parameters */
1014 for (i = 0; i < NUM_GFX_ARGS; i++)
1017 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
1018 image_config_suffix[i].type);
1020 if (image_config_suffix[i].type == TYPE_TOKEN)
1021 parameter[i] = get_element_from_token(parameter_raw[i]);
1024 graphic_info[graphic].bitmap = src_bitmap;
1026 /* start with reliable default values */
1027 graphic_info[graphic].src_x = 0;
1028 graphic_info[graphic].src_y = 0;
1029 graphic_info[graphic].width = TILEX;
1030 graphic_info[graphic].height = TILEY;
1031 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1032 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1033 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1034 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1035 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1036 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1037 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1038 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1039 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1040 graphic_info[graphic].anim_delay_fixed = 0;
1041 graphic_info[graphic].anim_delay_random = 0;
1042 graphic_info[graphic].post_delay_fixed = 0;
1043 graphic_info[graphic].post_delay_random = 0;
1045 /* optional x and y tile position of animation frame sequence */
1046 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1047 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1048 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1049 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1051 /* optional x and y pixel position of animation frame sequence */
1052 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1054 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1057 /* optional width and height of each animation frame */
1058 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1059 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1060 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1061 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1063 /* optional zoom factor for scaling up the image to a larger size */
1064 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1065 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1066 if (graphic_info[graphic].scale_up_factor < 1)
1067 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1071 /* get final bitmap size (with scaling, but without small images) */
1072 int src_bitmap_width = get_scaled_graphic_width(graphic);
1073 int src_bitmap_height = get_scaled_graphic_height(graphic);
1075 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1076 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1079 /* correct x or y offset dependent of vertical or horizontal frame order */
1080 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1082 graphic_info[graphic].offset_y =
1083 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1084 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1085 anim_frames_per_line = anim_frames_per_col;
1087 else /* frames are ordered horizontally */
1089 graphic_info[graphic].offset_x =
1090 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1091 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1092 anim_frames_per_line = anim_frames_per_row;
1095 /* optionally, the x and y offset of frames can be specified directly */
1096 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1097 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1098 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1099 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1101 /* optionally, moving animations may have separate start and end graphics */
1102 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1104 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1105 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1107 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1108 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1109 graphic_info[graphic].offset2_y =
1110 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1111 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1112 else /* frames are ordered horizontally */
1113 graphic_info[graphic].offset2_x =
1114 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1115 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1117 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1118 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1119 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1120 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1121 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1123 /* optionally, the second movement tile can be specified as start tile */
1124 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1125 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1127 /* automatically determine correct number of frames, if not defined */
1128 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1129 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1130 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1131 graphic_info[graphic].anim_frames = anim_frames_per_row;
1132 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1133 graphic_info[graphic].anim_frames = anim_frames_per_col;
1135 graphic_info[graphic].anim_frames = 1;
1137 graphic_info[graphic].anim_frames_per_line =
1138 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1139 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1141 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1142 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1143 graphic_info[graphic].anim_delay = 1;
1145 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1147 if (graphic_info[graphic].anim_frames == 1)
1148 graphic_info[graphic].anim_mode = ANIM_NONE;
1151 /* automatically determine correct start frame, if not defined */
1152 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1153 graphic_info[graphic].anim_start_frame = 0;
1154 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1155 graphic_info[graphic].anim_start_frame =
1156 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1158 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1160 /* animation synchronized with global frame counter, not move position */
1161 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1163 /* optional element for cloning crumble graphics */
1164 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1165 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1167 /* optional element for cloning digging graphics */
1168 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1169 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1171 /* optional border size for "crumbling" diggable graphics */
1172 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1173 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1175 /* this is only used for player "boring" and "sleeping" actions */
1176 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1177 graphic_info[graphic].anim_delay_fixed =
1178 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1179 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1180 graphic_info[graphic].anim_delay_random =
1181 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1182 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1183 graphic_info[graphic].post_delay_fixed =
1184 parameter[GFX_ARG_POST_DELAY_FIXED];
1185 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1186 graphic_info[graphic].post_delay_random =
1187 parameter[GFX_ARG_POST_DELAY_RANDOM];
1189 /* this is only used for toon animations */
1190 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1191 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1193 /* this is only used for drawing font characters */
1194 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1195 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1197 /* this is only used for drawing envelope graphics */
1198 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1201 static void InitGraphicInfo()
1203 int fallback_graphic = IMG_CHAR_EXCLAM;
1204 int num_images = getImageListSize();
1207 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1208 static boolean clipmasks_initialized = FALSE;
1210 XGCValues clip_gc_values;
1211 unsigned long clip_gc_valuemask;
1212 GC copy_clipmask_gc = None;
1215 checked_free(graphic_info);
1217 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1220 printf("::: graphic_info: %d entries\n", num_images);
1223 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1224 if (clipmasks_initialized)
1226 for (i = 0; i < num_images; i++)
1228 if (graphic_info[i].clip_mask)
1229 XFreePixmap(display, graphic_info[i].clip_mask);
1230 if (graphic_info[i].clip_gc)
1231 XFreeGC(display, graphic_info[i].clip_gc);
1233 graphic_info[i].clip_mask = None;
1234 graphic_info[i].clip_gc = None;
1239 for (i = 0; i < num_images; i++)
1243 int first_frame, last_frame;
1244 int src_bitmap_width, src_bitmap_height;
1247 printf("::: image: '%s' [%d]\n", image->token, i);
1251 printf("::: image # %d: '%s' ['%s']\n",
1253 getTokenFromImageID(i));
1256 set_graphic_parameters(i, i);
1258 /* now check if no animation frames are outside of the loaded image */
1260 if (graphic_info[i].bitmap == NULL)
1261 continue; /* skip check for optional images that are undefined */
1263 /* get final bitmap size (with scaling, but without small images) */
1264 src_bitmap_width = get_scaled_graphic_width(i);
1265 src_bitmap_height = get_scaled_graphic_height(i);
1268 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1269 if (src_x < 0 || src_y < 0 ||
1270 src_x + TILEX > src_bitmap_width ||
1271 src_y + TILEY > src_bitmap_height)
1273 Error(ERR_RETURN_LINE, "-");
1274 Error(ERR_RETURN, "warning: error found in config file:");
1275 Error(ERR_RETURN, "- config file: '%s'",
1276 getImageConfigFilename());
1277 Error(ERR_RETURN, "- config token: '%s'",
1278 getTokenFromImageID(i));
1279 Error(ERR_RETURN, "- image file: '%s'",
1280 src_bitmap->source_filename);
1282 "error: first animation frame out of bounds (%d, %d)",
1284 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1287 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1290 if (i == fallback_graphic)
1291 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1293 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1294 Error(ERR_RETURN_LINE, "-");
1296 set_graphic_parameters(i, fallback_graphic);
1299 last_frame = graphic_info[i].anim_frames - 1;
1300 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1301 if (src_x < 0 || src_y < 0 ||
1302 src_x + TILEX > src_bitmap_width ||
1303 src_y + TILEY > src_bitmap_height)
1305 Error(ERR_RETURN_LINE, "-");
1306 Error(ERR_RETURN, "warning: error found in config file:");
1307 Error(ERR_RETURN, "- config file: '%s'",
1308 getImageConfigFilename());
1309 Error(ERR_RETURN, "- config token: '%s'",
1310 getTokenFromImageID(i));
1311 Error(ERR_RETURN, "- image file: '%s'",
1312 src_bitmap->source_filename);
1314 "error: last animation frame (%d) out of bounds (%d, %d)",
1315 last_frame, src_x, src_y);
1316 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1318 if (i == fallback_graphic)
1319 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1321 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1322 Error(ERR_RETURN_LINE, "-");
1324 set_graphic_parameters(i, fallback_graphic);
1327 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1328 /* currently we only need a tile clip mask from the first frame */
1329 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1331 if (copy_clipmask_gc == None)
1333 clip_gc_values.graphics_exposures = False;
1334 clip_gc_valuemask = GCGraphicsExposures;
1335 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1336 clip_gc_valuemask, &clip_gc_values);
1339 graphic_info[i].clip_mask =
1340 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1342 src_pixmap = src_bitmap->clip_mask;
1343 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1344 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1346 clip_gc_values.graphics_exposures = False;
1347 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1348 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1350 graphic_info[i].clip_gc =
1351 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1355 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1356 if (copy_clipmask_gc)
1357 XFreeGC(display, copy_clipmask_gc);
1359 clipmasks_initialized = TRUE;
1363 static void InitElementSoundInfo()
1365 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1366 int num_property_mappings = getSoundListPropertyMappingSize();
1369 /* set values to -1 to identify later as "uninitialized" values */
1370 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1371 for (act = 0; act < NUM_ACTIONS; act++)
1372 element_info[i].sound[act] = -1;
1374 /* initialize element/sound mapping from static configuration */
1375 for (i = 0; element_to_sound[i].element > -1; i++)
1377 int element = element_to_sound[i].element;
1378 int action = element_to_sound[i].action;
1379 int sound = element_to_sound[i].sound;
1380 boolean is_class = element_to_sound[i].is_class;
1383 action = ACTION_DEFAULT;
1386 element_info[element].sound[action] = sound;
1388 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1389 if (strcmp(element_info[j].class_name,
1390 element_info[element].class_name) == 0)
1391 element_info[j].sound[action] = sound;
1394 /* initialize element class/sound mapping from dynamic configuration */
1395 for (i = 0; i < num_property_mappings; i++)
1397 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1398 int action = property_mapping[i].ext1_index;
1399 int sound = property_mapping[i].artwork_index;
1401 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1405 action = ACTION_DEFAULT;
1407 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1408 if (strcmp(element_info[j].class_name,
1409 element_info[element_class].class_name) == 0)
1410 element_info[j].sound[action] = sound;
1413 /* initialize element/sound mapping from dynamic configuration */
1414 for (i = 0; i < num_property_mappings; i++)
1416 int element = property_mapping[i].base_index;
1417 int action = property_mapping[i].ext1_index;
1418 int sound = property_mapping[i].artwork_index;
1420 if (element >= MAX_NUM_ELEMENTS)
1424 action = ACTION_DEFAULT;
1426 element_info[element].sound[action] = sound;
1429 /* now set all '-1' values to element specific default values */
1430 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1432 for (act = 0; act < NUM_ACTIONS; act++)
1434 /* generic default action sound (defined by "[default]" directive) */
1435 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1437 /* look for special default action sound (classic game specific) */
1438 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1439 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1440 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1441 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1442 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1443 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1445 /* !!! there's no such thing as a "default action sound" !!! */
1447 /* look for element specific default sound (independent from action) */
1448 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1449 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1453 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1454 /* !!! make this better !!! */
1455 if (i == EL_EMPTY_SPACE)
1456 default_action_sound = element_info[EL_DEFAULT].sound[act];
1459 /* no sound for this specific action -- use default action sound */
1460 if (element_info[i].sound[act] == -1)
1461 element_info[i].sound[act] = default_action_sound;
1466 static void InitGameModeSoundInfo()
1470 /* set values to -1 to identify later as "uninitialized" values */
1471 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1474 /* initialize gamemode/sound mapping from static configuration */
1475 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1477 int gamemode = gamemode_to_sound[i].gamemode;
1478 int sound = gamemode_to_sound[i].sound;
1481 gamemode = GAME_MODE_DEFAULT;
1483 menu.sound[gamemode] = sound;
1486 /* now set all '-1' values to levelset specific default values */
1487 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1488 if (menu.sound[i] == -1)
1489 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1493 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1494 if (menu.sound[i] != -1)
1495 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1499 static void set_sound_parameters(int sound, char **parameter_raw)
1501 int parameter[NUM_SND_ARGS];
1504 /* get integer values from string parameters */
1505 for (i = 0; i < NUM_SND_ARGS; i++)
1507 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1508 sound_config_suffix[i].type);
1510 /* explicit loop mode setting in configuration overrides default value */
1511 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1512 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1514 /* sound volume to change the original volume when loading the sound file */
1515 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1517 /* sound priority to give certain sounds a higher or lower priority */
1518 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1521 static void InitSoundInfo()
1524 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1525 int num_property_mappings = getSoundListPropertyMappingSize();
1527 int *sound_effect_properties;
1528 int num_sounds = getSoundListSize();
1531 checked_free(sound_info);
1533 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1534 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1536 /* initialize sound effect for all elements to "no sound" */
1537 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1538 for (j = 0; j < NUM_ACTIONS; j++)
1539 element_info[i].sound[j] = SND_UNDEFINED;
1541 for (i = 0; i < num_sounds; i++)
1543 struct FileInfo *sound = getSoundListEntry(i);
1544 int len_effect_text = strlen(sound->token);
1546 sound_effect_properties[i] = ACTION_OTHER;
1547 sound_info[i].loop = FALSE; /* default: play sound only once */
1550 printf("::: sound %d: '%s'\n", i, sound->token);
1553 /* determine all loop sounds and identify certain sound classes */
1555 for (j = 0; element_action_info[j].suffix; j++)
1557 int len_action_text = strlen(element_action_info[j].suffix);
1559 if (len_action_text < len_effect_text &&
1560 strcmp(&sound->token[len_effect_text - len_action_text],
1561 element_action_info[j].suffix) == 0)
1563 sound_effect_properties[i] = element_action_info[j].value;
1564 sound_info[i].loop = element_action_info[j].is_loop_sound;
1571 if (strcmp(sound->token, "custom_42") == 0)
1572 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1575 /* associate elements and some selected sound actions */
1577 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1579 if (element_info[j].class_name)
1581 int len_class_text = strlen(element_info[j].class_name);
1583 if (len_class_text + 1 < len_effect_text &&
1584 strncmp(sound->token,
1585 element_info[j].class_name, len_class_text) == 0 &&
1586 sound->token[len_class_text] == '.')
1588 int sound_action_value = sound_effect_properties[i];
1590 element_info[j].sound[sound_action_value] = i;
1595 set_sound_parameters(i, sound->parameter);
1598 free(sound_effect_properties);
1601 /* !!! now handled in InitElementSoundInfo() !!! */
1602 /* initialize element/sound mapping from dynamic configuration */
1603 for (i = 0; i < num_property_mappings; i++)
1605 int element = property_mapping[i].base_index;
1606 int action = property_mapping[i].ext1_index;
1607 int sound = property_mapping[i].artwork_index;
1610 action = ACTION_DEFAULT;
1612 printf("::: %d: %d, %d, %d ['%s']\n",
1613 i, element, action, sound, element_info[element].token_name);
1615 element_info[element].sound[action] = sound;
1622 int element = EL_CUSTOM_11;
1625 while (element_action_info[j].suffix)
1627 printf("element %d, sound action '%s' == %d\n",
1628 element, element_action_info[j].suffix,
1629 element_info[element].sound[j]);
1634 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1640 int element = EL_SAND;
1641 int sound_action = ACTION_DIGGING;
1644 while (element_action_info[j].suffix)
1646 if (element_action_info[j].value == sound_action)
1647 printf("element %d, sound action '%s' == %d\n",
1648 element, element_action_info[j].suffix,
1649 element_info[element].sound[sound_action]);
1656 static void InitGameModeMusicInfo()
1658 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1659 int num_property_mappings = getMusicListPropertyMappingSize();
1660 int default_levelset_music = -1;
1663 /* set values to -1 to identify later as "uninitialized" values */
1664 for (i = 0; i < MAX_LEVELS; i++)
1665 levelset.music[i] = -1;
1666 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1669 /* initialize gamemode/music mapping from static configuration */
1670 for (i = 0; gamemode_to_music[i].music > -1; i++)
1672 int gamemode = gamemode_to_music[i].gamemode;
1673 int music = gamemode_to_music[i].music;
1676 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1680 gamemode = GAME_MODE_DEFAULT;
1682 menu.music[gamemode] = music;
1685 /* initialize gamemode/music mapping from dynamic configuration */
1686 for (i = 0; i < num_property_mappings; i++)
1688 int prefix = property_mapping[i].base_index;
1689 int gamemode = property_mapping[i].ext1_index;
1690 int level = property_mapping[i].ext2_index;
1691 int music = property_mapping[i].artwork_index;
1694 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1695 prefix, gamemode, level, music);
1698 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1702 gamemode = GAME_MODE_DEFAULT;
1704 /* level specific music only allowed for in-game music */
1705 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1706 gamemode = GAME_MODE_PLAYING;
1711 default_levelset_music = music;
1714 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1715 levelset.music[level] = music;
1716 if (gamemode != GAME_MODE_PLAYING)
1717 menu.music[gamemode] = music;
1720 /* now set all '-1' values to menu specific default values */
1721 /* (undefined values of "levelset.music[]" might stay at "-1" to
1722 allow dynamic selection of music files from music directory!) */
1723 for (i = 0; i < MAX_LEVELS; i++)
1724 if (levelset.music[i] == -1)
1725 levelset.music[i] = default_levelset_music;
1726 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1727 if (menu.music[i] == -1)
1728 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1732 for (i = 0; i < MAX_LEVELS; i++)
1733 if (levelset.music[i] != -1)
1734 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1735 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1736 if (menu.music[i] != -1)
1737 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1741 static void set_music_parameters(int music, char **parameter_raw)
1743 int parameter[NUM_MUS_ARGS];
1746 /* get integer values from string parameters */
1747 for (i = 0; i < NUM_MUS_ARGS; i++)
1749 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1750 music_config_suffix[i].type);
1752 /* explicit loop mode setting in configuration overrides default value */
1753 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1754 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1757 static void InitMusicInfo()
1759 int num_music = getMusicListSize();
1762 checked_free(music_info);
1764 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1766 for (i = 0; i < num_music; i++)
1768 struct FileInfo *music = getMusicListEntry(i);
1769 int len_music_text = strlen(music->token);
1771 music_info[i].loop = TRUE; /* default: play music in loop mode */
1773 /* determine all loop music */
1775 for (j = 0; music_prefix_info[j].prefix; j++)
1777 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1779 if (len_prefix_text < len_music_text &&
1780 strncmp(music->token,
1781 music_prefix_info[j].prefix, len_prefix_text) == 0)
1783 music_info[i].loop = music_prefix_info[j].is_loop_music;
1789 set_music_parameters(i, music->parameter);
1793 static void ReinitializeGraphics()
1795 InitGraphicInfo(); /* graphic properties mapping */
1796 InitElementGraphicInfo(); /* element game graphic mapping */
1797 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1799 InitElementSmallImages(); /* scale images to all needed sizes */
1800 InitFontGraphicInfo(); /* initialize text drawing functions */
1802 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1804 SetMainBackgroundImage(IMG_BACKGROUND);
1805 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1811 static void ReinitializeSounds()
1813 InitSoundInfo(); /* sound properties mapping */
1814 InitElementSoundInfo(); /* element game sound mapping */
1815 InitGameModeSoundInfo(); /* game mode sound mapping */
1817 InitPlayLevelSound(); /* internal game sound settings */
1820 static void ReinitializeMusic()
1822 InitMusicInfo(); /* music properties mapping */
1823 InitGameModeMusicInfo(); /* game mode music mapping */
1826 static int get_special_property_bit(int element, int property_bit_nr)
1828 struct PropertyBitInfo
1834 static struct PropertyBitInfo pb_can_move_into_acid[] =
1836 /* the player may be able fall into acid when gravity is activated */
1841 { EL_SP_MURPHY, 0 },
1842 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1844 /* all element that can move may be able to also move into acid */
1847 { EL_BUG_RIGHT, 1 },
1850 { EL_SPACESHIP, 2 },
1851 { EL_SPACESHIP_LEFT, 2 },
1852 { EL_SPACESHIP_RIGHT, 2 },
1853 { EL_SPACESHIP_UP, 2 },
1854 { EL_SPACESHIP_DOWN, 2 },
1855 { EL_BD_BUTTERFLY, 3 },
1856 { EL_BD_BUTTERFLY_LEFT, 3 },
1857 { EL_BD_BUTTERFLY_RIGHT, 3 },
1858 { EL_BD_BUTTERFLY_UP, 3 },
1859 { EL_BD_BUTTERFLY_DOWN, 3 },
1860 { EL_BD_FIREFLY, 4 },
1861 { EL_BD_FIREFLY_LEFT, 4 },
1862 { EL_BD_FIREFLY_RIGHT, 4 },
1863 { EL_BD_FIREFLY_UP, 4 },
1864 { EL_BD_FIREFLY_DOWN, 4 },
1866 { EL_DARK_YAMYAM, 6 },
1869 { EL_PACMAN_LEFT, 8 },
1870 { EL_PACMAN_RIGHT, 8 },
1871 { EL_PACMAN_UP, 8 },
1872 { EL_PACMAN_DOWN, 8 },
1874 { EL_MOLE_LEFT, 9 },
1875 { EL_MOLE_RIGHT, 9 },
1877 { EL_MOLE_DOWN, 9 },
1881 { EL_SATELLITE, 13 },
1882 { EL_SP_SNIKSNAK, 14 },
1883 { EL_SP_ELECTRON, 15 },
1890 static struct PropertyBitInfo pb_dont_collide_with[] =
1892 { EL_SP_SNIKSNAK, 0 },
1893 { EL_SP_ELECTRON, 1 },
1901 struct PropertyBitInfo *pb_info;
1904 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1905 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1910 struct PropertyBitInfo *pb_info = NULL;
1913 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1914 if (pb_definition[i].bit_nr == property_bit_nr)
1915 pb_info = pb_definition[i].pb_info;
1917 if (pb_info == NULL)
1920 for (i = 0; pb_info[i].element != -1; i++)
1921 if (pb_info[i].element == element)
1922 return pb_info[i].bit_nr;
1928 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1929 boolean property_value)
1931 int bit_nr = get_special_property_bit(element, property_bit_nr);
1936 *bitfield |= (1 << bit_nr);
1938 *bitfield &= ~(1 << bit_nr);
1942 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1944 int bit_nr = get_special_property_bit(element, property_bit_nr);
1947 return ((*bitfield & (1 << bit_nr)) != 0);
1954 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1956 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1960 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1963 level->can_move_into_acid_bits |= (1 << bit_nr);
1967 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1969 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1972 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1978 void InitElementPropertiesStatic()
1980 static int ep_diggable[] =
1985 EL_SP_BUGGY_BASE_ACTIVATING,
1988 EL_INVISIBLE_SAND_ACTIVE,
1991 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1992 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1996 EL_SP_BUGGY_BASE_ACTIVE,
2002 static int ep_collectible_only[] =
2023 EL_DYNABOMB_INCREASE_NUMBER,
2024 EL_DYNABOMB_INCREASE_SIZE,
2025 EL_DYNABOMB_INCREASE_POWER,
2044 static int ep_dont_run_into[] =
2046 /* same elements as in 'ep_dont_touch' */
2052 /* same elements as in 'ep_dont_collide_with' */
2064 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2068 EL_SP_BUGGY_BASE_ACTIVE,
2074 static int ep_dont_collide_with[] =
2076 /* same elements as in 'ep_dont_touch' */
2092 static int ep_dont_touch[] =
2101 static int ep_indestructible[] =
2105 EL_ACID_POOL_TOPLEFT,
2106 EL_ACID_POOL_TOPRIGHT,
2107 EL_ACID_POOL_BOTTOMLEFT,
2108 EL_ACID_POOL_BOTTOM,
2109 EL_ACID_POOL_BOTTOMRIGHT,
2110 EL_SP_HARDWARE_GRAY,
2111 EL_SP_HARDWARE_GREEN,
2112 EL_SP_HARDWARE_BLUE,
2114 EL_SP_HARDWARE_YELLOW,
2115 EL_SP_HARDWARE_BASE_1,
2116 EL_SP_HARDWARE_BASE_2,
2117 EL_SP_HARDWARE_BASE_3,
2118 EL_SP_HARDWARE_BASE_4,
2119 EL_SP_HARDWARE_BASE_5,
2120 EL_SP_HARDWARE_BASE_6,
2121 EL_INVISIBLE_STEELWALL,
2122 EL_INVISIBLE_STEELWALL_ACTIVE,
2123 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2124 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2125 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2126 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2127 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2128 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2129 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2130 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2131 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2132 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2133 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2134 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2136 EL_LIGHT_SWITCH_ACTIVE,
2137 EL_SIGN_EXCLAMATION,
2138 EL_SIGN_RADIOACTIVITY,
2149 EL_STEELWALL_SLIPPERY,
2180 EL_SWITCHGATE_OPENING,
2181 EL_SWITCHGATE_CLOSED,
2182 EL_SWITCHGATE_CLOSING,
2184 EL_SWITCHGATE_SWITCH_UP,
2185 EL_SWITCHGATE_SWITCH_DOWN,
2188 EL_TIMEGATE_OPENING,
2190 EL_TIMEGATE_CLOSING,
2193 EL_TIMEGATE_SWITCH_ACTIVE,
2198 EL_TUBE_VERTICAL_LEFT,
2199 EL_TUBE_VERTICAL_RIGHT,
2200 EL_TUBE_HORIZONTAL_UP,
2201 EL_TUBE_HORIZONTAL_DOWN,
2209 static int ep_slippery[] =
2223 EL_ROBOT_WHEEL_ACTIVE,
2229 EL_ACID_POOL_TOPLEFT,
2230 EL_ACID_POOL_TOPRIGHT,
2240 EL_STEELWALL_SLIPPERY,
2243 EL_EMC_WALL_SLIPPERY_1,
2244 EL_EMC_WALL_SLIPPERY_2,
2245 EL_EMC_WALL_SLIPPERY_3,
2246 EL_EMC_WALL_SLIPPERY_4,
2250 static int ep_can_change[] =
2255 static int ep_can_move[] =
2257 /* same elements as in 'pb_can_move_into_acid' */
2279 static int ep_can_fall[] =
2294 EL_BD_MAGIC_WALL_FULL,
2307 static int ep_can_smash_player[] =
2332 static int ep_can_smash_enemies[] =
2340 static int ep_can_smash_everything[] =
2348 static int ep_explodes_by_fire[] =
2350 /* same elements as in 'ep_explodes_impact' */
2355 /* same elements as in 'ep_explodes_smashed' */
2364 EL_DYNABOMB_PLAYER_1_ACTIVE,
2365 EL_DYNABOMB_PLAYER_2_ACTIVE,
2366 EL_DYNABOMB_PLAYER_3_ACTIVE,
2367 EL_DYNABOMB_PLAYER_4_ACTIVE,
2368 EL_DYNABOMB_INCREASE_NUMBER,
2369 EL_DYNABOMB_INCREASE_SIZE,
2370 EL_DYNABOMB_INCREASE_POWER,
2371 EL_SP_DISK_RED_ACTIVE,
2384 static int ep_explodes_smashed[] =
2386 /* same elements as in 'ep_explodes_impact' */
2399 static int ep_explodes_impact[] =
2407 static int ep_walkable_over[] =
2411 EL_SOKOBAN_FIELD_EMPTY,
2429 static int ep_walkable_inside[] =
2434 EL_TUBE_VERTICAL_LEFT,
2435 EL_TUBE_VERTICAL_RIGHT,
2436 EL_TUBE_HORIZONTAL_UP,
2437 EL_TUBE_HORIZONTAL_DOWN,
2445 static int ep_walkable_under[] =
2450 static int ep_passable_over[] =
2473 static int ep_passable_inside[] =
2479 EL_SP_PORT_HORIZONTAL,
2480 EL_SP_PORT_VERTICAL,
2482 EL_SP_GRAVITY_PORT_LEFT,
2483 EL_SP_GRAVITY_PORT_RIGHT,
2484 EL_SP_GRAVITY_PORT_UP,
2485 EL_SP_GRAVITY_PORT_DOWN,
2486 EL_SP_GRAVITY_ON_PORT_LEFT,
2487 EL_SP_GRAVITY_ON_PORT_RIGHT,
2488 EL_SP_GRAVITY_ON_PORT_UP,
2489 EL_SP_GRAVITY_ON_PORT_DOWN,
2490 EL_SP_GRAVITY_OFF_PORT_LEFT,
2491 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2492 EL_SP_GRAVITY_OFF_PORT_UP,
2493 EL_SP_GRAVITY_OFF_PORT_DOWN,
2497 static int ep_passable_under[] =
2502 static int ep_droppable[] =
2507 static int ep_explodes_1x1_old[] =
2512 static int ep_pushable[] =
2524 EL_SOKOBAN_FIELD_FULL,
2532 static int ep_explodes_cross_old[] =
2537 static int ep_protected[] =
2539 /* same elements as in 'ep_walkable_inside' */
2543 EL_TUBE_VERTICAL_LEFT,
2544 EL_TUBE_VERTICAL_RIGHT,
2545 EL_TUBE_HORIZONTAL_UP,
2546 EL_TUBE_HORIZONTAL_DOWN,
2552 /* same elements as in 'ep_passable_over' */
2572 /* same elements as in 'ep_passable_inside' */
2577 EL_SP_PORT_HORIZONTAL,
2578 EL_SP_PORT_VERTICAL,
2580 EL_SP_GRAVITY_PORT_LEFT,
2581 EL_SP_GRAVITY_PORT_RIGHT,
2582 EL_SP_GRAVITY_PORT_UP,
2583 EL_SP_GRAVITY_PORT_DOWN,
2584 EL_SP_GRAVITY_ON_PORT_LEFT,
2585 EL_SP_GRAVITY_ON_PORT_RIGHT,
2586 EL_SP_GRAVITY_ON_PORT_UP,
2587 EL_SP_GRAVITY_ON_PORT_DOWN,
2588 EL_SP_GRAVITY_OFF_PORT_LEFT,
2589 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2590 EL_SP_GRAVITY_OFF_PORT_UP,
2591 EL_SP_GRAVITY_OFF_PORT_DOWN,
2595 static int ep_throwable[] =
2600 static int ep_can_explode[] =
2602 /* same elements as in 'ep_explodes_impact' */
2607 /* same elements as in 'ep_explodes_smashed' */
2613 /* elements that can explode by explosion or by dragonfire */
2616 EL_DYNABOMB_PLAYER_1_ACTIVE,
2617 EL_DYNABOMB_PLAYER_2_ACTIVE,
2618 EL_DYNABOMB_PLAYER_3_ACTIVE,
2619 EL_DYNABOMB_PLAYER_4_ACTIVE,
2620 EL_DYNABOMB_INCREASE_NUMBER,
2621 EL_DYNABOMB_INCREASE_SIZE,
2622 EL_DYNABOMB_INCREASE_POWER,
2623 EL_SP_DISK_RED_ACTIVE,
2631 /* elements that can explode only by explosion */
2636 static int ep_gravity_reachable[] =
2642 EL_INVISIBLE_SAND_ACTIVE,
2647 EL_SP_PORT_HORIZONTAL,
2648 EL_SP_PORT_VERTICAL,
2650 EL_SP_GRAVITY_PORT_LEFT,
2651 EL_SP_GRAVITY_PORT_RIGHT,
2652 EL_SP_GRAVITY_PORT_UP,
2653 EL_SP_GRAVITY_PORT_DOWN,
2654 EL_SP_GRAVITY_ON_PORT_LEFT,
2655 EL_SP_GRAVITY_ON_PORT_RIGHT,
2656 EL_SP_GRAVITY_ON_PORT_UP,
2657 EL_SP_GRAVITY_ON_PORT_DOWN,
2658 EL_SP_GRAVITY_OFF_PORT_LEFT,
2659 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2660 EL_SP_GRAVITY_OFF_PORT_UP,
2661 EL_SP_GRAVITY_OFF_PORT_DOWN,
2666 static int ep_player[] =
2673 EL_SOKOBAN_FIELD_PLAYER,
2678 static int ep_can_pass_magic_wall[] =
2691 static int ep_switchable[] =
2695 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2696 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2697 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2698 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2699 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2700 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2701 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2702 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2703 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2704 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2705 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2706 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2707 EL_SWITCHGATE_SWITCH_UP,
2708 EL_SWITCHGATE_SWITCH_DOWN,
2710 EL_LIGHT_SWITCH_ACTIVE,
2712 EL_BALLOON_SWITCH_LEFT,
2713 EL_BALLOON_SWITCH_RIGHT,
2714 EL_BALLOON_SWITCH_UP,
2715 EL_BALLOON_SWITCH_DOWN,
2716 EL_BALLOON_SWITCH_ANY,
2719 EL_EMC_MAGIC_BALL_SWITCH,
2723 static int ep_bd_element[] =
2756 static int ep_sp_element[] =
2758 /* should always be valid */
2761 /* standard classic Supaplex elements */
2768 EL_SP_HARDWARE_GRAY,
2776 EL_SP_GRAVITY_PORT_RIGHT,
2777 EL_SP_GRAVITY_PORT_DOWN,
2778 EL_SP_GRAVITY_PORT_LEFT,
2779 EL_SP_GRAVITY_PORT_UP,
2784 EL_SP_PORT_VERTICAL,
2785 EL_SP_PORT_HORIZONTAL,
2791 EL_SP_HARDWARE_BASE_1,
2792 EL_SP_HARDWARE_GREEN,
2793 EL_SP_HARDWARE_BLUE,
2795 EL_SP_HARDWARE_YELLOW,
2796 EL_SP_HARDWARE_BASE_2,
2797 EL_SP_HARDWARE_BASE_3,
2798 EL_SP_HARDWARE_BASE_4,
2799 EL_SP_HARDWARE_BASE_5,
2800 EL_SP_HARDWARE_BASE_6,
2804 /* additional elements that appeared in newer Supaplex levels */
2807 /* additional gravity port elements (not switching, but setting gravity) */
2808 EL_SP_GRAVITY_ON_PORT_LEFT,
2809 EL_SP_GRAVITY_ON_PORT_RIGHT,
2810 EL_SP_GRAVITY_ON_PORT_UP,
2811 EL_SP_GRAVITY_ON_PORT_DOWN,
2812 EL_SP_GRAVITY_OFF_PORT_LEFT,
2813 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2814 EL_SP_GRAVITY_OFF_PORT_UP,
2815 EL_SP_GRAVITY_OFF_PORT_DOWN,
2817 /* more than one Murphy in a level results in an inactive clone */
2820 /* runtime Supaplex elements */
2821 EL_SP_DISK_RED_ACTIVE,
2822 EL_SP_TERMINAL_ACTIVE,
2823 EL_SP_BUGGY_BASE_ACTIVATING,
2824 EL_SP_BUGGY_BASE_ACTIVE,
2830 static int ep_sb_element[] =
2835 EL_SOKOBAN_FIELD_EMPTY,
2836 EL_SOKOBAN_FIELD_FULL,
2837 EL_SOKOBAN_FIELD_PLAYER,
2842 EL_INVISIBLE_STEELWALL,
2846 static int ep_gem[] =
2857 static int ep_food_dark_yamyam[] =
2884 static int ep_food_penguin[] =
2897 static int ep_food_pig[] =
2908 static int ep_historic_wall[] =
2933 EL_EXPANDABLE_WALL_HORIZONTAL,
2934 EL_EXPANDABLE_WALL_VERTICAL,
2935 EL_EXPANDABLE_WALL_ANY,
2936 EL_EXPANDABLE_WALL_GROWING,
2943 EL_SP_HARDWARE_GRAY,
2944 EL_SP_HARDWARE_GREEN,
2945 EL_SP_HARDWARE_BLUE,
2947 EL_SP_HARDWARE_YELLOW,
2948 EL_SP_HARDWARE_BASE_1,
2949 EL_SP_HARDWARE_BASE_2,
2950 EL_SP_HARDWARE_BASE_3,
2951 EL_SP_HARDWARE_BASE_4,
2952 EL_SP_HARDWARE_BASE_5,
2953 EL_SP_HARDWARE_BASE_6,
2955 EL_SP_TERMINAL_ACTIVE,
2958 EL_INVISIBLE_STEELWALL,
2959 EL_INVISIBLE_STEELWALL_ACTIVE,
2961 EL_INVISIBLE_WALL_ACTIVE,
2962 EL_STEELWALL_SLIPPERY,
2978 static int ep_historic_solid[] =
2982 EL_EXPANDABLE_WALL_HORIZONTAL,
2983 EL_EXPANDABLE_WALL_VERTICAL,
2984 EL_EXPANDABLE_WALL_ANY,
2997 EL_QUICKSAND_FILLING,
2998 EL_QUICKSAND_EMPTYING,
3000 EL_MAGIC_WALL_ACTIVE,
3001 EL_MAGIC_WALL_EMPTYING,
3002 EL_MAGIC_WALL_FILLING,
3006 EL_BD_MAGIC_WALL_ACTIVE,
3007 EL_BD_MAGIC_WALL_EMPTYING,
3008 EL_BD_MAGIC_WALL_FULL,
3009 EL_BD_MAGIC_WALL_FILLING,
3010 EL_BD_MAGIC_WALL_DEAD,
3019 EL_SP_TERMINAL_ACTIVE,
3023 EL_INVISIBLE_WALL_ACTIVE,
3024 EL_SWITCHGATE_SWITCH_UP,
3025 EL_SWITCHGATE_SWITCH_DOWN,
3027 EL_TIMEGATE_SWITCH_ACTIVE,
3039 /* the following elements are a direct copy of "indestructible" elements,
3040 except "EL_ACID", which is "indestructible", but not "solid"! */
3045 EL_ACID_POOL_TOPLEFT,
3046 EL_ACID_POOL_TOPRIGHT,
3047 EL_ACID_POOL_BOTTOMLEFT,
3048 EL_ACID_POOL_BOTTOM,
3049 EL_ACID_POOL_BOTTOMRIGHT,
3050 EL_SP_HARDWARE_GRAY,
3051 EL_SP_HARDWARE_GREEN,
3052 EL_SP_HARDWARE_BLUE,
3054 EL_SP_HARDWARE_YELLOW,
3055 EL_SP_HARDWARE_BASE_1,
3056 EL_SP_HARDWARE_BASE_2,
3057 EL_SP_HARDWARE_BASE_3,
3058 EL_SP_HARDWARE_BASE_4,
3059 EL_SP_HARDWARE_BASE_5,
3060 EL_SP_HARDWARE_BASE_6,
3061 EL_INVISIBLE_STEELWALL,
3062 EL_INVISIBLE_STEELWALL_ACTIVE,
3063 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3064 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3065 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3066 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3067 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3068 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3069 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3070 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3071 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3072 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3073 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3074 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3076 EL_LIGHT_SWITCH_ACTIVE,
3077 EL_SIGN_EXCLAMATION,
3078 EL_SIGN_RADIOACTIVITY,
3089 EL_STEELWALL_SLIPPERY,
3112 EL_SWITCHGATE_OPENING,
3113 EL_SWITCHGATE_CLOSED,
3114 EL_SWITCHGATE_CLOSING,
3116 EL_TIMEGATE_OPENING,
3118 EL_TIMEGATE_CLOSING,
3122 EL_TUBE_VERTICAL_LEFT,
3123 EL_TUBE_VERTICAL_RIGHT,
3124 EL_TUBE_HORIZONTAL_UP,
3125 EL_TUBE_HORIZONTAL_DOWN,
3133 static int ep_classic_enemy[] =
3149 static int ep_belt[] =
3151 EL_CONVEYOR_BELT_1_LEFT,
3152 EL_CONVEYOR_BELT_1_MIDDLE,
3153 EL_CONVEYOR_BELT_1_RIGHT,
3154 EL_CONVEYOR_BELT_2_LEFT,
3155 EL_CONVEYOR_BELT_2_MIDDLE,
3156 EL_CONVEYOR_BELT_2_RIGHT,
3157 EL_CONVEYOR_BELT_3_LEFT,
3158 EL_CONVEYOR_BELT_3_MIDDLE,
3159 EL_CONVEYOR_BELT_3_RIGHT,
3160 EL_CONVEYOR_BELT_4_LEFT,
3161 EL_CONVEYOR_BELT_4_MIDDLE,
3162 EL_CONVEYOR_BELT_4_RIGHT,
3166 static int ep_belt_active[] =
3168 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3169 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3170 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3171 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3172 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3173 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3174 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3175 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3176 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3177 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3178 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3179 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3183 static int ep_belt_switch[] =
3185 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3186 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3187 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3188 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3189 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3190 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3191 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3192 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3193 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3194 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3195 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3196 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3200 static int ep_tube[] =
3207 EL_TUBE_HORIZONTAL_UP,
3208 EL_TUBE_HORIZONTAL_DOWN,
3210 EL_TUBE_VERTICAL_LEFT,
3211 EL_TUBE_VERTICAL_RIGHT,
3216 static int ep_keygate[] =
3245 static int ep_amoeboid[] =
3255 static int ep_amoebalive[] =
3264 static int ep_has_content[] =
3274 static int ep_can_turn_each_move[] =
3276 /* !!! do something with this one !!! */
3280 static int ep_can_grow[] =
3292 static int ep_active_bomb[] =
3295 EL_DYNABOMB_PLAYER_1_ACTIVE,
3296 EL_DYNABOMB_PLAYER_2_ACTIVE,
3297 EL_DYNABOMB_PLAYER_3_ACTIVE,
3298 EL_DYNABOMB_PLAYER_4_ACTIVE,
3299 EL_SP_DISK_RED_ACTIVE,
3303 static int ep_inactive[] =
3352 EL_INVISIBLE_STEELWALL,
3360 EL_WALL_EMERALD_YELLOW,
3361 EL_DYNABOMB_INCREASE_NUMBER,
3362 EL_DYNABOMB_INCREASE_SIZE,
3363 EL_DYNABOMB_INCREASE_POWER,
3367 EL_SOKOBAN_FIELD_EMPTY,
3368 EL_SOKOBAN_FIELD_FULL,
3369 EL_WALL_EMERALD_RED,
3370 EL_WALL_EMERALD_PURPLE,
3371 EL_ACID_POOL_TOPLEFT,
3372 EL_ACID_POOL_TOPRIGHT,
3373 EL_ACID_POOL_BOTTOMLEFT,
3374 EL_ACID_POOL_BOTTOM,
3375 EL_ACID_POOL_BOTTOMRIGHT,
3379 EL_BD_MAGIC_WALL_DEAD,
3380 EL_AMOEBA_TO_DIAMOND,
3388 EL_SP_GRAVITY_PORT_RIGHT,
3389 EL_SP_GRAVITY_PORT_DOWN,
3390 EL_SP_GRAVITY_PORT_LEFT,
3391 EL_SP_GRAVITY_PORT_UP,
3392 EL_SP_PORT_HORIZONTAL,
3393 EL_SP_PORT_VERTICAL,
3404 EL_SP_HARDWARE_GRAY,
3405 EL_SP_HARDWARE_GREEN,
3406 EL_SP_HARDWARE_BLUE,
3408 EL_SP_HARDWARE_YELLOW,
3409 EL_SP_HARDWARE_BASE_1,
3410 EL_SP_HARDWARE_BASE_2,
3411 EL_SP_HARDWARE_BASE_3,
3412 EL_SP_HARDWARE_BASE_4,
3413 EL_SP_HARDWARE_BASE_5,
3414 EL_SP_HARDWARE_BASE_6,
3415 EL_SP_GRAVITY_ON_PORT_LEFT,
3416 EL_SP_GRAVITY_ON_PORT_RIGHT,
3417 EL_SP_GRAVITY_ON_PORT_UP,
3418 EL_SP_GRAVITY_ON_PORT_DOWN,
3419 EL_SP_GRAVITY_OFF_PORT_LEFT,
3420 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3421 EL_SP_GRAVITY_OFF_PORT_UP,
3422 EL_SP_GRAVITY_OFF_PORT_DOWN,
3423 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3424 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3425 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3426 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3427 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3428 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3429 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3430 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3431 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3432 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3433 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3434 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3435 EL_SIGN_EXCLAMATION,
3436 EL_SIGN_RADIOACTIVITY,
3447 EL_STEELWALL_SLIPPERY,
3452 EL_EMC_WALL_SLIPPERY_1,
3453 EL_EMC_WALL_SLIPPERY_2,
3454 EL_EMC_WALL_SLIPPERY_3,
3455 EL_EMC_WALL_SLIPPERY_4,
3475 static int ep_em_slippery_wall[] =
3480 static int ep_gfx_crumbled[] =
3493 } element_properties[] =
3495 { ep_diggable, EP_DIGGABLE },
3496 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3497 { ep_dont_run_into, EP_DONT_RUN_INTO },
3498 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3499 { ep_dont_touch, EP_DONT_TOUCH },
3500 { ep_indestructible, EP_INDESTRUCTIBLE },
3501 { ep_slippery, EP_SLIPPERY },
3502 { ep_can_change, EP_CAN_CHANGE },
3503 { ep_can_move, EP_CAN_MOVE },
3504 { ep_can_fall, EP_CAN_FALL },
3505 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3506 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3507 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3508 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3509 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3510 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3511 { ep_walkable_over, EP_WALKABLE_OVER },
3512 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3513 { ep_walkable_under, EP_WALKABLE_UNDER },
3514 { ep_passable_over, EP_PASSABLE_OVER },
3515 { ep_passable_inside, EP_PASSABLE_INSIDE },
3516 { ep_passable_under, EP_PASSABLE_UNDER },
3517 { ep_droppable, EP_DROPPABLE },
3518 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3519 { ep_pushable, EP_PUSHABLE },
3520 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3521 { ep_protected, EP_PROTECTED },
3522 { ep_throwable, EP_THROWABLE },
3523 { ep_can_explode, EP_CAN_EXPLODE },
3524 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3526 { ep_player, EP_PLAYER },
3527 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3528 { ep_switchable, EP_SWITCHABLE },
3529 { ep_bd_element, EP_BD_ELEMENT },
3530 { ep_sp_element, EP_SP_ELEMENT },
3531 { ep_sb_element, EP_SB_ELEMENT },
3533 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3534 { ep_food_penguin, EP_FOOD_PENGUIN },
3535 { ep_food_pig, EP_FOOD_PIG },
3536 { ep_historic_wall, EP_HISTORIC_WALL },
3537 { ep_historic_solid, EP_HISTORIC_SOLID },
3538 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3539 { ep_belt, EP_BELT },
3540 { ep_belt_active, EP_BELT_ACTIVE },
3541 { ep_belt_switch, EP_BELT_SWITCH },
3542 { ep_tube, EP_TUBE },
3543 { ep_keygate, EP_KEYGATE },
3544 { ep_amoeboid, EP_AMOEBOID },
3545 { ep_amoebalive, EP_AMOEBALIVE },
3546 { ep_has_content, EP_HAS_CONTENT },
3547 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3548 { ep_can_grow, EP_CAN_GROW },
3549 { ep_active_bomb, EP_ACTIVE_BOMB },
3550 { ep_inactive, EP_INACTIVE },
3552 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3554 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3559 static int copy_properties[][5] =
3563 EL_BUG_LEFT, EL_BUG_RIGHT,
3564 EL_BUG_UP, EL_BUG_DOWN
3568 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3569 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3573 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3574 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3578 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3579 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3583 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3584 EL_PACMAN_UP, EL_PACMAN_DOWN
3588 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3589 EL_MOLE_UP, EL_MOLE_DOWN
3599 /* always start with reliable default values (element has no properties) */
3600 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3601 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3602 SET_PROPERTY(i, j, FALSE);
3604 /* set all base element properties from above array definitions */
3605 for (i = 0; element_properties[i].elements != NULL; i++)
3606 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3607 SET_PROPERTY((element_properties[i].elements)[j],
3608 element_properties[i].property, TRUE);
3610 /* copy properties to some elements that are only stored in level file */
3611 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3612 for (j = 0; copy_properties[j][0] != -1; j++)
3613 if (HAS_PROPERTY(copy_properties[j][0], i))
3614 for (k = 1; k <= 4; k++)
3615 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3618 void InitElementPropertiesEngine(int engine_version)
3621 static int active_properties[] =
3626 EP_DONT_COLLIDE_WITH,
3630 EP_CAN_PASS_MAGIC_WALL,
3635 EP_EXPLODES_BY_FIRE,
3648 EP_EM_SLIPPERY_WALL,
3652 static int no_wall_properties[] =
3655 EP_COLLECTIBLE_ONLY,
3657 EP_DONT_COLLIDE_WITH,
3660 EP_CAN_SMASH_PLAYER,
3661 EP_CAN_SMASH_ENEMIES,
3662 EP_CAN_SMASH_EVERYTHING,
3667 EP_FOOD_DARK_YAMYAM,
3684 InitElementPropertiesStatic();
3687 /* important: after initialization in InitElementPropertiesStatic(), the
3688 elements are not again initialized to a default value; therefore all
3689 changes have to make sure that they leave the element with a defined
3690 property (which means that conditional property changes must be set to
3691 a reliable default value before) */
3693 /* set all special, combined or engine dependent element properties */
3694 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3697 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3698 SET_PROPERTY(i, j, FALSE);
3701 /* ---------- INACTIVE ------------------------------------------------- */
3702 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3704 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3705 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3706 IS_WALKABLE_INSIDE(i) ||
3707 IS_WALKABLE_UNDER(i)));
3709 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3710 IS_PASSABLE_INSIDE(i) ||
3711 IS_PASSABLE_UNDER(i)));
3713 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3714 IS_PASSABLE_OVER(i)));
3716 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3717 IS_PASSABLE_INSIDE(i)));
3719 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3720 IS_PASSABLE_UNDER(i)));
3722 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3725 /* ---------- COLLECTIBLE ---------------------------------------------- */
3726 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3730 /* ---------- SNAPPABLE ------------------------------------------------ */
3731 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3732 IS_COLLECTIBLE(i) ||
3736 /* ---------- WALL ----------------------------------------------------- */
3737 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3739 for (j = 0; no_wall_properties[j] != -1; j++)
3740 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3741 i >= EL_FIRST_RUNTIME_UNREAL)
3742 SET_PROPERTY(i, EP_WALL, FALSE);
3744 if (IS_HISTORIC_WALL(i))
3745 SET_PROPERTY(i, EP_WALL, TRUE);
3747 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3748 if (engine_version < VERSION_IDENT(2,2,0,0))
3749 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3751 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3753 !IS_COLLECTIBLE(i)));
3756 /* ---------- PROTECTED ------------------------------------------------ */
3757 if (IS_ACCESSIBLE_INSIDE(i))
3758 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3761 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3763 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3764 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3766 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3767 IS_INDESTRUCTIBLE(i)));
3769 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3771 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3772 else if (engine_version < VERSION_IDENT(2,2,0,0))
3773 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3776 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3781 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3782 !IS_WALKABLE_OVER(i) &&
3783 !IS_WALKABLE_UNDER(i)));
3785 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3790 if (IS_CUSTOM_ELEMENT(i))
3792 /* these are additional properties which are initially false when set */
3794 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3796 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3797 if (DONT_COLLIDE_WITH(i))
3798 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3800 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3801 if (CAN_SMASH_EVERYTHING(i))
3802 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3803 if (CAN_SMASH_ENEMIES(i))
3804 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3807 /* ---------- CAN_SMASH ------------------------------------------------ */
3808 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3809 CAN_SMASH_ENEMIES(i) ||
3810 CAN_SMASH_EVERYTHING(i)));
3813 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3814 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3815 CAN_EXPLODE_SMASHED(i) ||
3816 CAN_EXPLODE_IMPACT(i)));
3820 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3822 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3823 !CAN_EXPLODE_CROSS(i)));
3825 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3826 !CAN_EXPLODE_1X1(i) &&
3827 !CAN_EXPLODE_CROSS(i)));
3831 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3832 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3833 EXPLODES_BY_FIRE(i)));
3835 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3836 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3837 EXPLODES_SMASHED(i)));
3839 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3840 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3841 EXPLODES_IMPACT(i)));
3843 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3844 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3846 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3847 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3848 i == EL_BLACK_ORB));
3850 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3851 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3853 IS_CUSTOM_ELEMENT(i)));
3855 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3856 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3857 i == EL_SP_ELECTRON));
3859 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3860 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3861 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3862 getMoveIntoAcidProperty(&level, i));
3864 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3865 if (MAYBE_DONT_COLLIDE_WITH(i))
3866 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3867 getDontCollideWithProperty(&level, i));
3869 /* ---------- SP_PORT -------------------------------------------------- */
3870 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3871 IS_PASSABLE_INSIDE(i)));
3873 /* ---------- CAN_CHANGE ----------------------------------------------- */
3874 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3875 for (j = 0; j < element_info[i].num_change_pages; j++)
3876 if (element_info[i].change_page[j].can_change)
3877 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3879 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3881 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3882 element_info[i].crumbled[ACTION_DEFAULT] !=
3883 element_info[i].graphic[ACTION_DEFAULT]);
3885 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3886 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3887 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3892 /* determine inactive elements (used for engine main loop optimization) */
3893 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3895 boolean active = FALSE;
3897 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3899 if (HAS_PROPERTY(i, j))
3905 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3910 /* dynamically adjust element properties according to game engine version */
3912 static int ep_em_slippery_wall[] =
3917 EL_EXPANDABLE_WALL_HORIZONTAL,
3918 EL_EXPANDABLE_WALL_VERTICAL,
3919 EL_EXPANDABLE_WALL_ANY,
3923 /* special EM style gems behaviour */
3924 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3925 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3926 level.em_slippery_gems);
3928 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3929 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3930 (level.em_slippery_gems &&
3931 engine_version > VERSION_IDENT(2,0,1,0)));
3935 /* set default push delay values (corrected since version 3.0.7-1) */
3936 if (engine_version < VERSION_IDENT(3,0,7,1))
3938 game.default_push_delay_fixed = 2;
3939 game.default_push_delay_random = 8;
3943 game.default_push_delay_fixed = 8;
3944 game.default_push_delay_random = 8;
3947 /* set uninitialized push delay values of custom elements in older levels */
3948 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3950 int element = EL_CUSTOM_START + i;
3952 if (element_info[element].push_delay_fixed == -1)
3953 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3954 if (element_info[element].push_delay_random == -1)
3955 element_info[element].push_delay_random = game.default_push_delay_random;
3958 /* set some other uninitialized values of custom elements in older levels */
3959 if (engine_version < VERSION_IDENT(3,1,0,0))
3961 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3963 int element = EL_CUSTOM_START + i;
3965 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3967 element_info[element].explosion_delay = 17;
3968 element_info[element].ignition_delay = 8;
3973 /* set element properties that were handled incorrectly in older levels */
3974 if (engine_version < VERSION_IDENT(3,1,0,0))
3976 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3977 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3983 /* this is needed because some graphics depend on element properties */
3984 if (game_status == GAME_MODE_PLAYING)
3985 InitElementGraphicInfo();
3988 static void InitGlobal()
3992 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3994 /* check if element_name_info entry defined for each element in "main.h" */
3995 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3996 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3998 element_info[i].token_name = element_name_info[i].token_name;
3999 element_info[i].class_name = element_name_info[i].class_name;
4000 element_info[i].editor_description=element_name_info[i].editor_description;
4003 global.autoplay_leveldir = NULL;
4004 global.convert_leveldir = NULL;
4006 global.frames_per_second = 0;
4007 global.fps_slowdown = FALSE;
4008 global.fps_slowdown_factor = 1;
4011 void Execute_Command(char *command)
4015 if (strcmp(command, "print graphicsinfo.conf") == 0)
4017 printf("# You can configure additional/alternative image files here.\n");
4018 printf("# (The entries below are default and therefore commented out.)\n");
4020 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4022 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4025 for (i = 0; image_config[i].token != NULL; i++)
4026 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4027 image_config[i].value));
4031 else if (strcmp(command, "print soundsinfo.conf") == 0)
4033 printf("# You can configure additional/alternative sound files here.\n");
4034 printf("# (The entries below are default and therefore commented out.)\n");
4036 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4038 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4041 for (i = 0; sound_config[i].token != NULL; i++)
4042 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4043 sound_config[i].value));
4047 else if (strcmp(command, "print musicinfo.conf") == 0)
4049 printf("# You can configure additional/alternative music files here.\n");
4050 printf("# (The entries below are default and therefore commented out.)\n");
4052 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4054 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4057 for (i = 0; music_config[i].token != NULL; i++)
4058 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4059 music_config[i].value));
4063 else if (strcmp(command, "print editorsetup.conf") == 0)
4065 printf("# You can configure your personal editor element list here.\n");
4066 printf("# (The entries below are default and therefore commented out.)\n");
4069 PrintEditorElementList();
4073 else if (strcmp(command, "print helpanim.conf") == 0)
4075 printf("# You can configure different element help animations here.\n");
4076 printf("# (The entries below are default and therefore commented out.)\n");
4079 for (i = 0; helpanim_config[i].token != NULL; i++)
4081 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4082 helpanim_config[i].value));
4084 if (strcmp(helpanim_config[i].token, "end") == 0)
4090 else if (strcmp(command, "print helptext.conf") == 0)
4092 printf("# You can configure different element help text here.\n");
4093 printf("# (The entries below are default and therefore commented out.)\n");
4096 for (i = 0; helptext_config[i].token != NULL; i++)
4097 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4098 helptext_config[i].value));
4102 else if (strncmp(command, "dump level ", 11) == 0)
4104 char *filename = &command[11];
4106 if (access(filename, F_OK) != 0)
4107 Error(ERR_EXIT, "cannot open file '%s'", filename);
4109 LoadLevelFromFilename(&level, filename);
4114 else if (strncmp(command, "dump tape ", 10) == 0)
4116 char *filename = &command[10];
4118 if (access(filename, F_OK) != 0)
4119 Error(ERR_EXIT, "cannot open file '%s'", filename);
4121 LoadTapeFromFilename(filename);
4126 else if (strncmp(command, "autoplay ", 9) == 0)
4128 char *str_copy = getStringCopy(&command[9]);
4129 char *str_ptr = strchr(str_copy, ' ');
4131 global.autoplay_leveldir = str_copy;
4132 global.autoplay_level_nr = -1;
4134 if (str_ptr != NULL)
4136 *str_ptr++ = '\0'; /* terminate leveldir string */
4137 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4140 else if (strncmp(command, "convert ", 8) == 0)
4142 char *str_copy = getStringCopy(&command[8]);
4143 char *str_ptr = strchr(str_copy, ' ');
4145 global.convert_leveldir = str_copy;
4146 global.convert_level_nr = -1;
4148 if (str_ptr != NULL)
4150 *str_ptr++ = '\0'; /* terminate leveldir string */
4151 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4156 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4160 static void InitSetup()
4162 LoadSetup(); /* global setup info */
4164 /* set some options from setup file */
4166 if (setup.options.verbose)
4167 options.verbose = TRUE;
4170 static void InitPlayerInfo()
4174 /* choose default local player */
4175 local_player = &stored_player[0];
4177 for (i = 0; i < MAX_PLAYERS; i++)
4178 stored_player[i].connected = FALSE;
4180 local_player->connected = TRUE;
4183 static void InitArtworkInfo()
4188 static char *get_string_in_brackets(char *string)
4190 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4192 sprintf(string_in_brackets, "[%s]", string);
4194 return string_in_brackets;
4197 static char *get_level_id_suffix(int id_nr)
4199 char *id_suffix = checked_malloc(1 + 3 + 1);
4201 if (id_nr < 0 || id_nr > 999)
4204 sprintf(id_suffix, ".%03d", id_nr);
4210 static char *get_element_class_token(int element)
4212 char *element_class_name = element_info[element].class_name;
4213 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4215 sprintf(element_class_token, "[%s]", element_class_name);
4217 return element_class_token;
4220 static char *get_action_class_token(int action)
4222 char *action_class_name = &element_action_info[action].suffix[1];
4223 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4225 sprintf(action_class_token, "[%s]", action_class_name);
4227 return action_class_token;
4231 static void InitArtworkConfig()
4233 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4234 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4235 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4236 static char *action_id_suffix[NUM_ACTIONS + 1];
4237 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4238 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4239 static char *level_id_suffix[MAX_LEVELS + 1];
4240 static char *dummy[1] = { NULL };
4241 static char *ignore_generic_tokens[] =
4247 static char **ignore_image_tokens;
4248 static char **ignore_sound_tokens;
4249 static char **ignore_music_tokens;
4250 int num_ignore_generic_tokens;
4251 int num_ignore_image_tokens;
4252 int num_ignore_sound_tokens;
4253 int num_ignore_music_tokens;
4256 /* dynamically determine list of generic tokens to be ignored */
4257 num_ignore_generic_tokens = 0;
4258 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4259 num_ignore_generic_tokens++;
4261 /* dynamically determine list of image tokens to be ignored */
4262 num_ignore_image_tokens = num_ignore_generic_tokens;
4263 for (i = 0; image_config_vars[i].token != NULL; i++)
4264 num_ignore_image_tokens++;
4265 ignore_image_tokens =
4266 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4267 for (i = 0; i < num_ignore_generic_tokens; i++)
4268 ignore_image_tokens[i] = ignore_generic_tokens[i];
4269 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4270 ignore_image_tokens[num_ignore_generic_tokens + i] =
4271 image_config_vars[i].token;
4272 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4274 /* dynamically determine list of sound tokens to be ignored */
4275 num_ignore_sound_tokens = num_ignore_generic_tokens;
4276 ignore_sound_tokens =
4277 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4278 for (i = 0; i < num_ignore_generic_tokens; i++)
4279 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4280 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4282 /* dynamically determine list of music tokens to be ignored */
4283 num_ignore_music_tokens = num_ignore_generic_tokens;
4284 ignore_music_tokens =
4285 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4286 for (i = 0; i < num_ignore_generic_tokens; i++)
4287 ignore_music_tokens[i] = ignore_generic_tokens[i];
4288 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4290 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4291 image_id_prefix[i] = element_info[i].token_name;
4292 for (i = 0; i < NUM_FONTS; i++)
4293 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4294 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4296 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4297 sound_id_prefix[i] = element_info[i].token_name;
4298 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4299 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4300 get_string_in_brackets(element_info[i].class_name);
4301 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4303 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4304 music_id_prefix[i] = music_prefix_info[i].prefix;
4305 music_id_prefix[MAX_LEVELS] = NULL;
4307 for (i = 0; i < NUM_ACTIONS; i++)
4308 action_id_suffix[i] = element_action_info[i].suffix;
4309 action_id_suffix[NUM_ACTIONS] = NULL;
4311 for (i = 0; i < NUM_DIRECTIONS; i++)
4312 direction_id_suffix[i] = element_direction_info[i].suffix;
4313 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4315 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4316 special_id_suffix[i] = special_suffix_info[i].suffix;
4317 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4319 for (i = 0; i < MAX_LEVELS; i++)
4320 level_id_suffix[i] = get_level_id_suffix(i);
4321 level_id_suffix[MAX_LEVELS] = NULL;
4323 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4324 image_id_prefix, action_id_suffix, direction_id_suffix,
4325 special_id_suffix, ignore_image_tokens);
4326 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4327 sound_id_prefix, action_id_suffix, dummy,
4328 special_id_suffix, ignore_sound_tokens);
4329 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4330 music_id_prefix, special_id_suffix, level_id_suffix,
4331 dummy, ignore_music_tokens);
4334 static void InitMixer()
4342 char *filename_font_initial = NULL;
4343 Bitmap *bitmap_font_initial = NULL;
4346 /* determine settings for initial font (for displaying startup messages) */
4347 for (i = 0; image_config[i].token != NULL; i++)
4349 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4351 char font_token[128];
4354 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4355 len_font_token = strlen(font_token);
4357 if (strcmp(image_config[i].token, font_token) == 0)
4358 filename_font_initial = image_config[i].value;
4359 else if (strlen(image_config[i].token) > len_font_token &&
4360 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4362 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4363 font_initial[j].src_x = atoi(image_config[i].value);
4364 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4365 font_initial[j].src_y = atoi(image_config[i].value);
4366 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4367 font_initial[j].width = atoi(image_config[i].value);
4368 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4369 font_initial[j].height = atoi(image_config[i].value);
4374 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4376 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4377 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4380 if (filename_font_initial == NULL) /* should not happen */
4381 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4383 /* create additional image buffers for double-buffering */
4384 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4385 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4387 /* initialize screen properties */
4388 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4389 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4391 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4392 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4393 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4395 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4397 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4398 font_initial[j].bitmap = bitmap_font_initial;
4400 InitFontGraphicInfo();
4402 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4403 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4405 DrawInitText("Loading graphics:", 120, FC_GREEN);
4407 InitTileClipmasks();
4410 void InitGfxBackground()
4414 drawto = backbuffer;
4415 fieldbuffer = bitmap_db_field;
4416 SetDrawtoField(DRAW_BACKBUFFER);
4418 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4419 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4420 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4421 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4423 for (x = 0; x < MAX_BUF_XSIZE; x++)
4424 for (y = 0; y < MAX_BUF_YSIZE; y++)
4427 redraw_mask = REDRAW_ALL;
4430 static void InitLevelInfo()
4432 LoadLevelInfo(); /* global level info */
4433 LoadLevelSetup_LastSeries(); /* last played series info */
4434 LoadLevelSetup_SeriesInfo(); /* last played level info */
4437 void InitLevelArtworkInfo()
4439 LoadLevelArtworkInfo();
4442 static void InitImages()
4445 setLevelArtworkDir(artwork.gfx_first);
4449 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4450 leveldir_current->identifier,
4451 artwork.gfx_current_identifier,
4452 artwork.gfx_current->identifier,
4453 leveldir_current->graphics_set,
4454 leveldir_current->graphics_path);
4457 ReloadCustomImages();
4459 LoadCustomElementDescriptions();
4460 LoadSpecialMenuDesignSettings();
4462 ReinitializeGraphics();
4465 static void InitSound(char *identifier)
4467 if (identifier == NULL)
4468 identifier = artwork.snd_current->identifier;
4471 /* set artwork path to send it to the sound server process */
4472 setLevelArtworkDir(artwork.snd_first);
4475 InitReloadCustomSounds(identifier);
4476 ReinitializeSounds();
4479 static void InitMusic(char *identifier)
4481 if (identifier == NULL)
4482 identifier = artwork.mus_current->identifier;
4485 /* set artwork path to send it to the sound server process */
4486 setLevelArtworkDir(artwork.mus_first);
4489 InitReloadCustomMusic(identifier);
4490 ReinitializeMusic();
4493 void InitNetworkServer()
4495 #if defined(NETWORK_AVALIABLE)
4499 if (!options.network)
4502 #if defined(NETWORK_AVALIABLE)
4503 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4505 if (!ConnectToServer(options.server_host, options.server_port))
4506 Error(ERR_EXIT, "cannot connect to network game server");
4508 SendToServer_PlayerName(setup.player_name);
4509 SendToServer_ProtocolVersion();
4512 SendToServer_NrWanted(nr_wanted);
4516 static char *getNewArtworkIdentifier(int type)
4518 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4519 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4520 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4521 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4522 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4523 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4524 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4525 char *leveldir_identifier = leveldir_current->identifier;
4527 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4528 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4530 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4532 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4533 char *artwork_current_identifier;
4534 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4536 /* leveldir_current may be invalid (level group, parent link) */
4537 if (!validLevelSeries(leveldir_current))
4540 /* 1st step: determine artwork set to be activated in descending order:
4541 --------------------------------------------------------------------
4542 1. setup artwork (when configured to override everything else)
4543 2. artwork set configured in "levelinfo.conf" of current level set
4544 (artwork in level directory will have priority when loading later)
4545 3. artwork in level directory (stored in artwork sub-directory)
4546 4. setup artwork (currently configured in setup menu) */
4548 if (setup_override_artwork)
4549 artwork_current_identifier = setup_artwork_set;
4550 else if (leveldir_artwork_set != NULL)
4551 artwork_current_identifier = leveldir_artwork_set;
4552 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4553 artwork_current_identifier = leveldir_identifier;
4555 artwork_current_identifier = setup_artwork_set;
4558 /* 2nd step: check if it is really needed to reload artwork set
4559 ------------------------------------------------------------ */
4562 if (type == ARTWORK_TYPE_GRAPHICS)
4563 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4564 artwork_new_identifier,
4565 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4566 artwork_current_identifier,
4567 leveldir_current->graphics_set,
4568 leveldir_current->identifier);
4571 /* ---------- reload if level set and also artwork set has changed ------- */
4572 if (leveldir_current_identifier[type] != leveldir_identifier &&
4573 (last_has_level_artwork_set[type] || has_level_artwork_set))
4574 artwork_new_identifier = artwork_current_identifier;
4576 leveldir_current_identifier[type] = leveldir_identifier;
4577 last_has_level_artwork_set[type] = has_level_artwork_set;
4580 if (type == ARTWORK_TYPE_GRAPHICS)
4581 printf("::: 1: '%s'\n", artwork_new_identifier);
4584 /* ---------- reload if "override artwork" setting has changed ----------- */
4585 if (last_override_level_artwork[type] != setup_override_artwork)
4586 artwork_new_identifier = artwork_current_identifier;
4588 last_override_level_artwork[type] = setup_override_artwork;
4591 if (type == ARTWORK_TYPE_GRAPHICS)
4592 printf("::: 2: '%s'\n", artwork_new_identifier);
4595 /* ---------- reload if current artwork identifier has changed ----------- */
4596 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4597 artwork_current_identifier) != 0)
4598 artwork_new_identifier = artwork_current_identifier;
4600 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4603 if (type == ARTWORK_TYPE_GRAPHICS)
4604 printf("::: 3: '%s'\n", artwork_new_identifier);
4607 /* ---------- do not reload directly after starting ---------------------- */
4608 if (!initialized[type])
4609 artwork_new_identifier = NULL;
4611 initialized[type] = TRUE;
4614 if (type == ARTWORK_TYPE_GRAPHICS)
4615 printf("::: 4: '%s'\n", artwork_new_identifier);
4619 if (type == ARTWORK_TYPE_GRAPHICS)
4620 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4621 artwork.gfx_current_identifier, artwork_current_identifier,
4622 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4623 artwork_new_identifier);
4626 return artwork_new_identifier;
4629 void ReloadCustomArtwork(int force_reload)
4631 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4632 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4633 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4634 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4635 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4636 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4637 boolean redraw_screen = FALSE;
4639 if (gfx_new_identifier != NULL || force_reload_gfx)
4642 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4643 artwork.gfx_current_identifier,
4645 artwork.gfx_current->identifier,
4646 leveldir_current->graphics_set);
4649 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4654 printf("... '%s'\n",
4655 leveldir_current->graphics_set);
4658 FreeTileClipmasks();
4659 InitTileClipmasks();
4661 redraw_screen = TRUE;
4664 if (snd_new_identifier != NULL || force_reload_snd)
4666 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4668 InitSound(snd_new_identifier);
4670 redraw_screen = TRUE;
4673 if (mus_new_identifier != NULL || force_reload_mus)
4675 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4677 InitMusic(mus_new_identifier);
4679 redraw_screen = TRUE;
4684 InitGfxBackground();
4686 /* force redraw of (open or closed) door graphics */
4687 SetDoorState(DOOR_OPEN_ALL);
4688 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4692 void KeyboardAutoRepeatOffUnlessAutoplay()
4694 if (global.autoplay_leveldir == NULL)
4695 KeyboardAutoRepeatOff();
4699 /* ========================================================================= */
4701 /* ========================================================================= */
4705 InitGlobal(); /* initialize some global variables */
4707 if (options.execute_command)
4708 Execute_Command(options.execute_command);
4710 if (options.serveronly)
4712 #if defined(PLATFORM_UNIX)
4713 NetworkServer(options.server_port, options.serveronly);
4715 Error(ERR_WARN, "networking only supported in Unix version");
4718 exit(0); /* never reached, server loops forever */
4724 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4725 InitArtworkConfig(); /* needed before forking sound child process */
4730 InitRND(NEW_RANDOMIZE);
4731 InitSimpleRND(NEW_RANDOMIZE);
4736 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4739 InitEventFilter(FilterMouseMotionEvents);
4741 InitElementPropertiesStatic();
4742 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4747 InitLevelArtworkInfo();
4749 InitImages(); /* needs to know current level directory */
4750 InitSound(NULL); /* needs to know current level directory */
4751 InitMusic(NULL); /* needs to know current level directory */
4753 InitGfxBackground();
4755 if (global.autoplay_leveldir)
4760 else if (global.convert_leveldir)
4766 game_status = GAME_MODE_MAIN;
4774 InitNetworkServer();
4777 void CloseAllAndExit(int exit_value)
4782 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4789 FreeTileClipmasks();
4791 #if defined(TARGET_SDL)
4792 if (network_server) /* terminate network server */
4793 SDL_KillThread(server_thread);
4796 CloseVideoDisplay();
4797 ClosePlatformDependentStuff();