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,
2172 EL_SWITCHGATE_OPENING,
2173 EL_SWITCHGATE_CLOSED,
2174 EL_SWITCHGATE_CLOSING,
2176 EL_SWITCHGATE_SWITCH_UP,
2177 EL_SWITCHGATE_SWITCH_DOWN,
2180 EL_TIMEGATE_OPENING,
2182 EL_TIMEGATE_CLOSING,
2185 EL_TIMEGATE_SWITCH_ACTIVE,
2190 EL_TUBE_VERTICAL_LEFT,
2191 EL_TUBE_VERTICAL_RIGHT,
2192 EL_TUBE_HORIZONTAL_UP,
2193 EL_TUBE_HORIZONTAL_DOWN,
2201 static int ep_slippery[] =
2215 EL_ROBOT_WHEEL_ACTIVE,
2221 EL_ACID_POOL_TOPLEFT,
2222 EL_ACID_POOL_TOPRIGHT,
2232 EL_STEELWALL_SLIPPERY,
2235 EL_EMC_WALL_SLIPPERY_1,
2236 EL_EMC_WALL_SLIPPERY_2,
2237 EL_EMC_WALL_SLIPPERY_3,
2238 EL_EMC_WALL_SLIPPERY_4,
2242 static int ep_can_change[] =
2247 static int ep_can_move[] =
2249 /* same elements as in 'pb_can_move_into_acid' */
2271 static int ep_can_fall[] =
2286 EL_BD_MAGIC_WALL_FULL,
2299 static int ep_can_smash_player[] =
2324 static int ep_can_smash_enemies[] =
2332 static int ep_can_smash_everything[] =
2340 static int ep_explodes_by_fire[] =
2342 /* same elements as in 'ep_explodes_impact' */
2347 /* same elements as in 'ep_explodes_smashed' */
2356 EL_DYNABOMB_PLAYER_1_ACTIVE,
2357 EL_DYNABOMB_PLAYER_2_ACTIVE,
2358 EL_DYNABOMB_PLAYER_3_ACTIVE,
2359 EL_DYNABOMB_PLAYER_4_ACTIVE,
2360 EL_DYNABOMB_INCREASE_NUMBER,
2361 EL_DYNABOMB_INCREASE_SIZE,
2362 EL_DYNABOMB_INCREASE_POWER,
2363 EL_SP_DISK_RED_ACTIVE,
2376 static int ep_explodes_smashed[] =
2378 /* same elements as in 'ep_explodes_impact' */
2391 static int ep_explodes_impact[] =
2399 static int ep_walkable_over[] =
2403 EL_SOKOBAN_FIELD_EMPTY,
2421 static int ep_walkable_inside[] =
2426 EL_TUBE_VERTICAL_LEFT,
2427 EL_TUBE_VERTICAL_RIGHT,
2428 EL_TUBE_HORIZONTAL_UP,
2429 EL_TUBE_HORIZONTAL_DOWN,
2437 static int ep_walkable_under[] =
2442 static int ep_passable_over[] =
2465 static int ep_passable_inside[] =
2471 EL_SP_PORT_HORIZONTAL,
2472 EL_SP_PORT_VERTICAL,
2474 EL_SP_GRAVITY_PORT_LEFT,
2475 EL_SP_GRAVITY_PORT_RIGHT,
2476 EL_SP_GRAVITY_PORT_UP,
2477 EL_SP_GRAVITY_PORT_DOWN,
2478 EL_SP_GRAVITY_ON_PORT_LEFT,
2479 EL_SP_GRAVITY_ON_PORT_RIGHT,
2480 EL_SP_GRAVITY_ON_PORT_UP,
2481 EL_SP_GRAVITY_ON_PORT_DOWN,
2482 EL_SP_GRAVITY_OFF_PORT_LEFT,
2483 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2484 EL_SP_GRAVITY_OFF_PORT_UP,
2485 EL_SP_GRAVITY_OFF_PORT_DOWN,
2489 static int ep_passable_under[] =
2494 static int ep_droppable[] =
2499 static int ep_explodes_1x1_old[] =
2504 static int ep_pushable[] =
2516 EL_SOKOBAN_FIELD_FULL,
2524 static int ep_explodes_cross_old[] =
2529 static int ep_protected[] =
2531 /* same elements as in 'ep_walkable_inside' */
2535 EL_TUBE_VERTICAL_LEFT,
2536 EL_TUBE_VERTICAL_RIGHT,
2537 EL_TUBE_HORIZONTAL_UP,
2538 EL_TUBE_HORIZONTAL_DOWN,
2544 /* same elements as in 'ep_passable_over' */
2564 /* same elements as in 'ep_passable_inside' */
2569 EL_SP_PORT_HORIZONTAL,
2570 EL_SP_PORT_VERTICAL,
2572 EL_SP_GRAVITY_PORT_LEFT,
2573 EL_SP_GRAVITY_PORT_RIGHT,
2574 EL_SP_GRAVITY_PORT_UP,
2575 EL_SP_GRAVITY_PORT_DOWN,
2576 EL_SP_GRAVITY_ON_PORT_LEFT,
2577 EL_SP_GRAVITY_ON_PORT_RIGHT,
2578 EL_SP_GRAVITY_ON_PORT_UP,
2579 EL_SP_GRAVITY_ON_PORT_DOWN,
2580 EL_SP_GRAVITY_OFF_PORT_LEFT,
2581 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2582 EL_SP_GRAVITY_OFF_PORT_UP,
2583 EL_SP_GRAVITY_OFF_PORT_DOWN,
2587 static int ep_throwable[] =
2592 static int ep_can_explode[] =
2594 /* same elements as in 'ep_explodes_impact' */
2599 /* same elements as in 'ep_explodes_smashed' */
2605 /* elements that can explode by explosion or by dragonfire */
2608 EL_DYNABOMB_PLAYER_1_ACTIVE,
2609 EL_DYNABOMB_PLAYER_2_ACTIVE,
2610 EL_DYNABOMB_PLAYER_3_ACTIVE,
2611 EL_DYNABOMB_PLAYER_4_ACTIVE,
2612 EL_DYNABOMB_INCREASE_NUMBER,
2613 EL_DYNABOMB_INCREASE_SIZE,
2614 EL_DYNABOMB_INCREASE_POWER,
2615 EL_SP_DISK_RED_ACTIVE,
2623 /* elements that can explode only by explosion */
2628 static int ep_gravity_reachable[] =
2634 EL_INVISIBLE_SAND_ACTIVE,
2639 EL_SP_PORT_HORIZONTAL,
2640 EL_SP_PORT_VERTICAL,
2642 EL_SP_GRAVITY_PORT_LEFT,
2643 EL_SP_GRAVITY_PORT_RIGHT,
2644 EL_SP_GRAVITY_PORT_UP,
2645 EL_SP_GRAVITY_PORT_DOWN,
2646 EL_SP_GRAVITY_ON_PORT_LEFT,
2647 EL_SP_GRAVITY_ON_PORT_RIGHT,
2648 EL_SP_GRAVITY_ON_PORT_UP,
2649 EL_SP_GRAVITY_ON_PORT_DOWN,
2650 EL_SP_GRAVITY_OFF_PORT_LEFT,
2651 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2652 EL_SP_GRAVITY_OFF_PORT_UP,
2653 EL_SP_GRAVITY_OFF_PORT_DOWN,
2658 static int ep_player[] =
2665 EL_SOKOBAN_FIELD_PLAYER,
2670 static int ep_can_pass_magic_wall[] =
2683 static int ep_switchable[] =
2687 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2688 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2689 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2690 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2691 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2692 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2693 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2694 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2695 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2696 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2697 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2698 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2699 EL_SWITCHGATE_SWITCH_UP,
2700 EL_SWITCHGATE_SWITCH_DOWN,
2702 EL_LIGHT_SWITCH_ACTIVE,
2704 EL_BALLOON_SWITCH_LEFT,
2705 EL_BALLOON_SWITCH_RIGHT,
2706 EL_BALLOON_SWITCH_UP,
2707 EL_BALLOON_SWITCH_DOWN,
2708 EL_BALLOON_SWITCH_ANY,
2711 EL_EMC_MAGIC_BALL_SWITCH,
2715 static int ep_bd_element[] =
2748 static int ep_sp_element[] =
2750 /* should always be valid */
2753 /* standard classic Supaplex elements */
2760 EL_SP_HARDWARE_GRAY,
2768 EL_SP_GRAVITY_PORT_RIGHT,
2769 EL_SP_GRAVITY_PORT_DOWN,
2770 EL_SP_GRAVITY_PORT_LEFT,
2771 EL_SP_GRAVITY_PORT_UP,
2776 EL_SP_PORT_VERTICAL,
2777 EL_SP_PORT_HORIZONTAL,
2783 EL_SP_HARDWARE_BASE_1,
2784 EL_SP_HARDWARE_GREEN,
2785 EL_SP_HARDWARE_BLUE,
2787 EL_SP_HARDWARE_YELLOW,
2788 EL_SP_HARDWARE_BASE_2,
2789 EL_SP_HARDWARE_BASE_3,
2790 EL_SP_HARDWARE_BASE_4,
2791 EL_SP_HARDWARE_BASE_5,
2792 EL_SP_HARDWARE_BASE_6,
2796 /* additional elements that appeared in newer Supaplex levels */
2799 /* additional gravity port elements (not switching, but setting gravity) */
2800 EL_SP_GRAVITY_ON_PORT_LEFT,
2801 EL_SP_GRAVITY_ON_PORT_RIGHT,
2802 EL_SP_GRAVITY_ON_PORT_UP,
2803 EL_SP_GRAVITY_ON_PORT_DOWN,
2804 EL_SP_GRAVITY_OFF_PORT_LEFT,
2805 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2806 EL_SP_GRAVITY_OFF_PORT_UP,
2807 EL_SP_GRAVITY_OFF_PORT_DOWN,
2809 /* more than one Murphy in a level results in an inactive clone */
2812 /* runtime Supaplex elements */
2813 EL_SP_DISK_RED_ACTIVE,
2814 EL_SP_TERMINAL_ACTIVE,
2815 EL_SP_BUGGY_BASE_ACTIVATING,
2816 EL_SP_BUGGY_BASE_ACTIVE,
2822 static int ep_sb_element[] =
2827 EL_SOKOBAN_FIELD_EMPTY,
2828 EL_SOKOBAN_FIELD_FULL,
2829 EL_SOKOBAN_FIELD_PLAYER,
2834 EL_INVISIBLE_STEELWALL,
2838 static int ep_gem[] =
2849 static int ep_food_dark_yamyam[] =
2876 static int ep_food_penguin[] =
2889 static int ep_food_pig[] =
2900 static int ep_historic_wall[] =
2925 EL_EXPANDABLE_WALL_HORIZONTAL,
2926 EL_EXPANDABLE_WALL_VERTICAL,
2927 EL_EXPANDABLE_WALL_ANY,
2928 EL_EXPANDABLE_WALL_GROWING,
2935 EL_SP_HARDWARE_GRAY,
2936 EL_SP_HARDWARE_GREEN,
2937 EL_SP_HARDWARE_BLUE,
2939 EL_SP_HARDWARE_YELLOW,
2940 EL_SP_HARDWARE_BASE_1,
2941 EL_SP_HARDWARE_BASE_2,
2942 EL_SP_HARDWARE_BASE_3,
2943 EL_SP_HARDWARE_BASE_4,
2944 EL_SP_HARDWARE_BASE_5,
2945 EL_SP_HARDWARE_BASE_6,
2947 EL_SP_TERMINAL_ACTIVE,
2950 EL_INVISIBLE_STEELWALL,
2951 EL_INVISIBLE_STEELWALL_ACTIVE,
2953 EL_INVISIBLE_WALL_ACTIVE,
2954 EL_STEELWALL_SLIPPERY,
2970 static int ep_historic_solid[] =
2974 EL_EXPANDABLE_WALL_HORIZONTAL,
2975 EL_EXPANDABLE_WALL_VERTICAL,
2976 EL_EXPANDABLE_WALL_ANY,
2989 EL_QUICKSAND_FILLING,
2990 EL_QUICKSAND_EMPTYING,
2992 EL_MAGIC_WALL_ACTIVE,
2993 EL_MAGIC_WALL_EMPTYING,
2994 EL_MAGIC_WALL_FILLING,
2998 EL_BD_MAGIC_WALL_ACTIVE,
2999 EL_BD_MAGIC_WALL_EMPTYING,
3000 EL_BD_MAGIC_WALL_FULL,
3001 EL_BD_MAGIC_WALL_FILLING,
3002 EL_BD_MAGIC_WALL_DEAD,
3011 EL_SP_TERMINAL_ACTIVE,
3015 EL_INVISIBLE_WALL_ACTIVE,
3016 EL_SWITCHGATE_SWITCH_UP,
3017 EL_SWITCHGATE_SWITCH_DOWN,
3019 EL_TIMEGATE_SWITCH_ACTIVE,
3031 /* the following elements are a direct copy of "indestructible" elements,
3032 except "EL_ACID", which is "indestructible", but not "solid"! */
3037 EL_ACID_POOL_TOPLEFT,
3038 EL_ACID_POOL_TOPRIGHT,
3039 EL_ACID_POOL_BOTTOMLEFT,
3040 EL_ACID_POOL_BOTTOM,
3041 EL_ACID_POOL_BOTTOMRIGHT,
3042 EL_SP_HARDWARE_GRAY,
3043 EL_SP_HARDWARE_GREEN,
3044 EL_SP_HARDWARE_BLUE,
3046 EL_SP_HARDWARE_YELLOW,
3047 EL_SP_HARDWARE_BASE_1,
3048 EL_SP_HARDWARE_BASE_2,
3049 EL_SP_HARDWARE_BASE_3,
3050 EL_SP_HARDWARE_BASE_4,
3051 EL_SP_HARDWARE_BASE_5,
3052 EL_SP_HARDWARE_BASE_6,
3053 EL_INVISIBLE_STEELWALL,
3054 EL_INVISIBLE_STEELWALL_ACTIVE,
3055 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3056 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3057 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3058 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3059 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3060 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3061 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3062 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3063 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3064 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3065 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3066 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3068 EL_LIGHT_SWITCH_ACTIVE,
3069 EL_SIGN_EXCLAMATION,
3070 EL_SIGN_RADIOACTIVITY,
3081 EL_STEELWALL_SLIPPERY,
3104 EL_SWITCHGATE_OPENING,
3105 EL_SWITCHGATE_CLOSED,
3106 EL_SWITCHGATE_CLOSING,
3108 EL_TIMEGATE_OPENING,
3110 EL_TIMEGATE_CLOSING,
3114 EL_TUBE_VERTICAL_LEFT,
3115 EL_TUBE_VERTICAL_RIGHT,
3116 EL_TUBE_HORIZONTAL_UP,
3117 EL_TUBE_HORIZONTAL_DOWN,
3125 static int ep_classic_enemy[] =
3141 static int ep_belt[] =
3143 EL_CONVEYOR_BELT_1_LEFT,
3144 EL_CONVEYOR_BELT_1_MIDDLE,
3145 EL_CONVEYOR_BELT_1_RIGHT,
3146 EL_CONVEYOR_BELT_2_LEFT,
3147 EL_CONVEYOR_BELT_2_MIDDLE,
3148 EL_CONVEYOR_BELT_2_RIGHT,
3149 EL_CONVEYOR_BELT_3_LEFT,
3150 EL_CONVEYOR_BELT_3_MIDDLE,
3151 EL_CONVEYOR_BELT_3_RIGHT,
3152 EL_CONVEYOR_BELT_4_LEFT,
3153 EL_CONVEYOR_BELT_4_MIDDLE,
3154 EL_CONVEYOR_BELT_4_RIGHT,
3158 static int ep_belt_active[] =
3160 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3161 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3162 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3163 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3164 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3165 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3166 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3167 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3168 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3169 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3170 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3171 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3175 static int ep_belt_switch[] =
3177 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3178 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3179 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3180 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3181 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3182 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3183 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3184 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3185 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3186 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3187 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3188 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3192 static int ep_tube[] =
3199 EL_TUBE_HORIZONTAL_UP,
3200 EL_TUBE_HORIZONTAL_DOWN,
3202 EL_TUBE_VERTICAL_LEFT,
3203 EL_TUBE_VERTICAL_RIGHT,
3208 static int ep_keygate[] =
3237 static int ep_amoeboid[] =
3247 static int ep_amoebalive[] =
3256 static int ep_has_content[] =
3266 static int ep_can_turn_each_move[] =
3268 /* !!! do something with this one !!! */
3272 static int ep_can_grow[] =
3284 static int ep_active_bomb[] =
3287 EL_DYNABOMB_PLAYER_1_ACTIVE,
3288 EL_DYNABOMB_PLAYER_2_ACTIVE,
3289 EL_DYNABOMB_PLAYER_3_ACTIVE,
3290 EL_DYNABOMB_PLAYER_4_ACTIVE,
3291 EL_SP_DISK_RED_ACTIVE,
3295 static int ep_inactive[] =
3344 EL_INVISIBLE_STEELWALL,
3352 EL_WALL_EMERALD_YELLOW,
3353 EL_DYNABOMB_INCREASE_NUMBER,
3354 EL_DYNABOMB_INCREASE_SIZE,
3355 EL_DYNABOMB_INCREASE_POWER,
3359 EL_SOKOBAN_FIELD_EMPTY,
3360 EL_SOKOBAN_FIELD_FULL,
3361 EL_WALL_EMERALD_RED,
3362 EL_WALL_EMERALD_PURPLE,
3363 EL_ACID_POOL_TOPLEFT,
3364 EL_ACID_POOL_TOPRIGHT,
3365 EL_ACID_POOL_BOTTOMLEFT,
3366 EL_ACID_POOL_BOTTOM,
3367 EL_ACID_POOL_BOTTOMRIGHT,
3371 EL_BD_MAGIC_WALL_DEAD,
3372 EL_AMOEBA_TO_DIAMOND,
3380 EL_SP_GRAVITY_PORT_RIGHT,
3381 EL_SP_GRAVITY_PORT_DOWN,
3382 EL_SP_GRAVITY_PORT_LEFT,
3383 EL_SP_GRAVITY_PORT_UP,
3384 EL_SP_PORT_HORIZONTAL,
3385 EL_SP_PORT_VERTICAL,
3396 EL_SP_HARDWARE_GRAY,
3397 EL_SP_HARDWARE_GREEN,
3398 EL_SP_HARDWARE_BLUE,
3400 EL_SP_HARDWARE_YELLOW,
3401 EL_SP_HARDWARE_BASE_1,
3402 EL_SP_HARDWARE_BASE_2,
3403 EL_SP_HARDWARE_BASE_3,
3404 EL_SP_HARDWARE_BASE_4,
3405 EL_SP_HARDWARE_BASE_5,
3406 EL_SP_HARDWARE_BASE_6,
3407 EL_SP_GRAVITY_ON_PORT_LEFT,
3408 EL_SP_GRAVITY_ON_PORT_RIGHT,
3409 EL_SP_GRAVITY_ON_PORT_UP,
3410 EL_SP_GRAVITY_ON_PORT_DOWN,
3411 EL_SP_GRAVITY_OFF_PORT_LEFT,
3412 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3413 EL_SP_GRAVITY_OFF_PORT_UP,
3414 EL_SP_GRAVITY_OFF_PORT_DOWN,
3415 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3416 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3417 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3418 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3419 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3420 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3421 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3422 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3423 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3424 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3425 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3426 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3427 EL_SIGN_EXCLAMATION,
3428 EL_SIGN_RADIOACTIVITY,
3439 EL_STEELWALL_SLIPPERY,
3444 EL_EMC_WALL_SLIPPERY_1,
3445 EL_EMC_WALL_SLIPPERY_2,
3446 EL_EMC_WALL_SLIPPERY_3,
3447 EL_EMC_WALL_SLIPPERY_4,
3467 static int ep_em_slippery_wall[] =
3472 static int ep_gfx_crumbled[] =
3485 } element_properties[] =
3487 { ep_diggable, EP_DIGGABLE },
3488 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3489 { ep_dont_run_into, EP_DONT_RUN_INTO },
3490 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3491 { ep_dont_touch, EP_DONT_TOUCH },
3492 { ep_indestructible, EP_INDESTRUCTIBLE },
3493 { ep_slippery, EP_SLIPPERY },
3494 { ep_can_change, EP_CAN_CHANGE },
3495 { ep_can_move, EP_CAN_MOVE },
3496 { ep_can_fall, EP_CAN_FALL },
3497 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3498 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3499 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3500 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3501 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3502 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3503 { ep_walkable_over, EP_WALKABLE_OVER },
3504 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3505 { ep_walkable_under, EP_WALKABLE_UNDER },
3506 { ep_passable_over, EP_PASSABLE_OVER },
3507 { ep_passable_inside, EP_PASSABLE_INSIDE },
3508 { ep_passable_under, EP_PASSABLE_UNDER },
3509 { ep_droppable, EP_DROPPABLE },
3510 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3511 { ep_pushable, EP_PUSHABLE },
3512 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3513 { ep_protected, EP_PROTECTED },
3514 { ep_throwable, EP_THROWABLE },
3515 { ep_can_explode, EP_CAN_EXPLODE },
3516 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3518 { ep_player, EP_PLAYER },
3519 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3520 { ep_switchable, EP_SWITCHABLE },
3521 { ep_bd_element, EP_BD_ELEMENT },
3522 { ep_sp_element, EP_SP_ELEMENT },
3523 { ep_sb_element, EP_SB_ELEMENT },
3525 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3526 { ep_food_penguin, EP_FOOD_PENGUIN },
3527 { ep_food_pig, EP_FOOD_PIG },
3528 { ep_historic_wall, EP_HISTORIC_WALL },
3529 { ep_historic_solid, EP_HISTORIC_SOLID },
3530 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3531 { ep_belt, EP_BELT },
3532 { ep_belt_active, EP_BELT_ACTIVE },
3533 { ep_belt_switch, EP_BELT_SWITCH },
3534 { ep_tube, EP_TUBE },
3535 { ep_keygate, EP_KEYGATE },
3536 { ep_amoeboid, EP_AMOEBOID },
3537 { ep_amoebalive, EP_AMOEBALIVE },
3538 { ep_has_content, EP_HAS_CONTENT },
3539 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3540 { ep_can_grow, EP_CAN_GROW },
3541 { ep_active_bomb, EP_ACTIVE_BOMB },
3542 { ep_inactive, EP_INACTIVE },
3544 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3546 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3551 static int copy_properties[][5] =
3555 EL_BUG_LEFT, EL_BUG_RIGHT,
3556 EL_BUG_UP, EL_BUG_DOWN
3560 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3561 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3565 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3566 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3570 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3571 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3575 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3576 EL_PACMAN_UP, EL_PACMAN_DOWN
3580 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3581 EL_MOLE_UP, EL_MOLE_DOWN
3591 /* always start with reliable default values (element has no properties) */
3592 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3593 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3594 SET_PROPERTY(i, j, FALSE);
3596 /* set all base element properties from above array definitions */
3597 for (i = 0; element_properties[i].elements != NULL; i++)
3598 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3599 SET_PROPERTY((element_properties[i].elements)[j],
3600 element_properties[i].property, TRUE);
3602 /* copy properties to some elements that are only stored in level file */
3603 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3604 for (j = 0; copy_properties[j][0] != -1; j++)
3605 if (HAS_PROPERTY(copy_properties[j][0], i))
3606 for (k = 1; k <= 4; k++)
3607 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3610 void InitElementPropertiesEngine(int engine_version)
3613 static int active_properties[] =
3618 EP_DONT_COLLIDE_WITH,
3622 EP_CAN_PASS_MAGIC_WALL,
3627 EP_EXPLODES_BY_FIRE,
3640 EP_EM_SLIPPERY_WALL,
3644 static int no_wall_properties[] =
3647 EP_COLLECTIBLE_ONLY,
3649 EP_DONT_COLLIDE_WITH,
3652 EP_CAN_SMASH_PLAYER,
3653 EP_CAN_SMASH_ENEMIES,
3654 EP_CAN_SMASH_EVERYTHING,
3659 EP_FOOD_DARK_YAMYAM,
3676 InitElementPropertiesStatic();
3679 /* important: after initialization in InitElementPropertiesStatic(), the
3680 elements are not again initialized to a default value; therefore all
3681 changes have to make sure that they leave the element with a defined
3682 property (which means that conditional property changes must be set to
3683 a reliable default value before) */
3685 /* set all special, combined or engine dependent element properties */
3686 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3689 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3690 SET_PROPERTY(i, j, FALSE);
3693 /* ---------- INACTIVE ------------------------------------------------- */
3694 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3696 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3697 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3698 IS_WALKABLE_INSIDE(i) ||
3699 IS_WALKABLE_UNDER(i)));
3701 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3702 IS_PASSABLE_INSIDE(i) ||
3703 IS_PASSABLE_UNDER(i)));
3705 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3706 IS_PASSABLE_OVER(i)));
3708 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3709 IS_PASSABLE_INSIDE(i)));
3711 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3712 IS_PASSABLE_UNDER(i)));
3714 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3717 /* ---------- COLLECTIBLE ---------------------------------------------- */
3718 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3722 /* ---------- SNAPPABLE ------------------------------------------------ */
3723 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3724 IS_COLLECTIBLE(i) ||
3728 /* ---------- WALL ----------------------------------------------------- */
3729 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3731 for (j = 0; no_wall_properties[j] != -1; j++)
3732 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3733 i >= EL_FIRST_RUNTIME_UNREAL)
3734 SET_PROPERTY(i, EP_WALL, FALSE);
3736 if (IS_HISTORIC_WALL(i))
3737 SET_PROPERTY(i, EP_WALL, TRUE);
3739 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3740 if (engine_version < VERSION_IDENT(2,2,0,0))
3741 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3743 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3745 !IS_COLLECTIBLE(i)));
3748 /* ---------- PROTECTED ------------------------------------------------ */
3749 if (IS_ACCESSIBLE_INSIDE(i))
3750 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3753 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3755 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3756 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3758 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3759 IS_INDESTRUCTIBLE(i)));
3761 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3763 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3764 else if (engine_version < VERSION_IDENT(2,2,0,0))
3765 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3768 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3773 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3774 !IS_WALKABLE_OVER(i) &&
3775 !IS_WALKABLE_UNDER(i)));
3777 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3782 if (IS_CUSTOM_ELEMENT(i))
3784 /* these are additional properties which are initially false when set */
3786 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3788 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3789 if (DONT_COLLIDE_WITH(i))
3790 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3792 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3793 if (CAN_SMASH_EVERYTHING(i))
3794 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3795 if (CAN_SMASH_ENEMIES(i))
3796 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3799 /* ---------- CAN_SMASH ------------------------------------------------ */
3800 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3801 CAN_SMASH_ENEMIES(i) ||
3802 CAN_SMASH_EVERYTHING(i)));
3805 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3806 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3807 CAN_EXPLODE_SMASHED(i) ||
3808 CAN_EXPLODE_IMPACT(i)));
3812 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3814 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3815 !CAN_EXPLODE_CROSS(i)));
3817 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3818 !CAN_EXPLODE_1X1(i) &&
3819 !CAN_EXPLODE_CROSS(i)));
3823 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3824 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3825 EXPLODES_BY_FIRE(i)));
3827 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3828 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3829 EXPLODES_SMASHED(i)));
3831 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3832 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3833 EXPLODES_IMPACT(i)));
3835 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3836 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3838 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3839 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3840 i == EL_BLACK_ORB));
3842 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3843 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3845 IS_CUSTOM_ELEMENT(i)));
3847 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3848 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3849 i == EL_SP_ELECTRON));
3851 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3852 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3853 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3854 getMoveIntoAcidProperty(&level, i));
3856 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3857 if (MAYBE_DONT_COLLIDE_WITH(i))
3858 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3859 getDontCollideWithProperty(&level, i));
3861 /* ---------- SP_PORT -------------------------------------------------- */
3862 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3863 IS_PASSABLE_INSIDE(i)));
3865 /* ---------- CAN_CHANGE ----------------------------------------------- */
3866 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3867 for (j = 0; j < element_info[i].num_change_pages; j++)
3868 if (element_info[i].change_page[j].can_change)
3869 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3871 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3873 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3874 element_info[i].crumbled[ACTION_DEFAULT] !=
3875 element_info[i].graphic[ACTION_DEFAULT]);
3877 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3878 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3879 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3884 /* determine inactive elements (used for engine main loop optimization) */
3885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3887 boolean active = FALSE;
3889 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3891 if (HAS_PROPERTY(i, j))
3897 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3902 /* dynamically adjust element properties according to game engine version */
3904 static int ep_em_slippery_wall[] =
3909 EL_EXPANDABLE_WALL_HORIZONTAL,
3910 EL_EXPANDABLE_WALL_VERTICAL,
3911 EL_EXPANDABLE_WALL_ANY,
3915 /* special EM style gems behaviour */
3916 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3917 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3918 level.em_slippery_gems);
3920 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3921 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3922 (level.em_slippery_gems &&
3923 engine_version > VERSION_IDENT(2,0,1,0)));
3927 /* set default push delay values (corrected since version 3.0.7-1) */
3928 if (engine_version < VERSION_IDENT(3,0,7,1))
3930 game.default_push_delay_fixed = 2;
3931 game.default_push_delay_random = 8;
3935 game.default_push_delay_fixed = 8;
3936 game.default_push_delay_random = 8;
3939 /* set uninitialized push delay values of custom elements in older levels */
3940 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3942 int element = EL_CUSTOM_START + i;
3944 if (element_info[element].push_delay_fixed == -1)
3945 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3946 if (element_info[element].push_delay_random == -1)
3947 element_info[element].push_delay_random = game.default_push_delay_random;
3950 /* set some other uninitialized values of custom elements in older levels */
3951 if (engine_version < VERSION_IDENT(3,1,0,0))
3953 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3955 int element = EL_CUSTOM_START + i;
3957 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3959 element_info[element].explosion_delay = 17;
3960 element_info[element].ignition_delay = 8;
3965 /* set element properties that were handled incorrectly in older levels */
3966 if (engine_version < VERSION_IDENT(3,1,0,0))
3968 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3969 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3975 /* this is needed because some graphics depend on element properties */
3976 if (game_status == GAME_MODE_PLAYING)
3977 InitElementGraphicInfo();
3980 static void InitGlobal()
3984 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3986 /* check if element_name_info entry defined for each element in "main.h" */
3987 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3988 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3990 element_info[i].token_name = element_name_info[i].token_name;
3991 element_info[i].class_name = element_name_info[i].class_name;
3992 element_info[i].editor_description=element_name_info[i].editor_description;
3995 global.autoplay_leveldir = NULL;
3996 global.convert_leveldir = NULL;
3998 global.frames_per_second = 0;
3999 global.fps_slowdown = FALSE;
4000 global.fps_slowdown_factor = 1;
4003 void Execute_Command(char *command)
4007 if (strcmp(command, "print graphicsinfo.conf") == 0)
4009 printf("# You can configure additional/alternative image files here.\n");
4010 printf("# (The entries below are default and therefore commented out.)\n");
4012 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4014 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4017 for (i = 0; image_config[i].token != NULL; i++)
4018 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4019 image_config[i].value));
4023 else if (strcmp(command, "print soundsinfo.conf") == 0)
4025 printf("# You can configure additional/alternative sound files here.\n");
4026 printf("# (The entries below are default and therefore commented out.)\n");
4028 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4030 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4033 for (i = 0; sound_config[i].token != NULL; i++)
4034 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4035 sound_config[i].value));
4039 else if (strcmp(command, "print musicinfo.conf") == 0)
4041 printf("# You can configure additional/alternative music files here.\n");
4042 printf("# (The entries below are default and therefore commented out.)\n");
4044 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4046 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4049 for (i = 0; music_config[i].token != NULL; i++)
4050 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4051 music_config[i].value));
4055 else if (strcmp(command, "print editorsetup.conf") == 0)
4057 printf("# You can configure your personal editor element list here.\n");
4058 printf("# (The entries below are default and therefore commented out.)\n");
4061 PrintEditorElementList();
4065 else if (strcmp(command, "print helpanim.conf") == 0)
4067 printf("# You can configure different element help animations here.\n");
4068 printf("# (The entries below are default and therefore commented out.)\n");
4071 for (i = 0; helpanim_config[i].token != NULL; i++)
4073 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4074 helpanim_config[i].value));
4076 if (strcmp(helpanim_config[i].token, "end") == 0)
4082 else if (strcmp(command, "print helptext.conf") == 0)
4084 printf("# You can configure different element help text here.\n");
4085 printf("# (The entries below are default and therefore commented out.)\n");
4088 for (i = 0; helptext_config[i].token != NULL; i++)
4089 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4090 helptext_config[i].value));
4094 else if (strncmp(command, "dump level ", 11) == 0)
4096 char *filename = &command[11];
4098 if (access(filename, F_OK) != 0)
4099 Error(ERR_EXIT, "cannot open file '%s'", filename);
4101 LoadLevelFromFilename(&level, filename);
4106 else if (strncmp(command, "dump tape ", 10) == 0)
4108 char *filename = &command[10];
4110 if (access(filename, F_OK) != 0)
4111 Error(ERR_EXIT, "cannot open file '%s'", filename);
4113 LoadTapeFromFilename(filename);
4118 else if (strncmp(command, "autoplay ", 9) == 0)
4120 char *str_copy = getStringCopy(&command[9]);
4121 char *str_ptr = strchr(str_copy, ' ');
4123 global.autoplay_leveldir = str_copy;
4124 global.autoplay_level_nr = -1;
4126 if (str_ptr != NULL)
4128 *str_ptr++ = '\0'; /* terminate leveldir string */
4129 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4132 else if (strncmp(command, "convert ", 8) == 0)
4134 char *str_copy = getStringCopy(&command[8]);
4135 char *str_ptr = strchr(str_copy, ' ');
4137 global.convert_leveldir = str_copy;
4138 global.convert_level_nr = -1;
4140 if (str_ptr != NULL)
4142 *str_ptr++ = '\0'; /* terminate leveldir string */
4143 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4148 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4152 static void InitSetup()
4154 LoadSetup(); /* global setup info */
4156 /* set some options from setup file */
4158 if (setup.options.verbose)
4159 options.verbose = TRUE;
4162 static void InitPlayerInfo()
4166 /* choose default local player */
4167 local_player = &stored_player[0];
4169 for (i = 0; i < MAX_PLAYERS; i++)
4170 stored_player[i].connected = FALSE;
4172 local_player->connected = TRUE;
4175 static void InitArtworkInfo()
4180 static char *get_string_in_brackets(char *string)
4182 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4184 sprintf(string_in_brackets, "[%s]", string);
4186 return string_in_brackets;
4189 static char *get_level_id_suffix(int id_nr)
4191 char *id_suffix = checked_malloc(1 + 3 + 1);
4193 if (id_nr < 0 || id_nr > 999)
4196 sprintf(id_suffix, ".%03d", id_nr);
4202 static char *get_element_class_token(int element)
4204 char *element_class_name = element_info[element].class_name;
4205 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4207 sprintf(element_class_token, "[%s]", element_class_name);
4209 return element_class_token;
4212 static char *get_action_class_token(int action)
4214 char *action_class_name = &element_action_info[action].suffix[1];
4215 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4217 sprintf(action_class_token, "[%s]", action_class_name);
4219 return action_class_token;
4223 static void InitArtworkConfig()
4225 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4226 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4227 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4228 static char *action_id_suffix[NUM_ACTIONS + 1];
4229 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4230 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4231 static char *level_id_suffix[MAX_LEVELS + 1];
4232 static char *dummy[1] = { NULL };
4233 static char *ignore_generic_tokens[] =
4239 static char **ignore_image_tokens;
4240 static char **ignore_sound_tokens;
4241 static char **ignore_music_tokens;
4242 int num_ignore_generic_tokens;
4243 int num_ignore_image_tokens;
4244 int num_ignore_sound_tokens;
4245 int num_ignore_music_tokens;
4248 /* dynamically determine list of generic tokens to be ignored */
4249 num_ignore_generic_tokens = 0;
4250 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4251 num_ignore_generic_tokens++;
4253 /* dynamically determine list of image tokens to be ignored */
4254 num_ignore_image_tokens = num_ignore_generic_tokens;
4255 for (i = 0; image_config_vars[i].token != NULL; i++)
4256 num_ignore_image_tokens++;
4257 ignore_image_tokens =
4258 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4259 for (i = 0; i < num_ignore_generic_tokens; i++)
4260 ignore_image_tokens[i] = ignore_generic_tokens[i];
4261 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4262 ignore_image_tokens[num_ignore_generic_tokens + i] =
4263 image_config_vars[i].token;
4264 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4266 /* dynamically determine list of sound tokens to be ignored */
4267 num_ignore_sound_tokens = num_ignore_generic_tokens;
4268 ignore_sound_tokens =
4269 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4270 for (i = 0; i < num_ignore_generic_tokens; i++)
4271 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4272 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4274 /* dynamically determine list of music tokens to be ignored */
4275 num_ignore_music_tokens = num_ignore_generic_tokens;
4276 ignore_music_tokens =
4277 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4278 for (i = 0; i < num_ignore_generic_tokens; i++)
4279 ignore_music_tokens[i] = ignore_generic_tokens[i];
4280 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4282 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4283 image_id_prefix[i] = element_info[i].token_name;
4284 for (i = 0; i < NUM_FONTS; i++)
4285 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4286 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4288 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4289 sound_id_prefix[i] = element_info[i].token_name;
4290 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4291 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4292 get_string_in_brackets(element_info[i].class_name);
4293 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4295 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4296 music_id_prefix[i] = music_prefix_info[i].prefix;
4297 music_id_prefix[MAX_LEVELS] = NULL;
4299 for (i = 0; i < NUM_ACTIONS; i++)
4300 action_id_suffix[i] = element_action_info[i].suffix;
4301 action_id_suffix[NUM_ACTIONS] = NULL;
4303 for (i = 0; i < NUM_DIRECTIONS; i++)
4304 direction_id_suffix[i] = element_direction_info[i].suffix;
4305 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4307 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4308 special_id_suffix[i] = special_suffix_info[i].suffix;
4309 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4311 for (i = 0; i < MAX_LEVELS; i++)
4312 level_id_suffix[i] = get_level_id_suffix(i);
4313 level_id_suffix[MAX_LEVELS] = NULL;
4315 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4316 image_id_prefix, action_id_suffix, direction_id_suffix,
4317 special_id_suffix, ignore_image_tokens);
4318 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4319 sound_id_prefix, action_id_suffix, dummy,
4320 special_id_suffix, ignore_sound_tokens);
4321 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4322 music_id_prefix, special_id_suffix, level_id_suffix,
4323 dummy, ignore_music_tokens);
4326 static void InitMixer()
4334 char *filename_font_initial = NULL;
4335 Bitmap *bitmap_font_initial = NULL;
4338 /* determine settings for initial font (for displaying startup messages) */
4339 for (i = 0; image_config[i].token != NULL; i++)
4341 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4343 char font_token[128];
4346 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4347 len_font_token = strlen(font_token);
4349 if (strcmp(image_config[i].token, font_token) == 0)
4350 filename_font_initial = image_config[i].value;
4351 else if (strlen(image_config[i].token) > len_font_token &&
4352 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4354 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4355 font_initial[j].src_x = atoi(image_config[i].value);
4356 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4357 font_initial[j].src_y = atoi(image_config[i].value);
4358 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4359 font_initial[j].width = atoi(image_config[i].value);
4360 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4361 font_initial[j].height = atoi(image_config[i].value);
4366 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4368 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4369 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4372 if (filename_font_initial == NULL) /* should not happen */
4373 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4375 /* create additional image buffers for double-buffering */
4376 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4377 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4379 /* initialize screen properties */
4380 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4381 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4383 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4384 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4385 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4387 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4389 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4390 font_initial[j].bitmap = bitmap_font_initial;
4392 InitFontGraphicInfo();
4394 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4395 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4397 DrawInitText("Loading graphics:", 120, FC_GREEN);
4399 InitTileClipmasks();
4402 void InitGfxBackground()
4406 drawto = backbuffer;
4407 fieldbuffer = bitmap_db_field;
4408 SetDrawtoField(DRAW_BACKBUFFER);
4410 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4411 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4412 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4413 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4415 for (x = 0; x < MAX_BUF_XSIZE; x++)
4416 for (y = 0; y < MAX_BUF_YSIZE; y++)
4419 redraw_mask = REDRAW_ALL;
4422 static void InitLevelInfo()
4424 LoadLevelInfo(); /* global level info */
4425 LoadLevelSetup_LastSeries(); /* last played series info */
4426 LoadLevelSetup_SeriesInfo(); /* last played level info */
4429 void InitLevelArtworkInfo()
4431 LoadLevelArtworkInfo();
4434 static void InitImages()
4437 setLevelArtworkDir(artwork.gfx_first);
4441 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4442 leveldir_current->identifier,
4443 artwork.gfx_current_identifier,
4444 artwork.gfx_current->identifier,
4445 leveldir_current->graphics_set,
4446 leveldir_current->graphics_path);
4449 ReloadCustomImages();
4451 LoadCustomElementDescriptions();
4452 LoadSpecialMenuDesignSettings();
4454 ReinitializeGraphics();
4457 static void InitSound(char *identifier)
4459 if (identifier == NULL)
4460 identifier = artwork.snd_current->identifier;
4463 /* set artwork path to send it to the sound server process */
4464 setLevelArtworkDir(artwork.snd_first);
4467 InitReloadCustomSounds(identifier);
4468 ReinitializeSounds();
4471 static void InitMusic(char *identifier)
4473 if (identifier == NULL)
4474 identifier = artwork.mus_current->identifier;
4477 /* set artwork path to send it to the sound server process */
4478 setLevelArtworkDir(artwork.mus_first);
4481 InitReloadCustomMusic(identifier);
4482 ReinitializeMusic();
4485 void InitNetworkServer()
4487 #if defined(NETWORK_AVALIABLE)
4491 if (!options.network)
4494 #if defined(NETWORK_AVALIABLE)
4495 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4497 if (!ConnectToServer(options.server_host, options.server_port))
4498 Error(ERR_EXIT, "cannot connect to network game server");
4500 SendToServer_PlayerName(setup.player_name);
4501 SendToServer_ProtocolVersion();
4504 SendToServer_NrWanted(nr_wanted);
4508 static char *getNewArtworkIdentifier(int type)
4510 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4511 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4512 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4513 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4514 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4515 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4516 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4517 char *leveldir_identifier = leveldir_current->identifier;
4519 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4520 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4522 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4524 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4525 char *artwork_current_identifier;
4526 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4528 /* leveldir_current may be invalid (level group, parent link) */
4529 if (!validLevelSeries(leveldir_current))
4532 /* 1st step: determine artwork set to be activated in descending order:
4533 --------------------------------------------------------------------
4534 1. setup artwork (when configured to override everything else)
4535 2. artwork set configured in "levelinfo.conf" of current level set
4536 (artwork in level directory will have priority when loading later)
4537 3. artwork in level directory (stored in artwork sub-directory)
4538 4. setup artwork (currently configured in setup menu) */
4540 if (setup_override_artwork)
4541 artwork_current_identifier = setup_artwork_set;
4542 else if (leveldir_artwork_set != NULL)
4543 artwork_current_identifier = leveldir_artwork_set;
4544 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4545 artwork_current_identifier = leveldir_identifier;
4547 artwork_current_identifier = setup_artwork_set;
4550 /* 2nd step: check if it is really needed to reload artwork set
4551 ------------------------------------------------------------ */
4554 if (type == ARTWORK_TYPE_GRAPHICS)
4555 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4556 artwork_new_identifier,
4557 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4558 artwork_current_identifier,
4559 leveldir_current->graphics_set,
4560 leveldir_current->identifier);
4563 /* ---------- reload if level set and also artwork set has changed ------- */
4564 if (leveldir_current_identifier[type] != leveldir_identifier &&
4565 (last_has_level_artwork_set[type] || has_level_artwork_set))
4566 artwork_new_identifier = artwork_current_identifier;
4568 leveldir_current_identifier[type] = leveldir_identifier;
4569 last_has_level_artwork_set[type] = has_level_artwork_set;
4572 if (type == ARTWORK_TYPE_GRAPHICS)
4573 printf("::: 1: '%s'\n", artwork_new_identifier);
4576 /* ---------- reload if "override artwork" setting has changed ----------- */
4577 if (last_override_level_artwork[type] != setup_override_artwork)
4578 artwork_new_identifier = artwork_current_identifier;
4580 last_override_level_artwork[type] = setup_override_artwork;
4583 if (type == ARTWORK_TYPE_GRAPHICS)
4584 printf("::: 2: '%s'\n", artwork_new_identifier);
4587 /* ---------- reload if current artwork identifier has changed ----------- */
4588 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4589 artwork_current_identifier) != 0)
4590 artwork_new_identifier = artwork_current_identifier;
4592 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4595 if (type == ARTWORK_TYPE_GRAPHICS)
4596 printf("::: 3: '%s'\n", artwork_new_identifier);
4599 /* ---------- do not reload directly after starting ---------------------- */
4600 if (!initialized[type])
4601 artwork_new_identifier = NULL;
4603 initialized[type] = TRUE;
4606 if (type == ARTWORK_TYPE_GRAPHICS)
4607 printf("::: 4: '%s'\n", artwork_new_identifier);
4611 if (type == ARTWORK_TYPE_GRAPHICS)
4612 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4613 artwork.gfx_current_identifier, artwork_current_identifier,
4614 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4615 artwork_new_identifier);
4618 return artwork_new_identifier;
4621 void ReloadCustomArtwork(int force_reload)
4623 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4624 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4625 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4626 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4627 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4628 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4629 boolean redraw_screen = FALSE;
4631 if (gfx_new_identifier != NULL || force_reload_gfx)
4634 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4635 artwork.gfx_current_identifier,
4637 artwork.gfx_current->identifier,
4638 leveldir_current->graphics_set);
4641 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4646 printf("... '%s'\n",
4647 leveldir_current->graphics_set);
4650 FreeTileClipmasks();
4651 InitTileClipmasks();
4653 redraw_screen = TRUE;
4656 if (snd_new_identifier != NULL || force_reload_snd)
4658 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4660 InitSound(snd_new_identifier);
4662 redraw_screen = TRUE;
4665 if (mus_new_identifier != NULL || force_reload_mus)
4667 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4669 InitMusic(mus_new_identifier);
4671 redraw_screen = TRUE;
4676 InitGfxBackground();
4678 /* force redraw of (open or closed) door graphics */
4679 SetDoorState(DOOR_OPEN_ALL);
4680 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4684 void KeyboardAutoRepeatOffUnlessAutoplay()
4686 if (global.autoplay_leveldir == NULL)
4687 KeyboardAutoRepeatOff();
4691 /* ========================================================================= */
4693 /* ========================================================================= */
4697 InitGlobal(); /* initialize some global variables */
4699 if (options.execute_command)
4700 Execute_Command(options.execute_command);
4702 if (options.serveronly)
4704 #if defined(PLATFORM_UNIX)
4705 NetworkServer(options.server_port, options.serveronly);
4707 Error(ERR_WARN, "networking only supported in Unix version");
4709 exit(0); /* never reached */
4715 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4716 InitArtworkConfig(); /* needed before forking sound child process */
4721 InitRND(NEW_RANDOMIZE);
4722 InitSimpleRND(NEW_RANDOMIZE);
4727 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4730 InitEventFilter(FilterMouseMotionEvents);
4732 InitElementPropertiesStatic();
4733 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4738 InitLevelArtworkInfo();
4740 InitImages(); /* needs to know current level directory */
4741 InitSound(NULL); /* needs to know current level directory */
4742 InitMusic(NULL); /* needs to know current level directory */
4744 InitGfxBackground();
4746 if (global.autoplay_leveldir)
4751 else if (global.convert_leveldir)
4757 game_status = GAME_MODE_MAIN;
4765 InitNetworkServer();
4768 void CloseAllAndExit(int exit_value)
4773 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4780 FreeTileClipmasks();
4782 #if defined(TARGET_SDL)
4783 if (network_server) /* terminate network server */
4784 SDL_KillThread(server_thread);
4787 CloseVideoDisplay();
4788 ClosePlatformDependentStuff();