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 */
262 for (i = 0; i < num_property_mappings; i++)
263 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
267 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
268 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_TITLE; i++)
269 InitElementSmallImagesScaledUp(i);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 void SetBitmaps_EM(Bitmap **em_bitmap)
277 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
278 em_bitmap[1] = graphic_info[IMG_EMC_SCORE].bitmap;
279 em_bitmap[2] = graphic_info[IMG_EMC_SPRITE].bitmap;
280 em_bitmap[3] = graphic_info[IMG_EMC_TITLE].bitmap;
284 static int getFontBitmapID(int font_nr)
288 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
289 special = game_status;
290 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
291 special = GFX_SPECIAL_ARG_MAIN;
292 else if (game_status == GAME_MODE_PLAYING)
293 special = GFX_SPECIAL_ARG_DOOR;
296 return font_info[font_nr].special_bitmap_id[special];
301 void InitFontGraphicInfo()
303 static struct FontBitmapInfo *font_bitmap_info = NULL;
304 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
305 int num_property_mappings = getImageListPropertyMappingSize();
306 int num_font_bitmaps = NUM_FONTS;
309 if (graphic_info == NULL) /* still at startup phase */
311 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
316 /* ---------- initialize font graphic definitions ---------- */
318 /* always start with reliable default values (normal font graphics) */
320 for (i = 0; i < NUM_FONTS; i++)
321 font_info[i].graphic = IMG_FONT_INITIAL_1;
323 for (i = 0; i < NUM_FONTS; i++)
324 font_info[i].graphic = FONT_INITIAL_1;
327 /* initialize normal font/graphic mapping from static configuration */
328 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
330 int font_nr = font_to_graphic[i].font_nr;
331 int special = font_to_graphic[i].special;
332 int graphic = font_to_graphic[i].graphic;
337 font_info[font_nr].graphic = graphic;
340 /* always start with reliable default values (special font graphics) */
341 for (i = 0; i < NUM_FONTS; i++)
343 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
345 font_info[i].special_graphic[j] = font_info[i].graphic;
346 font_info[i].special_bitmap_id[j] = i;
350 /* initialize special font/graphic mapping from static configuration */
351 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
353 int font_nr = font_to_graphic[i].font_nr;
354 int special = font_to_graphic[i].special;
355 int graphic = font_to_graphic[i].graphic;
357 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
359 font_info[font_nr].special_graphic[special] = graphic;
360 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
365 /* initialize special element/graphic mapping from dynamic configuration */
366 for (i = 0; i < num_property_mappings; i++)
368 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
369 int special = property_mapping[i].ext3_index;
370 int graphic = property_mapping[i].artwork_index;
375 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
377 font_info[font_nr].special_graphic[special] = graphic;
378 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
383 /* ---------- initialize font bitmap array ---------- */
385 if (font_bitmap_info != NULL)
386 FreeFontInfo(font_bitmap_info);
389 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
391 /* ---------- initialize font bitmap definitions ---------- */
393 for (i = 0; i < NUM_FONTS; i++)
395 if (i < NUM_INITIAL_FONTS)
397 font_bitmap_info[i] = font_initial[i];
401 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
403 int font_bitmap_id = font_info[i].special_bitmap_id[j];
404 int graphic = font_info[i].special_graphic[j];
406 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
407 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
409 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
410 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
413 /* copy font relevant information from graphics information */
414 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
415 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
416 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
417 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
418 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
419 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
420 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
422 font_bitmap_info[font_bitmap_id].num_chars =
423 graphic_info[graphic].anim_frames;
424 font_bitmap_info[font_bitmap_id].num_chars_per_line =
425 graphic_info[graphic].anim_frames_per_line;
429 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
432 void InitElementGraphicInfo()
434 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
435 int num_property_mappings = getImageListPropertyMappingSize();
438 if (graphic_info == NULL) /* still at startup phase */
441 /* set values to -1 to identify later as "uninitialized" values */
442 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
444 for (act = 0; act < NUM_ACTIONS; act++)
446 element_info[i].graphic[act] = -1;
447 element_info[i].crumbled[act] = -1;
449 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
451 element_info[i].direction_graphic[act][dir] = -1;
452 element_info[i].direction_crumbled[act][dir] = -1;
457 /* initialize normal element/graphic mapping from static configuration */
458 for (i = 0; element_to_graphic[i].element > -1; i++)
460 int element = element_to_graphic[i].element;
461 int action = element_to_graphic[i].action;
462 int direction = element_to_graphic[i].direction;
463 boolean crumbled = element_to_graphic[i].crumbled;
464 int graphic = element_to_graphic[i].graphic;
465 int base_graphic = el2baseimg(element);
467 if (graphic_info[graphic].bitmap == NULL)
470 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
473 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
474 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
476 /* if the base graphic ("emerald", for example) has been redefined,
477 but not the action graphic ("emerald.falling", for example), do not
478 use an existing (in this case considered obsolete) action graphic
479 anymore, but use the automatically determined default graphic */
480 if (base_redefined && !act_dir_redefined)
485 action = ACTION_DEFAULT;
490 element_info[element].direction_crumbled[action][direction] = graphic;
492 element_info[element].crumbled[action] = graphic;
497 element_info[element].direction_graphic[action][direction] = graphic;
499 element_info[element].graphic[action] = graphic;
503 /* initialize normal element/graphic mapping from dynamic configuration */
504 for (i = 0; i < num_property_mappings; i++)
506 int element = property_mapping[i].base_index;
507 int action = property_mapping[i].ext1_index;
508 int direction = property_mapping[i].ext2_index;
509 int special = property_mapping[i].ext3_index;
510 int graphic = property_mapping[i].artwork_index;
511 boolean crumbled = FALSE;
513 if (special == GFX_SPECIAL_ARG_CRUMBLED)
519 if (graphic_info[graphic].bitmap == NULL)
522 if (element >= MAX_NUM_ELEMENTS || special != -1)
526 action = ACTION_DEFAULT;
531 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
532 element_info[element].direction_crumbled[action][dir] = -1;
535 element_info[element].direction_crumbled[action][direction] = graphic;
537 element_info[element].crumbled[action] = graphic;
542 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
543 element_info[element].direction_graphic[action][dir] = -1;
546 element_info[element].direction_graphic[action][direction] = graphic;
548 element_info[element].graphic[action] = graphic;
552 /* now copy all graphics that are defined to be cloned from other graphics */
553 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
555 int graphic = element_info[i].graphic[ACTION_DEFAULT];
556 int crumbled_like, diggable_like;
561 crumbled_like = graphic_info[graphic].crumbled_like;
562 diggable_like = graphic_info[graphic].diggable_like;
564 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
566 for (act = 0; act < NUM_ACTIONS; act++)
567 element_info[i].crumbled[act] =
568 element_info[crumbled_like].crumbled[act];
569 for (act = 0; act < NUM_ACTIONS; act++)
570 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
571 element_info[i].direction_crumbled[act][dir] =
572 element_info[crumbled_like].direction_crumbled[act][dir];
575 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
577 element_info[i].graphic[ACTION_DIGGING] =
578 element_info[diggable_like].graphic[ACTION_DIGGING];
579 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
580 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
581 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
586 /* set hardcoded definitions for some runtime elements without graphic */
587 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
591 /* now set all undefined/invalid graphics to -1 to set to default after it */
592 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
594 for (act = 0; act < NUM_ACTIONS; act++)
598 graphic = element_info[i].graphic[act];
599 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
600 element_info[i].graphic[act] = -1;
602 graphic = element_info[i].crumbled[act];
603 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
604 element_info[i].crumbled[act] = -1;
606 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
608 graphic = element_info[i].direction_graphic[act][dir];
609 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
610 element_info[i].direction_graphic[act][dir] = -1;
612 graphic = element_info[i].direction_crumbled[act][dir];
613 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
614 element_info[i].direction_crumbled[act][dir] = -1;
620 /* now set all '-1' values to element specific default values */
621 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
623 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
624 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
625 int default_direction_graphic[NUM_DIRECTIONS];
626 int default_direction_crumbled[NUM_DIRECTIONS];
628 if (default_graphic == -1)
629 default_graphic = IMG_UNKNOWN;
630 if (default_crumbled == -1)
631 default_crumbled = IMG_EMPTY;
633 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
635 default_direction_graphic[dir] =
636 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
637 default_direction_crumbled[dir] =
638 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
640 if (default_direction_graphic[dir] == -1)
641 default_direction_graphic[dir] = default_graphic;
642 if (default_direction_crumbled[dir] == -1)
643 default_direction_crumbled[dir] = default_crumbled;
646 for (act = 0; act < NUM_ACTIONS; act++)
648 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
649 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
650 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
651 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
652 act == ACTION_TURNING_FROM_RIGHT ||
653 act == ACTION_TURNING_FROM_UP ||
654 act == ACTION_TURNING_FROM_DOWN);
656 /* generic default action graphic (defined by "[default]" directive) */
657 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
658 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
660 /* look for special default action graphic (classic game specific) */
661 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
662 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
663 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
664 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
665 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
666 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
668 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
669 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
670 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
671 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
672 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
673 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
676 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
677 /* !!! make this better !!! */
678 if (i == EL_EMPTY_SPACE)
680 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
681 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
685 if (default_action_graphic == -1)
686 default_action_graphic = default_graphic;
687 if (default_action_crumbled == -1)
688 default_action_crumbled = default_crumbled;
690 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
692 int default_action_direction_graphic = element_info[i].graphic[act];
693 int default_action_direction_crumbled = element_info[i].crumbled[act];
695 /* no graphic for current action -- use default direction graphic */
696 if (default_action_direction_graphic == -1)
697 default_action_direction_graphic =
698 (act_remove ? IMG_EMPTY :
700 element_info[i].direction_graphic[ACTION_TURNING][dir] :
701 default_direction_graphic[dir]);
702 if (default_action_direction_crumbled == -1)
703 default_action_direction_crumbled =
704 (act_remove ? IMG_EMPTY :
706 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
707 default_direction_crumbled[dir]);
709 if (element_info[i].direction_graphic[act][dir] == -1)
710 element_info[i].direction_graphic[act][dir] =
711 default_action_direction_graphic;
712 if (element_info[i].direction_crumbled[act][dir] == -1)
713 element_info[i].direction_crumbled[act][dir] =
714 default_action_direction_crumbled;
717 /* no graphic for this specific action -- use default action graphic */
718 if (element_info[i].graphic[act] == -1)
719 element_info[i].graphic[act] =
720 (act_remove ? IMG_EMPTY :
721 act_turning ? element_info[i].graphic[ACTION_TURNING] :
722 default_action_graphic);
723 if (element_info[i].crumbled[act] == -1)
724 element_info[i].crumbled[act] =
725 (act_remove ? IMG_EMPTY :
726 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
727 default_action_crumbled);
732 /* set animation mode to "none" for each graphic with only 1 frame */
733 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
735 for (act = 0; act < NUM_ACTIONS; act++)
737 int graphic = element_info[i].graphic[act];
738 int crumbled = element_info[i].crumbled[act];
740 if (graphic_info[graphic].anim_frames == 1)
741 graphic_info[graphic].anim_mode = ANIM_NONE;
742 if (graphic_info[crumbled].anim_frames == 1)
743 graphic_info[crumbled].anim_mode = ANIM_NONE;
745 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
747 graphic = element_info[i].direction_graphic[act][dir];
748 crumbled = element_info[i].direction_crumbled[act][dir];
750 if (graphic_info[graphic].anim_frames == 1)
751 graphic_info[graphic].anim_mode = ANIM_NONE;
752 if (graphic_info[crumbled].anim_frames == 1)
753 graphic_info[crumbled].anim_mode = ANIM_NONE;
763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
764 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
766 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
767 element_info[i].token_name, i);
773 void InitElementSpecialGraphicInfo()
775 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
776 int num_property_mappings = getImageListPropertyMappingSize();
779 /* always start with reliable default values */
780 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
781 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
782 element_info[i].special_graphic[j] =
783 element_info[i].graphic[ACTION_DEFAULT];
785 /* initialize special element/graphic mapping from static configuration */
786 for (i = 0; element_to_special_graphic[i].element > -1; i++)
788 int element = element_to_special_graphic[i].element;
789 int special = element_to_special_graphic[i].special;
790 int graphic = element_to_special_graphic[i].graphic;
791 int base_graphic = el2baseimg(element);
792 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
793 boolean special_redefined = getImageListEntry(graphic)->redefined;
795 /* if the base graphic ("emerald", for example) has been redefined,
796 but not the special graphic ("emerald.EDITOR", for example), do not
797 use an existing (in this case considered obsolete) special graphic
798 anymore, but use the automatically created (down-scaled) graphic */
799 if (base_redefined && !special_redefined)
802 element_info[element].special_graphic[special] = graphic;
805 /* initialize special element/graphic mapping from dynamic configuration */
806 for (i = 0; i < num_property_mappings; i++)
808 int element = property_mapping[i].base_index;
809 int special = property_mapping[i].ext3_index;
810 int graphic = property_mapping[i].artwork_index;
812 if (element >= MAX_NUM_ELEMENTS)
815 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
816 element_info[element].special_graphic[special] = graphic;
820 /* now set all undefined/invalid graphics to default */
821 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
822 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
823 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
824 element_info[i].special_graphic[j] =
825 element_info[i].graphic[ACTION_DEFAULT];
829 static int get_element_from_token(char *token)
833 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
834 if (strcmp(element_info[i].token_name, token) == 0)
840 static void set_graphic_parameters(int graphic, char **parameter_raw)
842 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
843 int parameter[NUM_GFX_ARGS];
844 int anim_frames_per_row = 1, anim_frames_per_col = 1;
845 int anim_frames_per_line = 1;
848 /* get integer values from string parameters */
849 for (i = 0; i < NUM_GFX_ARGS; i++)
852 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
853 image_config_suffix[i].type);
855 if (image_config_suffix[i].type == TYPE_TOKEN)
856 parameter[i] = get_element_from_token(parameter_raw[i]);
859 graphic_info[graphic].bitmap = src_bitmap;
861 /* start with reliable default values */
862 graphic_info[graphic].src_x = 0;
863 graphic_info[graphic].src_y = 0;
864 graphic_info[graphic].width = TILEX;
865 graphic_info[graphic].height = TILEY;
866 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
867 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
868 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
869 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
870 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
871 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
872 graphic_info[graphic].anim_delay_fixed = 0;
873 graphic_info[graphic].anim_delay_random = 0;
874 graphic_info[graphic].post_delay_fixed = 0;
875 graphic_info[graphic].post_delay_random = 0;
877 /* optional x and y tile position of animation frame sequence */
878 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
879 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
880 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
881 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
883 /* optional x and y pixel position of animation frame sequence */
884 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
886 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
887 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
889 /* optional width and height of each animation frame */
890 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
891 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
892 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
893 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
897 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
898 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
901 /* correct x or y offset dependent of vertical or horizontal frame order */
902 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
904 graphic_info[graphic].offset_y =
905 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
906 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
907 anim_frames_per_line = anim_frames_per_col;
909 else /* frames are ordered horizontally */
911 graphic_info[graphic].offset_x =
912 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
913 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
914 anim_frames_per_line = anim_frames_per_row;
917 /* optionally, the x and y offset of frames can be specified directly */
918 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
919 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
920 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
921 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
923 /* automatically determine correct number of frames, if not defined */
924 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
925 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
926 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
927 graphic_info[graphic].anim_frames = anim_frames_per_row;
928 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
929 graphic_info[graphic].anim_frames = anim_frames_per_col;
931 graphic_info[graphic].anim_frames = 1;
933 graphic_info[graphic].anim_frames_per_line =
934 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
935 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
937 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
938 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
939 graphic_info[graphic].anim_delay = 1;
941 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
943 if (graphic_info[graphic].anim_frames == 1)
944 graphic_info[graphic].anim_mode = ANIM_NONE;
947 /* automatically determine correct start frame, if not defined */
948 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
949 graphic_info[graphic].anim_start_frame = 0;
950 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
951 graphic_info[graphic].anim_start_frame =
952 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
954 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
956 /* animation synchronized with global frame counter, not move position */
957 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
959 /* optional element for cloning crumble graphics */
960 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
961 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
963 /* optional element for cloning digging graphics */
964 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
965 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
967 /* optional border size for "crumbling" diggable graphics */
968 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
969 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
971 /* optional zoom factor for scaling up the image to a larger size */
972 if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
973 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
974 if (graphic_info[graphic].scale_up_factor < 1)
975 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
977 /* this is only used for player "boring" and "sleeping" actions */
978 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
979 graphic_info[graphic].anim_delay_fixed =
980 parameter[GFX_ARG_ANIM_DELAY_FIXED];
981 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].anim_delay_random =
983 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
984 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
985 graphic_info[graphic].post_delay_fixed =
986 parameter[GFX_ARG_POST_DELAY_FIXED];
987 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].post_delay_random =
989 parameter[GFX_ARG_POST_DELAY_RANDOM];
991 /* this is only used for toon animations */
992 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
993 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
995 /* this is only used for drawing font characters */
996 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
997 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
999 /* this is only used for drawing envelope graphics */
1000 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1003 static void InitGraphicInfo()
1005 int fallback_graphic = IMG_CHAR_EXCLAM;
1006 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1007 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1008 int num_images = getImageListSize();
1011 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1012 static boolean clipmasks_initialized = FALSE;
1014 XGCValues clip_gc_values;
1015 unsigned long clip_gc_valuemask;
1016 GC copy_clipmask_gc = None;
1019 checked_free(graphic_info);
1021 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1024 printf("::: graphic_info: %d entries\n", num_images);
1027 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1028 if (clipmasks_initialized)
1030 for (i = 0; i < num_images; i++)
1032 if (graphic_info[i].clip_mask)
1033 XFreePixmap(display, graphic_info[i].clip_mask);
1034 if (graphic_info[i].clip_gc)
1035 XFreeGC(display, graphic_info[i].clip_gc);
1037 graphic_info[i].clip_mask = None;
1038 graphic_info[i].clip_gc = None;
1043 for (i = 0; i < num_images; i++)
1045 struct FileInfo *image = getImageListEntry(i);
1048 int first_frame, last_frame;
1051 printf("::: image: '%s' [%d]\n", image->token, i);
1055 printf("::: image # %d: '%s' ['%s']\n",
1057 getTokenFromImageID(i));
1060 set_graphic_parameters(i, image->parameter);
1062 /* now check if no animation frames are outside of the loaded image */
1064 if (graphic_info[i].bitmap == NULL)
1065 continue; /* skip check for optional images that are undefined */
1068 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1069 if (src_x < 0 || src_y < 0 ||
1070 src_x + TILEX > src_bitmap->width ||
1071 src_y + TILEY > src_bitmap->height)
1073 Error(ERR_RETURN_LINE, "-");
1074 Error(ERR_RETURN, "warning: error found in config file:");
1075 Error(ERR_RETURN, "- config file: '%s'",
1076 getImageConfigFilename());
1077 Error(ERR_RETURN, "- config token: '%s'",
1078 getTokenFromImageID(i));
1079 Error(ERR_RETURN, "- image file: '%s'",
1080 src_bitmap->source_filename);
1082 "error: first animation frame out of bounds (%d, %d)",
1084 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1086 if (i == fallback_graphic)
1087 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1089 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1090 Error(ERR_RETURN_LINE, "-");
1092 set_graphic_parameters(i, fallback_image->default_parameter);
1093 graphic_info[i].bitmap = fallback_bitmap;
1096 last_frame = graphic_info[i].anim_frames - 1;
1097 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1098 if (src_x < 0 || src_y < 0 ||
1099 src_x + TILEX > src_bitmap->width ||
1100 src_y + TILEY > src_bitmap->height)
1102 Error(ERR_RETURN_LINE, "-");
1103 Error(ERR_RETURN, "warning: error found in config file:");
1104 Error(ERR_RETURN, "- config file: '%s'",
1105 getImageConfigFilename());
1106 Error(ERR_RETURN, "- config token: '%s'",
1107 getTokenFromImageID(i));
1108 Error(ERR_RETURN, "- image file: '%s'",
1109 src_bitmap->source_filename);
1111 "error: last animation frame (%d) out of bounds (%d, %d)",
1112 last_frame, src_x, src_y);
1113 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1115 if (i == fallback_graphic)
1116 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1118 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1119 Error(ERR_RETURN_LINE, "-");
1121 set_graphic_parameters(i, fallback_image->default_parameter);
1122 graphic_info[i].bitmap = fallback_bitmap;
1125 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1126 /* currently we need only a tile clip mask from the first frame */
1127 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1129 if (copy_clipmask_gc == None)
1131 clip_gc_values.graphics_exposures = False;
1132 clip_gc_valuemask = GCGraphicsExposures;
1133 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1134 clip_gc_valuemask, &clip_gc_values);
1137 graphic_info[i].clip_mask =
1138 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1140 src_pixmap = src_bitmap->clip_mask;
1141 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1142 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1144 clip_gc_values.graphics_exposures = False;
1145 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1146 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1148 graphic_info[i].clip_gc =
1149 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1153 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1154 if (copy_clipmask_gc)
1155 XFreeGC(display, copy_clipmask_gc);
1157 clipmasks_initialized = TRUE;
1161 static void InitElementSoundInfo()
1163 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1164 int num_property_mappings = getSoundListPropertyMappingSize();
1167 /* set values to -1 to identify later as "uninitialized" values */
1168 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1169 for (act = 0; act < NUM_ACTIONS; act++)
1170 element_info[i].sound[act] = -1;
1172 /* initialize element/sound mapping from static configuration */
1173 for (i = 0; element_to_sound[i].element > -1; i++)
1175 int element = element_to_sound[i].element;
1176 int action = element_to_sound[i].action;
1177 int sound = element_to_sound[i].sound;
1178 boolean is_class = element_to_sound[i].is_class;
1181 action = ACTION_DEFAULT;
1184 element_info[element].sound[action] = sound;
1186 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1187 if (strcmp(element_info[j].class_name,
1188 element_info[element].class_name) == 0)
1189 element_info[j].sound[action] = sound;
1192 /* initialize element class/sound mapping from dynamic configuration */
1193 for (i = 0; i < num_property_mappings; i++)
1195 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1196 int action = property_mapping[i].ext1_index;
1197 int sound = property_mapping[i].artwork_index;
1199 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1203 action = ACTION_DEFAULT;
1205 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1206 if (strcmp(element_info[j].class_name,
1207 element_info[element_class].class_name) == 0)
1208 element_info[j].sound[action] = sound;
1211 /* initialize element/sound mapping from dynamic configuration */
1212 for (i = 0; i < num_property_mappings; i++)
1214 int element = property_mapping[i].base_index;
1215 int action = property_mapping[i].ext1_index;
1216 int sound = property_mapping[i].artwork_index;
1218 if (element >= MAX_NUM_ELEMENTS)
1222 action = ACTION_DEFAULT;
1224 element_info[element].sound[action] = sound;
1227 /* now set all '-1' values to element specific default values */
1228 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1230 for (act = 0; act < NUM_ACTIONS; act++)
1232 /* generic default action sound (defined by "[default]" directive) */
1233 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1235 /* look for special default action sound (classic game specific) */
1236 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1237 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1238 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1239 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1240 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1241 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1243 /* !!! there's no such thing as a "default action sound" !!! */
1245 /* look for element specific default sound (independent from action) */
1246 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1247 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1250 /* no sound for this specific action -- use default action sound */
1251 if (element_info[i].sound[act] == -1)
1252 element_info[i].sound[act] = default_action_sound;
1257 static void InitGameModeSoundInfo()
1261 /* set values to -1 to identify later as "uninitialized" values */
1262 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1265 /* initialize gamemode/sound mapping from static configuration */
1266 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1268 int gamemode = gamemode_to_sound[i].gamemode;
1269 int sound = gamemode_to_sound[i].sound;
1272 gamemode = GAME_MODE_DEFAULT;
1274 menu.sound[gamemode] = sound;
1277 /* now set all '-1' values to levelset specific default values */
1278 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1279 if (menu.sound[i] == -1)
1280 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1284 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1285 if (menu.sound[i] != -1)
1286 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1290 static void set_sound_parameters(int sound, char **parameter_raw)
1292 int parameter[NUM_SND_ARGS];
1295 /* get integer values from string parameters */
1296 for (i = 0; i < NUM_SND_ARGS; i++)
1298 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1299 sound_config_suffix[i].type);
1301 /* explicit loop mode setting in configuration overrides default value */
1302 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1303 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1306 static void InitSoundInfo()
1309 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1310 int num_property_mappings = getSoundListPropertyMappingSize();
1312 int *sound_effect_properties;
1313 int num_sounds = getSoundListSize();
1316 checked_free(sound_info);
1318 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1319 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1321 /* initialize sound effect for all elements to "no sound" */
1322 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1323 for (j = 0; j < NUM_ACTIONS; j++)
1324 element_info[i].sound[j] = SND_UNDEFINED;
1326 for (i = 0; i < num_sounds; i++)
1328 struct FileInfo *sound = getSoundListEntry(i);
1329 int len_effect_text = strlen(sound->token);
1331 sound_effect_properties[i] = ACTION_OTHER;
1332 sound_info[i].loop = FALSE; /* default: play sound only once */
1335 printf("::: sound %d: '%s'\n", i, sound->token);
1338 /* determine all loop sounds and identify certain sound classes */
1340 for (j = 0; element_action_info[j].suffix; j++)
1342 int len_action_text = strlen(element_action_info[j].suffix);
1344 if (len_action_text < len_effect_text &&
1345 strcmp(&sound->token[len_effect_text - len_action_text],
1346 element_action_info[j].suffix) == 0)
1348 sound_effect_properties[i] = element_action_info[j].value;
1349 sound_info[i].loop = element_action_info[j].is_loop_sound;
1356 if (strcmp(sound->token, "custom_42") == 0)
1357 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1360 /* associate elements and some selected sound actions */
1362 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1364 if (element_info[j].class_name)
1366 int len_class_text = strlen(element_info[j].class_name);
1368 if (len_class_text + 1 < len_effect_text &&
1369 strncmp(sound->token,
1370 element_info[j].class_name, len_class_text) == 0 &&
1371 sound->token[len_class_text] == '.')
1373 int sound_action_value = sound_effect_properties[i];
1375 element_info[j].sound[sound_action_value] = i;
1380 set_sound_parameters(i, sound->parameter);
1383 free(sound_effect_properties);
1386 /* !!! now handled in InitElementSoundInfo() !!! */
1387 /* initialize element/sound mapping from dynamic configuration */
1388 for (i = 0; i < num_property_mappings; i++)
1390 int element = property_mapping[i].base_index;
1391 int action = property_mapping[i].ext1_index;
1392 int sound = property_mapping[i].artwork_index;
1395 action = ACTION_DEFAULT;
1397 printf("::: %d: %d, %d, %d ['%s']\n",
1398 i, element, action, sound, element_info[element].token_name);
1400 element_info[element].sound[action] = sound;
1407 int element = EL_CUSTOM_11;
1410 while (element_action_info[j].suffix)
1412 printf("element %d, sound action '%s' == %d\n",
1413 element, element_action_info[j].suffix,
1414 element_info[element].sound[j]);
1419 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1425 int element = EL_SAND;
1426 int sound_action = ACTION_DIGGING;
1429 while (element_action_info[j].suffix)
1431 if (element_action_info[j].value == sound_action)
1432 printf("element %d, sound action '%s' == %d\n",
1433 element, element_action_info[j].suffix,
1434 element_info[element].sound[sound_action]);
1441 static void InitGameModeMusicInfo()
1443 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1444 int num_property_mappings = getMusicListPropertyMappingSize();
1445 int default_levelset_music = -1;
1448 /* set values to -1 to identify later as "uninitialized" values */
1449 for (i = 0; i < MAX_LEVELS; i++)
1450 levelset.music[i] = -1;
1451 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1454 /* initialize gamemode/music mapping from static configuration */
1455 for (i = 0; gamemode_to_music[i].music > -1; i++)
1457 int gamemode = gamemode_to_music[i].gamemode;
1458 int music = gamemode_to_music[i].music;
1461 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1465 gamemode = GAME_MODE_DEFAULT;
1467 menu.music[gamemode] = music;
1470 /* initialize gamemode/music mapping from dynamic configuration */
1471 for (i = 0; i < num_property_mappings; i++)
1473 int prefix = property_mapping[i].base_index;
1474 int gamemode = property_mapping[i].ext1_index;
1475 int level = property_mapping[i].ext2_index;
1476 int music = property_mapping[i].artwork_index;
1479 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1480 prefix, gamemode, level, music);
1483 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1487 gamemode = GAME_MODE_DEFAULT;
1489 /* level specific music only allowed for in-game music */
1490 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1491 gamemode = GAME_MODE_PLAYING;
1496 default_levelset_music = music;
1499 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1500 levelset.music[level] = music;
1501 if (gamemode != GAME_MODE_PLAYING)
1502 menu.music[gamemode] = music;
1505 /* now set all '-1' values to menu specific default values */
1506 /* (undefined values of "levelset.music[]" might stay at "-1" to
1507 allow dynamic selection of music files from music directory!) */
1508 for (i = 0; i < MAX_LEVELS; i++)
1509 if (levelset.music[i] == -1)
1510 levelset.music[i] = default_levelset_music;
1511 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1512 if (menu.music[i] == -1)
1513 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1517 for (i = 0; i < MAX_LEVELS; i++)
1518 if (levelset.music[i] != -1)
1519 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1520 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1521 if (menu.music[i] != -1)
1522 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1526 static void set_music_parameters(int music, char **parameter_raw)
1528 int parameter[NUM_MUS_ARGS];
1531 /* get integer values from string parameters */
1532 for (i = 0; i < NUM_MUS_ARGS; i++)
1534 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1535 music_config_suffix[i].type);
1537 /* explicit loop mode setting in configuration overrides default value */
1538 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1539 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1542 static void InitMusicInfo()
1544 int num_music = getMusicListSize();
1547 checked_free(music_info);
1549 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1551 for (i = 0; i < num_music; i++)
1553 struct FileInfo *music = getMusicListEntry(i);
1554 int len_music_text = strlen(music->token);
1556 music_info[i].loop = TRUE; /* default: play music in loop mode */
1558 /* determine all loop music */
1560 for (j = 0; music_prefix_info[j].prefix; j++)
1562 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1564 if (len_prefix_text < len_music_text &&
1565 strncmp(music->token,
1566 music_prefix_info[j].prefix, len_prefix_text) == 0)
1568 music_info[i].loop = music_prefix_info[j].is_loop_music;
1574 set_music_parameters(i, music->parameter);
1578 static void ReinitializeGraphics()
1580 InitGraphicInfo(); /* graphic properties mapping */
1581 InitElementGraphicInfo(); /* element game graphic mapping */
1582 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1584 InitElementSmallImages(); /* create editor and preview images */
1585 InitFontGraphicInfo(); /* initialize text drawing functions */
1587 SetMainBackgroundImage(IMG_BACKGROUND);
1588 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1594 static void ReinitializeSounds()
1596 InitSoundInfo(); /* sound properties mapping */
1597 InitElementSoundInfo(); /* element game sound mapping */
1598 InitGameModeSoundInfo(); /* game mode sound mapping */
1600 InitPlayLevelSound(); /* internal game sound settings */
1603 static void ReinitializeMusic()
1605 InitMusicInfo(); /* music properties mapping */
1606 InitGameModeMusicInfo(); /* game mode music mapping */
1609 static int get_special_property_bit(int element, int property_bit_nr)
1611 struct PropertyBitInfo
1617 static struct PropertyBitInfo pb_can_move_into_acid[] =
1619 /* the player may be able fall into acid when gravity is activated */
1624 { EL_SP_MURPHY, 0 },
1625 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1627 /* all element that can move may be able to also move into acid */
1630 { EL_BUG_RIGHT, 1 },
1633 { EL_SPACESHIP, 2 },
1634 { EL_SPACESHIP_LEFT, 2 },
1635 { EL_SPACESHIP_RIGHT, 2 },
1636 { EL_SPACESHIP_UP, 2 },
1637 { EL_SPACESHIP_DOWN, 2 },
1638 { EL_BD_BUTTERFLY, 3 },
1639 { EL_BD_BUTTERFLY_LEFT, 3 },
1640 { EL_BD_BUTTERFLY_RIGHT, 3 },
1641 { EL_BD_BUTTERFLY_UP, 3 },
1642 { EL_BD_BUTTERFLY_DOWN, 3 },
1643 { EL_BD_FIREFLY, 4 },
1644 { EL_BD_FIREFLY_LEFT, 4 },
1645 { EL_BD_FIREFLY_RIGHT, 4 },
1646 { EL_BD_FIREFLY_UP, 4 },
1647 { EL_BD_FIREFLY_DOWN, 4 },
1649 { EL_DARK_YAMYAM, 6 },
1652 { EL_PACMAN_LEFT, 8 },
1653 { EL_PACMAN_RIGHT, 8 },
1654 { EL_PACMAN_UP, 8 },
1655 { EL_PACMAN_DOWN, 8 },
1657 { EL_MOLE_LEFT, 9 },
1658 { EL_MOLE_RIGHT, 9 },
1660 { EL_MOLE_DOWN, 9 },
1664 { EL_SATELLITE, 13 },
1665 { EL_SP_SNIKSNAK, 14 },
1666 { EL_SP_ELECTRON, 15 },
1673 static struct PropertyBitInfo pb_dont_collide_with[] =
1675 { EL_SP_SNIKSNAK, 0 },
1676 { EL_SP_ELECTRON, 1 },
1684 struct PropertyBitInfo *pb_info;
1687 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1688 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1693 struct PropertyBitInfo *pb_info = NULL;
1696 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1697 if (pb_definition[i].bit_nr == property_bit_nr)
1698 pb_info = pb_definition[i].pb_info;
1700 if (pb_info == NULL)
1703 for (i = 0; pb_info[i].element != -1; i++)
1704 if (pb_info[i].element == element)
1705 return pb_info[i].bit_nr;
1711 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1712 boolean property_value)
1714 int bit_nr = get_special_property_bit(element, property_bit_nr);
1719 *bitfield |= (1 << bit_nr);
1721 *bitfield &= ~(1 << bit_nr);
1725 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1727 int bit_nr = get_special_property_bit(element, property_bit_nr);
1730 return ((*bitfield & (1 << bit_nr)) != 0);
1737 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1739 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1743 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1746 level->can_move_into_acid_bits |= (1 << bit_nr);
1750 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1752 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1755 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1761 void InitElementPropertiesStatic()
1763 static int ep_diggable[] =
1768 EL_SP_BUGGY_BASE_ACTIVATING,
1771 EL_INVISIBLE_SAND_ACTIVE,
1773 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1774 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1778 EL_SP_BUGGY_BASE_ACTIVE,
1783 static int ep_collectible_only[] =
1800 EL_DYNABOMB_INCREASE_NUMBER,
1801 EL_DYNABOMB_INCREASE_SIZE,
1802 EL_DYNABOMB_INCREASE_POWER,
1819 static int ep_dont_run_into[] =
1821 /* same elements as in 'ep_dont_touch' */
1827 /* same elements as in 'ep_dont_collide_with' */
1839 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1843 EL_SP_BUGGY_BASE_ACTIVE,
1848 static int ep_dont_collide_with[] =
1850 /* same elements as in 'ep_dont_touch' */
1866 static int ep_dont_touch[] =
1875 static int ep_indestructible[] =
1879 EL_ACID_POOL_TOPLEFT,
1880 EL_ACID_POOL_TOPRIGHT,
1881 EL_ACID_POOL_BOTTOMLEFT,
1882 EL_ACID_POOL_BOTTOM,
1883 EL_ACID_POOL_BOTTOMRIGHT,
1884 EL_SP_HARDWARE_GRAY,
1885 EL_SP_HARDWARE_GREEN,
1886 EL_SP_HARDWARE_BLUE,
1888 EL_SP_HARDWARE_YELLOW,
1889 EL_SP_HARDWARE_BASE_1,
1890 EL_SP_HARDWARE_BASE_2,
1891 EL_SP_HARDWARE_BASE_3,
1892 EL_SP_HARDWARE_BASE_4,
1893 EL_SP_HARDWARE_BASE_5,
1894 EL_SP_HARDWARE_BASE_6,
1895 EL_INVISIBLE_STEELWALL,
1896 EL_INVISIBLE_STEELWALL_ACTIVE,
1897 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1898 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1899 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1900 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1901 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1902 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1903 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1904 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1905 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1906 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1907 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1908 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1910 EL_LIGHT_SWITCH_ACTIVE,
1911 EL_SIGN_EXCLAMATION,
1912 EL_SIGN_RADIOACTIVITY,
1923 EL_STEELWALL_SLIPPERY,
1946 EL_SWITCHGATE_OPENING,
1947 EL_SWITCHGATE_CLOSED,
1948 EL_SWITCHGATE_CLOSING,
1950 EL_SWITCHGATE_SWITCH_UP,
1951 EL_SWITCHGATE_SWITCH_DOWN,
1954 EL_TIMEGATE_OPENING,
1956 EL_TIMEGATE_CLOSING,
1959 EL_TIMEGATE_SWITCH_ACTIVE,
1964 EL_TUBE_VERTICAL_LEFT,
1965 EL_TUBE_VERTICAL_RIGHT,
1966 EL_TUBE_HORIZONTAL_UP,
1967 EL_TUBE_HORIZONTAL_DOWN,
1975 static int ep_slippery[] =
1989 EL_ROBOT_WHEEL_ACTIVE,
1995 EL_ACID_POOL_TOPLEFT,
1996 EL_ACID_POOL_TOPRIGHT,
2006 EL_STEELWALL_SLIPPERY,
2012 static int ep_can_change[] =
2017 static int ep_can_move[] =
2019 /* same elements as in 'pb_can_move_into_acid' */
2040 static int ep_can_fall[] =
2055 EL_BD_MAGIC_WALL_FULL,
2068 static int ep_can_smash_player[] =
2093 static int ep_can_smash_enemies[] =
2101 static int ep_can_smash_everything[] =
2109 static int ep_explodes_by_fire[] =
2111 /* same elements as in 'ep_explodes_impact' */
2116 /* same elements as in 'ep_explodes_smashed' */
2125 EL_DYNABOMB_PLAYER_1_ACTIVE,
2126 EL_DYNABOMB_PLAYER_2_ACTIVE,
2127 EL_DYNABOMB_PLAYER_3_ACTIVE,
2128 EL_DYNABOMB_PLAYER_4_ACTIVE,
2129 EL_DYNABOMB_INCREASE_NUMBER,
2130 EL_DYNABOMB_INCREASE_SIZE,
2131 EL_DYNABOMB_INCREASE_POWER,
2132 EL_SP_DISK_RED_ACTIVE,
2145 static int ep_explodes_smashed[] =
2147 /* same elements as in 'ep_explodes_impact' */
2160 static int ep_explodes_impact[] =
2168 static int ep_walkable_over[] =
2172 EL_SOKOBAN_FIELD_EMPTY,
2190 static int ep_walkable_inside[] =
2195 EL_TUBE_VERTICAL_LEFT,
2196 EL_TUBE_VERTICAL_RIGHT,
2197 EL_TUBE_HORIZONTAL_UP,
2198 EL_TUBE_HORIZONTAL_DOWN,
2206 static int ep_walkable_under[] =
2211 static int ep_passable_over[] =
2226 static int ep_passable_inside[] =
2232 EL_SP_PORT_HORIZONTAL,
2233 EL_SP_PORT_VERTICAL,
2235 EL_SP_GRAVITY_PORT_LEFT,
2236 EL_SP_GRAVITY_PORT_RIGHT,
2237 EL_SP_GRAVITY_PORT_UP,
2238 EL_SP_GRAVITY_PORT_DOWN,
2239 EL_SP_GRAVITY_ON_PORT_LEFT,
2240 EL_SP_GRAVITY_ON_PORT_RIGHT,
2241 EL_SP_GRAVITY_ON_PORT_UP,
2242 EL_SP_GRAVITY_ON_PORT_DOWN,
2243 EL_SP_GRAVITY_OFF_PORT_LEFT,
2244 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2245 EL_SP_GRAVITY_OFF_PORT_UP,
2246 EL_SP_GRAVITY_OFF_PORT_DOWN,
2250 static int ep_passable_under[] =
2255 static int ep_droppable[] =
2260 static int ep_explodes_1x1_old[] =
2265 static int ep_pushable[] =
2277 EL_SOKOBAN_FIELD_FULL,
2284 static int ep_explodes_cross_old[] =
2289 static int ep_protected[] =
2291 /* same elements as in 'ep_walkable_inside' */
2295 EL_TUBE_VERTICAL_LEFT,
2296 EL_TUBE_VERTICAL_RIGHT,
2297 EL_TUBE_HORIZONTAL_UP,
2298 EL_TUBE_HORIZONTAL_DOWN,
2304 /* same elements as in 'ep_passable_over' */
2316 /* same elements as in 'ep_passable_inside' */
2321 EL_SP_PORT_HORIZONTAL,
2322 EL_SP_PORT_VERTICAL,
2324 EL_SP_GRAVITY_PORT_LEFT,
2325 EL_SP_GRAVITY_PORT_RIGHT,
2326 EL_SP_GRAVITY_PORT_UP,
2327 EL_SP_GRAVITY_PORT_DOWN,
2328 EL_SP_GRAVITY_ON_PORT_LEFT,
2329 EL_SP_GRAVITY_ON_PORT_RIGHT,
2330 EL_SP_GRAVITY_ON_PORT_UP,
2331 EL_SP_GRAVITY_ON_PORT_DOWN,
2332 EL_SP_GRAVITY_OFF_PORT_LEFT,
2333 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2334 EL_SP_GRAVITY_OFF_PORT_UP,
2335 EL_SP_GRAVITY_OFF_PORT_DOWN,
2339 static int ep_throwable[] =
2344 static int ep_can_explode[] =
2346 /* same elements as in 'ep_explodes_impact' */
2351 /* same elements as in 'ep_explodes_smashed' */
2357 /* elements that can explode by explosion or by dragonfire */
2360 EL_DYNABOMB_PLAYER_1_ACTIVE,
2361 EL_DYNABOMB_PLAYER_2_ACTIVE,
2362 EL_DYNABOMB_PLAYER_3_ACTIVE,
2363 EL_DYNABOMB_PLAYER_4_ACTIVE,
2364 EL_DYNABOMB_INCREASE_NUMBER,
2365 EL_DYNABOMB_INCREASE_SIZE,
2366 EL_DYNABOMB_INCREASE_POWER,
2367 EL_SP_DISK_RED_ACTIVE,
2375 /* elements that can explode only by explosion */
2380 static int ep_gravity_reachable[] =
2386 EL_INVISIBLE_SAND_ACTIVE,
2391 EL_SP_PORT_HORIZONTAL,
2392 EL_SP_PORT_VERTICAL,
2394 EL_SP_GRAVITY_PORT_LEFT,
2395 EL_SP_GRAVITY_PORT_RIGHT,
2396 EL_SP_GRAVITY_PORT_UP,
2397 EL_SP_GRAVITY_PORT_DOWN,
2398 EL_SP_GRAVITY_ON_PORT_LEFT,
2399 EL_SP_GRAVITY_ON_PORT_RIGHT,
2400 EL_SP_GRAVITY_ON_PORT_UP,
2401 EL_SP_GRAVITY_ON_PORT_DOWN,
2402 EL_SP_GRAVITY_OFF_PORT_LEFT,
2403 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2404 EL_SP_GRAVITY_OFF_PORT_UP,
2405 EL_SP_GRAVITY_OFF_PORT_DOWN,
2409 static int ep_player[] =
2416 EL_SOKOBAN_FIELD_PLAYER,
2421 static int ep_can_pass_magic_wall[] =
2434 static int ep_switchable[] =
2438 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2439 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2440 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2441 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2442 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2443 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2444 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2445 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2446 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2447 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2448 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2449 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2450 EL_SWITCHGATE_SWITCH_UP,
2451 EL_SWITCHGATE_SWITCH_DOWN,
2453 EL_LIGHT_SWITCH_ACTIVE,
2455 EL_BALLOON_SWITCH_LEFT,
2456 EL_BALLOON_SWITCH_RIGHT,
2457 EL_BALLOON_SWITCH_UP,
2458 EL_BALLOON_SWITCH_DOWN,
2459 EL_BALLOON_SWITCH_ANY,
2465 static int ep_bd_element[] =
2498 static int ep_sp_element[] =
2500 /* should always be valid */
2503 /* standard classic Supaplex elements */
2510 EL_SP_HARDWARE_GRAY,
2518 EL_SP_GRAVITY_PORT_RIGHT,
2519 EL_SP_GRAVITY_PORT_DOWN,
2520 EL_SP_GRAVITY_PORT_LEFT,
2521 EL_SP_GRAVITY_PORT_UP,
2526 EL_SP_PORT_VERTICAL,
2527 EL_SP_PORT_HORIZONTAL,
2533 EL_SP_HARDWARE_BASE_1,
2534 EL_SP_HARDWARE_GREEN,
2535 EL_SP_HARDWARE_BLUE,
2537 EL_SP_HARDWARE_YELLOW,
2538 EL_SP_HARDWARE_BASE_2,
2539 EL_SP_HARDWARE_BASE_3,
2540 EL_SP_HARDWARE_BASE_4,
2541 EL_SP_HARDWARE_BASE_5,
2542 EL_SP_HARDWARE_BASE_6,
2546 /* additional elements that appeared in newer Supaplex levels */
2549 /* additional gravity port elements (not switching, but setting gravity) */
2550 EL_SP_GRAVITY_ON_PORT_LEFT,
2551 EL_SP_GRAVITY_ON_PORT_RIGHT,
2552 EL_SP_GRAVITY_ON_PORT_UP,
2553 EL_SP_GRAVITY_ON_PORT_DOWN,
2554 EL_SP_GRAVITY_OFF_PORT_LEFT,
2555 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2556 EL_SP_GRAVITY_OFF_PORT_UP,
2557 EL_SP_GRAVITY_OFF_PORT_DOWN,
2559 /* more than one Murphy in a level results in an inactive clone */
2562 /* runtime Supaplex elements */
2563 EL_SP_DISK_RED_ACTIVE,
2564 EL_SP_TERMINAL_ACTIVE,
2565 EL_SP_BUGGY_BASE_ACTIVATING,
2566 EL_SP_BUGGY_BASE_ACTIVE,
2572 static int ep_sb_element[] =
2577 EL_SOKOBAN_FIELD_EMPTY,
2578 EL_SOKOBAN_FIELD_FULL,
2579 EL_SOKOBAN_FIELD_PLAYER,
2584 EL_INVISIBLE_STEELWALL,
2588 static int ep_gem[] =
2599 static int ep_food_dark_yamyam[] =
2626 static int ep_food_penguin[] =
2639 static int ep_food_pig[] =
2650 static int ep_historic_wall[] =
2675 EL_EXPANDABLE_WALL_HORIZONTAL,
2676 EL_EXPANDABLE_WALL_VERTICAL,
2677 EL_EXPANDABLE_WALL_ANY,
2678 EL_EXPANDABLE_WALL_GROWING,
2685 EL_SP_HARDWARE_GRAY,
2686 EL_SP_HARDWARE_GREEN,
2687 EL_SP_HARDWARE_BLUE,
2689 EL_SP_HARDWARE_YELLOW,
2690 EL_SP_HARDWARE_BASE_1,
2691 EL_SP_HARDWARE_BASE_2,
2692 EL_SP_HARDWARE_BASE_3,
2693 EL_SP_HARDWARE_BASE_4,
2694 EL_SP_HARDWARE_BASE_5,
2695 EL_SP_HARDWARE_BASE_6,
2697 EL_SP_TERMINAL_ACTIVE,
2700 EL_INVISIBLE_STEELWALL,
2701 EL_INVISIBLE_STEELWALL_ACTIVE,
2703 EL_INVISIBLE_WALL_ACTIVE,
2704 EL_STEELWALL_SLIPPERY,
2720 static int ep_historic_solid[] =
2724 EL_EXPANDABLE_WALL_HORIZONTAL,
2725 EL_EXPANDABLE_WALL_VERTICAL,
2726 EL_EXPANDABLE_WALL_ANY,
2739 EL_QUICKSAND_FILLING,
2740 EL_QUICKSAND_EMPTYING,
2742 EL_MAGIC_WALL_ACTIVE,
2743 EL_MAGIC_WALL_EMPTYING,
2744 EL_MAGIC_WALL_FILLING,
2748 EL_BD_MAGIC_WALL_ACTIVE,
2749 EL_BD_MAGIC_WALL_EMPTYING,
2750 EL_BD_MAGIC_WALL_FULL,
2751 EL_BD_MAGIC_WALL_FILLING,
2752 EL_BD_MAGIC_WALL_DEAD,
2761 EL_SP_TERMINAL_ACTIVE,
2765 EL_INVISIBLE_WALL_ACTIVE,
2766 EL_SWITCHGATE_SWITCH_UP,
2767 EL_SWITCHGATE_SWITCH_DOWN,
2769 EL_TIMEGATE_SWITCH_ACTIVE,
2781 /* the following elements are a direct copy of "indestructible" elements,
2782 except "EL_ACID", which is "indestructible", but not "solid"! */
2787 EL_ACID_POOL_TOPLEFT,
2788 EL_ACID_POOL_TOPRIGHT,
2789 EL_ACID_POOL_BOTTOMLEFT,
2790 EL_ACID_POOL_BOTTOM,
2791 EL_ACID_POOL_BOTTOMRIGHT,
2792 EL_SP_HARDWARE_GRAY,
2793 EL_SP_HARDWARE_GREEN,
2794 EL_SP_HARDWARE_BLUE,
2796 EL_SP_HARDWARE_YELLOW,
2797 EL_SP_HARDWARE_BASE_1,
2798 EL_SP_HARDWARE_BASE_2,
2799 EL_SP_HARDWARE_BASE_3,
2800 EL_SP_HARDWARE_BASE_4,
2801 EL_SP_HARDWARE_BASE_5,
2802 EL_SP_HARDWARE_BASE_6,
2803 EL_INVISIBLE_STEELWALL,
2804 EL_INVISIBLE_STEELWALL_ACTIVE,
2805 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2806 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2807 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2808 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2811 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2812 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2813 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2814 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2815 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2816 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2818 EL_LIGHT_SWITCH_ACTIVE,
2819 EL_SIGN_EXCLAMATION,
2820 EL_SIGN_RADIOACTIVITY,
2831 EL_STEELWALL_SLIPPERY,
2854 EL_SWITCHGATE_OPENING,
2855 EL_SWITCHGATE_CLOSED,
2856 EL_SWITCHGATE_CLOSING,
2858 EL_TIMEGATE_OPENING,
2860 EL_TIMEGATE_CLOSING,
2864 EL_TUBE_VERTICAL_LEFT,
2865 EL_TUBE_VERTICAL_RIGHT,
2866 EL_TUBE_HORIZONTAL_UP,
2867 EL_TUBE_HORIZONTAL_DOWN,
2875 static int ep_classic_enemy[] =
2891 static int ep_belt[] =
2893 EL_CONVEYOR_BELT_1_LEFT,
2894 EL_CONVEYOR_BELT_1_MIDDLE,
2895 EL_CONVEYOR_BELT_1_RIGHT,
2896 EL_CONVEYOR_BELT_2_LEFT,
2897 EL_CONVEYOR_BELT_2_MIDDLE,
2898 EL_CONVEYOR_BELT_2_RIGHT,
2899 EL_CONVEYOR_BELT_3_LEFT,
2900 EL_CONVEYOR_BELT_3_MIDDLE,
2901 EL_CONVEYOR_BELT_3_RIGHT,
2902 EL_CONVEYOR_BELT_4_LEFT,
2903 EL_CONVEYOR_BELT_4_MIDDLE,
2904 EL_CONVEYOR_BELT_4_RIGHT,
2908 static int ep_belt_active[] =
2910 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2911 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2912 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2913 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2914 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2915 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2916 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2917 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2918 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2919 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2920 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2921 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2925 static int ep_belt_switch[] =
2927 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2928 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2929 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2930 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2931 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2932 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2933 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2934 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2935 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2936 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2937 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2938 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2942 static int ep_tube[] =
2949 EL_TUBE_HORIZONTAL_UP,
2950 EL_TUBE_HORIZONTAL_DOWN,
2952 EL_TUBE_VERTICAL_LEFT,
2953 EL_TUBE_VERTICAL_RIGHT,
2958 static int ep_keygate[] =
2979 static int ep_amoeboid[] =
2989 static int ep_amoebalive[] =
2998 static int ep_has_content[] =
3008 static int ep_can_turn_each_move[] =
3010 /* !!! do something with this one !!! */
3014 static int ep_can_grow[] =
3026 static int ep_active_bomb[] =
3029 EL_DYNABOMB_PLAYER_1_ACTIVE,
3030 EL_DYNABOMB_PLAYER_2_ACTIVE,
3031 EL_DYNABOMB_PLAYER_3_ACTIVE,
3032 EL_DYNABOMB_PLAYER_4_ACTIVE,
3033 EL_SP_DISK_RED_ACTIVE,
3037 static int ep_inactive[] =
3074 EL_INVISIBLE_STEELWALL,
3082 EL_WALL_EMERALD_YELLOW,
3083 EL_DYNABOMB_INCREASE_NUMBER,
3084 EL_DYNABOMB_INCREASE_SIZE,
3085 EL_DYNABOMB_INCREASE_POWER,
3089 EL_SOKOBAN_FIELD_EMPTY,
3090 EL_SOKOBAN_FIELD_FULL,
3091 EL_WALL_EMERALD_RED,
3092 EL_WALL_EMERALD_PURPLE,
3093 EL_ACID_POOL_TOPLEFT,
3094 EL_ACID_POOL_TOPRIGHT,
3095 EL_ACID_POOL_BOTTOMLEFT,
3096 EL_ACID_POOL_BOTTOM,
3097 EL_ACID_POOL_BOTTOMRIGHT,
3101 EL_BD_MAGIC_WALL_DEAD,
3102 EL_AMOEBA_TO_DIAMOND,
3110 EL_SP_GRAVITY_PORT_RIGHT,
3111 EL_SP_GRAVITY_PORT_DOWN,
3112 EL_SP_GRAVITY_PORT_LEFT,
3113 EL_SP_GRAVITY_PORT_UP,
3114 EL_SP_PORT_HORIZONTAL,
3115 EL_SP_PORT_VERTICAL,
3126 EL_SP_HARDWARE_GRAY,
3127 EL_SP_HARDWARE_GREEN,
3128 EL_SP_HARDWARE_BLUE,
3130 EL_SP_HARDWARE_YELLOW,
3131 EL_SP_HARDWARE_BASE_1,
3132 EL_SP_HARDWARE_BASE_2,
3133 EL_SP_HARDWARE_BASE_3,
3134 EL_SP_HARDWARE_BASE_4,
3135 EL_SP_HARDWARE_BASE_5,
3136 EL_SP_HARDWARE_BASE_6,
3137 EL_SP_GRAVITY_ON_PORT_LEFT,
3138 EL_SP_GRAVITY_ON_PORT_RIGHT,
3139 EL_SP_GRAVITY_ON_PORT_UP,
3140 EL_SP_GRAVITY_ON_PORT_DOWN,
3141 EL_SP_GRAVITY_OFF_PORT_LEFT,
3142 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3143 EL_SP_GRAVITY_OFF_PORT_UP,
3144 EL_SP_GRAVITY_OFF_PORT_DOWN,
3145 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3146 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3147 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3148 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3149 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3150 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3151 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3152 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3153 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3154 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3155 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3156 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3157 EL_SIGN_EXCLAMATION,
3158 EL_SIGN_RADIOACTIVITY,
3169 EL_STEELWALL_SLIPPERY,
3185 static int ep_em_slippery_wall[] =
3190 static int ep_gfx_crumbled[] =
3203 } element_properties[] =
3205 { ep_diggable, EP_DIGGABLE },
3206 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3207 { ep_dont_run_into, EP_DONT_RUN_INTO },
3208 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3209 { ep_dont_touch, EP_DONT_TOUCH },
3210 { ep_indestructible, EP_INDESTRUCTIBLE },
3211 { ep_slippery, EP_SLIPPERY },
3212 { ep_can_change, EP_CAN_CHANGE },
3213 { ep_can_move, EP_CAN_MOVE },
3214 { ep_can_fall, EP_CAN_FALL },
3215 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3216 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3217 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3218 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3219 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3220 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3221 { ep_walkable_over, EP_WALKABLE_OVER },
3222 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3223 { ep_walkable_under, EP_WALKABLE_UNDER },
3224 { ep_passable_over, EP_PASSABLE_OVER },
3225 { ep_passable_inside, EP_PASSABLE_INSIDE },
3226 { ep_passable_under, EP_PASSABLE_UNDER },
3227 { ep_droppable, EP_DROPPABLE },
3228 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3229 { ep_pushable, EP_PUSHABLE },
3230 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3231 { ep_protected, EP_PROTECTED },
3232 { ep_throwable, EP_THROWABLE },
3233 { ep_can_explode, EP_CAN_EXPLODE },
3234 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3236 { ep_player, EP_PLAYER },
3237 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3238 { ep_switchable, EP_SWITCHABLE },
3239 { ep_bd_element, EP_BD_ELEMENT },
3240 { ep_sp_element, EP_SP_ELEMENT },
3241 { ep_sb_element, EP_SB_ELEMENT },
3243 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3244 { ep_food_penguin, EP_FOOD_PENGUIN },
3245 { ep_food_pig, EP_FOOD_PIG },
3246 { ep_historic_wall, EP_HISTORIC_WALL },
3247 { ep_historic_solid, EP_HISTORIC_SOLID },
3248 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3249 { ep_belt, EP_BELT },
3250 { ep_belt_active, EP_BELT_ACTIVE },
3251 { ep_belt_switch, EP_BELT_SWITCH },
3252 { ep_tube, EP_TUBE },
3253 { ep_keygate, EP_KEYGATE },
3254 { ep_amoeboid, EP_AMOEBOID },
3255 { ep_amoebalive, EP_AMOEBALIVE },
3256 { ep_has_content, EP_HAS_CONTENT },
3257 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3258 { ep_can_grow, EP_CAN_GROW },
3259 { ep_active_bomb, EP_ACTIVE_BOMB },
3260 { ep_inactive, EP_INACTIVE },
3262 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3264 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3269 static int copy_properties[][5] =
3273 EL_BUG_LEFT, EL_BUG_RIGHT,
3274 EL_BUG_UP, EL_BUG_DOWN
3278 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3279 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3283 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3284 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3288 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3289 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3293 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3294 EL_PACMAN_UP, EL_PACMAN_DOWN
3298 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3299 EL_MOLE_UP, EL_MOLE_DOWN
3309 /* always start with reliable default values (element has no properties) */
3310 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3311 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3312 SET_PROPERTY(i, j, FALSE);
3314 /* set all base element properties from above array definitions */
3315 for (i = 0; element_properties[i].elements != NULL; i++)
3316 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3317 SET_PROPERTY((element_properties[i].elements)[j],
3318 element_properties[i].property, TRUE);
3320 /* copy properties to some elements that are only stored in level file */
3321 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3322 for (j = 0; copy_properties[j][0] != -1; j++)
3323 if (HAS_PROPERTY(copy_properties[j][0], i))
3324 for (k = 1; k <= 4; k++)
3325 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3328 void InitElementPropertiesEngine(int engine_version)
3331 static int active_properties[] =
3336 EP_DONT_COLLIDE_WITH,
3340 EP_CAN_PASS_MAGIC_WALL,
3345 EP_EXPLODES_BY_FIRE,
3358 EP_EM_SLIPPERY_WALL,
3362 static int no_wall_properties[] =
3365 EP_COLLECTIBLE_ONLY,
3367 EP_DONT_COLLIDE_WITH,
3370 EP_CAN_SMASH_PLAYER,
3371 EP_CAN_SMASH_ENEMIES,
3372 EP_CAN_SMASH_EVERYTHING,
3377 EP_FOOD_DARK_YAMYAM,
3394 InitElementPropertiesStatic();
3397 /* important: after initialization in InitElementPropertiesStatic(), the
3398 elements are not again initialized to a default value; therefore all
3399 changes have to make sure that they leave the element with a defined
3400 property (which means that conditional property changes must be set to
3401 a reliable default value before) */
3403 /* set all special, combined or engine dependent element properties */
3404 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3407 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3408 SET_PROPERTY(i, j, FALSE);
3411 /* ---------- INACTIVE ------------------------------------------------- */
3412 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3414 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3415 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3416 IS_WALKABLE_INSIDE(i) ||
3417 IS_WALKABLE_UNDER(i)));
3419 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3420 IS_PASSABLE_INSIDE(i) ||
3421 IS_PASSABLE_UNDER(i)));
3423 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3424 IS_PASSABLE_OVER(i)));
3426 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3427 IS_PASSABLE_INSIDE(i)));
3429 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3430 IS_PASSABLE_UNDER(i)));
3432 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3435 /* ---------- COLLECTIBLE ---------------------------------------------- */
3436 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3440 /* ---------- SNAPPABLE ------------------------------------------------ */
3441 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3442 IS_COLLECTIBLE(i) ||
3446 /* ---------- WALL ----------------------------------------------------- */
3447 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3449 for (j = 0; no_wall_properties[j] != -1; j++)
3450 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3451 i >= EL_FIRST_RUNTIME_UNREAL)
3452 SET_PROPERTY(i, EP_WALL, FALSE);
3454 if (IS_HISTORIC_WALL(i))
3455 SET_PROPERTY(i, EP_WALL, TRUE);
3457 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3458 if (engine_version < VERSION_IDENT(2,2,0,0))
3459 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3461 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3463 !IS_COLLECTIBLE(i)));
3466 /* ---------- PROTECTED ------------------------------------------------ */
3467 if (IS_ACCESSIBLE_INSIDE(i))
3468 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3471 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3473 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3474 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3476 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3477 IS_INDESTRUCTIBLE(i)));
3479 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3481 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3482 else if (engine_version < VERSION_IDENT(2,2,0,0))
3483 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3486 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3491 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3492 !IS_WALKABLE_OVER(i) &&
3493 !IS_WALKABLE_UNDER(i)));
3495 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3500 if (IS_CUSTOM_ELEMENT(i))
3502 /* these are additional properties which are initially false when set */
3504 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3506 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3507 if (DONT_COLLIDE_WITH(i))
3508 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3510 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3511 if (CAN_SMASH_EVERYTHING(i))
3512 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3513 if (CAN_SMASH_ENEMIES(i))
3514 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3517 /* ---------- CAN_SMASH ------------------------------------------------ */
3518 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3519 CAN_SMASH_ENEMIES(i) ||
3520 CAN_SMASH_EVERYTHING(i)));
3523 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3524 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3525 CAN_EXPLODE_SMASHED(i) ||
3526 CAN_EXPLODE_IMPACT(i)));
3530 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3532 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3533 !CAN_EXPLODE_CROSS(i)));
3535 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3536 !CAN_EXPLODE_1X1(i) &&
3537 !CAN_EXPLODE_CROSS(i)));
3541 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3542 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3543 EXPLODES_BY_FIRE(i)));
3545 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3546 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3547 EXPLODES_SMASHED(i)));
3549 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3550 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3551 EXPLODES_IMPACT(i)));
3553 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3554 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3556 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3557 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3558 i == EL_BLACK_ORB));
3560 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3561 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3563 IS_CUSTOM_ELEMENT(i)));
3565 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3566 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3567 i == EL_SP_ELECTRON));
3569 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3570 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3571 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3572 getMoveIntoAcidProperty(&level, i));
3574 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3575 if (MAYBE_DONT_COLLIDE_WITH(i))
3576 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3577 getDontCollideWithProperty(&level, i));
3579 /* ---------- SP_PORT -------------------------------------------------- */
3580 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3581 IS_PASSABLE_INSIDE(i)));
3583 /* ---------- CAN_CHANGE ----------------------------------------------- */
3584 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3585 for (j = 0; j < element_info[i].num_change_pages; j++)
3586 if (element_info[i].change_page[j].can_change)
3587 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3589 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3590 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3591 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3595 /* determine inactive elements (used for engine main loop optimization) */
3596 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3598 boolean active = FALSE;
3600 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3602 if (HAS_PROPERTY(i, j))
3608 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3613 /* dynamically adjust element properties according to game engine version */
3615 static int ep_em_slippery_wall[] =
3620 EL_EXPANDABLE_WALL_HORIZONTAL,
3621 EL_EXPANDABLE_WALL_VERTICAL,
3622 EL_EXPANDABLE_WALL_ANY,
3626 /* special EM style gems behaviour */
3627 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3628 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3629 level.em_slippery_gems);
3631 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3632 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3633 (level.em_slippery_gems &&
3634 engine_version > VERSION_IDENT(2,0,1,0)));
3638 /* set default push delay values (corrected since version 3.0.7-1) */
3639 if (engine_version < VERSION_IDENT(3,0,7,1))
3641 game.default_push_delay_fixed = 2;
3642 game.default_push_delay_random = 8;
3646 game.default_push_delay_fixed = 8;
3647 game.default_push_delay_random = 8;
3650 /* set uninitialized push delay values of custom elements in older levels */
3651 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3653 int element = EL_CUSTOM_START + i;
3655 if (element_info[element].push_delay_fixed == -1)
3656 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3657 if (element_info[element].push_delay_random == -1)
3658 element_info[element].push_delay_random = game.default_push_delay_random;
3661 /* set some other uninitialized values of custom elements in older levels */
3662 if (engine_version < VERSION_IDENT(3,1,0,0))
3664 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3666 int element = EL_CUSTOM_START + i;
3668 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3670 element_info[element].explosion_delay = 17;
3671 element_info[element].ignition_delay = 8;
3676 /* set element properties that were handled incorrectly in older levels */
3677 if (engine_version < VERSION_IDENT(3,1,0,0))
3679 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3680 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3686 /* this is needed because some graphics depend on element properties */
3687 if (game_status == GAME_MODE_PLAYING)
3688 InitElementGraphicInfo();
3691 static void InitGlobal()
3695 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3697 element_info[i].token_name = element_name_info[i].token_name;
3698 element_info[i].class_name = element_name_info[i].class_name;
3699 element_info[i].editor_description=element_name_info[i].editor_description;
3702 global.autoplay_leveldir = NULL;
3703 global.convert_leveldir = NULL;
3705 global.frames_per_second = 0;
3706 global.fps_slowdown = FALSE;
3707 global.fps_slowdown_factor = 1;
3710 void Execute_Command(char *command)
3714 if (strcmp(command, "print graphicsinfo.conf") == 0)
3716 printf("# You can configure additional/alternative image files here.\n");
3717 printf("# (The entries below are default and therefore commented out.)\n");
3719 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3721 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3724 for (i = 0; image_config[i].token != NULL; i++)
3725 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3726 image_config[i].value));
3730 else if (strcmp(command, "print soundsinfo.conf") == 0)
3732 printf("# You can configure additional/alternative sound files here.\n");
3733 printf("# (The entries below are default and therefore commented out.)\n");
3735 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3737 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3740 for (i = 0; sound_config[i].token != NULL; i++)
3741 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3742 sound_config[i].value));
3746 else if (strcmp(command, "print musicinfo.conf") == 0)
3748 printf("# You can configure additional/alternative music files here.\n");
3749 printf("# (The entries below are default and therefore commented out.)\n");
3751 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3753 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3756 for (i = 0; music_config[i].token != NULL; i++)
3757 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3758 music_config[i].value));
3762 else if (strcmp(command, "print editorsetup.conf") == 0)
3764 printf("# You can configure your personal editor element list here.\n");
3765 printf("# (The entries below are default and therefore commented out.)\n");
3768 PrintEditorElementList();
3772 else if (strcmp(command, "print helpanim.conf") == 0)
3774 printf("# You can configure different element help animations here.\n");
3775 printf("# (The entries below are default and therefore commented out.)\n");
3778 for (i = 0; helpanim_config[i].token != NULL; i++)
3780 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3781 helpanim_config[i].value));
3783 if (strcmp(helpanim_config[i].token, "end") == 0)
3789 else if (strcmp(command, "print helptext.conf") == 0)
3791 printf("# You can configure different element help text here.\n");
3792 printf("# (The entries below are default and therefore commented out.)\n");
3795 for (i = 0; helptext_config[i].token != NULL; i++)
3796 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3797 helptext_config[i].value));
3801 else if (strncmp(command, "dump level ", 11) == 0)
3803 char *filename = &command[11];
3805 if (access(filename, F_OK) != 0)
3806 Error(ERR_EXIT, "cannot open file '%s'", filename);
3808 LoadLevelFromFilename(&level, filename);
3813 else if (strncmp(command, "dump tape ", 10) == 0)
3815 char *filename = &command[10];
3817 if (access(filename, F_OK) != 0)
3818 Error(ERR_EXIT, "cannot open file '%s'", filename);
3820 LoadTapeFromFilename(filename);
3825 else if (strncmp(command, "autoplay ", 9) == 0)
3827 char *str_copy = getStringCopy(&command[9]);
3828 char *str_ptr = strchr(str_copy, ' ');
3830 global.autoplay_leveldir = str_copy;
3831 global.autoplay_level_nr = -1;
3833 if (str_ptr != NULL)
3835 *str_ptr++ = '\0'; /* terminate leveldir string */
3836 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3839 else if (strncmp(command, "convert ", 8) == 0)
3841 char *str_copy = getStringCopy(&command[8]);
3842 char *str_ptr = strchr(str_copy, ' ');
3844 global.convert_leveldir = str_copy;
3845 global.convert_level_nr = -1;
3847 if (str_ptr != NULL)
3849 *str_ptr++ = '\0'; /* terminate leveldir string */
3850 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3855 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3859 static void InitSetup()
3861 LoadSetup(); /* global setup info */
3863 /* set some options from setup file */
3865 if (setup.options.verbose)
3866 options.verbose = TRUE;
3869 static void InitPlayerInfo()
3873 /* choose default local player */
3874 local_player = &stored_player[0];
3876 for (i = 0; i < MAX_PLAYERS; i++)
3877 stored_player[i].connected = FALSE;
3879 local_player->connected = TRUE;
3882 static void InitArtworkInfo()
3887 static char *get_string_in_brackets(char *string)
3889 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3891 sprintf(string_in_brackets, "[%s]", string);
3893 return string_in_brackets;
3896 static char *get_level_id_suffix(int id_nr)
3898 char *id_suffix = checked_malloc(1 + 3 + 1);
3900 if (id_nr < 0 || id_nr > 999)
3903 sprintf(id_suffix, ".%03d", id_nr);
3909 static char *get_element_class_token(int element)
3911 char *element_class_name = element_info[element].class_name;
3912 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3914 sprintf(element_class_token, "[%s]", element_class_name);
3916 return element_class_token;
3919 static char *get_action_class_token(int action)
3921 char *action_class_name = &element_action_info[action].suffix[1];
3922 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3924 sprintf(action_class_token, "[%s]", action_class_name);
3926 return action_class_token;
3930 static void InitArtworkConfig()
3932 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3933 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3934 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3935 static char *action_id_suffix[NUM_ACTIONS + 1];
3936 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3937 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3938 static char *level_id_suffix[MAX_LEVELS + 1];
3939 static char *dummy[1] = { NULL };
3940 static char *ignore_generic_tokens[] =
3946 static char **ignore_image_tokens;
3947 static char **ignore_sound_tokens;
3948 static char **ignore_music_tokens;
3949 int num_ignore_generic_tokens;
3950 int num_ignore_image_tokens;
3951 int num_ignore_sound_tokens;
3952 int num_ignore_music_tokens;
3955 /* dynamically determine list of generic tokens to be ignored */
3956 num_ignore_generic_tokens = 0;
3957 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3958 num_ignore_generic_tokens++;
3960 /* dynamically determine list of image tokens to be ignored */
3961 num_ignore_image_tokens = num_ignore_generic_tokens;
3962 for (i = 0; image_config_vars[i].token != NULL; i++)
3963 num_ignore_image_tokens++;
3964 ignore_image_tokens =
3965 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3966 for (i = 0; i < num_ignore_generic_tokens; i++)
3967 ignore_image_tokens[i] = ignore_generic_tokens[i];
3968 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3969 ignore_image_tokens[num_ignore_generic_tokens + i] =
3970 image_config_vars[i].token;
3971 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3973 /* dynamically determine list of sound tokens to be ignored */
3974 num_ignore_sound_tokens = num_ignore_generic_tokens;
3975 ignore_sound_tokens =
3976 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3977 for (i = 0; i < num_ignore_generic_tokens; i++)
3978 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3979 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3981 /* dynamically determine list of music tokens to be ignored */
3982 num_ignore_music_tokens = num_ignore_generic_tokens;
3983 ignore_music_tokens =
3984 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3985 for (i = 0; i < num_ignore_generic_tokens; i++)
3986 ignore_music_tokens[i] = ignore_generic_tokens[i];
3987 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3989 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3990 image_id_prefix[i] = element_info[i].token_name;
3991 for (i = 0; i < NUM_FONTS; i++)
3992 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3993 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3995 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3996 sound_id_prefix[i] = element_info[i].token_name;
3997 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3998 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3999 get_string_in_brackets(element_info[i].class_name);
4000 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4002 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4003 music_id_prefix[i] = music_prefix_info[i].prefix;
4004 music_id_prefix[MAX_LEVELS] = NULL;
4006 for (i = 0; i < NUM_ACTIONS; i++)
4007 action_id_suffix[i] = element_action_info[i].suffix;
4008 action_id_suffix[NUM_ACTIONS] = NULL;
4010 for (i = 0; i < NUM_DIRECTIONS; i++)
4011 direction_id_suffix[i] = element_direction_info[i].suffix;
4012 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4014 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4015 special_id_suffix[i] = special_suffix_info[i].suffix;
4016 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4018 for (i = 0; i < MAX_LEVELS; i++)
4019 level_id_suffix[i] = get_level_id_suffix(i);
4020 level_id_suffix[MAX_LEVELS] = NULL;
4022 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4023 image_id_prefix, action_id_suffix, direction_id_suffix,
4024 special_id_suffix, ignore_image_tokens);
4025 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4026 sound_id_prefix, action_id_suffix, dummy,
4027 special_id_suffix, ignore_sound_tokens);
4028 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4029 music_id_prefix, special_id_suffix, level_id_suffix,
4030 dummy, ignore_music_tokens);
4033 static void InitMixer()
4041 char *filename_font_initial = NULL;
4042 Bitmap *bitmap_font_initial = NULL;
4045 /* determine settings for initial font (for displaying startup messages) */
4046 for (i = 0; image_config[i].token != NULL; i++)
4048 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4050 char font_token[128];
4053 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4054 len_font_token = strlen(font_token);
4056 if (strcmp(image_config[i].token, font_token) == 0)
4057 filename_font_initial = image_config[i].value;
4058 else if (strlen(image_config[i].token) > len_font_token &&
4059 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4061 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4062 font_initial[j].src_x = atoi(image_config[i].value);
4063 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4064 font_initial[j].src_y = atoi(image_config[i].value);
4065 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4066 font_initial[j].width = atoi(image_config[i].value);
4067 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4068 font_initial[j].height = atoi(image_config[i].value);
4073 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4075 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4076 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4079 if (filename_font_initial == NULL) /* should not happen */
4080 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4082 /* create additional image buffers for double-buffering */
4083 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4084 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4086 /* initialize screen properties */
4087 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4088 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4090 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4091 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4092 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4094 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4096 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4097 font_initial[j].bitmap = bitmap_font_initial;
4099 InitFontGraphicInfo();
4101 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4102 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4104 DrawInitText("Loading graphics:", 120, FC_GREEN);
4106 InitTileClipmasks();
4109 void InitGfxBackground()
4113 drawto = backbuffer;
4114 fieldbuffer = bitmap_db_field;
4115 SetDrawtoField(DRAW_BACKBUFFER);
4117 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4118 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4119 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4120 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4122 for (x = 0; x < MAX_BUF_XSIZE; x++)
4123 for (y = 0; y < MAX_BUF_YSIZE; y++)
4126 redraw_mask = REDRAW_ALL;
4129 static void InitLevelInfo()
4131 LoadLevelInfo(); /* global level info */
4132 LoadLevelSetup_LastSeries(); /* last played series info */
4133 LoadLevelSetup_SeriesInfo(); /* last played level info */
4136 void InitLevelArtworkInfo()
4138 LoadLevelArtworkInfo();
4141 static void InitImages()
4144 setLevelArtworkDir(artwork.gfx_first);
4148 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4149 leveldir_current->identifier,
4150 artwork.gfx_current_identifier,
4151 artwork.gfx_current->identifier,
4152 leveldir_current->graphics_set,
4153 leveldir_current->graphics_path);
4156 ReloadCustomImages();
4158 LoadCustomElementDescriptions();
4159 LoadSpecialMenuDesignSettings();
4161 ReinitializeGraphics();
4164 static void InitSound(char *identifier)
4166 if (identifier == NULL)
4167 identifier = artwork.snd_current->identifier;
4170 /* set artwork path to send it to the sound server process */
4171 setLevelArtworkDir(artwork.snd_first);
4174 InitReloadCustomSounds(identifier);
4175 ReinitializeSounds();
4178 static void InitMusic(char *identifier)
4180 if (identifier == NULL)
4181 identifier = artwork.mus_current->identifier;
4184 /* set artwork path to send it to the sound server process */
4185 setLevelArtworkDir(artwork.mus_first);
4188 InitReloadCustomMusic(identifier);
4189 ReinitializeMusic();
4192 void InitNetworkServer()
4194 #if defined(NETWORK_AVALIABLE)
4198 if (!options.network)
4201 #if defined(NETWORK_AVALIABLE)
4202 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4204 if (!ConnectToServer(options.server_host, options.server_port))
4205 Error(ERR_EXIT, "cannot connect to network game server");
4207 SendToServer_PlayerName(setup.player_name);
4208 SendToServer_ProtocolVersion();
4211 SendToServer_NrWanted(nr_wanted);
4215 static char *getNewArtworkIdentifier(int type)
4217 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4218 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4219 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4220 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4221 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4222 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4223 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4224 char *leveldir_identifier = leveldir_current->identifier;
4226 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4227 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4229 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4231 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4232 char *artwork_current_identifier;
4233 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4235 /* leveldir_current may be invalid (level group, parent link) */
4236 if (!validLevelSeries(leveldir_current))
4239 /* 1st step: determine artwork set to be activated in descending order:
4240 --------------------------------------------------------------------
4241 1. setup artwork (when configured to override everything else)
4242 2. artwork set configured in "levelinfo.conf" of current level set
4243 (artwork in level directory will have priority when loading later)
4244 3. artwork in level directory (stored in artwork sub-directory)
4245 4. setup artwork (currently configured in setup menu) */
4247 if (setup_override_artwork)
4248 artwork_current_identifier = setup_artwork_set;
4249 else if (leveldir_artwork_set != NULL)
4250 artwork_current_identifier = leveldir_artwork_set;
4251 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4252 artwork_current_identifier = leveldir_identifier;
4254 artwork_current_identifier = setup_artwork_set;
4257 /* 2nd step: check if it is really needed to reload artwork set
4258 ------------------------------------------------------------ */
4261 if (type == ARTWORK_TYPE_GRAPHICS)
4262 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4263 artwork_new_identifier,
4264 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4265 artwork_current_identifier,
4266 leveldir_current->graphics_set,
4267 leveldir_current->identifier);
4270 /* ---------- reload if level set and also artwork set has changed ------- */
4271 if (leveldir_current_identifier[type] != leveldir_identifier &&
4272 (last_has_level_artwork_set[type] || has_level_artwork_set))
4273 artwork_new_identifier = artwork_current_identifier;
4275 leveldir_current_identifier[type] = leveldir_identifier;
4276 last_has_level_artwork_set[type] = has_level_artwork_set;
4279 if (type == ARTWORK_TYPE_GRAPHICS)
4280 printf("::: 1: '%s'\n", artwork_new_identifier);
4283 /* ---------- reload if "override artwork" setting has changed ----------- */
4284 if (last_override_level_artwork[type] != setup_override_artwork)
4285 artwork_new_identifier = artwork_current_identifier;
4287 last_override_level_artwork[type] = setup_override_artwork;
4290 if (type == ARTWORK_TYPE_GRAPHICS)
4291 printf("::: 2: '%s'\n", artwork_new_identifier);
4294 /* ---------- reload if current artwork identifier has changed ----------- */
4295 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4296 artwork_current_identifier) != 0)
4297 artwork_new_identifier = artwork_current_identifier;
4299 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4302 if (type == ARTWORK_TYPE_GRAPHICS)
4303 printf("::: 3: '%s'\n", artwork_new_identifier);
4306 /* ---------- do not reload directly after starting ---------------------- */
4307 if (!initialized[type])
4308 artwork_new_identifier = NULL;
4310 initialized[type] = TRUE;
4313 if (type == ARTWORK_TYPE_GRAPHICS)
4314 printf("::: 4: '%s'\n", artwork_new_identifier);
4318 if (type == ARTWORK_TYPE_GRAPHICS)
4319 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4320 artwork.gfx_current_identifier, artwork_current_identifier,
4321 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4322 artwork_new_identifier);
4325 return artwork_new_identifier;
4328 void ReloadCustomArtwork(int force_reload)
4330 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4331 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4332 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4333 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4334 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4335 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4336 boolean redraw_screen = FALSE;
4338 if (gfx_new_identifier != NULL || force_reload_gfx)
4341 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4342 artwork.gfx_current_identifier,
4344 artwork.gfx_current->identifier,
4345 leveldir_current->graphics_set);
4348 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4353 printf("... '%s'\n",
4354 leveldir_current->graphics_set);
4357 FreeTileClipmasks();
4358 InitTileClipmasks();
4360 redraw_screen = TRUE;
4363 if (snd_new_identifier != NULL || force_reload_snd)
4365 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4367 InitSound(snd_new_identifier);
4369 redraw_screen = TRUE;
4372 if (mus_new_identifier != NULL || force_reload_mus)
4374 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4376 InitMusic(mus_new_identifier);
4378 redraw_screen = TRUE;
4383 InitGfxBackground();
4385 /* force redraw of (open or closed) door graphics */
4386 SetDoorState(DOOR_OPEN_ALL);
4387 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4391 void KeyboardAutoRepeatOffUnlessAutoplay()
4393 if (global.autoplay_leveldir == NULL)
4394 KeyboardAutoRepeatOff();
4398 /* ========================================================================= */
4400 /* ========================================================================= */
4404 InitGlobal(); /* initialize some global variables */
4406 if (options.execute_command)
4407 Execute_Command(options.execute_command);
4409 if (options.serveronly)
4411 #if defined(PLATFORM_UNIX)
4412 NetworkServer(options.server_port, options.serveronly);
4414 Error(ERR_WARN, "networking only supported in Unix version");
4416 exit(0); /* never reached */
4422 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4423 InitArtworkConfig(); /* needed before forking sound child process */
4428 InitRND(NEW_RANDOMIZE);
4429 InitSimpleRND(NEW_RANDOMIZE);
4434 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4437 InitEventFilter(FilterMouseMotionEvents);
4439 InitElementPropertiesStatic();
4440 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4445 InitLevelArtworkInfo();
4447 InitImages(); /* needs to know current level directory */
4448 InitSound(NULL); /* needs to know current level directory */
4449 InitMusic(NULL); /* needs to know current level directory */
4451 InitGfxBackground();
4453 if (global.autoplay_leveldir)
4458 else if (global.convert_leveldir)
4464 game_status = GAME_MODE_MAIN;
4472 InitNetworkServer();
4475 void CloseAllAndExit(int exit_value)
4480 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4487 FreeTileClipmasks();
4489 #if defined(TARGET_SDL)
4490 if (network_server) /* terminate network server */
4491 SDL_KillThread(server_thread);
4494 CloseVideoDisplay();
4495 ClosePlatformDependentStuff();