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];
642 if (graphic != -1 && graphic_info[graphic].double_movement)
644 struct GraphicInfo *g = &graphic_info[graphic];
645 int src_x_front = g->src_x;
646 int src_y_front = g->src_y;
647 int src_x_back = g->src_x + g->offset2_x;
648 int src_y_back = g->src_y + g->offset2_y;
649 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
651 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
652 src_y_front < src_y_back);
656 printf("::: CHECKING ELEMENT %d ('%s'), ACTION '%s', DIRECTION %d\n",
657 i, element_info[i].token_name,
658 element_action_info[act].suffix, move_dir);
661 /* swap frontside and backside graphic tile coordinates, if needed */
662 if (!frames_are_ordered_diagonally &&
663 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
664 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
665 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
666 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)))
668 /* get current (wrong) backside tile coordinates */
669 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
672 /* set frontside tile coordinates to backside tile coordinates */
673 g->src_x = src_x_back;
674 g->src_y = src_y_back;
676 /* invert tile offset to point to new backside tile coordinates */
681 printf(" CORRECTED\n");
690 /* now set all '-1' values to element specific default values */
691 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
693 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
694 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
695 int default_direction_graphic[NUM_DIRECTIONS];
696 int default_direction_crumbled[NUM_DIRECTIONS];
698 if (default_graphic == -1)
699 default_graphic = IMG_UNKNOWN;
700 if (default_crumbled == -1)
701 default_crumbled = IMG_EMPTY;
703 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
705 default_direction_graphic[dir] =
706 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
707 default_direction_crumbled[dir] =
708 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
710 if (default_direction_graphic[dir] == -1)
711 default_direction_graphic[dir] = default_graphic;
712 if (default_direction_crumbled[dir] == -1)
713 default_direction_crumbled[dir] = default_crumbled;
716 for (act = 0; act < NUM_ACTIONS; act++)
718 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
719 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
720 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
721 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
722 act == ACTION_TURNING_FROM_RIGHT ||
723 act == ACTION_TURNING_FROM_UP ||
724 act == ACTION_TURNING_FROM_DOWN);
726 /* generic default action graphic (defined by "[default]" directive) */
727 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
728 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
730 /* look for special default action graphic (classic game specific) */
731 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
732 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
733 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
734 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
735 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
736 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
738 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
739 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
740 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
741 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
742 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
743 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
746 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
747 /* !!! make this better !!! */
748 if (i == EL_EMPTY_SPACE)
750 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
751 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
755 if (default_action_graphic == -1)
756 default_action_graphic = default_graphic;
757 if (default_action_crumbled == -1)
758 default_action_crumbled = default_crumbled;
760 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
762 int default_action_direction_graphic = element_info[i].graphic[act];
763 int default_action_direction_crumbled = element_info[i].crumbled[act];
765 /* no graphic for current action -- use default direction graphic */
766 /* !!! maybe it's better to use default _action_ graphic here !!! */
767 if (default_action_direction_graphic == -1)
768 default_action_direction_graphic =
769 (act_remove ? IMG_EMPTY :
771 element_info[i].direction_graphic[ACTION_TURNING][dir] :
772 default_direction_graphic[dir]);
773 if (default_action_direction_crumbled == -1)
774 default_action_direction_crumbled =
775 (act_remove ? IMG_EMPTY :
777 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
778 default_direction_crumbled[dir]);
780 if (element_info[i].direction_graphic[act][dir] == -1)
781 element_info[i].direction_graphic[act][dir] =
782 default_action_direction_graphic;
783 if (element_info[i].direction_crumbled[act][dir] == -1)
784 element_info[i].direction_crumbled[act][dir] =
785 default_action_direction_crumbled;
788 /* no graphic for this specific action -- use default action graphic */
789 if (element_info[i].graphic[act] == -1)
790 element_info[i].graphic[act] =
791 (act_remove ? IMG_EMPTY :
792 act_turning ? element_info[i].graphic[ACTION_TURNING] :
793 default_action_graphic);
794 if (element_info[i].crumbled[act] == -1)
795 element_info[i].crumbled[act] =
796 (act_remove ? IMG_EMPTY :
797 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
798 default_action_crumbled);
803 /* set animation mode to "none" for each graphic with only 1 frame */
804 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
806 for (act = 0; act < NUM_ACTIONS; act++)
808 int graphic = element_info[i].graphic[act];
809 int crumbled = element_info[i].crumbled[act];
811 if (graphic_info[graphic].anim_frames == 1)
812 graphic_info[graphic].anim_mode = ANIM_NONE;
813 if (graphic_info[crumbled].anim_frames == 1)
814 graphic_info[crumbled].anim_mode = ANIM_NONE;
816 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
818 graphic = element_info[i].direction_graphic[act][dir];
819 crumbled = element_info[i].direction_crumbled[act][dir];
821 if (graphic_info[graphic].anim_frames == 1)
822 graphic_info[graphic].anim_mode = ANIM_NONE;
823 if (graphic_info[crumbled].anim_frames == 1)
824 graphic_info[crumbled].anim_mode = ANIM_NONE;
834 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
835 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
837 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
838 element_info[i].token_name, i);
844 void InitElementSpecialGraphicInfo()
846 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
847 int num_property_mappings = getImageListPropertyMappingSize();
850 /* always start with reliable default values */
851 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
852 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
853 element_info[i].special_graphic[j] =
854 element_info[i].graphic[ACTION_DEFAULT];
856 /* initialize special element/graphic mapping from static configuration */
857 for (i = 0; element_to_special_graphic[i].element > -1; i++)
859 int element = element_to_special_graphic[i].element;
860 int special = element_to_special_graphic[i].special;
861 int graphic = element_to_special_graphic[i].graphic;
862 int base_graphic = el2baseimg(element);
863 boolean base_redefined =
864 getImageListEntryFromImageID(base_graphic)->redefined;
865 boolean special_redefined =
866 getImageListEntryFromImageID(graphic)->redefined;
868 /* if the base graphic ("emerald", for example) has been redefined,
869 but not the special graphic ("emerald.EDITOR", for example), do not
870 use an existing (in this case considered obsolete) special graphic
871 anymore, but use the automatically created (down-scaled) graphic */
872 if (base_redefined && !special_redefined)
875 element_info[element].special_graphic[special] = graphic;
878 /* initialize special element/graphic mapping from dynamic configuration */
879 for (i = 0; i < num_property_mappings; i++)
881 int element = property_mapping[i].base_index;
882 int special = property_mapping[i].ext3_index;
883 int graphic = property_mapping[i].artwork_index;
885 if (element >= MAX_NUM_ELEMENTS)
888 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
889 element_info[element].special_graphic[special] = graphic;
893 /* now set all undefined/invalid graphics to default */
894 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
895 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
896 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
897 element_info[i].special_graphic[j] =
898 element_info[i].graphic[ACTION_DEFAULT];
902 static int get_element_from_token(char *token)
906 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
907 if (strcmp(element_info[i].token_name, token) == 0)
913 static int get_scaled_graphic_width(int graphic)
915 int original_width = getOriginalImageWidthFromImageID(graphic);
916 int scale_up_factor = graphic_info[graphic].scale_up_factor;
918 return original_width * scale_up_factor;
921 static int get_scaled_graphic_height(int graphic)
923 int original_height = getOriginalImageHeightFromImageID(graphic);
924 int scale_up_factor = graphic_info[graphic].scale_up_factor;
926 return original_height * scale_up_factor;
929 static void set_graphic_parameters(int graphic, int graphic_copy_from)
931 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
932 char **parameter_raw = image->parameter;
933 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
934 int parameter[NUM_GFX_ARGS];
935 int anim_frames_per_row = 1, anim_frames_per_col = 1;
936 int anim_frames_per_line = 1;
939 /* get integer values from string parameters */
940 for (i = 0; i < NUM_GFX_ARGS; i++)
943 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
944 image_config_suffix[i].type);
946 if (image_config_suffix[i].type == TYPE_TOKEN)
947 parameter[i] = get_element_from_token(parameter_raw[i]);
950 graphic_info[graphic].bitmap = src_bitmap;
952 /* start with reliable default values */
953 graphic_info[graphic].src_x = 0;
954 graphic_info[graphic].src_y = 0;
955 graphic_info[graphic].width = TILEX;
956 graphic_info[graphic].height = TILEY;
957 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
958 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
959 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
960 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
961 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
962 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
963 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
964 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
965 graphic_info[graphic].anim_delay_fixed = 0;
966 graphic_info[graphic].anim_delay_random = 0;
967 graphic_info[graphic].post_delay_fixed = 0;
968 graphic_info[graphic].post_delay_random = 0;
970 /* optional x and y tile position of animation frame sequence */
971 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
972 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
973 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
976 /* optional x and y pixel position of animation frame sequence */
977 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
979 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
980 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
982 /* optional width and height of each animation frame */
983 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
984 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
985 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
986 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
988 /* optional zoom factor for scaling up the image to a larger size */
989 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
991 if (graphic_info[graphic].scale_up_factor < 1)
992 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
996 /* get final bitmap size (with scaling, but without small images) */
997 int src_bitmap_width = get_scaled_graphic_width(graphic);
998 int src_bitmap_height = get_scaled_graphic_height(graphic);
1000 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1001 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1004 /* correct x or y offset dependent of vertical or horizontal frame order */
1005 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1007 graphic_info[graphic].offset_y =
1008 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1009 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1010 anim_frames_per_line = anim_frames_per_col;
1012 else /* frames are ordered horizontally */
1014 graphic_info[graphic].offset_x =
1015 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1016 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1017 anim_frames_per_line = anim_frames_per_row;
1020 /* optionally, the x and y offset of frames can be specified directly */
1021 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1022 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1023 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1024 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1026 /* optionally, moving animations may have separate start and end graphics */
1027 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1029 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1030 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1032 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1033 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1034 graphic_info[graphic].offset2_y =
1035 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1036 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1037 else /* frames are ordered horizontally */
1038 graphic_info[graphic].offset2_x =
1039 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1040 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1042 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1043 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1044 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1045 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1048 /* automatically determine correct number of frames, if not defined */
1049 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1050 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1051 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1052 graphic_info[graphic].anim_frames = anim_frames_per_row;
1053 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1054 graphic_info[graphic].anim_frames = anim_frames_per_col;
1056 graphic_info[graphic].anim_frames = 1;
1058 graphic_info[graphic].anim_frames_per_line =
1059 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1060 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1062 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1063 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1064 graphic_info[graphic].anim_delay = 1;
1066 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1068 if (graphic_info[graphic].anim_frames == 1)
1069 graphic_info[graphic].anim_mode = ANIM_NONE;
1072 /* automatically determine correct start frame, if not defined */
1073 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1074 graphic_info[graphic].anim_start_frame = 0;
1075 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1076 graphic_info[graphic].anim_start_frame =
1077 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1079 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1081 /* animation synchronized with global frame counter, not move position */
1082 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1084 /* optional element for cloning crumble graphics */
1085 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1086 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1088 /* optional element for cloning digging graphics */
1089 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1090 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1092 /* optional border size for "crumbling" diggable graphics */
1093 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1094 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1096 /* this is only used for player "boring" and "sleeping" actions */
1097 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1098 graphic_info[graphic].anim_delay_fixed =
1099 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1100 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1101 graphic_info[graphic].anim_delay_random =
1102 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1103 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1104 graphic_info[graphic].post_delay_fixed =
1105 parameter[GFX_ARG_POST_DELAY_FIXED];
1106 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1107 graphic_info[graphic].post_delay_random =
1108 parameter[GFX_ARG_POST_DELAY_RANDOM];
1110 /* this is only used for toon animations */
1111 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1112 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1114 /* this is only used for drawing font characters */
1115 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1116 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1118 /* this is only used for drawing envelope graphics */
1119 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1122 static void InitGraphicInfo()
1124 int fallback_graphic = IMG_CHAR_EXCLAM;
1125 int num_images = getImageListSize();
1128 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1129 static boolean clipmasks_initialized = FALSE;
1131 XGCValues clip_gc_values;
1132 unsigned long clip_gc_valuemask;
1133 GC copy_clipmask_gc = None;
1136 checked_free(graphic_info);
1138 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1141 printf("::: graphic_info: %d entries\n", num_images);
1144 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1145 if (clipmasks_initialized)
1147 for (i = 0; i < num_images; i++)
1149 if (graphic_info[i].clip_mask)
1150 XFreePixmap(display, graphic_info[i].clip_mask);
1151 if (graphic_info[i].clip_gc)
1152 XFreeGC(display, graphic_info[i].clip_gc);
1154 graphic_info[i].clip_mask = None;
1155 graphic_info[i].clip_gc = None;
1160 for (i = 0; i < num_images; i++)
1164 int first_frame, last_frame;
1165 int src_bitmap_width, src_bitmap_height;
1168 printf("::: image: '%s' [%d]\n", image->token, i);
1172 printf("::: image # %d: '%s' ['%s']\n",
1174 getTokenFromImageID(i));
1177 set_graphic_parameters(i, i);
1179 /* now check if no animation frames are outside of the loaded image */
1181 if (graphic_info[i].bitmap == NULL)
1182 continue; /* skip check for optional images that are undefined */
1184 /* get final bitmap size (with scaling, but without small images) */
1185 src_bitmap_width = get_scaled_graphic_width(i);
1186 src_bitmap_height = get_scaled_graphic_height(i);
1189 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1190 if (src_x < 0 || src_y < 0 ||
1191 src_x + TILEX > src_bitmap_width ||
1192 src_y + TILEY > src_bitmap_height)
1194 Error(ERR_RETURN_LINE, "-");
1195 Error(ERR_RETURN, "warning: error found in config file:");
1196 Error(ERR_RETURN, "- config file: '%s'",
1197 getImageConfigFilename());
1198 Error(ERR_RETURN, "- config token: '%s'",
1199 getTokenFromImageID(i));
1200 Error(ERR_RETURN, "- image file: '%s'",
1201 src_bitmap->source_filename);
1203 "error: first animation frame out of bounds (%d, %d)",
1205 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1208 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1211 if (i == fallback_graphic)
1212 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1214 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1215 Error(ERR_RETURN_LINE, "-");
1217 set_graphic_parameters(i, fallback_graphic);
1220 last_frame = graphic_info[i].anim_frames - 1;
1221 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1222 if (src_x < 0 || src_y < 0 ||
1223 src_x + TILEX > src_bitmap_width ||
1224 src_y + TILEY > src_bitmap_height)
1226 Error(ERR_RETURN_LINE, "-");
1227 Error(ERR_RETURN, "warning: error found in config file:");
1228 Error(ERR_RETURN, "- config file: '%s'",
1229 getImageConfigFilename());
1230 Error(ERR_RETURN, "- config token: '%s'",
1231 getTokenFromImageID(i));
1232 Error(ERR_RETURN, "- image file: '%s'",
1233 src_bitmap->source_filename);
1235 "error: last animation frame (%d) out of bounds (%d, %d)",
1236 last_frame, src_x, src_y);
1237 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1239 if (i == fallback_graphic)
1240 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1242 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1243 Error(ERR_RETURN_LINE, "-");
1245 set_graphic_parameters(i, fallback_graphic);
1248 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1249 /* currently we only need a tile clip mask from the first frame */
1250 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1252 if (copy_clipmask_gc == None)
1254 clip_gc_values.graphics_exposures = False;
1255 clip_gc_valuemask = GCGraphicsExposures;
1256 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1257 clip_gc_valuemask, &clip_gc_values);
1260 graphic_info[i].clip_mask =
1261 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1263 src_pixmap = src_bitmap->clip_mask;
1264 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1265 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1267 clip_gc_values.graphics_exposures = False;
1268 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1269 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1271 graphic_info[i].clip_gc =
1272 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1276 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1277 if (copy_clipmask_gc)
1278 XFreeGC(display, copy_clipmask_gc);
1280 clipmasks_initialized = TRUE;
1284 static void InitElementSoundInfo()
1286 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1287 int num_property_mappings = getSoundListPropertyMappingSize();
1290 /* set values to -1 to identify later as "uninitialized" values */
1291 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1292 for (act = 0; act < NUM_ACTIONS; act++)
1293 element_info[i].sound[act] = -1;
1295 /* initialize element/sound mapping from static configuration */
1296 for (i = 0; element_to_sound[i].element > -1; i++)
1298 int element = element_to_sound[i].element;
1299 int action = element_to_sound[i].action;
1300 int sound = element_to_sound[i].sound;
1301 boolean is_class = element_to_sound[i].is_class;
1304 action = ACTION_DEFAULT;
1307 element_info[element].sound[action] = sound;
1309 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1310 if (strcmp(element_info[j].class_name,
1311 element_info[element].class_name) == 0)
1312 element_info[j].sound[action] = sound;
1315 /* initialize element class/sound mapping from dynamic configuration */
1316 for (i = 0; i < num_property_mappings; i++)
1318 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1319 int action = property_mapping[i].ext1_index;
1320 int sound = property_mapping[i].artwork_index;
1322 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1326 action = ACTION_DEFAULT;
1328 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1329 if (strcmp(element_info[j].class_name,
1330 element_info[element_class].class_name) == 0)
1331 element_info[j].sound[action] = sound;
1334 /* initialize element/sound mapping from dynamic configuration */
1335 for (i = 0; i < num_property_mappings; i++)
1337 int element = property_mapping[i].base_index;
1338 int action = property_mapping[i].ext1_index;
1339 int sound = property_mapping[i].artwork_index;
1341 if (element >= MAX_NUM_ELEMENTS)
1345 action = ACTION_DEFAULT;
1347 element_info[element].sound[action] = sound;
1350 /* now set all '-1' values to element specific default values */
1351 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1353 for (act = 0; act < NUM_ACTIONS; act++)
1355 /* generic default action sound (defined by "[default]" directive) */
1356 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1358 /* look for special default action sound (classic game specific) */
1359 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1360 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1361 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1362 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1363 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1364 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1366 /* !!! there's no such thing as a "default action sound" !!! */
1368 /* look for element specific default sound (independent from action) */
1369 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1370 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1374 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1375 /* !!! make this better !!! */
1376 if (i == EL_EMPTY_SPACE)
1377 default_action_sound = element_info[EL_DEFAULT].sound[act];
1380 /* no sound for this specific action -- use default action sound */
1381 if (element_info[i].sound[act] == -1)
1382 element_info[i].sound[act] = default_action_sound;
1387 static void InitGameModeSoundInfo()
1391 /* set values to -1 to identify later as "uninitialized" values */
1392 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1395 /* initialize gamemode/sound mapping from static configuration */
1396 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1398 int gamemode = gamemode_to_sound[i].gamemode;
1399 int sound = gamemode_to_sound[i].sound;
1402 gamemode = GAME_MODE_DEFAULT;
1404 menu.sound[gamemode] = sound;
1407 /* now set all '-1' values to levelset specific default values */
1408 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1409 if (menu.sound[i] == -1)
1410 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1414 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1415 if (menu.sound[i] != -1)
1416 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1420 static void set_sound_parameters(int sound, char **parameter_raw)
1422 int parameter[NUM_SND_ARGS];
1425 /* get integer values from string parameters */
1426 for (i = 0; i < NUM_SND_ARGS; i++)
1428 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1429 sound_config_suffix[i].type);
1431 /* explicit loop mode setting in configuration overrides default value */
1432 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1433 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1435 /* sound volume to change the original volume when loading the sound file */
1436 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1438 /* sound priority to give certain sounds a higher or lower priority */
1439 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1442 static void InitSoundInfo()
1445 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1446 int num_property_mappings = getSoundListPropertyMappingSize();
1448 int *sound_effect_properties;
1449 int num_sounds = getSoundListSize();
1452 checked_free(sound_info);
1454 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1455 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1457 /* initialize sound effect for all elements to "no sound" */
1458 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1459 for (j = 0; j < NUM_ACTIONS; j++)
1460 element_info[i].sound[j] = SND_UNDEFINED;
1462 for (i = 0; i < num_sounds; i++)
1464 struct FileInfo *sound = getSoundListEntry(i);
1465 int len_effect_text = strlen(sound->token);
1467 sound_effect_properties[i] = ACTION_OTHER;
1468 sound_info[i].loop = FALSE; /* default: play sound only once */
1471 printf("::: sound %d: '%s'\n", i, sound->token);
1474 /* determine all loop sounds and identify certain sound classes */
1476 for (j = 0; element_action_info[j].suffix; j++)
1478 int len_action_text = strlen(element_action_info[j].suffix);
1480 if (len_action_text < len_effect_text &&
1481 strcmp(&sound->token[len_effect_text - len_action_text],
1482 element_action_info[j].suffix) == 0)
1484 sound_effect_properties[i] = element_action_info[j].value;
1485 sound_info[i].loop = element_action_info[j].is_loop_sound;
1492 if (strcmp(sound->token, "custom_42") == 0)
1493 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1496 /* associate elements and some selected sound actions */
1498 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1500 if (element_info[j].class_name)
1502 int len_class_text = strlen(element_info[j].class_name);
1504 if (len_class_text + 1 < len_effect_text &&
1505 strncmp(sound->token,
1506 element_info[j].class_name, len_class_text) == 0 &&
1507 sound->token[len_class_text] == '.')
1509 int sound_action_value = sound_effect_properties[i];
1511 element_info[j].sound[sound_action_value] = i;
1516 set_sound_parameters(i, sound->parameter);
1519 free(sound_effect_properties);
1522 /* !!! now handled in InitElementSoundInfo() !!! */
1523 /* initialize element/sound mapping from dynamic configuration */
1524 for (i = 0; i < num_property_mappings; i++)
1526 int element = property_mapping[i].base_index;
1527 int action = property_mapping[i].ext1_index;
1528 int sound = property_mapping[i].artwork_index;
1531 action = ACTION_DEFAULT;
1533 printf("::: %d: %d, %d, %d ['%s']\n",
1534 i, element, action, sound, element_info[element].token_name);
1536 element_info[element].sound[action] = sound;
1543 int element = EL_CUSTOM_11;
1546 while (element_action_info[j].suffix)
1548 printf("element %d, sound action '%s' == %d\n",
1549 element, element_action_info[j].suffix,
1550 element_info[element].sound[j]);
1555 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1561 int element = EL_SAND;
1562 int sound_action = ACTION_DIGGING;
1565 while (element_action_info[j].suffix)
1567 if (element_action_info[j].value == sound_action)
1568 printf("element %d, sound action '%s' == %d\n",
1569 element, element_action_info[j].suffix,
1570 element_info[element].sound[sound_action]);
1577 static void InitGameModeMusicInfo()
1579 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1580 int num_property_mappings = getMusicListPropertyMappingSize();
1581 int default_levelset_music = -1;
1584 /* set values to -1 to identify later as "uninitialized" values */
1585 for (i = 0; i < MAX_LEVELS; i++)
1586 levelset.music[i] = -1;
1587 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1590 /* initialize gamemode/music mapping from static configuration */
1591 for (i = 0; gamemode_to_music[i].music > -1; i++)
1593 int gamemode = gamemode_to_music[i].gamemode;
1594 int music = gamemode_to_music[i].music;
1597 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1601 gamemode = GAME_MODE_DEFAULT;
1603 menu.music[gamemode] = music;
1606 /* initialize gamemode/music mapping from dynamic configuration */
1607 for (i = 0; i < num_property_mappings; i++)
1609 int prefix = property_mapping[i].base_index;
1610 int gamemode = property_mapping[i].ext1_index;
1611 int level = property_mapping[i].ext2_index;
1612 int music = property_mapping[i].artwork_index;
1615 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1616 prefix, gamemode, level, music);
1619 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1623 gamemode = GAME_MODE_DEFAULT;
1625 /* level specific music only allowed for in-game music */
1626 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1627 gamemode = GAME_MODE_PLAYING;
1632 default_levelset_music = music;
1635 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1636 levelset.music[level] = music;
1637 if (gamemode != GAME_MODE_PLAYING)
1638 menu.music[gamemode] = music;
1641 /* now set all '-1' values to menu specific default values */
1642 /* (undefined values of "levelset.music[]" might stay at "-1" to
1643 allow dynamic selection of music files from music directory!) */
1644 for (i = 0; i < MAX_LEVELS; i++)
1645 if (levelset.music[i] == -1)
1646 levelset.music[i] = default_levelset_music;
1647 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1648 if (menu.music[i] == -1)
1649 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1653 for (i = 0; i < MAX_LEVELS; i++)
1654 if (levelset.music[i] != -1)
1655 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1656 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1657 if (menu.music[i] != -1)
1658 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1662 static void set_music_parameters(int music, char **parameter_raw)
1664 int parameter[NUM_MUS_ARGS];
1667 /* get integer values from string parameters */
1668 for (i = 0; i < NUM_MUS_ARGS; i++)
1670 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1671 music_config_suffix[i].type);
1673 /* explicit loop mode setting in configuration overrides default value */
1674 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1675 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1678 static void InitMusicInfo()
1680 int num_music = getMusicListSize();
1683 checked_free(music_info);
1685 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1687 for (i = 0; i < num_music; i++)
1689 struct FileInfo *music = getMusicListEntry(i);
1690 int len_music_text = strlen(music->token);
1692 music_info[i].loop = TRUE; /* default: play music in loop mode */
1694 /* determine all loop music */
1696 for (j = 0; music_prefix_info[j].prefix; j++)
1698 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1700 if (len_prefix_text < len_music_text &&
1701 strncmp(music->token,
1702 music_prefix_info[j].prefix, len_prefix_text) == 0)
1704 music_info[i].loop = music_prefix_info[j].is_loop_music;
1710 set_music_parameters(i, music->parameter);
1714 static void ReinitializeGraphics()
1716 InitGraphicInfo(); /* graphic properties mapping */
1717 InitElementGraphicInfo(); /* element game graphic mapping */
1718 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1720 InitElementSmallImages(); /* scale images to all needed sizes */
1721 InitFontGraphicInfo(); /* initialize text drawing functions */
1723 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1725 SetMainBackgroundImage(IMG_BACKGROUND);
1726 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1732 static void ReinitializeSounds()
1734 InitSoundInfo(); /* sound properties mapping */
1735 InitElementSoundInfo(); /* element game sound mapping */
1736 InitGameModeSoundInfo(); /* game mode sound mapping */
1738 InitPlayLevelSound(); /* internal game sound settings */
1741 static void ReinitializeMusic()
1743 InitMusicInfo(); /* music properties mapping */
1744 InitGameModeMusicInfo(); /* game mode music mapping */
1747 static int get_special_property_bit(int element, int property_bit_nr)
1749 struct PropertyBitInfo
1755 static struct PropertyBitInfo pb_can_move_into_acid[] =
1757 /* the player may be able fall into acid when gravity is activated */
1762 { EL_SP_MURPHY, 0 },
1763 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1765 /* all element that can move may be able to also move into acid */
1768 { EL_BUG_RIGHT, 1 },
1771 { EL_SPACESHIP, 2 },
1772 { EL_SPACESHIP_LEFT, 2 },
1773 { EL_SPACESHIP_RIGHT, 2 },
1774 { EL_SPACESHIP_UP, 2 },
1775 { EL_SPACESHIP_DOWN, 2 },
1776 { EL_BD_BUTTERFLY, 3 },
1777 { EL_BD_BUTTERFLY_LEFT, 3 },
1778 { EL_BD_BUTTERFLY_RIGHT, 3 },
1779 { EL_BD_BUTTERFLY_UP, 3 },
1780 { EL_BD_BUTTERFLY_DOWN, 3 },
1781 { EL_BD_FIREFLY, 4 },
1782 { EL_BD_FIREFLY_LEFT, 4 },
1783 { EL_BD_FIREFLY_RIGHT, 4 },
1784 { EL_BD_FIREFLY_UP, 4 },
1785 { EL_BD_FIREFLY_DOWN, 4 },
1787 { EL_DARK_YAMYAM, 6 },
1790 { EL_PACMAN_LEFT, 8 },
1791 { EL_PACMAN_RIGHT, 8 },
1792 { EL_PACMAN_UP, 8 },
1793 { EL_PACMAN_DOWN, 8 },
1795 { EL_MOLE_LEFT, 9 },
1796 { EL_MOLE_RIGHT, 9 },
1798 { EL_MOLE_DOWN, 9 },
1802 { EL_SATELLITE, 13 },
1803 { EL_SP_SNIKSNAK, 14 },
1804 { EL_SP_ELECTRON, 15 },
1811 static struct PropertyBitInfo pb_dont_collide_with[] =
1813 { EL_SP_SNIKSNAK, 0 },
1814 { EL_SP_ELECTRON, 1 },
1822 struct PropertyBitInfo *pb_info;
1825 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1826 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1831 struct PropertyBitInfo *pb_info = NULL;
1834 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1835 if (pb_definition[i].bit_nr == property_bit_nr)
1836 pb_info = pb_definition[i].pb_info;
1838 if (pb_info == NULL)
1841 for (i = 0; pb_info[i].element != -1; i++)
1842 if (pb_info[i].element == element)
1843 return pb_info[i].bit_nr;
1849 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1850 boolean property_value)
1852 int bit_nr = get_special_property_bit(element, property_bit_nr);
1857 *bitfield |= (1 << bit_nr);
1859 *bitfield &= ~(1 << bit_nr);
1863 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1865 int bit_nr = get_special_property_bit(element, property_bit_nr);
1868 return ((*bitfield & (1 << bit_nr)) != 0);
1875 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1877 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1881 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1884 level->can_move_into_acid_bits |= (1 << bit_nr);
1888 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1890 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1893 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1899 void InitElementPropertiesStatic()
1901 static int ep_diggable[] =
1906 EL_SP_BUGGY_BASE_ACTIVATING,
1909 EL_INVISIBLE_SAND_ACTIVE,
1912 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1913 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1917 EL_SP_BUGGY_BASE_ACTIVE,
1923 static int ep_collectible_only[] =
1944 EL_DYNABOMB_INCREASE_NUMBER,
1945 EL_DYNABOMB_INCREASE_SIZE,
1946 EL_DYNABOMB_INCREASE_POWER,
1965 static int ep_dont_run_into[] =
1967 /* same elements as in 'ep_dont_touch' */
1973 /* same elements as in 'ep_dont_collide_with' */
1985 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1989 EL_SP_BUGGY_BASE_ACTIVE,
1995 static int ep_dont_collide_with[] =
1997 /* same elements as in 'ep_dont_touch' */
2013 static int ep_dont_touch[] =
2022 static int ep_indestructible[] =
2026 EL_ACID_POOL_TOPLEFT,
2027 EL_ACID_POOL_TOPRIGHT,
2028 EL_ACID_POOL_BOTTOMLEFT,
2029 EL_ACID_POOL_BOTTOM,
2030 EL_ACID_POOL_BOTTOMRIGHT,
2031 EL_SP_HARDWARE_GRAY,
2032 EL_SP_HARDWARE_GREEN,
2033 EL_SP_HARDWARE_BLUE,
2035 EL_SP_HARDWARE_YELLOW,
2036 EL_SP_HARDWARE_BASE_1,
2037 EL_SP_HARDWARE_BASE_2,
2038 EL_SP_HARDWARE_BASE_3,
2039 EL_SP_HARDWARE_BASE_4,
2040 EL_SP_HARDWARE_BASE_5,
2041 EL_SP_HARDWARE_BASE_6,
2042 EL_INVISIBLE_STEELWALL,
2043 EL_INVISIBLE_STEELWALL_ACTIVE,
2044 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2045 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2046 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2047 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2048 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2049 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2050 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2051 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2052 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2053 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2054 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2055 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2057 EL_LIGHT_SWITCH_ACTIVE,
2058 EL_SIGN_EXCLAMATION,
2059 EL_SIGN_RADIOACTIVITY,
2070 EL_STEELWALL_SLIPPERY,
2093 EL_SWITCHGATE_OPENING,
2094 EL_SWITCHGATE_CLOSED,
2095 EL_SWITCHGATE_CLOSING,
2097 EL_SWITCHGATE_SWITCH_UP,
2098 EL_SWITCHGATE_SWITCH_DOWN,
2101 EL_TIMEGATE_OPENING,
2103 EL_TIMEGATE_CLOSING,
2106 EL_TIMEGATE_SWITCH_ACTIVE,
2111 EL_TUBE_VERTICAL_LEFT,
2112 EL_TUBE_VERTICAL_RIGHT,
2113 EL_TUBE_HORIZONTAL_UP,
2114 EL_TUBE_HORIZONTAL_DOWN,
2122 static int ep_slippery[] =
2136 EL_ROBOT_WHEEL_ACTIVE,
2142 EL_ACID_POOL_TOPLEFT,
2143 EL_ACID_POOL_TOPRIGHT,
2153 EL_STEELWALL_SLIPPERY,
2156 EL_EMC_WALL_SLIPPERY_1,
2157 EL_EMC_WALL_SLIPPERY_2,
2158 EL_EMC_WALL_SLIPPERY_3,
2159 EL_EMC_WALL_SLIPPERY_4,
2163 static int ep_can_change[] =
2168 static int ep_can_move[] =
2170 /* same elements as in 'pb_can_move_into_acid' */
2192 static int ep_can_fall[] =
2207 EL_BD_MAGIC_WALL_FULL,
2220 static int ep_can_smash_player[] =
2245 static int ep_can_smash_enemies[] =
2253 static int ep_can_smash_everything[] =
2261 static int ep_explodes_by_fire[] =
2263 /* same elements as in 'ep_explodes_impact' */
2268 /* same elements as in 'ep_explodes_smashed' */
2277 EL_DYNABOMB_PLAYER_1_ACTIVE,
2278 EL_DYNABOMB_PLAYER_2_ACTIVE,
2279 EL_DYNABOMB_PLAYER_3_ACTIVE,
2280 EL_DYNABOMB_PLAYER_4_ACTIVE,
2281 EL_DYNABOMB_INCREASE_NUMBER,
2282 EL_DYNABOMB_INCREASE_SIZE,
2283 EL_DYNABOMB_INCREASE_POWER,
2284 EL_SP_DISK_RED_ACTIVE,
2297 static int ep_explodes_smashed[] =
2299 /* same elements as in 'ep_explodes_impact' */
2312 static int ep_explodes_impact[] =
2320 static int ep_walkable_over[] =
2324 EL_SOKOBAN_FIELD_EMPTY,
2342 static int ep_walkable_inside[] =
2347 EL_TUBE_VERTICAL_LEFT,
2348 EL_TUBE_VERTICAL_RIGHT,
2349 EL_TUBE_HORIZONTAL_UP,
2350 EL_TUBE_HORIZONTAL_DOWN,
2358 static int ep_walkable_under[] =
2363 static int ep_passable_over[] =
2386 static int ep_passable_inside[] =
2392 EL_SP_PORT_HORIZONTAL,
2393 EL_SP_PORT_VERTICAL,
2395 EL_SP_GRAVITY_PORT_LEFT,
2396 EL_SP_GRAVITY_PORT_RIGHT,
2397 EL_SP_GRAVITY_PORT_UP,
2398 EL_SP_GRAVITY_PORT_DOWN,
2399 EL_SP_GRAVITY_ON_PORT_LEFT,
2400 EL_SP_GRAVITY_ON_PORT_RIGHT,
2401 EL_SP_GRAVITY_ON_PORT_UP,
2402 EL_SP_GRAVITY_ON_PORT_DOWN,
2403 EL_SP_GRAVITY_OFF_PORT_LEFT,
2404 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2405 EL_SP_GRAVITY_OFF_PORT_UP,
2406 EL_SP_GRAVITY_OFF_PORT_DOWN,
2410 static int ep_passable_under[] =
2415 static int ep_droppable[] =
2420 static int ep_explodes_1x1_old[] =
2425 static int ep_pushable[] =
2437 EL_SOKOBAN_FIELD_FULL,
2445 static int ep_explodes_cross_old[] =
2450 static int ep_protected[] =
2452 /* same elements as in 'ep_walkable_inside' */
2456 EL_TUBE_VERTICAL_LEFT,
2457 EL_TUBE_VERTICAL_RIGHT,
2458 EL_TUBE_HORIZONTAL_UP,
2459 EL_TUBE_HORIZONTAL_DOWN,
2465 /* same elements as in 'ep_passable_over' */
2485 /* same elements as in 'ep_passable_inside' */
2490 EL_SP_PORT_HORIZONTAL,
2491 EL_SP_PORT_VERTICAL,
2493 EL_SP_GRAVITY_PORT_LEFT,
2494 EL_SP_GRAVITY_PORT_RIGHT,
2495 EL_SP_GRAVITY_PORT_UP,
2496 EL_SP_GRAVITY_PORT_DOWN,
2497 EL_SP_GRAVITY_ON_PORT_LEFT,
2498 EL_SP_GRAVITY_ON_PORT_RIGHT,
2499 EL_SP_GRAVITY_ON_PORT_UP,
2500 EL_SP_GRAVITY_ON_PORT_DOWN,
2501 EL_SP_GRAVITY_OFF_PORT_LEFT,
2502 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2503 EL_SP_GRAVITY_OFF_PORT_UP,
2504 EL_SP_GRAVITY_OFF_PORT_DOWN,
2508 static int ep_throwable[] =
2513 static int ep_can_explode[] =
2515 /* same elements as in 'ep_explodes_impact' */
2520 /* same elements as in 'ep_explodes_smashed' */
2526 /* elements that can explode by explosion or by dragonfire */
2529 EL_DYNABOMB_PLAYER_1_ACTIVE,
2530 EL_DYNABOMB_PLAYER_2_ACTIVE,
2531 EL_DYNABOMB_PLAYER_3_ACTIVE,
2532 EL_DYNABOMB_PLAYER_4_ACTIVE,
2533 EL_DYNABOMB_INCREASE_NUMBER,
2534 EL_DYNABOMB_INCREASE_SIZE,
2535 EL_DYNABOMB_INCREASE_POWER,
2536 EL_SP_DISK_RED_ACTIVE,
2544 /* elements that can explode only by explosion */
2549 static int ep_gravity_reachable[] =
2555 EL_INVISIBLE_SAND_ACTIVE,
2560 EL_SP_PORT_HORIZONTAL,
2561 EL_SP_PORT_VERTICAL,
2563 EL_SP_GRAVITY_PORT_LEFT,
2564 EL_SP_GRAVITY_PORT_RIGHT,
2565 EL_SP_GRAVITY_PORT_UP,
2566 EL_SP_GRAVITY_PORT_DOWN,
2567 EL_SP_GRAVITY_ON_PORT_LEFT,
2568 EL_SP_GRAVITY_ON_PORT_RIGHT,
2569 EL_SP_GRAVITY_ON_PORT_UP,
2570 EL_SP_GRAVITY_ON_PORT_DOWN,
2571 EL_SP_GRAVITY_OFF_PORT_LEFT,
2572 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2573 EL_SP_GRAVITY_OFF_PORT_UP,
2574 EL_SP_GRAVITY_OFF_PORT_DOWN,
2579 static int ep_player[] =
2586 EL_SOKOBAN_FIELD_PLAYER,
2591 static int ep_can_pass_magic_wall[] =
2604 static int ep_switchable[] =
2608 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2609 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2610 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2611 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2612 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2613 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2614 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2615 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2616 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2617 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2618 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2619 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2620 EL_SWITCHGATE_SWITCH_UP,
2621 EL_SWITCHGATE_SWITCH_DOWN,
2623 EL_LIGHT_SWITCH_ACTIVE,
2625 EL_BALLOON_SWITCH_LEFT,
2626 EL_BALLOON_SWITCH_RIGHT,
2627 EL_BALLOON_SWITCH_UP,
2628 EL_BALLOON_SWITCH_DOWN,
2629 EL_BALLOON_SWITCH_ANY,
2632 EL_EMC_MAGIC_BALL_SWITCH,
2636 static int ep_bd_element[] =
2669 static int ep_sp_element[] =
2671 /* should always be valid */
2674 /* standard classic Supaplex elements */
2681 EL_SP_HARDWARE_GRAY,
2689 EL_SP_GRAVITY_PORT_RIGHT,
2690 EL_SP_GRAVITY_PORT_DOWN,
2691 EL_SP_GRAVITY_PORT_LEFT,
2692 EL_SP_GRAVITY_PORT_UP,
2697 EL_SP_PORT_VERTICAL,
2698 EL_SP_PORT_HORIZONTAL,
2704 EL_SP_HARDWARE_BASE_1,
2705 EL_SP_HARDWARE_GREEN,
2706 EL_SP_HARDWARE_BLUE,
2708 EL_SP_HARDWARE_YELLOW,
2709 EL_SP_HARDWARE_BASE_2,
2710 EL_SP_HARDWARE_BASE_3,
2711 EL_SP_HARDWARE_BASE_4,
2712 EL_SP_HARDWARE_BASE_5,
2713 EL_SP_HARDWARE_BASE_6,
2717 /* additional elements that appeared in newer Supaplex levels */
2720 /* additional gravity port elements (not switching, but setting gravity) */
2721 EL_SP_GRAVITY_ON_PORT_LEFT,
2722 EL_SP_GRAVITY_ON_PORT_RIGHT,
2723 EL_SP_GRAVITY_ON_PORT_UP,
2724 EL_SP_GRAVITY_ON_PORT_DOWN,
2725 EL_SP_GRAVITY_OFF_PORT_LEFT,
2726 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2727 EL_SP_GRAVITY_OFF_PORT_UP,
2728 EL_SP_GRAVITY_OFF_PORT_DOWN,
2730 /* more than one Murphy in a level results in an inactive clone */
2733 /* runtime Supaplex elements */
2734 EL_SP_DISK_RED_ACTIVE,
2735 EL_SP_TERMINAL_ACTIVE,
2736 EL_SP_BUGGY_BASE_ACTIVATING,
2737 EL_SP_BUGGY_BASE_ACTIVE,
2743 static int ep_sb_element[] =
2748 EL_SOKOBAN_FIELD_EMPTY,
2749 EL_SOKOBAN_FIELD_FULL,
2750 EL_SOKOBAN_FIELD_PLAYER,
2755 EL_INVISIBLE_STEELWALL,
2759 static int ep_gem[] =
2770 static int ep_food_dark_yamyam[] =
2797 static int ep_food_penguin[] =
2810 static int ep_food_pig[] =
2821 static int ep_historic_wall[] =
2846 EL_EXPANDABLE_WALL_HORIZONTAL,
2847 EL_EXPANDABLE_WALL_VERTICAL,
2848 EL_EXPANDABLE_WALL_ANY,
2849 EL_EXPANDABLE_WALL_GROWING,
2856 EL_SP_HARDWARE_GRAY,
2857 EL_SP_HARDWARE_GREEN,
2858 EL_SP_HARDWARE_BLUE,
2860 EL_SP_HARDWARE_YELLOW,
2861 EL_SP_HARDWARE_BASE_1,
2862 EL_SP_HARDWARE_BASE_2,
2863 EL_SP_HARDWARE_BASE_3,
2864 EL_SP_HARDWARE_BASE_4,
2865 EL_SP_HARDWARE_BASE_5,
2866 EL_SP_HARDWARE_BASE_6,
2868 EL_SP_TERMINAL_ACTIVE,
2871 EL_INVISIBLE_STEELWALL,
2872 EL_INVISIBLE_STEELWALL_ACTIVE,
2874 EL_INVISIBLE_WALL_ACTIVE,
2875 EL_STEELWALL_SLIPPERY,
2891 static int ep_historic_solid[] =
2895 EL_EXPANDABLE_WALL_HORIZONTAL,
2896 EL_EXPANDABLE_WALL_VERTICAL,
2897 EL_EXPANDABLE_WALL_ANY,
2910 EL_QUICKSAND_FILLING,
2911 EL_QUICKSAND_EMPTYING,
2913 EL_MAGIC_WALL_ACTIVE,
2914 EL_MAGIC_WALL_EMPTYING,
2915 EL_MAGIC_WALL_FILLING,
2919 EL_BD_MAGIC_WALL_ACTIVE,
2920 EL_BD_MAGIC_WALL_EMPTYING,
2921 EL_BD_MAGIC_WALL_FULL,
2922 EL_BD_MAGIC_WALL_FILLING,
2923 EL_BD_MAGIC_WALL_DEAD,
2932 EL_SP_TERMINAL_ACTIVE,
2936 EL_INVISIBLE_WALL_ACTIVE,
2937 EL_SWITCHGATE_SWITCH_UP,
2938 EL_SWITCHGATE_SWITCH_DOWN,
2940 EL_TIMEGATE_SWITCH_ACTIVE,
2952 /* the following elements are a direct copy of "indestructible" elements,
2953 except "EL_ACID", which is "indestructible", but not "solid"! */
2958 EL_ACID_POOL_TOPLEFT,
2959 EL_ACID_POOL_TOPRIGHT,
2960 EL_ACID_POOL_BOTTOMLEFT,
2961 EL_ACID_POOL_BOTTOM,
2962 EL_ACID_POOL_BOTTOMRIGHT,
2963 EL_SP_HARDWARE_GRAY,
2964 EL_SP_HARDWARE_GREEN,
2965 EL_SP_HARDWARE_BLUE,
2967 EL_SP_HARDWARE_YELLOW,
2968 EL_SP_HARDWARE_BASE_1,
2969 EL_SP_HARDWARE_BASE_2,
2970 EL_SP_HARDWARE_BASE_3,
2971 EL_SP_HARDWARE_BASE_4,
2972 EL_SP_HARDWARE_BASE_5,
2973 EL_SP_HARDWARE_BASE_6,
2974 EL_INVISIBLE_STEELWALL,
2975 EL_INVISIBLE_STEELWALL_ACTIVE,
2976 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2977 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2978 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2979 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2980 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2981 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2982 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2983 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2984 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2985 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2986 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2987 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2989 EL_LIGHT_SWITCH_ACTIVE,
2990 EL_SIGN_EXCLAMATION,
2991 EL_SIGN_RADIOACTIVITY,
3002 EL_STEELWALL_SLIPPERY,
3025 EL_SWITCHGATE_OPENING,
3026 EL_SWITCHGATE_CLOSED,
3027 EL_SWITCHGATE_CLOSING,
3029 EL_TIMEGATE_OPENING,
3031 EL_TIMEGATE_CLOSING,
3035 EL_TUBE_VERTICAL_LEFT,
3036 EL_TUBE_VERTICAL_RIGHT,
3037 EL_TUBE_HORIZONTAL_UP,
3038 EL_TUBE_HORIZONTAL_DOWN,
3046 static int ep_classic_enemy[] =
3062 static int ep_belt[] =
3064 EL_CONVEYOR_BELT_1_LEFT,
3065 EL_CONVEYOR_BELT_1_MIDDLE,
3066 EL_CONVEYOR_BELT_1_RIGHT,
3067 EL_CONVEYOR_BELT_2_LEFT,
3068 EL_CONVEYOR_BELT_2_MIDDLE,
3069 EL_CONVEYOR_BELT_2_RIGHT,
3070 EL_CONVEYOR_BELT_3_LEFT,
3071 EL_CONVEYOR_BELT_3_MIDDLE,
3072 EL_CONVEYOR_BELT_3_RIGHT,
3073 EL_CONVEYOR_BELT_4_LEFT,
3074 EL_CONVEYOR_BELT_4_MIDDLE,
3075 EL_CONVEYOR_BELT_4_RIGHT,
3079 static int ep_belt_active[] =
3081 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3082 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3083 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3084 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3085 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3086 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3087 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3088 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3089 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3090 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3091 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3092 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3096 static int ep_belt_switch[] =
3098 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3099 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3100 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3101 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3102 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3103 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3104 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3105 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3106 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3107 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3108 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3109 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3113 static int ep_tube[] =
3120 EL_TUBE_HORIZONTAL_UP,
3121 EL_TUBE_HORIZONTAL_DOWN,
3123 EL_TUBE_VERTICAL_LEFT,
3124 EL_TUBE_VERTICAL_RIGHT,
3129 static int ep_keygate[] =
3158 static int ep_amoeboid[] =
3168 static int ep_amoebalive[] =
3177 static int ep_has_content[] =
3187 static int ep_can_turn_each_move[] =
3189 /* !!! do something with this one !!! */
3193 static int ep_can_grow[] =
3205 static int ep_active_bomb[] =
3208 EL_DYNABOMB_PLAYER_1_ACTIVE,
3209 EL_DYNABOMB_PLAYER_2_ACTIVE,
3210 EL_DYNABOMB_PLAYER_3_ACTIVE,
3211 EL_DYNABOMB_PLAYER_4_ACTIVE,
3212 EL_SP_DISK_RED_ACTIVE,
3216 static int ep_inactive[] =
3265 EL_INVISIBLE_STEELWALL,
3273 EL_WALL_EMERALD_YELLOW,
3274 EL_DYNABOMB_INCREASE_NUMBER,
3275 EL_DYNABOMB_INCREASE_SIZE,
3276 EL_DYNABOMB_INCREASE_POWER,
3280 EL_SOKOBAN_FIELD_EMPTY,
3281 EL_SOKOBAN_FIELD_FULL,
3282 EL_WALL_EMERALD_RED,
3283 EL_WALL_EMERALD_PURPLE,
3284 EL_ACID_POOL_TOPLEFT,
3285 EL_ACID_POOL_TOPRIGHT,
3286 EL_ACID_POOL_BOTTOMLEFT,
3287 EL_ACID_POOL_BOTTOM,
3288 EL_ACID_POOL_BOTTOMRIGHT,
3292 EL_BD_MAGIC_WALL_DEAD,
3293 EL_AMOEBA_TO_DIAMOND,
3301 EL_SP_GRAVITY_PORT_RIGHT,
3302 EL_SP_GRAVITY_PORT_DOWN,
3303 EL_SP_GRAVITY_PORT_LEFT,
3304 EL_SP_GRAVITY_PORT_UP,
3305 EL_SP_PORT_HORIZONTAL,
3306 EL_SP_PORT_VERTICAL,
3317 EL_SP_HARDWARE_GRAY,
3318 EL_SP_HARDWARE_GREEN,
3319 EL_SP_HARDWARE_BLUE,
3321 EL_SP_HARDWARE_YELLOW,
3322 EL_SP_HARDWARE_BASE_1,
3323 EL_SP_HARDWARE_BASE_2,
3324 EL_SP_HARDWARE_BASE_3,
3325 EL_SP_HARDWARE_BASE_4,
3326 EL_SP_HARDWARE_BASE_5,
3327 EL_SP_HARDWARE_BASE_6,
3328 EL_SP_GRAVITY_ON_PORT_LEFT,
3329 EL_SP_GRAVITY_ON_PORT_RIGHT,
3330 EL_SP_GRAVITY_ON_PORT_UP,
3331 EL_SP_GRAVITY_ON_PORT_DOWN,
3332 EL_SP_GRAVITY_OFF_PORT_LEFT,
3333 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3334 EL_SP_GRAVITY_OFF_PORT_UP,
3335 EL_SP_GRAVITY_OFF_PORT_DOWN,
3336 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3337 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3338 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3339 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3340 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3341 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3342 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3343 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3344 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3345 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3346 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3347 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3348 EL_SIGN_EXCLAMATION,
3349 EL_SIGN_RADIOACTIVITY,
3360 EL_STEELWALL_SLIPPERY,
3365 EL_EMC_WALL_SLIPPERY_1,
3366 EL_EMC_WALL_SLIPPERY_2,
3367 EL_EMC_WALL_SLIPPERY_3,
3368 EL_EMC_WALL_SLIPPERY_4,
3388 static int ep_em_slippery_wall[] =
3393 static int ep_gfx_crumbled[] =
3406 } element_properties[] =
3408 { ep_diggable, EP_DIGGABLE },
3409 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3410 { ep_dont_run_into, EP_DONT_RUN_INTO },
3411 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3412 { ep_dont_touch, EP_DONT_TOUCH },
3413 { ep_indestructible, EP_INDESTRUCTIBLE },
3414 { ep_slippery, EP_SLIPPERY },
3415 { ep_can_change, EP_CAN_CHANGE },
3416 { ep_can_move, EP_CAN_MOVE },
3417 { ep_can_fall, EP_CAN_FALL },
3418 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3419 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3420 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3421 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3422 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3423 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3424 { ep_walkable_over, EP_WALKABLE_OVER },
3425 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3426 { ep_walkable_under, EP_WALKABLE_UNDER },
3427 { ep_passable_over, EP_PASSABLE_OVER },
3428 { ep_passable_inside, EP_PASSABLE_INSIDE },
3429 { ep_passable_under, EP_PASSABLE_UNDER },
3430 { ep_droppable, EP_DROPPABLE },
3431 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3432 { ep_pushable, EP_PUSHABLE },
3433 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3434 { ep_protected, EP_PROTECTED },
3435 { ep_throwable, EP_THROWABLE },
3436 { ep_can_explode, EP_CAN_EXPLODE },
3437 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3439 { ep_player, EP_PLAYER },
3440 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3441 { ep_switchable, EP_SWITCHABLE },
3442 { ep_bd_element, EP_BD_ELEMENT },
3443 { ep_sp_element, EP_SP_ELEMENT },
3444 { ep_sb_element, EP_SB_ELEMENT },
3446 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3447 { ep_food_penguin, EP_FOOD_PENGUIN },
3448 { ep_food_pig, EP_FOOD_PIG },
3449 { ep_historic_wall, EP_HISTORIC_WALL },
3450 { ep_historic_solid, EP_HISTORIC_SOLID },
3451 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3452 { ep_belt, EP_BELT },
3453 { ep_belt_active, EP_BELT_ACTIVE },
3454 { ep_belt_switch, EP_BELT_SWITCH },
3455 { ep_tube, EP_TUBE },
3456 { ep_keygate, EP_KEYGATE },
3457 { ep_amoeboid, EP_AMOEBOID },
3458 { ep_amoebalive, EP_AMOEBALIVE },
3459 { ep_has_content, EP_HAS_CONTENT },
3460 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3461 { ep_can_grow, EP_CAN_GROW },
3462 { ep_active_bomb, EP_ACTIVE_BOMB },
3463 { ep_inactive, EP_INACTIVE },
3465 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3467 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3472 static int copy_properties[][5] =
3476 EL_BUG_LEFT, EL_BUG_RIGHT,
3477 EL_BUG_UP, EL_BUG_DOWN
3481 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3482 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3486 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3487 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3491 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3492 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3496 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3497 EL_PACMAN_UP, EL_PACMAN_DOWN
3501 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3502 EL_MOLE_UP, EL_MOLE_DOWN
3512 /* always start with reliable default values (element has no properties) */
3513 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3514 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3515 SET_PROPERTY(i, j, FALSE);
3517 /* set all base element properties from above array definitions */
3518 for (i = 0; element_properties[i].elements != NULL; i++)
3519 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3520 SET_PROPERTY((element_properties[i].elements)[j],
3521 element_properties[i].property, TRUE);
3523 /* copy properties to some elements that are only stored in level file */
3524 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3525 for (j = 0; copy_properties[j][0] != -1; j++)
3526 if (HAS_PROPERTY(copy_properties[j][0], i))
3527 for (k = 1; k <= 4; k++)
3528 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3531 void InitElementPropertiesEngine(int engine_version)
3534 static int active_properties[] =
3539 EP_DONT_COLLIDE_WITH,
3543 EP_CAN_PASS_MAGIC_WALL,
3548 EP_EXPLODES_BY_FIRE,
3561 EP_EM_SLIPPERY_WALL,
3565 static int no_wall_properties[] =
3568 EP_COLLECTIBLE_ONLY,
3570 EP_DONT_COLLIDE_WITH,
3573 EP_CAN_SMASH_PLAYER,
3574 EP_CAN_SMASH_ENEMIES,
3575 EP_CAN_SMASH_EVERYTHING,
3580 EP_FOOD_DARK_YAMYAM,
3597 InitElementPropertiesStatic();
3600 /* important: after initialization in InitElementPropertiesStatic(), the
3601 elements are not again initialized to a default value; therefore all
3602 changes have to make sure that they leave the element with a defined
3603 property (which means that conditional property changes must be set to
3604 a reliable default value before) */
3606 /* set all special, combined or engine dependent element properties */
3607 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3610 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3611 SET_PROPERTY(i, j, FALSE);
3614 /* ---------- INACTIVE ------------------------------------------------- */
3615 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3617 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3618 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3619 IS_WALKABLE_INSIDE(i) ||
3620 IS_WALKABLE_UNDER(i)));
3622 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3623 IS_PASSABLE_INSIDE(i) ||
3624 IS_PASSABLE_UNDER(i)));
3626 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3627 IS_PASSABLE_OVER(i)));
3629 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3630 IS_PASSABLE_INSIDE(i)));
3632 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3633 IS_PASSABLE_UNDER(i)));
3635 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3638 /* ---------- COLLECTIBLE ---------------------------------------------- */
3639 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3643 /* ---------- SNAPPABLE ------------------------------------------------ */
3644 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3645 IS_COLLECTIBLE(i) ||
3649 /* ---------- WALL ----------------------------------------------------- */
3650 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3652 for (j = 0; no_wall_properties[j] != -1; j++)
3653 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3654 i >= EL_FIRST_RUNTIME_UNREAL)
3655 SET_PROPERTY(i, EP_WALL, FALSE);
3657 if (IS_HISTORIC_WALL(i))
3658 SET_PROPERTY(i, EP_WALL, TRUE);
3660 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3661 if (engine_version < VERSION_IDENT(2,2,0,0))
3662 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3664 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3666 !IS_COLLECTIBLE(i)));
3669 /* ---------- PROTECTED ------------------------------------------------ */
3670 if (IS_ACCESSIBLE_INSIDE(i))
3671 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3674 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3676 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3677 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3679 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3680 IS_INDESTRUCTIBLE(i)));
3682 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3684 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3685 else if (engine_version < VERSION_IDENT(2,2,0,0))
3686 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3689 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3694 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3695 !IS_WALKABLE_OVER(i) &&
3696 !IS_WALKABLE_UNDER(i)));
3698 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3703 if (IS_CUSTOM_ELEMENT(i))
3705 /* these are additional properties which are initially false when set */
3707 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3709 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3710 if (DONT_COLLIDE_WITH(i))
3711 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3713 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3714 if (CAN_SMASH_EVERYTHING(i))
3715 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3716 if (CAN_SMASH_ENEMIES(i))
3717 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3720 /* ---------- CAN_SMASH ------------------------------------------------ */
3721 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3722 CAN_SMASH_ENEMIES(i) ||
3723 CAN_SMASH_EVERYTHING(i)));
3726 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3727 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3728 CAN_EXPLODE_SMASHED(i) ||
3729 CAN_EXPLODE_IMPACT(i)));
3733 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3735 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3736 !CAN_EXPLODE_CROSS(i)));
3738 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3739 !CAN_EXPLODE_1X1(i) &&
3740 !CAN_EXPLODE_CROSS(i)));
3744 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3745 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3746 EXPLODES_BY_FIRE(i)));
3748 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3749 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3750 EXPLODES_SMASHED(i)));
3752 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3753 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3754 EXPLODES_IMPACT(i)));
3756 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3757 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3759 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3760 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3761 i == EL_BLACK_ORB));
3763 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3764 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3766 IS_CUSTOM_ELEMENT(i)));
3768 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3769 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3770 i == EL_SP_ELECTRON));
3772 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3773 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3774 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3775 getMoveIntoAcidProperty(&level, i));
3777 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3778 if (MAYBE_DONT_COLLIDE_WITH(i))
3779 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3780 getDontCollideWithProperty(&level, i));
3782 /* ---------- SP_PORT -------------------------------------------------- */
3783 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3784 IS_PASSABLE_INSIDE(i)));
3786 /* ---------- CAN_CHANGE ----------------------------------------------- */
3787 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3788 for (j = 0; j < element_info[i].num_change_pages; j++)
3789 if (element_info[i].change_page[j].can_change)
3790 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3792 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3793 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3794 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3798 /* determine inactive elements (used for engine main loop optimization) */
3799 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3801 boolean active = FALSE;
3803 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3805 if (HAS_PROPERTY(i, j))
3811 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3816 /* dynamically adjust element properties according to game engine version */
3818 static int ep_em_slippery_wall[] =
3823 EL_EXPANDABLE_WALL_HORIZONTAL,
3824 EL_EXPANDABLE_WALL_VERTICAL,
3825 EL_EXPANDABLE_WALL_ANY,
3829 /* special EM style gems behaviour */
3830 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3831 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3832 level.em_slippery_gems);
3834 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3835 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3836 (level.em_slippery_gems &&
3837 engine_version > VERSION_IDENT(2,0,1,0)));
3841 /* set default push delay values (corrected since version 3.0.7-1) */
3842 if (engine_version < VERSION_IDENT(3,0,7,1))
3844 game.default_push_delay_fixed = 2;
3845 game.default_push_delay_random = 8;
3849 game.default_push_delay_fixed = 8;
3850 game.default_push_delay_random = 8;
3853 /* set uninitialized push delay values of custom elements in older levels */
3854 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3856 int element = EL_CUSTOM_START + i;
3858 if (element_info[element].push_delay_fixed == -1)
3859 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3860 if (element_info[element].push_delay_random == -1)
3861 element_info[element].push_delay_random = game.default_push_delay_random;
3864 /* set some other uninitialized values of custom elements in older levels */
3865 if (engine_version < VERSION_IDENT(3,1,0,0))
3867 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3869 int element = EL_CUSTOM_START + i;
3871 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3873 element_info[element].explosion_delay = 17;
3874 element_info[element].ignition_delay = 8;
3879 /* set element properties that were handled incorrectly in older levels */
3880 if (engine_version < VERSION_IDENT(3,1,0,0))
3882 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3883 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3889 /* this is needed because some graphics depend on element properties */
3890 if (game_status == GAME_MODE_PLAYING)
3891 InitElementGraphicInfo();
3894 static void InitGlobal()
3898 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3900 /* check if element_name_info entry defined for each element in "main.h" */
3901 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3902 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3904 element_info[i].token_name = element_name_info[i].token_name;
3905 element_info[i].class_name = element_name_info[i].class_name;
3906 element_info[i].editor_description=element_name_info[i].editor_description;
3909 global.autoplay_leveldir = NULL;
3910 global.convert_leveldir = NULL;
3912 global.frames_per_second = 0;
3913 global.fps_slowdown = FALSE;
3914 global.fps_slowdown_factor = 1;
3917 void Execute_Command(char *command)
3921 if (strcmp(command, "print graphicsinfo.conf") == 0)
3923 printf("# You can configure additional/alternative image files here.\n");
3924 printf("# (The entries below are default and therefore commented out.)\n");
3926 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3928 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3931 for (i = 0; image_config[i].token != NULL; i++)
3932 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3933 image_config[i].value));
3937 else if (strcmp(command, "print soundsinfo.conf") == 0)
3939 printf("# You can configure additional/alternative sound files here.\n");
3940 printf("# (The entries below are default and therefore commented out.)\n");
3942 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3944 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3947 for (i = 0; sound_config[i].token != NULL; i++)
3948 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3949 sound_config[i].value));
3953 else if (strcmp(command, "print musicinfo.conf") == 0)
3955 printf("# You can configure additional/alternative music files here.\n");
3956 printf("# (The entries below are default and therefore commented out.)\n");
3958 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3960 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3963 for (i = 0; music_config[i].token != NULL; i++)
3964 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3965 music_config[i].value));
3969 else if (strcmp(command, "print editorsetup.conf") == 0)
3971 printf("# You can configure your personal editor element list here.\n");
3972 printf("# (The entries below are default and therefore commented out.)\n");
3975 PrintEditorElementList();
3979 else if (strcmp(command, "print helpanim.conf") == 0)
3981 printf("# You can configure different element help animations here.\n");
3982 printf("# (The entries below are default and therefore commented out.)\n");
3985 for (i = 0; helpanim_config[i].token != NULL; i++)
3987 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3988 helpanim_config[i].value));
3990 if (strcmp(helpanim_config[i].token, "end") == 0)
3996 else if (strcmp(command, "print helptext.conf") == 0)
3998 printf("# You can configure different element help text here.\n");
3999 printf("# (The entries below are default and therefore commented out.)\n");
4002 for (i = 0; helptext_config[i].token != NULL; i++)
4003 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4004 helptext_config[i].value));
4008 else if (strncmp(command, "dump level ", 11) == 0)
4010 char *filename = &command[11];
4012 if (access(filename, F_OK) != 0)
4013 Error(ERR_EXIT, "cannot open file '%s'", filename);
4015 LoadLevelFromFilename(&level, filename);
4020 else if (strncmp(command, "dump tape ", 10) == 0)
4022 char *filename = &command[10];
4024 if (access(filename, F_OK) != 0)
4025 Error(ERR_EXIT, "cannot open file '%s'", filename);
4027 LoadTapeFromFilename(filename);
4032 else if (strncmp(command, "autoplay ", 9) == 0)
4034 char *str_copy = getStringCopy(&command[9]);
4035 char *str_ptr = strchr(str_copy, ' ');
4037 global.autoplay_leveldir = str_copy;
4038 global.autoplay_level_nr = -1;
4040 if (str_ptr != NULL)
4042 *str_ptr++ = '\0'; /* terminate leveldir string */
4043 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4046 else if (strncmp(command, "convert ", 8) == 0)
4048 char *str_copy = getStringCopy(&command[8]);
4049 char *str_ptr = strchr(str_copy, ' ');
4051 global.convert_leveldir = str_copy;
4052 global.convert_level_nr = -1;
4054 if (str_ptr != NULL)
4056 *str_ptr++ = '\0'; /* terminate leveldir string */
4057 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4062 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4066 static void InitSetup()
4068 LoadSetup(); /* global setup info */
4070 /* set some options from setup file */
4072 if (setup.options.verbose)
4073 options.verbose = TRUE;
4076 static void InitPlayerInfo()
4080 /* choose default local player */
4081 local_player = &stored_player[0];
4083 for (i = 0; i < MAX_PLAYERS; i++)
4084 stored_player[i].connected = FALSE;
4086 local_player->connected = TRUE;
4089 static void InitArtworkInfo()
4094 static char *get_string_in_brackets(char *string)
4096 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4098 sprintf(string_in_brackets, "[%s]", string);
4100 return string_in_brackets;
4103 static char *get_level_id_suffix(int id_nr)
4105 char *id_suffix = checked_malloc(1 + 3 + 1);
4107 if (id_nr < 0 || id_nr > 999)
4110 sprintf(id_suffix, ".%03d", id_nr);
4116 static char *get_element_class_token(int element)
4118 char *element_class_name = element_info[element].class_name;
4119 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4121 sprintf(element_class_token, "[%s]", element_class_name);
4123 return element_class_token;
4126 static char *get_action_class_token(int action)
4128 char *action_class_name = &element_action_info[action].suffix[1];
4129 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4131 sprintf(action_class_token, "[%s]", action_class_name);
4133 return action_class_token;
4137 static void InitArtworkConfig()
4139 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4140 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4141 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4142 static char *action_id_suffix[NUM_ACTIONS + 1];
4143 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4144 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4145 static char *level_id_suffix[MAX_LEVELS + 1];
4146 static char *dummy[1] = { NULL };
4147 static char *ignore_generic_tokens[] =
4153 static char **ignore_image_tokens;
4154 static char **ignore_sound_tokens;
4155 static char **ignore_music_tokens;
4156 int num_ignore_generic_tokens;
4157 int num_ignore_image_tokens;
4158 int num_ignore_sound_tokens;
4159 int num_ignore_music_tokens;
4162 /* dynamically determine list of generic tokens to be ignored */
4163 num_ignore_generic_tokens = 0;
4164 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4165 num_ignore_generic_tokens++;
4167 /* dynamically determine list of image tokens to be ignored */
4168 num_ignore_image_tokens = num_ignore_generic_tokens;
4169 for (i = 0; image_config_vars[i].token != NULL; i++)
4170 num_ignore_image_tokens++;
4171 ignore_image_tokens =
4172 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4173 for (i = 0; i < num_ignore_generic_tokens; i++)
4174 ignore_image_tokens[i] = ignore_generic_tokens[i];
4175 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4176 ignore_image_tokens[num_ignore_generic_tokens + i] =
4177 image_config_vars[i].token;
4178 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4180 /* dynamically determine list of sound tokens to be ignored */
4181 num_ignore_sound_tokens = num_ignore_generic_tokens;
4182 ignore_sound_tokens =
4183 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4184 for (i = 0; i < num_ignore_generic_tokens; i++)
4185 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4186 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4188 /* dynamically determine list of music tokens to be ignored */
4189 num_ignore_music_tokens = num_ignore_generic_tokens;
4190 ignore_music_tokens =
4191 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4192 for (i = 0; i < num_ignore_generic_tokens; i++)
4193 ignore_music_tokens[i] = ignore_generic_tokens[i];
4194 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4196 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4197 image_id_prefix[i] = element_info[i].token_name;
4198 for (i = 0; i < NUM_FONTS; i++)
4199 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4200 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4202 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4203 sound_id_prefix[i] = element_info[i].token_name;
4204 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4205 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4206 get_string_in_brackets(element_info[i].class_name);
4207 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4209 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4210 music_id_prefix[i] = music_prefix_info[i].prefix;
4211 music_id_prefix[MAX_LEVELS] = NULL;
4213 for (i = 0; i < NUM_ACTIONS; i++)
4214 action_id_suffix[i] = element_action_info[i].suffix;
4215 action_id_suffix[NUM_ACTIONS] = NULL;
4217 for (i = 0; i < NUM_DIRECTIONS; i++)
4218 direction_id_suffix[i] = element_direction_info[i].suffix;
4219 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4221 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4222 special_id_suffix[i] = special_suffix_info[i].suffix;
4223 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4225 for (i = 0; i < MAX_LEVELS; i++)
4226 level_id_suffix[i] = get_level_id_suffix(i);
4227 level_id_suffix[MAX_LEVELS] = NULL;
4229 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4230 image_id_prefix, action_id_suffix, direction_id_suffix,
4231 special_id_suffix, ignore_image_tokens);
4232 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4233 sound_id_prefix, action_id_suffix, dummy,
4234 special_id_suffix, ignore_sound_tokens);
4235 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4236 music_id_prefix, special_id_suffix, level_id_suffix,
4237 dummy, ignore_music_tokens);
4240 static void InitMixer()
4248 char *filename_font_initial = NULL;
4249 Bitmap *bitmap_font_initial = NULL;
4252 /* determine settings for initial font (for displaying startup messages) */
4253 for (i = 0; image_config[i].token != NULL; i++)
4255 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4257 char font_token[128];
4260 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4261 len_font_token = strlen(font_token);
4263 if (strcmp(image_config[i].token, font_token) == 0)
4264 filename_font_initial = image_config[i].value;
4265 else if (strlen(image_config[i].token) > len_font_token &&
4266 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4268 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4269 font_initial[j].src_x = atoi(image_config[i].value);
4270 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4271 font_initial[j].src_y = atoi(image_config[i].value);
4272 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4273 font_initial[j].width = atoi(image_config[i].value);
4274 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4275 font_initial[j].height = atoi(image_config[i].value);
4280 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4282 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4283 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4286 if (filename_font_initial == NULL) /* should not happen */
4287 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4289 /* create additional image buffers for double-buffering */
4290 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4291 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4293 /* initialize screen properties */
4294 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4295 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4297 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4298 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4299 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4301 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4303 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4304 font_initial[j].bitmap = bitmap_font_initial;
4306 InitFontGraphicInfo();
4308 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4309 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4311 DrawInitText("Loading graphics:", 120, FC_GREEN);
4313 InitTileClipmasks();
4316 void InitGfxBackground()
4320 drawto = backbuffer;
4321 fieldbuffer = bitmap_db_field;
4322 SetDrawtoField(DRAW_BACKBUFFER);
4324 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4325 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4326 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4327 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4329 for (x = 0; x < MAX_BUF_XSIZE; x++)
4330 for (y = 0; y < MAX_BUF_YSIZE; y++)
4333 redraw_mask = REDRAW_ALL;
4336 static void InitLevelInfo()
4338 LoadLevelInfo(); /* global level info */
4339 LoadLevelSetup_LastSeries(); /* last played series info */
4340 LoadLevelSetup_SeriesInfo(); /* last played level info */
4343 void InitLevelArtworkInfo()
4345 LoadLevelArtworkInfo();
4348 static void InitImages()
4351 setLevelArtworkDir(artwork.gfx_first);
4355 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4356 leveldir_current->identifier,
4357 artwork.gfx_current_identifier,
4358 artwork.gfx_current->identifier,
4359 leveldir_current->graphics_set,
4360 leveldir_current->graphics_path);
4363 ReloadCustomImages();
4365 LoadCustomElementDescriptions();
4366 LoadSpecialMenuDesignSettings();
4368 ReinitializeGraphics();
4371 static void InitSound(char *identifier)
4373 if (identifier == NULL)
4374 identifier = artwork.snd_current->identifier;
4377 /* set artwork path to send it to the sound server process */
4378 setLevelArtworkDir(artwork.snd_first);
4381 InitReloadCustomSounds(identifier);
4382 ReinitializeSounds();
4385 static void InitMusic(char *identifier)
4387 if (identifier == NULL)
4388 identifier = artwork.mus_current->identifier;
4391 /* set artwork path to send it to the sound server process */
4392 setLevelArtworkDir(artwork.mus_first);
4395 InitReloadCustomMusic(identifier);
4396 ReinitializeMusic();
4399 void InitNetworkServer()
4401 #if defined(NETWORK_AVALIABLE)
4405 if (!options.network)
4408 #if defined(NETWORK_AVALIABLE)
4409 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4411 if (!ConnectToServer(options.server_host, options.server_port))
4412 Error(ERR_EXIT, "cannot connect to network game server");
4414 SendToServer_PlayerName(setup.player_name);
4415 SendToServer_ProtocolVersion();
4418 SendToServer_NrWanted(nr_wanted);
4422 static char *getNewArtworkIdentifier(int type)
4424 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4425 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4426 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4427 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4428 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4429 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4430 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4431 char *leveldir_identifier = leveldir_current->identifier;
4433 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4434 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4436 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4438 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4439 char *artwork_current_identifier;
4440 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4442 /* leveldir_current may be invalid (level group, parent link) */
4443 if (!validLevelSeries(leveldir_current))
4446 /* 1st step: determine artwork set to be activated in descending order:
4447 --------------------------------------------------------------------
4448 1. setup artwork (when configured to override everything else)
4449 2. artwork set configured in "levelinfo.conf" of current level set
4450 (artwork in level directory will have priority when loading later)
4451 3. artwork in level directory (stored in artwork sub-directory)
4452 4. setup artwork (currently configured in setup menu) */
4454 if (setup_override_artwork)
4455 artwork_current_identifier = setup_artwork_set;
4456 else if (leveldir_artwork_set != NULL)
4457 artwork_current_identifier = leveldir_artwork_set;
4458 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4459 artwork_current_identifier = leveldir_identifier;
4461 artwork_current_identifier = setup_artwork_set;
4464 /* 2nd step: check if it is really needed to reload artwork set
4465 ------------------------------------------------------------ */
4468 if (type == ARTWORK_TYPE_GRAPHICS)
4469 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4470 artwork_new_identifier,
4471 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4472 artwork_current_identifier,
4473 leveldir_current->graphics_set,
4474 leveldir_current->identifier);
4477 /* ---------- reload if level set and also artwork set has changed ------- */
4478 if (leveldir_current_identifier[type] != leveldir_identifier &&
4479 (last_has_level_artwork_set[type] || has_level_artwork_set))
4480 artwork_new_identifier = artwork_current_identifier;
4482 leveldir_current_identifier[type] = leveldir_identifier;
4483 last_has_level_artwork_set[type] = has_level_artwork_set;
4486 if (type == ARTWORK_TYPE_GRAPHICS)
4487 printf("::: 1: '%s'\n", artwork_new_identifier);
4490 /* ---------- reload if "override artwork" setting has changed ----------- */
4491 if (last_override_level_artwork[type] != setup_override_artwork)
4492 artwork_new_identifier = artwork_current_identifier;
4494 last_override_level_artwork[type] = setup_override_artwork;
4497 if (type == ARTWORK_TYPE_GRAPHICS)
4498 printf("::: 2: '%s'\n", artwork_new_identifier);
4501 /* ---------- reload if current artwork identifier has changed ----------- */
4502 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4503 artwork_current_identifier) != 0)
4504 artwork_new_identifier = artwork_current_identifier;
4506 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4509 if (type == ARTWORK_TYPE_GRAPHICS)
4510 printf("::: 3: '%s'\n", artwork_new_identifier);
4513 /* ---------- do not reload directly after starting ---------------------- */
4514 if (!initialized[type])
4515 artwork_new_identifier = NULL;
4517 initialized[type] = TRUE;
4520 if (type == ARTWORK_TYPE_GRAPHICS)
4521 printf("::: 4: '%s'\n", artwork_new_identifier);
4525 if (type == ARTWORK_TYPE_GRAPHICS)
4526 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4527 artwork.gfx_current_identifier, artwork_current_identifier,
4528 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4529 artwork_new_identifier);
4532 return artwork_new_identifier;
4535 void ReloadCustomArtwork(int force_reload)
4537 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4538 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4539 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4540 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4541 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4542 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4543 boolean redraw_screen = FALSE;
4545 if (gfx_new_identifier != NULL || force_reload_gfx)
4548 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4549 artwork.gfx_current_identifier,
4551 artwork.gfx_current->identifier,
4552 leveldir_current->graphics_set);
4555 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4560 printf("... '%s'\n",
4561 leveldir_current->graphics_set);
4564 FreeTileClipmasks();
4565 InitTileClipmasks();
4567 redraw_screen = TRUE;
4570 if (snd_new_identifier != NULL || force_reload_snd)
4572 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4574 InitSound(snd_new_identifier);
4576 redraw_screen = TRUE;
4579 if (mus_new_identifier != NULL || force_reload_mus)
4581 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4583 InitMusic(mus_new_identifier);
4585 redraw_screen = TRUE;
4590 InitGfxBackground();
4592 /* force redraw of (open or closed) door graphics */
4593 SetDoorState(DOOR_OPEN_ALL);
4594 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4598 void KeyboardAutoRepeatOffUnlessAutoplay()
4600 if (global.autoplay_leveldir == NULL)
4601 KeyboardAutoRepeatOff();
4605 /* ========================================================================= */
4607 /* ========================================================================= */
4611 InitGlobal(); /* initialize some global variables */
4613 if (options.execute_command)
4614 Execute_Command(options.execute_command);
4616 if (options.serveronly)
4618 #if defined(PLATFORM_UNIX)
4619 NetworkServer(options.server_port, options.serveronly);
4621 Error(ERR_WARN, "networking only supported in Unix version");
4623 exit(0); /* never reached */
4629 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4630 InitArtworkConfig(); /* needed before forking sound child process */
4635 InitRND(NEW_RANDOMIZE);
4636 InitSimpleRND(NEW_RANDOMIZE);
4641 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4644 InitEventFilter(FilterMouseMotionEvents);
4646 InitElementPropertiesStatic();
4647 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4652 InitLevelArtworkInfo();
4654 InitImages(); /* needs to know current level directory */
4655 InitSound(NULL); /* needs to know current level directory */
4656 InitMusic(NULL); /* needs to know current level directory */
4658 InitGfxBackground();
4660 if (global.autoplay_leveldir)
4665 else if (global.convert_leveldir)
4671 game_status = GAME_MODE_MAIN;
4679 InitNetworkServer();
4682 void CloseAllAndExit(int exit_value)
4687 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4694 FreeTileClipmasks();
4696 #if defined(TARGET_SDL)
4697 if (network_server) /* terminate network server */
4698 SDL_KillThread(server_thread);
4701 CloseVideoDisplay();
4702 ClosePlatformDependentStuff();