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_SPRITE; 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_SPRITE].bitmap;
282 static int getFontBitmapID(int font_nr)
286 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
287 special = game_status;
288 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
289 special = GFX_SPECIAL_ARG_MAIN;
290 else if (game_status == GAME_MODE_PLAYING)
291 special = GFX_SPECIAL_ARG_DOOR;
294 return font_info[font_nr].special_bitmap_id[special];
299 void InitFontGraphicInfo()
301 static struct FontBitmapInfo *font_bitmap_info = NULL;
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
304 int num_font_bitmaps = NUM_FONTS;
307 if (graphic_info == NULL) /* still at startup phase */
309 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
314 /* ---------- initialize font graphic definitions ---------- */
316 /* always start with reliable default values (normal font graphics) */
318 for (i = 0; i < NUM_FONTS; i++)
319 font_info[i].graphic = IMG_FONT_INITIAL_1;
321 for (i = 0; i < NUM_FONTS; i++)
322 font_info[i].graphic = FONT_INITIAL_1;
325 /* initialize normal font/graphic mapping from static configuration */
326 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
335 font_info[font_nr].graphic = graphic;
338 /* always start with reliable default values (special font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
341 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
343 font_info[i].special_graphic[j] = font_info[i].graphic;
344 font_info[i].special_bitmap_id[j] = i;
348 /* initialize special font/graphic mapping from static configuration */
349 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
351 int font_nr = font_to_graphic[i].font_nr;
352 int special = font_to_graphic[i].special;
353 int graphic = font_to_graphic[i].graphic;
355 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
357 font_info[font_nr].special_graphic[special] = graphic;
358 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
363 /* initialize special element/graphic mapping from dynamic configuration */
364 for (i = 0; i < num_property_mappings; i++)
366 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
367 int special = property_mapping[i].ext3_index;
368 int graphic = property_mapping[i].artwork_index;
373 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
375 font_info[font_nr].special_graphic[special] = graphic;
376 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
381 /* ---------- initialize font bitmap array ---------- */
383 if (font_bitmap_info != NULL)
384 FreeFontInfo(font_bitmap_info);
387 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
389 /* ---------- initialize font bitmap definitions ---------- */
391 for (i = 0; i < NUM_FONTS; i++)
393 if (i < NUM_INITIAL_FONTS)
395 font_bitmap_info[i] = font_initial[i];
399 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
401 int font_bitmap_id = font_info[i].special_bitmap_id[j];
402 int graphic = font_info[i].special_graphic[j];
404 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
405 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
407 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
408 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
411 /* copy font relevant information from graphics information */
412 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
413 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
414 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
415 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
416 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
417 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
418 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
420 font_bitmap_info[font_bitmap_id].num_chars =
421 graphic_info[graphic].anim_frames;
422 font_bitmap_info[font_bitmap_id].num_chars_per_line =
423 graphic_info[graphic].anim_frames_per_line;
427 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
430 void InitElementGraphicInfo()
432 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
433 int num_property_mappings = getImageListPropertyMappingSize();
436 if (graphic_info == NULL) /* still at startup phase */
439 /* set values to -1 to identify later as "uninitialized" values */
440 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
442 for (act = 0; act < NUM_ACTIONS; act++)
444 element_info[i].graphic[act] = -1;
445 element_info[i].crumbled[act] = -1;
447 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
449 element_info[i].direction_graphic[act][dir] = -1;
450 element_info[i].direction_crumbled[act][dir] = -1;
455 /* initialize normal element/graphic mapping from static configuration */
456 for (i = 0; element_to_graphic[i].element > -1; i++)
458 int element = element_to_graphic[i].element;
459 int action = element_to_graphic[i].action;
460 int direction = element_to_graphic[i].direction;
461 boolean crumbled = element_to_graphic[i].crumbled;
462 int graphic = element_to_graphic[i].graphic;
463 int base_graphic = el2baseimg(element);
465 if (graphic_info[graphic].bitmap == NULL)
468 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
471 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
472 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
474 /* if the base graphic ("emerald", for example) has been redefined,
475 but not the action graphic ("emerald.falling", for example), do not
476 use an existing (in this case considered obsolete) action graphic
477 anymore, but use the automatically determined default graphic */
478 if (base_redefined && !act_dir_redefined)
483 action = ACTION_DEFAULT;
488 element_info[element].direction_crumbled[action][direction] = graphic;
490 element_info[element].crumbled[action] = graphic;
495 element_info[element].direction_graphic[action][direction] = graphic;
497 element_info[element].graphic[action] = graphic;
501 /* initialize normal element/graphic mapping from dynamic configuration */
502 for (i = 0; i < num_property_mappings; i++)
504 int element = property_mapping[i].base_index;
505 int action = property_mapping[i].ext1_index;
506 int direction = property_mapping[i].ext2_index;
507 int special = property_mapping[i].ext3_index;
508 int graphic = property_mapping[i].artwork_index;
509 boolean crumbled = FALSE;
511 if (special == GFX_SPECIAL_ARG_CRUMBLED)
517 if (graphic_info[graphic].bitmap == NULL)
520 if (element >= MAX_NUM_ELEMENTS || special != -1)
524 action = ACTION_DEFAULT;
529 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
530 element_info[element].direction_crumbled[action][dir] = -1;
533 element_info[element].direction_crumbled[action][direction] = graphic;
535 element_info[element].crumbled[action] = graphic;
540 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
541 element_info[element].direction_graphic[action][dir] = -1;
544 element_info[element].direction_graphic[action][direction] = graphic;
546 element_info[element].graphic[action] = graphic;
550 /* now copy all graphics that are defined to be cloned from other graphics */
551 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
553 int graphic = element_info[i].graphic[ACTION_DEFAULT];
554 int crumbled_like, diggable_like;
559 crumbled_like = graphic_info[graphic].crumbled_like;
560 diggable_like = graphic_info[graphic].diggable_like;
562 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
564 for (act = 0; act < NUM_ACTIONS; act++)
565 element_info[i].crumbled[act] =
566 element_info[crumbled_like].crumbled[act];
567 for (act = 0; act < NUM_ACTIONS; act++)
568 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
569 element_info[i].direction_crumbled[act][dir] =
570 element_info[crumbled_like].direction_crumbled[act][dir];
573 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
575 element_info[i].graphic[ACTION_DIGGING] =
576 element_info[diggable_like].graphic[ACTION_DIGGING];
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
579 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
584 /* set hardcoded definitions for some runtime elements without graphic */
585 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
589 /* now set all undefined/invalid graphics to -1 to set to default after it */
590 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
592 for (act = 0; act < NUM_ACTIONS; act++)
596 graphic = element_info[i].graphic[act];
597 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
598 element_info[i].graphic[act] = -1;
600 graphic = element_info[i].crumbled[act];
601 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
602 element_info[i].crumbled[act] = -1;
604 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
606 graphic = element_info[i].direction_graphic[act][dir];
607 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
608 element_info[i].direction_graphic[act][dir] = -1;
610 graphic = element_info[i].direction_crumbled[act][dir];
611 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
612 element_info[i].direction_crumbled[act][dir] = -1;
618 /* now set all '-1' values to element specific default values */
619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
621 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
622 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
623 int default_direction_graphic[NUM_DIRECTIONS];
624 int default_direction_crumbled[NUM_DIRECTIONS];
626 if (default_graphic == -1)
627 default_graphic = IMG_UNKNOWN;
628 if (default_crumbled == -1)
629 default_crumbled = IMG_EMPTY;
631 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
633 default_direction_graphic[dir] =
634 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
635 default_direction_crumbled[dir] =
636 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
638 if (default_direction_graphic[dir] == -1)
639 default_direction_graphic[dir] = default_graphic;
640 if (default_direction_crumbled[dir] == -1)
641 default_direction_crumbled[dir] = default_crumbled;
644 for (act = 0; act < NUM_ACTIONS; act++)
646 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
647 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
648 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
649 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
650 act == ACTION_TURNING_FROM_RIGHT ||
651 act == ACTION_TURNING_FROM_UP ||
652 act == ACTION_TURNING_FROM_DOWN);
654 /* generic default action graphic (defined by "[default]" directive) */
655 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
656 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
658 /* look for special default action graphic (classic game specific) */
659 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
660 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
661 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
662 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
663 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
664 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
666 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
667 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
668 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
669 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
670 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
671 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
674 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
675 /* !!! make this better !!! */
676 if (i == EL_EMPTY_SPACE)
678 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
683 if (default_action_graphic == -1)
684 default_action_graphic = default_graphic;
685 if (default_action_crumbled == -1)
686 default_action_crumbled = default_crumbled;
688 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
690 int default_action_direction_graphic = element_info[i].graphic[act];
691 int default_action_direction_crumbled = element_info[i].crumbled[act];
693 /* no graphic for current action -- use default direction graphic */
694 if (default_action_direction_graphic == -1)
695 default_action_direction_graphic =
696 (act_remove ? IMG_EMPTY :
698 element_info[i].direction_graphic[ACTION_TURNING][dir] :
699 default_direction_graphic[dir]);
700 if (default_action_direction_crumbled == -1)
701 default_action_direction_crumbled =
702 (act_remove ? IMG_EMPTY :
704 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
705 default_direction_crumbled[dir]);
707 if (element_info[i].direction_graphic[act][dir] == -1)
708 element_info[i].direction_graphic[act][dir] =
709 default_action_direction_graphic;
710 if (element_info[i].direction_crumbled[act][dir] == -1)
711 element_info[i].direction_crumbled[act][dir] =
712 default_action_direction_crumbled;
715 /* no graphic for this specific action -- use default action graphic */
716 if (element_info[i].graphic[act] == -1)
717 element_info[i].graphic[act] =
718 (act_remove ? IMG_EMPTY :
719 act_turning ? element_info[i].graphic[ACTION_TURNING] :
720 default_action_graphic);
721 if (element_info[i].crumbled[act] == -1)
722 element_info[i].crumbled[act] =
723 (act_remove ? IMG_EMPTY :
724 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
725 default_action_crumbled);
730 /* set animation mode to "none" for each graphic with only 1 frame */
731 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
733 for (act = 0; act < NUM_ACTIONS; act++)
735 int graphic = element_info[i].graphic[act];
736 int crumbled = element_info[i].crumbled[act];
738 if (graphic_info[graphic].anim_frames == 1)
739 graphic_info[graphic].anim_mode = ANIM_NONE;
740 if (graphic_info[crumbled].anim_frames == 1)
741 graphic_info[crumbled].anim_mode = ANIM_NONE;
743 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
745 graphic = element_info[i].direction_graphic[act][dir];
746 crumbled = element_info[i].direction_crumbled[act][dir];
748 if (graphic_info[graphic].anim_frames == 1)
749 graphic_info[graphic].anim_mode = ANIM_NONE;
750 if (graphic_info[crumbled].anim_frames == 1)
751 graphic_info[crumbled].anim_mode = ANIM_NONE;
761 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
762 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
764 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
765 element_info[i].token_name, i);
771 void InitElementSpecialGraphicInfo()
773 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
774 int num_property_mappings = getImageListPropertyMappingSize();
777 /* always start with reliable default values */
778 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
779 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
780 element_info[i].special_graphic[j] =
781 element_info[i].graphic[ACTION_DEFAULT];
783 /* initialize special element/graphic mapping from static configuration */
784 for (i = 0; element_to_special_graphic[i].element > -1; i++)
786 int element = element_to_special_graphic[i].element;
787 int special = element_to_special_graphic[i].special;
788 int graphic = element_to_special_graphic[i].graphic;
789 int base_graphic = el2baseimg(element);
790 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
791 boolean special_redefined = getImageListEntry(graphic)->redefined;
793 /* if the base graphic ("emerald", for example) has been redefined,
794 but not the special graphic ("emerald.EDITOR", for example), do not
795 use an existing (in this case considered obsolete) special graphic
796 anymore, but use the automatically created (down-scaled) graphic */
797 if (base_redefined && !special_redefined)
800 element_info[element].special_graphic[special] = graphic;
803 /* initialize special element/graphic mapping from dynamic configuration */
804 for (i = 0; i < num_property_mappings; i++)
806 int element = property_mapping[i].base_index;
807 int special = property_mapping[i].ext3_index;
808 int graphic = property_mapping[i].artwork_index;
810 if (element >= MAX_NUM_ELEMENTS)
813 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
814 element_info[element].special_graphic[special] = graphic;
818 /* now set all undefined/invalid graphics to default */
819 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
821 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
822 element_info[i].special_graphic[j] =
823 element_info[i].graphic[ACTION_DEFAULT];
827 static int get_element_from_token(char *token)
831 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832 if (strcmp(element_info[i].token_name, token) == 0)
838 static void set_graphic_parameters(int graphic, char **parameter_raw)
840 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
841 int parameter[NUM_GFX_ARGS];
842 int anim_frames_per_row = 1, anim_frames_per_col = 1;
843 int anim_frames_per_line = 1;
846 /* get integer values from string parameters */
847 for (i = 0; i < NUM_GFX_ARGS; i++)
850 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
851 image_config_suffix[i].type);
853 if (image_config_suffix[i].type == TYPE_TOKEN)
854 parameter[i] = get_element_from_token(parameter_raw[i]);
857 graphic_info[graphic].bitmap = src_bitmap;
859 /* start with reliable default values */
860 graphic_info[graphic].src_x = 0;
861 graphic_info[graphic].src_y = 0;
862 graphic_info[graphic].width = TILEX;
863 graphic_info[graphic].height = TILEY;
864 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
865 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
866 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
867 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
868 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
869 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
870 graphic_info[graphic].anim_delay_fixed = 0;
871 graphic_info[graphic].anim_delay_random = 0;
872 graphic_info[graphic].post_delay_fixed = 0;
873 graphic_info[graphic].post_delay_random = 0;
875 /* optional x and y tile position of animation frame sequence */
876 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
877 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
878 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
879 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
881 /* optional x and y pixel position of animation frame sequence */
882 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
883 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
884 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
887 /* optional width and height of each animation frame */
888 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
889 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
890 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
891 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
895 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
896 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
899 /* correct x or y offset dependent of vertical or horizontal frame order */
900 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
902 graphic_info[graphic].offset_y =
903 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
904 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
905 anim_frames_per_line = anim_frames_per_col;
907 else /* frames are ordered horizontally */
909 graphic_info[graphic].offset_x =
910 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
911 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
912 anim_frames_per_line = anim_frames_per_row;
915 /* optionally, the x and y offset of frames can be specified directly */
916 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
917 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
918 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
919 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
921 /* automatically determine correct number of frames, if not defined */
922 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
923 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
924 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
925 graphic_info[graphic].anim_frames = anim_frames_per_row;
926 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
927 graphic_info[graphic].anim_frames = anim_frames_per_col;
929 graphic_info[graphic].anim_frames = 1;
931 graphic_info[graphic].anim_frames_per_line =
932 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
933 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
935 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
936 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
937 graphic_info[graphic].anim_delay = 1;
939 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
941 if (graphic_info[graphic].anim_frames == 1)
942 graphic_info[graphic].anim_mode = ANIM_NONE;
945 /* automatically determine correct start frame, if not defined */
946 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
947 graphic_info[graphic].anim_start_frame = 0;
948 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
949 graphic_info[graphic].anim_start_frame =
950 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
952 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
954 /* animation synchronized with global frame counter, not move position */
955 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
957 /* optional element for cloning crumble graphics */
958 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
959 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
961 /* optional element for cloning digging graphics */
962 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
963 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
965 /* optional border size for "crumbling" diggable graphics */
966 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
967 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
969 /* optional zoom factor for scaling up the image to a larger size */
970 if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
971 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
972 if (graphic_info[graphic].scale_up_factor < 1)
973 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
975 /* this is only used for player "boring" and "sleeping" actions */
976 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
977 graphic_info[graphic].anim_delay_fixed =
978 parameter[GFX_ARG_ANIM_DELAY_FIXED];
979 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
980 graphic_info[graphic].anim_delay_random =
981 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
982 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
983 graphic_info[graphic].post_delay_fixed =
984 parameter[GFX_ARG_POST_DELAY_FIXED];
985 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
986 graphic_info[graphic].post_delay_random =
987 parameter[GFX_ARG_POST_DELAY_RANDOM];
989 /* this is only used for toon animations */
990 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
991 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
993 /* this is only used for drawing font characters */
994 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
995 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
997 /* this is only used for drawing envelope graphics */
998 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1001 static void InitGraphicInfo()
1003 int fallback_graphic = IMG_CHAR_EXCLAM;
1004 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1005 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1006 int num_images = getImageListSize();
1009 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1010 static boolean clipmasks_initialized = FALSE;
1012 XGCValues clip_gc_values;
1013 unsigned long clip_gc_valuemask;
1014 GC copy_clipmask_gc = None;
1017 checked_free(graphic_info);
1019 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1022 printf("::: graphic_info: %d entries\n", num_images);
1025 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1026 if (clipmasks_initialized)
1028 for (i = 0; i < num_images; i++)
1030 if (graphic_info[i].clip_mask)
1031 XFreePixmap(display, graphic_info[i].clip_mask);
1032 if (graphic_info[i].clip_gc)
1033 XFreeGC(display, graphic_info[i].clip_gc);
1035 graphic_info[i].clip_mask = None;
1036 graphic_info[i].clip_gc = None;
1041 for (i = 0; i < num_images; i++)
1043 struct FileInfo *image = getImageListEntry(i);
1046 int first_frame, last_frame;
1049 printf("::: image: '%s' [%d]\n", image->token, i);
1053 printf("::: image # %d: '%s' ['%s']\n",
1055 getTokenFromImageID(i));
1058 set_graphic_parameters(i, image->parameter);
1060 /* now check if no animation frames are outside of the loaded image */
1062 if (graphic_info[i].bitmap == NULL)
1063 continue; /* skip check for optional images that are undefined */
1066 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1067 if (src_x < 0 || src_y < 0 ||
1068 src_x + TILEX > src_bitmap->width ||
1069 src_y + TILEY > src_bitmap->height)
1071 Error(ERR_RETURN_LINE, "-");
1072 Error(ERR_RETURN, "warning: error found in config file:");
1073 Error(ERR_RETURN, "- config file: '%s'",
1074 getImageConfigFilename());
1075 Error(ERR_RETURN, "- config token: '%s'",
1076 getTokenFromImageID(i));
1077 Error(ERR_RETURN, "- image file: '%s'",
1078 src_bitmap->source_filename);
1080 "error: first animation frame out of bounds (%d, %d)",
1082 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1084 if (i == fallback_graphic)
1085 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1087 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1088 Error(ERR_RETURN_LINE, "-");
1090 set_graphic_parameters(i, fallback_image->default_parameter);
1091 graphic_info[i].bitmap = fallback_bitmap;
1094 last_frame = graphic_info[i].anim_frames - 1;
1095 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1096 if (src_x < 0 || src_y < 0 ||
1097 src_x + TILEX > src_bitmap->width ||
1098 src_y + TILEY > src_bitmap->height)
1100 Error(ERR_RETURN_LINE, "-");
1101 Error(ERR_RETURN, "warning: error found in config file:");
1102 Error(ERR_RETURN, "- config file: '%s'",
1103 getImageConfigFilename());
1104 Error(ERR_RETURN, "- config token: '%s'",
1105 getTokenFromImageID(i));
1106 Error(ERR_RETURN, "- image file: '%s'",
1107 src_bitmap->source_filename);
1109 "error: last animation frame (%d) out of bounds (%d, %d)",
1110 last_frame, src_x, src_y);
1111 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1113 if (i == fallback_graphic)
1114 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1116 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1117 Error(ERR_RETURN_LINE, "-");
1119 set_graphic_parameters(i, fallback_image->default_parameter);
1120 graphic_info[i].bitmap = fallback_bitmap;
1123 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1124 /* currently we need only a tile clip mask from the first frame */
1125 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1127 if (copy_clipmask_gc == None)
1129 clip_gc_values.graphics_exposures = False;
1130 clip_gc_valuemask = GCGraphicsExposures;
1131 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1132 clip_gc_valuemask, &clip_gc_values);
1135 graphic_info[i].clip_mask =
1136 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1138 src_pixmap = src_bitmap->clip_mask;
1139 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1140 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1142 clip_gc_values.graphics_exposures = False;
1143 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1144 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1146 graphic_info[i].clip_gc =
1147 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1151 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1152 if (copy_clipmask_gc)
1153 XFreeGC(display, copy_clipmask_gc);
1155 clipmasks_initialized = TRUE;
1159 static void InitElementSoundInfo()
1161 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1162 int num_property_mappings = getSoundListPropertyMappingSize();
1165 /* set values to -1 to identify later as "uninitialized" values */
1166 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1167 for (act = 0; act < NUM_ACTIONS; act++)
1168 element_info[i].sound[act] = -1;
1170 /* initialize element/sound mapping from static configuration */
1171 for (i = 0; element_to_sound[i].element > -1; i++)
1173 int element = element_to_sound[i].element;
1174 int action = element_to_sound[i].action;
1175 int sound = element_to_sound[i].sound;
1176 boolean is_class = element_to_sound[i].is_class;
1179 action = ACTION_DEFAULT;
1182 element_info[element].sound[action] = sound;
1184 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1185 if (strcmp(element_info[j].class_name,
1186 element_info[element].class_name) == 0)
1187 element_info[j].sound[action] = sound;
1190 /* initialize element class/sound mapping from dynamic configuration */
1191 for (i = 0; i < num_property_mappings; i++)
1193 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1194 int action = property_mapping[i].ext1_index;
1195 int sound = property_mapping[i].artwork_index;
1197 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1201 action = ACTION_DEFAULT;
1203 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1204 if (strcmp(element_info[j].class_name,
1205 element_info[element_class].class_name) == 0)
1206 element_info[j].sound[action] = sound;
1209 /* initialize element/sound mapping from dynamic configuration */
1210 for (i = 0; i < num_property_mappings; i++)
1212 int element = property_mapping[i].base_index;
1213 int action = property_mapping[i].ext1_index;
1214 int sound = property_mapping[i].artwork_index;
1216 if (element >= MAX_NUM_ELEMENTS)
1220 action = ACTION_DEFAULT;
1222 element_info[element].sound[action] = sound;
1225 /* now set all '-1' values to element specific default values */
1226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1228 for (act = 0; act < NUM_ACTIONS; act++)
1230 /* generic default action sound (defined by "[default]" directive) */
1231 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1233 /* look for special default action sound (classic game specific) */
1234 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1235 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1236 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1237 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1238 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1239 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1241 /* !!! there's no such thing as a "default action sound" !!! */
1243 /* look for element specific default sound (independent from action) */
1244 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1245 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1248 /* no sound for this specific action -- use default action sound */
1249 if (element_info[i].sound[act] == -1)
1250 element_info[i].sound[act] = default_action_sound;
1255 static void InitGameModeSoundInfo()
1259 /* set values to -1 to identify later as "uninitialized" values */
1260 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1263 /* initialize gamemode/sound mapping from static configuration */
1264 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1266 int gamemode = gamemode_to_sound[i].gamemode;
1267 int sound = gamemode_to_sound[i].sound;
1270 gamemode = GAME_MODE_DEFAULT;
1272 menu.sound[gamemode] = sound;
1275 /* now set all '-1' values to levelset specific default values */
1276 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1277 if (menu.sound[i] == -1)
1278 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1282 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1283 if (menu.sound[i] != -1)
1284 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1288 static void set_sound_parameters(int sound, char **parameter_raw)
1290 int parameter[NUM_SND_ARGS];
1293 /* get integer values from string parameters */
1294 for (i = 0; i < NUM_SND_ARGS; i++)
1296 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1297 sound_config_suffix[i].type);
1299 /* explicit loop mode setting in configuration overrides default value */
1300 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1301 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1303 /* sound volume to change the original volume when loading the sound file */
1304 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1306 /* sound priority to give certain sounds a higher or lower priority */
1307 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1310 static void InitSoundInfo()
1313 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1314 int num_property_mappings = getSoundListPropertyMappingSize();
1316 int *sound_effect_properties;
1317 int num_sounds = getSoundListSize();
1320 checked_free(sound_info);
1322 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1323 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1325 /* initialize sound effect for all elements to "no sound" */
1326 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1327 for (j = 0; j < NUM_ACTIONS; j++)
1328 element_info[i].sound[j] = SND_UNDEFINED;
1330 for (i = 0; i < num_sounds; i++)
1332 struct FileInfo *sound = getSoundListEntry(i);
1333 int len_effect_text = strlen(sound->token);
1335 sound_effect_properties[i] = ACTION_OTHER;
1336 sound_info[i].loop = FALSE; /* default: play sound only once */
1339 printf("::: sound %d: '%s'\n", i, sound->token);
1342 /* determine all loop sounds and identify certain sound classes */
1344 for (j = 0; element_action_info[j].suffix; j++)
1346 int len_action_text = strlen(element_action_info[j].suffix);
1348 if (len_action_text < len_effect_text &&
1349 strcmp(&sound->token[len_effect_text - len_action_text],
1350 element_action_info[j].suffix) == 0)
1352 sound_effect_properties[i] = element_action_info[j].value;
1353 sound_info[i].loop = element_action_info[j].is_loop_sound;
1360 if (strcmp(sound->token, "custom_42") == 0)
1361 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1364 /* associate elements and some selected sound actions */
1366 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1368 if (element_info[j].class_name)
1370 int len_class_text = strlen(element_info[j].class_name);
1372 if (len_class_text + 1 < len_effect_text &&
1373 strncmp(sound->token,
1374 element_info[j].class_name, len_class_text) == 0 &&
1375 sound->token[len_class_text] == '.')
1377 int sound_action_value = sound_effect_properties[i];
1379 element_info[j].sound[sound_action_value] = i;
1384 set_sound_parameters(i, sound->parameter);
1387 free(sound_effect_properties);
1390 /* !!! now handled in InitElementSoundInfo() !!! */
1391 /* initialize element/sound mapping from dynamic configuration */
1392 for (i = 0; i < num_property_mappings; i++)
1394 int element = property_mapping[i].base_index;
1395 int action = property_mapping[i].ext1_index;
1396 int sound = property_mapping[i].artwork_index;
1399 action = ACTION_DEFAULT;
1401 printf("::: %d: %d, %d, %d ['%s']\n",
1402 i, element, action, sound, element_info[element].token_name);
1404 element_info[element].sound[action] = sound;
1411 int element = EL_CUSTOM_11;
1414 while (element_action_info[j].suffix)
1416 printf("element %d, sound action '%s' == %d\n",
1417 element, element_action_info[j].suffix,
1418 element_info[element].sound[j]);
1423 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1429 int element = EL_SAND;
1430 int sound_action = ACTION_DIGGING;
1433 while (element_action_info[j].suffix)
1435 if (element_action_info[j].value == sound_action)
1436 printf("element %d, sound action '%s' == %d\n",
1437 element, element_action_info[j].suffix,
1438 element_info[element].sound[sound_action]);
1445 static void InitGameModeMusicInfo()
1447 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1448 int num_property_mappings = getMusicListPropertyMappingSize();
1449 int default_levelset_music = -1;
1452 /* set values to -1 to identify later as "uninitialized" values */
1453 for (i = 0; i < MAX_LEVELS; i++)
1454 levelset.music[i] = -1;
1455 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1458 /* initialize gamemode/music mapping from static configuration */
1459 for (i = 0; gamemode_to_music[i].music > -1; i++)
1461 int gamemode = gamemode_to_music[i].gamemode;
1462 int music = gamemode_to_music[i].music;
1465 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1469 gamemode = GAME_MODE_DEFAULT;
1471 menu.music[gamemode] = music;
1474 /* initialize gamemode/music mapping from dynamic configuration */
1475 for (i = 0; i < num_property_mappings; i++)
1477 int prefix = property_mapping[i].base_index;
1478 int gamemode = property_mapping[i].ext1_index;
1479 int level = property_mapping[i].ext2_index;
1480 int music = property_mapping[i].artwork_index;
1483 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1484 prefix, gamemode, level, music);
1487 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1491 gamemode = GAME_MODE_DEFAULT;
1493 /* level specific music only allowed for in-game music */
1494 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1495 gamemode = GAME_MODE_PLAYING;
1500 default_levelset_music = music;
1503 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1504 levelset.music[level] = music;
1505 if (gamemode != GAME_MODE_PLAYING)
1506 menu.music[gamemode] = music;
1509 /* now set all '-1' values to menu specific default values */
1510 /* (undefined values of "levelset.music[]" might stay at "-1" to
1511 allow dynamic selection of music files from music directory!) */
1512 for (i = 0; i < MAX_LEVELS; i++)
1513 if (levelset.music[i] == -1)
1514 levelset.music[i] = default_levelset_music;
1515 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1516 if (menu.music[i] == -1)
1517 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1521 for (i = 0; i < MAX_LEVELS; i++)
1522 if (levelset.music[i] != -1)
1523 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1524 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1525 if (menu.music[i] != -1)
1526 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1530 static void set_music_parameters(int music, char **parameter_raw)
1532 int parameter[NUM_MUS_ARGS];
1535 /* get integer values from string parameters */
1536 for (i = 0; i < NUM_MUS_ARGS; i++)
1538 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1539 music_config_suffix[i].type);
1541 /* explicit loop mode setting in configuration overrides default value */
1542 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1543 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1546 static void InitMusicInfo()
1548 int num_music = getMusicListSize();
1551 checked_free(music_info);
1553 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1555 for (i = 0; i < num_music; i++)
1557 struct FileInfo *music = getMusicListEntry(i);
1558 int len_music_text = strlen(music->token);
1560 music_info[i].loop = TRUE; /* default: play music in loop mode */
1562 /* determine all loop music */
1564 for (j = 0; music_prefix_info[j].prefix; j++)
1566 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1568 if (len_prefix_text < len_music_text &&
1569 strncmp(music->token,
1570 music_prefix_info[j].prefix, len_prefix_text) == 0)
1572 music_info[i].loop = music_prefix_info[j].is_loop_music;
1578 set_music_parameters(i, music->parameter);
1582 static void ReinitializeGraphics()
1584 InitGraphicInfo(); /* graphic properties mapping */
1585 InitElementGraphicInfo(); /* element game graphic mapping */
1586 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1588 InitElementSmallImages(); /* create editor and preview images */
1589 InitFontGraphicInfo(); /* initialize text drawing functions */
1591 SetMainBackgroundImage(IMG_BACKGROUND);
1592 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1598 static void ReinitializeSounds()
1600 InitSoundInfo(); /* sound properties mapping */
1601 InitElementSoundInfo(); /* element game sound mapping */
1602 InitGameModeSoundInfo(); /* game mode sound mapping */
1604 InitPlayLevelSound(); /* internal game sound settings */
1607 static void ReinitializeMusic()
1609 InitMusicInfo(); /* music properties mapping */
1610 InitGameModeMusicInfo(); /* game mode music mapping */
1613 static int get_special_property_bit(int element, int property_bit_nr)
1615 struct PropertyBitInfo
1621 static struct PropertyBitInfo pb_can_move_into_acid[] =
1623 /* the player may be able fall into acid when gravity is activated */
1628 { EL_SP_MURPHY, 0 },
1629 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1631 /* all element that can move may be able to also move into acid */
1634 { EL_BUG_RIGHT, 1 },
1637 { EL_SPACESHIP, 2 },
1638 { EL_SPACESHIP_LEFT, 2 },
1639 { EL_SPACESHIP_RIGHT, 2 },
1640 { EL_SPACESHIP_UP, 2 },
1641 { EL_SPACESHIP_DOWN, 2 },
1642 { EL_BD_BUTTERFLY, 3 },
1643 { EL_BD_BUTTERFLY_LEFT, 3 },
1644 { EL_BD_BUTTERFLY_RIGHT, 3 },
1645 { EL_BD_BUTTERFLY_UP, 3 },
1646 { EL_BD_BUTTERFLY_DOWN, 3 },
1647 { EL_BD_FIREFLY, 4 },
1648 { EL_BD_FIREFLY_LEFT, 4 },
1649 { EL_BD_FIREFLY_RIGHT, 4 },
1650 { EL_BD_FIREFLY_UP, 4 },
1651 { EL_BD_FIREFLY_DOWN, 4 },
1653 { EL_DARK_YAMYAM, 6 },
1656 { EL_PACMAN_LEFT, 8 },
1657 { EL_PACMAN_RIGHT, 8 },
1658 { EL_PACMAN_UP, 8 },
1659 { EL_PACMAN_DOWN, 8 },
1661 { EL_MOLE_LEFT, 9 },
1662 { EL_MOLE_RIGHT, 9 },
1664 { EL_MOLE_DOWN, 9 },
1668 { EL_SATELLITE, 13 },
1669 { EL_SP_SNIKSNAK, 14 },
1670 { EL_SP_ELECTRON, 15 },
1677 static struct PropertyBitInfo pb_dont_collide_with[] =
1679 { EL_SP_SNIKSNAK, 0 },
1680 { EL_SP_ELECTRON, 1 },
1688 struct PropertyBitInfo *pb_info;
1691 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1692 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1697 struct PropertyBitInfo *pb_info = NULL;
1700 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1701 if (pb_definition[i].bit_nr == property_bit_nr)
1702 pb_info = pb_definition[i].pb_info;
1704 if (pb_info == NULL)
1707 for (i = 0; pb_info[i].element != -1; i++)
1708 if (pb_info[i].element == element)
1709 return pb_info[i].bit_nr;
1715 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1716 boolean property_value)
1718 int bit_nr = get_special_property_bit(element, property_bit_nr);
1723 *bitfield |= (1 << bit_nr);
1725 *bitfield &= ~(1 << bit_nr);
1729 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1731 int bit_nr = get_special_property_bit(element, property_bit_nr);
1734 return ((*bitfield & (1 << bit_nr)) != 0);
1741 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1743 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1747 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1750 level->can_move_into_acid_bits |= (1 << bit_nr);
1754 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1756 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1759 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1765 void InitElementPropertiesStatic()
1767 static int ep_diggable[] =
1772 EL_SP_BUGGY_BASE_ACTIVATING,
1775 EL_INVISIBLE_SAND_ACTIVE,
1777 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1778 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1782 EL_SP_BUGGY_BASE_ACTIVE,
1787 static int ep_collectible_only[] =
1804 EL_DYNABOMB_INCREASE_NUMBER,
1805 EL_DYNABOMB_INCREASE_SIZE,
1806 EL_DYNABOMB_INCREASE_POWER,
1823 static int ep_dont_run_into[] =
1825 /* same elements as in 'ep_dont_touch' */
1831 /* same elements as in 'ep_dont_collide_with' */
1843 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1847 EL_SP_BUGGY_BASE_ACTIVE,
1852 static int ep_dont_collide_with[] =
1854 /* same elements as in 'ep_dont_touch' */
1870 static int ep_dont_touch[] =
1879 static int ep_indestructible[] =
1883 EL_ACID_POOL_TOPLEFT,
1884 EL_ACID_POOL_TOPRIGHT,
1885 EL_ACID_POOL_BOTTOMLEFT,
1886 EL_ACID_POOL_BOTTOM,
1887 EL_ACID_POOL_BOTTOMRIGHT,
1888 EL_SP_HARDWARE_GRAY,
1889 EL_SP_HARDWARE_GREEN,
1890 EL_SP_HARDWARE_BLUE,
1892 EL_SP_HARDWARE_YELLOW,
1893 EL_SP_HARDWARE_BASE_1,
1894 EL_SP_HARDWARE_BASE_2,
1895 EL_SP_HARDWARE_BASE_3,
1896 EL_SP_HARDWARE_BASE_4,
1897 EL_SP_HARDWARE_BASE_5,
1898 EL_SP_HARDWARE_BASE_6,
1899 EL_INVISIBLE_STEELWALL,
1900 EL_INVISIBLE_STEELWALL_ACTIVE,
1901 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1902 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1903 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1904 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1905 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1906 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1907 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1908 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1909 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1910 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1911 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1912 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1914 EL_LIGHT_SWITCH_ACTIVE,
1915 EL_SIGN_EXCLAMATION,
1916 EL_SIGN_RADIOACTIVITY,
1927 EL_STEELWALL_SLIPPERY,
1950 EL_SWITCHGATE_OPENING,
1951 EL_SWITCHGATE_CLOSED,
1952 EL_SWITCHGATE_CLOSING,
1954 EL_SWITCHGATE_SWITCH_UP,
1955 EL_SWITCHGATE_SWITCH_DOWN,
1958 EL_TIMEGATE_OPENING,
1960 EL_TIMEGATE_CLOSING,
1963 EL_TIMEGATE_SWITCH_ACTIVE,
1968 EL_TUBE_VERTICAL_LEFT,
1969 EL_TUBE_VERTICAL_RIGHT,
1970 EL_TUBE_HORIZONTAL_UP,
1971 EL_TUBE_HORIZONTAL_DOWN,
1979 static int ep_slippery[] =
1993 EL_ROBOT_WHEEL_ACTIVE,
1999 EL_ACID_POOL_TOPLEFT,
2000 EL_ACID_POOL_TOPRIGHT,
2010 EL_STEELWALL_SLIPPERY,
2016 static int ep_can_change[] =
2021 static int ep_can_move[] =
2023 /* same elements as in 'pb_can_move_into_acid' */
2044 static int ep_can_fall[] =
2059 EL_BD_MAGIC_WALL_FULL,
2072 static int ep_can_smash_player[] =
2097 static int ep_can_smash_enemies[] =
2105 static int ep_can_smash_everything[] =
2113 static int ep_explodes_by_fire[] =
2115 /* same elements as in 'ep_explodes_impact' */
2120 /* same elements as in 'ep_explodes_smashed' */
2129 EL_DYNABOMB_PLAYER_1_ACTIVE,
2130 EL_DYNABOMB_PLAYER_2_ACTIVE,
2131 EL_DYNABOMB_PLAYER_3_ACTIVE,
2132 EL_DYNABOMB_PLAYER_4_ACTIVE,
2133 EL_DYNABOMB_INCREASE_NUMBER,
2134 EL_DYNABOMB_INCREASE_SIZE,
2135 EL_DYNABOMB_INCREASE_POWER,
2136 EL_SP_DISK_RED_ACTIVE,
2149 static int ep_explodes_smashed[] =
2151 /* same elements as in 'ep_explodes_impact' */
2164 static int ep_explodes_impact[] =
2172 static int ep_walkable_over[] =
2176 EL_SOKOBAN_FIELD_EMPTY,
2194 static int ep_walkable_inside[] =
2199 EL_TUBE_VERTICAL_LEFT,
2200 EL_TUBE_VERTICAL_RIGHT,
2201 EL_TUBE_HORIZONTAL_UP,
2202 EL_TUBE_HORIZONTAL_DOWN,
2210 static int ep_walkable_under[] =
2215 static int ep_passable_over[] =
2230 static int ep_passable_inside[] =
2236 EL_SP_PORT_HORIZONTAL,
2237 EL_SP_PORT_VERTICAL,
2239 EL_SP_GRAVITY_PORT_LEFT,
2240 EL_SP_GRAVITY_PORT_RIGHT,
2241 EL_SP_GRAVITY_PORT_UP,
2242 EL_SP_GRAVITY_PORT_DOWN,
2243 EL_SP_GRAVITY_ON_PORT_LEFT,
2244 EL_SP_GRAVITY_ON_PORT_RIGHT,
2245 EL_SP_GRAVITY_ON_PORT_UP,
2246 EL_SP_GRAVITY_ON_PORT_DOWN,
2247 EL_SP_GRAVITY_OFF_PORT_LEFT,
2248 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2249 EL_SP_GRAVITY_OFF_PORT_UP,
2250 EL_SP_GRAVITY_OFF_PORT_DOWN,
2254 static int ep_passable_under[] =
2259 static int ep_droppable[] =
2264 static int ep_explodes_1x1_old[] =
2269 static int ep_pushable[] =
2281 EL_SOKOBAN_FIELD_FULL,
2288 static int ep_explodes_cross_old[] =
2293 static int ep_protected[] =
2295 /* same elements as in 'ep_walkable_inside' */
2299 EL_TUBE_VERTICAL_LEFT,
2300 EL_TUBE_VERTICAL_RIGHT,
2301 EL_TUBE_HORIZONTAL_UP,
2302 EL_TUBE_HORIZONTAL_DOWN,
2308 /* same elements as in 'ep_passable_over' */
2320 /* same elements as in 'ep_passable_inside' */
2325 EL_SP_PORT_HORIZONTAL,
2326 EL_SP_PORT_VERTICAL,
2328 EL_SP_GRAVITY_PORT_LEFT,
2329 EL_SP_GRAVITY_PORT_RIGHT,
2330 EL_SP_GRAVITY_PORT_UP,
2331 EL_SP_GRAVITY_PORT_DOWN,
2332 EL_SP_GRAVITY_ON_PORT_LEFT,
2333 EL_SP_GRAVITY_ON_PORT_RIGHT,
2334 EL_SP_GRAVITY_ON_PORT_UP,
2335 EL_SP_GRAVITY_ON_PORT_DOWN,
2336 EL_SP_GRAVITY_OFF_PORT_LEFT,
2337 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2338 EL_SP_GRAVITY_OFF_PORT_UP,
2339 EL_SP_GRAVITY_OFF_PORT_DOWN,
2343 static int ep_throwable[] =
2348 static int ep_can_explode[] =
2350 /* same elements as in 'ep_explodes_impact' */
2355 /* same elements as in 'ep_explodes_smashed' */
2361 /* elements that can explode by explosion or by dragonfire */
2364 EL_DYNABOMB_PLAYER_1_ACTIVE,
2365 EL_DYNABOMB_PLAYER_2_ACTIVE,
2366 EL_DYNABOMB_PLAYER_3_ACTIVE,
2367 EL_DYNABOMB_PLAYER_4_ACTIVE,
2368 EL_DYNABOMB_INCREASE_NUMBER,
2369 EL_DYNABOMB_INCREASE_SIZE,
2370 EL_DYNABOMB_INCREASE_POWER,
2371 EL_SP_DISK_RED_ACTIVE,
2379 /* elements that can explode only by explosion */
2384 static int ep_gravity_reachable[] =
2390 EL_INVISIBLE_SAND_ACTIVE,
2395 EL_SP_PORT_HORIZONTAL,
2396 EL_SP_PORT_VERTICAL,
2398 EL_SP_GRAVITY_PORT_LEFT,
2399 EL_SP_GRAVITY_PORT_RIGHT,
2400 EL_SP_GRAVITY_PORT_UP,
2401 EL_SP_GRAVITY_PORT_DOWN,
2402 EL_SP_GRAVITY_ON_PORT_LEFT,
2403 EL_SP_GRAVITY_ON_PORT_RIGHT,
2404 EL_SP_GRAVITY_ON_PORT_UP,
2405 EL_SP_GRAVITY_ON_PORT_DOWN,
2406 EL_SP_GRAVITY_OFF_PORT_LEFT,
2407 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2408 EL_SP_GRAVITY_OFF_PORT_UP,
2409 EL_SP_GRAVITY_OFF_PORT_DOWN,
2413 static int ep_player[] =
2420 EL_SOKOBAN_FIELD_PLAYER,
2425 static int ep_can_pass_magic_wall[] =
2438 static int ep_switchable[] =
2442 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2443 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2444 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2445 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2446 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2447 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2448 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2449 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2450 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2451 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2452 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2453 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2454 EL_SWITCHGATE_SWITCH_UP,
2455 EL_SWITCHGATE_SWITCH_DOWN,
2457 EL_LIGHT_SWITCH_ACTIVE,
2459 EL_BALLOON_SWITCH_LEFT,
2460 EL_BALLOON_SWITCH_RIGHT,
2461 EL_BALLOON_SWITCH_UP,
2462 EL_BALLOON_SWITCH_DOWN,
2463 EL_BALLOON_SWITCH_ANY,
2469 static int ep_bd_element[] =
2502 static int ep_sp_element[] =
2504 /* should always be valid */
2507 /* standard classic Supaplex elements */
2514 EL_SP_HARDWARE_GRAY,
2522 EL_SP_GRAVITY_PORT_RIGHT,
2523 EL_SP_GRAVITY_PORT_DOWN,
2524 EL_SP_GRAVITY_PORT_LEFT,
2525 EL_SP_GRAVITY_PORT_UP,
2530 EL_SP_PORT_VERTICAL,
2531 EL_SP_PORT_HORIZONTAL,
2537 EL_SP_HARDWARE_BASE_1,
2538 EL_SP_HARDWARE_GREEN,
2539 EL_SP_HARDWARE_BLUE,
2541 EL_SP_HARDWARE_YELLOW,
2542 EL_SP_HARDWARE_BASE_2,
2543 EL_SP_HARDWARE_BASE_3,
2544 EL_SP_HARDWARE_BASE_4,
2545 EL_SP_HARDWARE_BASE_5,
2546 EL_SP_HARDWARE_BASE_6,
2550 /* additional elements that appeared in newer Supaplex levels */
2553 /* additional gravity port elements (not switching, but setting gravity) */
2554 EL_SP_GRAVITY_ON_PORT_LEFT,
2555 EL_SP_GRAVITY_ON_PORT_RIGHT,
2556 EL_SP_GRAVITY_ON_PORT_UP,
2557 EL_SP_GRAVITY_ON_PORT_DOWN,
2558 EL_SP_GRAVITY_OFF_PORT_LEFT,
2559 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2560 EL_SP_GRAVITY_OFF_PORT_UP,
2561 EL_SP_GRAVITY_OFF_PORT_DOWN,
2563 /* more than one Murphy in a level results in an inactive clone */
2566 /* runtime Supaplex elements */
2567 EL_SP_DISK_RED_ACTIVE,
2568 EL_SP_TERMINAL_ACTIVE,
2569 EL_SP_BUGGY_BASE_ACTIVATING,
2570 EL_SP_BUGGY_BASE_ACTIVE,
2576 static int ep_sb_element[] =
2581 EL_SOKOBAN_FIELD_EMPTY,
2582 EL_SOKOBAN_FIELD_FULL,
2583 EL_SOKOBAN_FIELD_PLAYER,
2588 EL_INVISIBLE_STEELWALL,
2592 static int ep_gem[] =
2603 static int ep_food_dark_yamyam[] =
2630 static int ep_food_penguin[] =
2643 static int ep_food_pig[] =
2654 static int ep_historic_wall[] =
2679 EL_EXPANDABLE_WALL_HORIZONTAL,
2680 EL_EXPANDABLE_WALL_VERTICAL,
2681 EL_EXPANDABLE_WALL_ANY,
2682 EL_EXPANDABLE_WALL_GROWING,
2689 EL_SP_HARDWARE_GRAY,
2690 EL_SP_HARDWARE_GREEN,
2691 EL_SP_HARDWARE_BLUE,
2693 EL_SP_HARDWARE_YELLOW,
2694 EL_SP_HARDWARE_BASE_1,
2695 EL_SP_HARDWARE_BASE_2,
2696 EL_SP_HARDWARE_BASE_3,
2697 EL_SP_HARDWARE_BASE_4,
2698 EL_SP_HARDWARE_BASE_5,
2699 EL_SP_HARDWARE_BASE_6,
2701 EL_SP_TERMINAL_ACTIVE,
2704 EL_INVISIBLE_STEELWALL,
2705 EL_INVISIBLE_STEELWALL_ACTIVE,
2707 EL_INVISIBLE_WALL_ACTIVE,
2708 EL_STEELWALL_SLIPPERY,
2724 static int ep_historic_solid[] =
2728 EL_EXPANDABLE_WALL_HORIZONTAL,
2729 EL_EXPANDABLE_WALL_VERTICAL,
2730 EL_EXPANDABLE_WALL_ANY,
2743 EL_QUICKSAND_FILLING,
2744 EL_QUICKSAND_EMPTYING,
2746 EL_MAGIC_WALL_ACTIVE,
2747 EL_MAGIC_WALL_EMPTYING,
2748 EL_MAGIC_WALL_FILLING,
2752 EL_BD_MAGIC_WALL_ACTIVE,
2753 EL_BD_MAGIC_WALL_EMPTYING,
2754 EL_BD_MAGIC_WALL_FULL,
2755 EL_BD_MAGIC_WALL_FILLING,
2756 EL_BD_MAGIC_WALL_DEAD,
2765 EL_SP_TERMINAL_ACTIVE,
2769 EL_INVISIBLE_WALL_ACTIVE,
2770 EL_SWITCHGATE_SWITCH_UP,
2771 EL_SWITCHGATE_SWITCH_DOWN,
2773 EL_TIMEGATE_SWITCH_ACTIVE,
2785 /* the following elements are a direct copy of "indestructible" elements,
2786 except "EL_ACID", which is "indestructible", but not "solid"! */
2791 EL_ACID_POOL_TOPLEFT,
2792 EL_ACID_POOL_TOPRIGHT,
2793 EL_ACID_POOL_BOTTOMLEFT,
2794 EL_ACID_POOL_BOTTOM,
2795 EL_ACID_POOL_BOTTOMRIGHT,
2796 EL_SP_HARDWARE_GRAY,
2797 EL_SP_HARDWARE_GREEN,
2798 EL_SP_HARDWARE_BLUE,
2800 EL_SP_HARDWARE_YELLOW,
2801 EL_SP_HARDWARE_BASE_1,
2802 EL_SP_HARDWARE_BASE_2,
2803 EL_SP_HARDWARE_BASE_3,
2804 EL_SP_HARDWARE_BASE_4,
2805 EL_SP_HARDWARE_BASE_5,
2806 EL_SP_HARDWARE_BASE_6,
2807 EL_INVISIBLE_STEELWALL,
2808 EL_INVISIBLE_STEELWALL_ACTIVE,
2809 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2810 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2811 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2812 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2813 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2814 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2815 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2816 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2817 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2818 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2819 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2820 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2822 EL_LIGHT_SWITCH_ACTIVE,
2823 EL_SIGN_EXCLAMATION,
2824 EL_SIGN_RADIOACTIVITY,
2835 EL_STEELWALL_SLIPPERY,
2858 EL_SWITCHGATE_OPENING,
2859 EL_SWITCHGATE_CLOSED,
2860 EL_SWITCHGATE_CLOSING,
2862 EL_TIMEGATE_OPENING,
2864 EL_TIMEGATE_CLOSING,
2868 EL_TUBE_VERTICAL_LEFT,
2869 EL_TUBE_VERTICAL_RIGHT,
2870 EL_TUBE_HORIZONTAL_UP,
2871 EL_TUBE_HORIZONTAL_DOWN,
2879 static int ep_classic_enemy[] =
2895 static int ep_belt[] =
2897 EL_CONVEYOR_BELT_1_LEFT,
2898 EL_CONVEYOR_BELT_1_MIDDLE,
2899 EL_CONVEYOR_BELT_1_RIGHT,
2900 EL_CONVEYOR_BELT_2_LEFT,
2901 EL_CONVEYOR_BELT_2_MIDDLE,
2902 EL_CONVEYOR_BELT_2_RIGHT,
2903 EL_CONVEYOR_BELT_3_LEFT,
2904 EL_CONVEYOR_BELT_3_MIDDLE,
2905 EL_CONVEYOR_BELT_3_RIGHT,
2906 EL_CONVEYOR_BELT_4_LEFT,
2907 EL_CONVEYOR_BELT_4_MIDDLE,
2908 EL_CONVEYOR_BELT_4_RIGHT,
2912 static int ep_belt_active[] =
2914 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2915 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2916 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2917 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2918 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2919 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2920 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2921 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2922 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2923 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2924 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2925 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2929 static int ep_belt_switch[] =
2931 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2932 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2933 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2934 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2935 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2936 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2937 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2938 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2939 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2940 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2941 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2942 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2946 static int ep_tube[] =
2953 EL_TUBE_HORIZONTAL_UP,
2954 EL_TUBE_HORIZONTAL_DOWN,
2956 EL_TUBE_VERTICAL_LEFT,
2957 EL_TUBE_VERTICAL_RIGHT,
2962 static int ep_keygate[] =
2983 static int ep_amoeboid[] =
2993 static int ep_amoebalive[] =
3002 static int ep_has_content[] =
3012 static int ep_can_turn_each_move[] =
3014 /* !!! do something with this one !!! */
3018 static int ep_can_grow[] =
3030 static int ep_active_bomb[] =
3033 EL_DYNABOMB_PLAYER_1_ACTIVE,
3034 EL_DYNABOMB_PLAYER_2_ACTIVE,
3035 EL_DYNABOMB_PLAYER_3_ACTIVE,
3036 EL_DYNABOMB_PLAYER_4_ACTIVE,
3037 EL_SP_DISK_RED_ACTIVE,
3041 static int ep_inactive[] =
3078 EL_INVISIBLE_STEELWALL,
3086 EL_WALL_EMERALD_YELLOW,
3087 EL_DYNABOMB_INCREASE_NUMBER,
3088 EL_DYNABOMB_INCREASE_SIZE,
3089 EL_DYNABOMB_INCREASE_POWER,
3093 EL_SOKOBAN_FIELD_EMPTY,
3094 EL_SOKOBAN_FIELD_FULL,
3095 EL_WALL_EMERALD_RED,
3096 EL_WALL_EMERALD_PURPLE,
3097 EL_ACID_POOL_TOPLEFT,
3098 EL_ACID_POOL_TOPRIGHT,
3099 EL_ACID_POOL_BOTTOMLEFT,
3100 EL_ACID_POOL_BOTTOM,
3101 EL_ACID_POOL_BOTTOMRIGHT,
3105 EL_BD_MAGIC_WALL_DEAD,
3106 EL_AMOEBA_TO_DIAMOND,
3114 EL_SP_GRAVITY_PORT_RIGHT,
3115 EL_SP_GRAVITY_PORT_DOWN,
3116 EL_SP_GRAVITY_PORT_LEFT,
3117 EL_SP_GRAVITY_PORT_UP,
3118 EL_SP_PORT_HORIZONTAL,
3119 EL_SP_PORT_VERTICAL,
3130 EL_SP_HARDWARE_GRAY,
3131 EL_SP_HARDWARE_GREEN,
3132 EL_SP_HARDWARE_BLUE,
3134 EL_SP_HARDWARE_YELLOW,
3135 EL_SP_HARDWARE_BASE_1,
3136 EL_SP_HARDWARE_BASE_2,
3137 EL_SP_HARDWARE_BASE_3,
3138 EL_SP_HARDWARE_BASE_4,
3139 EL_SP_HARDWARE_BASE_5,
3140 EL_SP_HARDWARE_BASE_6,
3141 EL_SP_GRAVITY_ON_PORT_LEFT,
3142 EL_SP_GRAVITY_ON_PORT_RIGHT,
3143 EL_SP_GRAVITY_ON_PORT_UP,
3144 EL_SP_GRAVITY_ON_PORT_DOWN,
3145 EL_SP_GRAVITY_OFF_PORT_LEFT,
3146 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3147 EL_SP_GRAVITY_OFF_PORT_UP,
3148 EL_SP_GRAVITY_OFF_PORT_DOWN,
3149 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3150 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3151 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3152 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3153 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3154 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3155 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3156 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3157 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3158 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3159 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3160 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3161 EL_SIGN_EXCLAMATION,
3162 EL_SIGN_RADIOACTIVITY,
3173 EL_STEELWALL_SLIPPERY,
3189 static int ep_em_slippery_wall[] =
3194 static int ep_gfx_crumbled[] =
3207 } element_properties[] =
3209 { ep_diggable, EP_DIGGABLE },
3210 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3211 { ep_dont_run_into, EP_DONT_RUN_INTO },
3212 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3213 { ep_dont_touch, EP_DONT_TOUCH },
3214 { ep_indestructible, EP_INDESTRUCTIBLE },
3215 { ep_slippery, EP_SLIPPERY },
3216 { ep_can_change, EP_CAN_CHANGE },
3217 { ep_can_move, EP_CAN_MOVE },
3218 { ep_can_fall, EP_CAN_FALL },
3219 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3220 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3221 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3222 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3223 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3224 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3225 { ep_walkable_over, EP_WALKABLE_OVER },
3226 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3227 { ep_walkable_under, EP_WALKABLE_UNDER },
3228 { ep_passable_over, EP_PASSABLE_OVER },
3229 { ep_passable_inside, EP_PASSABLE_INSIDE },
3230 { ep_passable_under, EP_PASSABLE_UNDER },
3231 { ep_droppable, EP_DROPPABLE },
3232 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3233 { ep_pushable, EP_PUSHABLE },
3234 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3235 { ep_protected, EP_PROTECTED },
3236 { ep_throwable, EP_THROWABLE },
3237 { ep_can_explode, EP_CAN_EXPLODE },
3238 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3240 { ep_player, EP_PLAYER },
3241 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3242 { ep_switchable, EP_SWITCHABLE },
3243 { ep_bd_element, EP_BD_ELEMENT },
3244 { ep_sp_element, EP_SP_ELEMENT },
3245 { ep_sb_element, EP_SB_ELEMENT },
3247 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3248 { ep_food_penguin, EP_FOOD_PENGUIN },
3249 { ep_food_pig, EP_FOOD_PIG },
3250 { ep_historic_wall, EP_HISTORIC_WALL },
3251 { ep_historic_solid, EP_HISTORIC_SOLID },
3252 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3253 { ep_belt, EP_BELT },
3254 { ep_belt_active, EP_BELT_ACTIVE },
3255 { ep_belt_switch, EP_BELT_SWITCH },
3256 { ep_tube, EP_TUBE },
3257 { ep_keygate, EP_KEYGATE },
3258 { ep_amoeboid, EP_AMOEBOID },
3259 { ep_amoebalive, EP_AMOEBALIVE },
3260 { ep_has_content, EP_HAS_CONTENT },
3261 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3262 { ep_can_grow, EP_CAN_GROW },
3263 { ep_active_bomb, EP_ACTIVE_BOMB },
3264 { ep_inactive, EP_INACTIVE },
3266 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3268 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3273 static int copy_properties[][5] =
3277 EL_BUG_LEFT, EL_BUG_RIGHT,
3278 EL_BUG_UP, EL_BUG_DOWN
3282 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3283 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3287 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3288 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3292 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3293 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3297 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3298 EL_PACMAN_UP, EL_PACMAN_DOWN
3302 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3303 EL_MOLE_UP, EL_MOLE_DOWN
3313 /* always start with reliable default values (element has no properties) */
3314 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3315 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3316 SET_PROPERTY(i, j, FALSE);
3318 /* set all base element properties from above array definitions */
3319 for (i = 0; element_properties[i].elements != NULL; i++)
3320 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3321 SET_PROPERTY((element_properties[i].elements)[j],
3322 element_properties[i].property, TRUE);
3324 /* copy properties to some elements that are only stored in level file */
3325 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3326 for (j = 0; copy_properties[j][0] != -1; j++)
3327 if (HAS_PROPERTY(copy_properties[j][0], i))
3328 for (k = 1; k <= 4; k++)
3329 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3332 void InitElementPropertiesEngine(int engine_version)
3335 static int active_properties[] =
3340 EP_DONT_COLLIDE_WITH,
3344 EP_CAN_PASS_MAGIC_WALL,
3349 EP_EXPLODES_BY_FIRE,
3362 EP_EM_SLIPPERY_WALL,
3366 static int no_wall_properties[] =
3369 EP_COLLECTIBLE_ONLY,
3371 EP_DONT_COLLIDE_WITH,
3374 EP_CAN_SMASH_PLAYER,
3375 EP_CAN_SMASH_ENEMIES,
3376 EP_CAN_SMASH_EVERYTHING,
3381 EP_FOOD_DARK_YAMYAM,
3398 InitElementPropertiesStatic();
3401 /* important: after initialization in InitElementPropertiesStatic(), the
3402 elements are not again initialized to a default value; therefore all
3403 changes have to make sure that they leave the element with a defined
3404 property (which means that conditional property changes must be set to
3405 a reliable default value before) */
3407 /* set all special, combined or engine dependent element properties */
3408 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3411 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3412 SET_PROPERTY(i, j, FALSE);
3415 /* ---------- INACTIVE ------------------------------------------------- */
3416 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3418 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3419 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3420 IS_WALKABLE_INSIDE(i) ||
3421 IS_WALKABLE_UNDER(i)));
3423 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3424 IS_PASSABLE_INSIDE(i) ||
3425 IS_PASSABLE_UNDER(i)));
3427 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3428 IS_PASSABLE_OVER(i)));
3430 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3431 IS_PASSABLE_INSIDE(i)));
3433 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3434 IS_PASSABLE_UNDER(i)));
3436 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3439 /* ---------- COLLECTIBLE ---------------------------------------------- */
3440 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3444 /* ---------- SNAPPABLE ------------------------------------------------ */
3445 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3446 IS_COLLECTIBLE(i) ||
3450 /* ---------- WALL ----------------------------------------------------- */
3451 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3453 for (j = 0; no_wall_properties[j] != -1; j++)
3454 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3455 i >= EL_FIRST_RUNTIME_UNREAL)
3456 SET_PROPERTY(i, EP_WALL, FALSE);
3458 if (IS_HISTORIC_WALL(i))
3459 SET_PROPERTY(i, EP_WALL, TRUE);
3461 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3462 if (engine_version < VERSION_IDENT(2,2,0,0))
3463 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3465 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3467 !IS_COLLECTIBLE(i)));
3470 /* ---------- PROTECTED ------------------------------------------------ */
3471 if (IS_ACCESSIBLE_INSIDE(i))
3472 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3475 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3477 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3478 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3480 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3481 IS_INDESTRUCTIBLE(i)));
3483 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3485 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3486 else if (engine_version < VERSION_IDENT(2,2,0,0))
3487 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3490 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3495 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3496 !IS_WALKABLE_OVER(i) &&
3497 !IS_WALKABLE_UNDER(i)));
3499 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3504 if (IS_CUSTOM_ELEMENT(i))
3506 /* these are additional properties which are initially false when set */
3508 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3510 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3511 if (DONT_COLLIDE_WITH(i))
3512 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3514 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3515 if (CAN_SMASH_EVERYTHING(i))
3516 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3517 if (CAN_SMASH_ENEMIES(i))
3518 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3521 /* ---------- CAN_SMASH ------------------------------------------------ */
3522 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3523 CAN_SMASH_ENEMIES(i) ||
3524 CAN_SMASH_EVERYTHING(i)));
3527 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3528 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3529 CAN_EXPLODE_SMASHED(i) ||
3530 CAN_EXPLODE_IMPACT(i)));
3534 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3536 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3537 !CAN_EXPLODE_CROSS(i)));
3539 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3540 !CAN_EXPLODE_1X1(i) &&
3541 !CAN_EXPLODE_CROSS(i)));
3545 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3546 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3547 EXPLODES_BY_FIRE(i)));
3549 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3550 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3551 EXPLODES_SMASHED(i)));
3553 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3554 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3555 EXPLODES_IMPACT(i)));
3557 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3558 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3560 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3561 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3562 i == EL_BLACK_ORB));
3564 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3565 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3567 IS_CUSTOM_ELEMENT(i)));
3569 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3570 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3571 i == EL_SP_ELECTRON));
3573 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3574 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3575 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3576 getMoveIntoAcidProperty(&level, i));
3578 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3579 if (MAYBE_DONT_COLLIDE_WITH(i))
3580 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3581 getDontCollideWithProperty(&level, i));
3583 /* ---------- SP_PORT -------------------------------------------------- */
3584 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3585 IS_PASSABLE_INSIDE(i)));
3587 /* ---------- CAN_CHANGE ----------------------------------------------- */
3588 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3589 for (j = 0; j < element_info[i].num_change_pages; j++)
3590 if (element_info[i].change_page[j].can_change)
3591 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3593 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3594 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3595 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3599 /* determine inactive elements (used for engine main loop optimization) */
3600 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3602 boolean active = FALSE;
3604 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3606 if (HAS_PROPERTY(i, j))
3612 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3617 /* dynamically adjust element properties according to game engine version */
3619 static int ep_em_slippery_wall[] =
3624 EL_EXPANDABLE_WALL_HORIZONTAL,
3625 EL_EXPANDABLE_WALL_VERTICAL,
3626 EL_EXPANDABLE_WALL_ANY,
3630 /* special EM style gems behaviour */
3631 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3632 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3633 level.em_slippery_gems);
3635 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3636 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3637 (level.em_slippery_gems &&
3638 engine_version > VERSION_IDENT(2,0,1,0)));
3642 /* set default push delay values (corrected since version 3.0.7-1) */
3643 if (engine_version < VERSION_IDENT(3,0,7,1))
3645 game.default_push_delay_fixed = 2;
3646 game.default_push_delay_random = 8;
3650 game.default_push_delay_fixed = 8;
3651 game.default_push_delay_random = 8;
3654 /* set uninitialized push delay values of custom elements in older levels */
3655 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3657 int element = EL_CUSTOM_START + i;
3659 if (element_info[element].push_delay_fixed == -1)
3660 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3661 if (element_info[element].push_delay_random == -1)
3662 element_info[element].push_delay_random = game.default_push_delay_random;
3665 /* set some other uninitialized values of custom elements in older levels */
3666 if (engine_version < VERSION_IDENT(3,1,0,0))
3668 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3670 int element = EL_CUSTOM_START + i;
3672 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3674 element_info[element].explosion_delay = 17;
3675 element_info[element].ignition_delay = 8;
3680 /* set element properties that were handled incorrectly in older levels */
3681 if (engine_version < VERSION_IDENT(3,1,0,0))
3683 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3684 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3690 /* this is needed because some graphics depend on element properties */
3691 if (game_status == GAME_MODE_PLAYING)
3692 InitElementGraphicInfo();
3695 static void InitGlobal()
3699 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3701 element_info[i].token_name = element_name_info[i].token_name;
3702 element_info[i].class_name = element_name_info[i].class_name;
3703 element_info[i].editor_description=element_name_info[i].editor_description;
3706 global.autoplay_leveldir = NULL;
3707 global.convert_leveldir = NULL;
3709 global.frames_per_second = 0;
3710 global.fps_slowdown = FALSE;
3711 global.fps_slowdown_factor = 1;
3714 void Execute_Command(char *command)
3718 if (strcmp(command, "print graphicsinfo.conf") == 0)
3720 printf("# You can configure additional/alternative image files here.\n");
3721 printf("# (The entries below are default and therefore commented out.)\n");
3723 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3725 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3728 for (i = 0; image_config[i].token != NULL; i++)
3729 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3730 image_config[i].value));
3734 else if (strcmp(command, "print soundsinfo.conf") == 0)
3736 printf("# You can configure additional/alternative sound files here.\n");
3737 printf("# (The entries below are default and therefore commented out.)\n");
3739 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3741 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3744 for (i = 0; sound_config[i].token != NULL; i++)
3745 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3746 sound_config[i].value));
3750 else if (strcmp(command, "print musicinfo.conf") == 0)
3752 printf("# You can configure additional/alternative music files here.\n");
3753 printf("# (The entries below are default and therefore commented out.)\n");
3755 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3757 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3760 for (i = 0; music_config[i].token != NULL; i++)
3761 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3762 music_config[i].value));
3766 else if (strcmp(command, "print editorsetup.conf") == 0)
3768 printf("# You can configure your personal editor element list here.\n");
3769 printf("# (The entries below are default and therefore commented out.)\n");
3772 PrintEditorElementList();
3776 else if (strcmp(command, "print helpanim.conf") == 0)
3778 printf("# You can configure different element help animations here.\n");
3779 printf("# (The entries below are default and therefore commented out.)\n");
3782 for (i = 0; helpanim_config[i].token != NULL; i++)
3784 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3785 helpanim_config[i].value));
3787 if (strcmp(helpanim_config[i].token, "end") == 0)
3793 else if (strcmp(command, "print helptext.conf") == 0)
3795 printf("# You can configure different element help text here.\n");
3796 printf("# (The entries below are default and therefore commented out.)\n");
3799 for (i = 0; helptext_config[i].token != NULL; i++)
3800 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3801 helptext_config[i].value));
3805 else if (strncmp(command, "dump level ", 11) == 0)
3807 char *filename = &command[11];
3809 if (access(filename, F_OK) != 0)
3810 Error(ERR_EXIT, "cannot open file '%s'", filename);
3812 LoadLevelFromFilename(&level, filename);
3817 else if (strncmp(command, "dump tape ", 10) == 0)
3819 char *filename = &command[10];
3821 if (access(filename, F_OK) != 0)
3822 Error(ERR_EXIT, "cannot open file '%s'", filename);
3824 LoadTapeFromFilename(filename);
3829 else if (strncmp(command, "autoplay ", 9) == 0)
3831 char *str_copy = getStringCopy(&command[9]);
3832 char *str_ptr = strchr(str_copy, ' ');
3834 global.autoplay_leveldir = str_copy;
3835 global.autoplay_level_nr = -1;
3837 if (str_ptr != NULL)
3839 *str_ptr++ = '\0'; /* terminate leveldir string */
3840 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3843 else if (strncmp(command, "convert ", 8) == 0)
3845 char *str_copy = getStringCopy(&command[8]);
3846 char *str_ptr = strchr(str_copy, ' ');
3848 global.convert_leveldir = str_copy;
3849 global.convert_level_nr = -1;
3851 if (str_ptr != NULL)
3853 *str_ptr++ = '\0'; /* terminate leveldir string */
3854 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3859 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3863 static void InitSetup()
3865 LoadSetup(); /* global setup info */
3867 /* set some options from setup file */
3869 if (setup.options.verbose)
3870 options.verbose = TRUE;
3873 static void InitPlayerInfo()
3877 /* choose default local player */
3878 local_player = &stored_player[0];
3880 for (i = 0; i < MAX_PLAYERS; i++)
3881 stored_player[i].connected = FALSE;
3883 local_player->connected = TRUE;
3886 static void InitArtworkInfo()
3891 static char *get_string_in_brackets(char *string)
3893 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3895 sprintf(string_in_brackets, "[%s]", string);
3897 return string_in_brackets;
3900 static char *get_level_id_suffix(int id_nr)
3902 char *id_suffix = checked_malloc(1 + 3 + 1);
3904 if (id_nr < 0 || id_nr > 999)
3907 sprintf(id_suffix, ".%03d", id_nr);
3913 static char *get_element_class_token(int element)
3915 char *element_class_name = element_info[element].class_name;
3916 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3918 sprintf(element_class_token, "[%s]", element_class_name);
3920 return element_class_token;
3923 static char *get_action_class_token(int action)
3925 char *action_class_name = &element_action_info[action].suffix[1];
3926 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3928 sprintf(action_class_token, "[%s]", action_class_name);
3930 return action_class_token;
3934 static void InitArtworkConfig()
3936 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3937 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3938 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3939 static char *action_id_suffix[NUM_ACTIONS + 1];
3940 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3941 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3942 static char *level_id_suffix[MAX_LEVELS + 1];
3943 static char *dummy[1] = { NULL };
3944 static char *ignore_generic_tokens[] =
3950 static char **ignore_image_tokens;
3951 static char **ignore_sound_tokens;
3952 static char **ignore_music_tokens;
3953 int num_ignore_generic_tokens;
3954 int num_ignore_image_tokens;
3955 int num_ignore_sound_tokens;
3956 int num_ignore_music_tokens;
3959 /* dynamically determine list of generic tokens to be ignored */
3960 num_ignore_generic_tokens = 0;
3961 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3962 num_ignore_generic_tokens++;
3964 /* dynamically determine list of image tokens to be ignored */
3965 num_ignore_image_tokens = num_ignore_generic_tokens;
3966 for (i = 0; image_config_vars[i].token != NULL; i++)
3967 num_ignore_image_tokens++;
3968 ignore_image_tokens =
3969 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3970 for (i = 0; i < num_ignore_generic_tokens; i++)
3971 ignore_image_tokens[i] = ignore_generic_tokens[i];
3972 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3973 ignore_image_tokens[num_ignore_generic_tokens + i] =
3974 image_config_vars[i].token;
3975 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3977 /* dynamically determine list of sound tokens to be ignored */
3978 num_ignore_sound_tokens = num_ignore_generic_tokens;
3979 ignore_sound_tokens =
3980 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3981 for (i = 0; i < num_ignore_generic_tokens; i++)
3982 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3983 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3985 /* dynamically determine list of music tokens to be ignored */
3986 num_ignore_music_tokens = num_ignore_generic_tokens;
3987 ignore_music_tokens =
3988 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3989 for (i = 0; i < num_ignore_generic_tokens; i++)
3990 ignore_music_tokens[i] = ignore_generic_tokens[i];
3991 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3993 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3994 image_id_prefix[i] = element_info[i].token_name;
3995 for (i = 0; i < NUM_FONTS; i++)
3996 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3997 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3999 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4000 sound_id_prefix[i] = element_info[i].token_name;
4001 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4002 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4003 get_string_in_brackets(element_info[i].class_name);
4004 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4006 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4007 music_id_prefix[i] = music_prefix_info[i].prefix;
4008 music_id_prefix[MAX_LEVELS] = NULL;
4010 for (i = 0; i < NUM_ACTIONS; i++)
4011 action_id_suffix[i] = element_action_info[i].suffix;
4012 action_id_suffix[NUM_ACTIONS] = NULL;
4014 for (i = 0; i < NUM_DIRECTIONS; i++)
4015 direction_id_suffix[i] = element_direction_info[i].suffix;
4016 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4018 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4019 special_id_suffix[i] = special_suffix_info[i].suffix;
4020 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4022 for (i = 0; i < MAX_LEVELS; i++)
4023 level_id_suffix[i] = get_level_id_suffix(i);
4024 level_id_suffix[MAX_LEVELS] = NULL;
4026 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4027 image_id_prefix, action_id_suffix, direction_id_suffix,
4028 special_id_suffix, ignore_image_tokens);
4029 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4030 sound_id_prefix, action_id_suffix, dummy,
4031 special_id_suffix, ignore_sound_tokens);
4032 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4033 music_id_prefix, special_id_suffix, level_id_suffix,
4034 dummy, ignore_music_tokens);
4037 static void InitMixer()
4045 char *filename_font_initial = NULL;
4046 Bitmap *bitmap_font_initial = NULL;
4049 /* determine settings for initial font (for displaying startup messages) */
4050 for (i = 0; image_config[i].token != NULL; i++)
4052 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4054 char font_token[128];
4057 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4058 len_font_token = strlen(font_token);
4060 if (strcmp(image_config[i].token, font_token) == 0)
4061 filename_font_initial = image_config[i].value;
4062 else if (strlen(image_config[i].token) > len_font_token &&
4063 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4065 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4066 font_initial[j].src_x = atoi(image_config[i].value);
4067 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4068 font_initial[j].src_y = atoi(image_config[i].value);
4069 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4070 font_initial[j].width = atoi(image_config[i].value);
4071 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4072 font_initial[j].height = atoi(image_config[i].value);
4077 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4079 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4080 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4083 if (filename_font_initial == NULL) /* should not happen */
4084 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4086 /* create additional image buffers for double-buffering */
4087 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4088 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4090 /* initialize screen properties */
4091 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4092 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4094 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4095 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4096 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4098 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4100 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4101 font_initial[j].bitmap = bitmap_font_initial;
4103 InitFontGraphicInfo();
4105 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4106 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4108 DrawInitText("Loading graphics:", 120, FC_GREEN);
4110 InitTileClipmasks();
4113 void InitGfxBackground()
4117 drawto = backbuffer;
4118 fieldbuffer = bitmap_db_field;
4119 SetDrawtoField(DRAW_BACKBUFFER);
4121 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4122 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4123 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4124 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4126 for (x = 0; x < MAX_BUF_XSIZE; x++)
4127 for (y = 0; y < MAX_BUF_YSIZE; y++)
4130 redraw_mask = REDRAW_ALL;
4133 static void InitLevelInfo()
4135 LoadLevelInfo(); /* global level info */
4136 LoadLevelSetup_LastSeries(); /* last played series info */
4137 LoadLevelSetup_SeriesInfo(); /* last played level info */
4140 void InitLevelArtworkInfo()
4142 LoadLevelArtworkInfo();
4145 static void InitImages()
4148 setLevelArtworkDir(artwork.gfx_first);
4152 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4153 leveldir_current->identifier,
4154 artwork.gfx_current_identifier,
4155 artwork.gfx_current->identifier,
4156 leveldir_current->graphics_set,
4157 leveldir_current->graphics_path);
4160 ReloadCustomImages();
4162 LoadCustomElementDescriptions();
4163 LoadSpecialMenuDesignSettings();
4165 ReinitializeGraphics();
4168 static void InitSound(char *identifier)
4170 if (identifier == NULL)
4171 identifier = artwork.snd_current->identifier;
4174 /* set artwork path to send it to the sound server process */
4175 setLevelArtworkDir(artwork.snd_first);
4178 InitReloadCustomSounds(identifier);
4179 ReinitializeSounds();
4182 static void InitMusic(char *identifier)
4184 if (identifier == NULL)
4185 identifier = artwork.mus_current->identifier;
4188 /* set artwork path to send it to the sound server process */
4189 setLevelArtworkDir(artwork.mus_first);
4192 InitReloadCustomMusic(identifier);
4193 ReinitializeMusic();
4196 void InitNetworkServer()
4198 #if defined(NETWORK_AVALIABLE)
4202 if (!options.network)
4205 #if defined(NETWORK_AVALIABLE)
4206 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4208 if (!ConnectToServer(options.server_host, options.server_port))
4209 Error(ERR_EXIT, "cannot connect to network game server");
4211 SendToServer_PlayerName(setup.player_name);
4212 SendToServer_ProtocolVersion();
4215 SendToServer_NrWanted(nr_wanted);
4219 static char *getNewArtworkIdentifier(int type)
4221 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4222 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4223 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4224 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4225 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4226 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4227 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4228 char *leveldir_identifier = leveldir_current->identifier;
4230 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4231 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4233 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4235 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4236 char *artwork_current_identifier;
4237 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4239 /* leveldir_current may be invalid (level group, parent link) */
4240 if (!validLevelSeries(leveldir_current))
4243 /* 1st step: determine artwork set to be activated in descending order:
4244 --------------------------------------------------------------------
4245 1. setup artwork (when configured to override everything else)
4246 2. artwork set configured in "levelinfo.conf" of current level set
4247 (artwork in level directory will have priority when loading later)
4248 3. artwork in level directory (stored in artwork sub-directory)
4249 4. setup artwork (currently configured in setup menu) */
4251 if (setup_override_artwork)
4252 artwork_current_identifier = setup_artwork_set;
4253 else if (leveldir_artwork_set != NULL)
4254 artwork_current_identifier = leveldir_artwork_set;
4255 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4256 artwork_current_identifier = leveldir_identifier;
4258 artwork_current_identifier = setup_artwork_set;
4261 /* 2nd step: check if it is really needed to reload artwork set
4262 ------------------------------------------------------------ */
4265 if (type == ARTWORK_TYPE_GRAPHICS)
4266 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4267 artwork_new_identifier,
4268 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4269 artwork_current_identifier,
4270 leveldir_current->graphics_set,
4271 leveldir_current->identifier);
4274 /* ---------- reload if level set and also artwork set has changed ------- */
4275 if (leveldir_current_identifier[type] != leveldir_identifier &&
4276 (last_has_level_artwork_set[type] || has_level_artwork_set))
4277 artwork_new_identifier = artwork_current_identifier;
4279 leveldir_current_identifier[type] = leveldir_identifier;
4280 last_has_level_artwork_set[type] = has_level_artwork_set;
4283 if (type == ARTWORK_TYPE_GRAPHICS)
4284 printf("::: 1: '%s'\n", artwork_new_identifier);
4287 /* ---------- reload if "override artwork" setting has changed ----------- */
4288 if (last_override_level_artwork[type] != setup_override_artwork)
4289 artwork_new_identifier = artwork_current_identifier;
4291 last_override_level_artwork[type] = setup_override_artwork;
4294 if (type == ARTWORK_TYPE_GRAPHICS)
4295 printf("::: 2: '%s'\n", artwork_new_identifier);
4298 /* ---------- reload if current artwork identifier has changed ----------- */
4299 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4300 artwork_current_identifier) != 0)
4301 artwork_new_identifier = artwork_current_identifier;
4303 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4306 if (type == ARTWORK_TYPE_GRAPHICS)
4307 printf("::: 3: '%s'\n", artwork_new_identifier);
4310 /* ---------- do not reload directly after starting ---------------------- */
4311 if (!initialized[type])
4312 artwork_new_identifier = NULL;
4314 initialized[type] = TRUE;
4317 if (type == ARTWORK_TYPE_GRAPHICS)
4318 printf("::: 4: '%s'\n", artwork_new_identifier);
4322 if (type == ARTWORK_TYPE_GRAPHICS)
4323 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4324 artwork.gfx_current_identifier, artwork_current_identifier,
4325 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4326 artwork_new_identifier);
4329 return artwork_new_identifier;
4332 void ReloadCustomArtwork(int force_reload)
4334 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4335 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4336 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4337 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4338 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4339 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4340 boolean redraw_screen = FALSE;
4342 if (gfx_new_identifier != NULL || force_reload_gfx)
4345 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4346 artwork.gfx_current_identifier,
4348 artwork.gfx_current->identifier,
4349 leveldir_current->graphics_set);
4352 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4357 printf("... '%s'\n",
4358 leveldir_current->graphics_set);
4361 FreeTileClipmasks();
4362 InitTileClipmasks();
4364 redraw_screen = TRUE;
4367 if (snd_new_identifier != NULL || force_reload_snd)
4369 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4371 InitSound(snd_new_identifier);
4373 redraw_screen = TRUE;
4376 if (mus_new_identifier != NULL || force_reload_mus)
4378 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4380 InitMusic(mus_new_identifier);
4382 redraw_screen = TRUE;
4387 InitGfxBackground();
4389 /* force redraw of (open or closed) door graphics */
4390 SetDoorState(DOOR_OPEN_ALL);
4391 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4395 void KeyboardAutoRepeatOffUnlessAutoplay()
4397 if (global.autoplay_leveldir == NULL)
4398 KeyboardAutoRepeatOff();
4402 /* ========================================================================= */
4404 /* ========================================================================= */
4408 InitGlobal(); /* initialize some global variables */
4410 if (options.execute_command)
4411 Execute_Command(options.execute_command);
4413 if (options.serveronly)
4415 #if defined(PLATFORM_UNIX)
4416 NetworkServer(options.server_port, options.serveronly);
4418 Error(ERR_WARN, "networking only supported in Unix version");
4420 exit(0); /* never reached */
4426 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4427 InitArtworkConfig(); /* needed before forking sound child process */
4432 InitRND(NEW_RANDOMIZE);
4433 InitSimpleRND(NEW_RANDOMIZE);
4438 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4441 InitEventFilter(FilterMouseMotionEvents);
4443 InitElementPropertiesStatic();
4444 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4449 InitLevelArtworkInfo();
4451 InitImages(); /* needs to know current level directory */
4452 InitSound(NULL); /* needs to know current level directory */
4453 InitMusic(NULL); /* needs to know current level directory */
4455 InitGfxBackground();
4457 if (global.autoplay_leveldir)
4462 else if (global.convert_leveldir)
4468 game_status = GAME_MODE_MAIN;
4476 InitNetworkServer();
4479 void CloseAllAndExit(int exit_value)
4484 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4491 FreeTileClipmasks();
4493 #if defined(TARGET_SDL)
4494 if (network_server) /* terminate network server */
4495 SDL_KillThread(server_thread);
4498 CloseVideoDisplay();
4499 ClosePlatformDependentStuff();