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];
893 /* optional zoom factor for scaling up the image to a larger size */
894 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
895 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
896 if (graphic_info[graphic].scale_up_factor < 1)
897 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
901 /* bitmap is not scaled at this stage, so calculate final size */
902 int scale_up_factor = graphic_info[graphic].scale_up_factor;
903 int src_bitmap_width = src_bitmap->width * scale_up_factor;
904 int src_bitmap_height = src_bitmap->height * scale_up_factor;
906 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
907 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
910 /* correct x or y offset dependent of vertical or horizontal frame order */
911 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
913 graphic_info[graphic].offset_y =
914 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
915 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
916 anim_frames_per_line = anim_frames_per_col;
918 else /* frames are ordered horizontally */
920 graphic_info[graphic].offset_x =
921 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
922 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
923 anim_frames_per_line = anim_frames_per_row;
926 /* optionally, the x and y offset of frames can be specified directly */
927 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
928 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
929 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
930 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
932 /* automatically determine correct number of frames, if not defined */
933 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
934 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
935 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
936 graphic_info[graphic].anim_frames = anim_frames_per_row;
937 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
938 graphic_info[graphic].anim_frames = anim_frames_per_col;
940 graphic_info[graphic].anim_frames = 1;
942 graphic_info[graphic].anim_frames_per_line =
943 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
944 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
946 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
947 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
948 graphic_info[graphic].anim_delay = 1;
950 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
952 if (graphic_info[graphic].anim_frames == 1)
953 graphic_info[graphic].anim_mode = ANIM_NONE;
956 /* automatically determine correct start frame, if not defined */
957 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
958 graphic_info[graphic].anim_start_frame = 0;
959 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
960 graphic_info[graphic].anim_start_frame =
961 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
963 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
965 /* animation synchronized with global frame counter, not move position */
966 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
968 /* optional element for cloning crumble graphics */
969 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
972 /* optional element for cloning digging graphics */
973 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
976 /* optional border size for "crumbling" diggable graphics */
977 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
980 /* this is only used for player "boring" and "sleeping" actions */
981 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].anim_delay_fixed =
983 parameter[GFX_ARG_ANIM_DELAY_FIXED];
984 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
985 graphic_info[graphic].anim_delay_random =
986 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
987 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].post_delay_fixed =
989 parameter[GFX_ARG_POST_DELAY_FIXED];
990 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
991 graphic_info[graphic].post_delay_random =
992 parameter[GFX_ARG_POST_DELAY_RANDOM];
994 /* this is only used for toon animations */
995 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
996 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
998 /* this is only used for drawing font characters */
999 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1000 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1002 /* this is only used for drawing envelope graphics */
1003 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1006 static void InitGraphicInfo()
1008 int fallback_graphic = IMG_CHAR_EXCLAM;
1009 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1010 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1011 int num_images = getImageListSize();
1014 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1015 static boolean clipmasks_initialized = FALSE;
1017 XGCValues clip_gc_values;
1018 unsigned long clip_gc_valuemask;
1019 GC copy_clipmask_gc = None;
1022 checked_free(graphic_info);
1024 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1027 printf("::: graphic_info: %d entries\n", num_images);
1030 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1031 if (clipmasks_initialized)
1033 for (i = 0; i < num_images; i++)
1035 if (graphic_info[i].clip_mask)
1036 XFreePixmap(display, graphic_info[i].clip_mask);
1037 if (graphic_info[i].clip_gc)
1038 XFreeGC(display, graphic_info[i].clip_gc);
1040 graphic_info[i].clip_mask = None;
1041 graphic_info[i].clip_gc = None;
1046 for (i = 0; i < num_images; i++)
1048 struct FileInfo *image = getImageListEntry(i);
1051 int first_frame, last_frame;
1052 int scale_up_factor, src_bitmap_width, src_bitmap_height;
1055 printf("::: image: '%s' [%d]\n", image->token, i);
1059 printf("::: image # %d: '%s' ['%s']\n",
1061 getTokenFromImageID(i));
1064 set_graphic_parameters(i, image->parameter);
1066 /* now check if no animation frames are outside of the loaded image */
1068 if (graphic_info[i].bitmap == NULL)
1069 continue; /* skip check for optional images that are undefined */
1071 /* bitmap is not scaled at this stage, so calculate final size */
1072 scale_up_factor = graphic_info[i].scale_up_factor;
1073 src_bitmap_width = graphic_info[i].bitmap->width * scale_up_factor;
1074 src_bitmap_height = graphic_info[i].bitmap->height * scale_up_factor;
1077 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1078 if (src_x < 0 || src_y < 0 ||
1079 src_x + TILEX > src_bitmap_width ||
1080 src_y + TILEY > src_bitmap_height)
1082 Error(ERR_RETURN_LINE, "-");
1083 Error(ERR_RETURN, "warning: error found in config file:");
1084 Error(ERR_RETURN, "- config file: '%s'",
1085 getImageConfigFilename());
1086 Error(ERR_RETURN, "- config token: '%s'",
1087 getTokenFromImageID(i));
1088 Error(ERR_RETURN, "- image file: '%s'",
1089 src_bitmap->source_filename);
1091 "error: first animation frame out of bounds (%d, %d)",
1093 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1096 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1099 if (i == fallback_graphic)
1100 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1102 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1103 Error(ERR_RETURN_LINE, "-");
1105 set_graphic_parameters(i, fallback_image->default_parameter);
1106 graphic_info[i].bitmap = fallback_bitmap;
1109 last_frame = graphic_info[i].anim_frames - 1;
1110 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1111 if (src_x < 0 || src_y < 0 ||
1112 src_x + TILEX > src_bitmap_width ||
1113 src_y + TILEY > src_bitmap_height)
1115 Error(ERR_RETURN_LINE, "-");
1116 Error(ERR_RETURN, "warning: error found in config file:");
1117 Error(ERR_RETURN, "- config file: '%s'",
1118 getImageConfigFilename());
1119 Error(ERR_RETURN, "- config token: '%s'",
1120 getTokenFromImageID(i));
1121 Error(ERR_RETURN, "- image file: '%s'",
1122 src_bitmap->source_filename);
1124 "error: last animation frame (%d) out of bounds (%d, %d)",
1125 last_frame, src_x, src_y);
1126 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1128 if (i == fallback_graphic)
1129 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1131 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1132 Error(ERR_RETURN_LINE, "-");
1134 set_graphic_parameters(i, fallback_image->default_parameter);
1135 graphic_info[i].bitmap = fallback_bitmap;
1138 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1139 /* currently we need only a tile clip mask from the first frame */
1140 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1142 if (copy_clipmask_gc == None)
1144 clip_gc_values.graphics_exposures = False;
1145 clip_gc_valuemask = GCGraphicsExposures;
1146 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1147 clip_gc_valuemask, &clip_gc_values);
1150 graphic_info[i].clip_mask =
1151 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1153 src_pixmap = src_bitmap->clip_mask;
1154 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1155 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1157 clip_gc_values.graphics_exposures = False;
1158 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1159 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1161 graphic_info[i].clip_gc =
1162 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1166 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1167 if (copy_clipmask_gc)
1168 XFreeGC(display, copy_clipmask_gc);
1170 clipmasks_initialized = TRUE;
1174 static void InitElementSoundInfo()
1176 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1177 int num_property_mappings = getSoundListPropertyMappingSize();
1180 /* set values to -1 to identify later as "uninitialized" values */
1181 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1182 for (act = 0; act < NUM_ACTIONS; act++)
1183 element_info[i].sound[act] = -1;
1185 /* initialize element/sound mapping from static configuration */
1186 for (i = 0; element_to_sound[i].element > -1; i++)
1188 int element = element_to_sound[i].element;
1189 int action = element_to_sound[i].action;
1190 int sound = element_to_sound[i].sound;
1191 boolean is_class = element_to_sound[i].is_class;
1194 action = ACTION_DEFAULT;
1197 element_info[element].sound[action] = sound;
1199 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1200 if (strcmp(element_info[j].class_name,
1201 element_info[element].class_name) == 0)
1202 element_info[j].sound[action] = sound;
1205 /* initialize element class/sound mapping from dynamic configuration */
1206 for (i = 0; i < num_property_mappings; i++)
1208 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1209 int action = property_mapping[i].ext1_index;
1210 int sound = property_mapping[i].artwork_index;
1212 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1216 action = ACTION_DEFAULT;
1218 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1219 if (strcmp(element_info[j].class_name,
1220 element_info[element_class].class_name) == 0)
1221 element_info[j].sound[action] = sound;
1224 /* initialize element/sound mapping from dynamic configuration */
1225 for (i = 0; i < num_property_mappings; i++)
1227 int element = property_mapping[i].base_index;
1228 int action = property_mapping[i].ext1_index;
1229 int sound = property_mapping[i].artwork_index;
1231 if (element >= MAX_NUM_ELEMENTS)
1235 action = ACTION_DEFAULT;
1237 element_info[element].sound[action] = sound;
1240 /* now set all '-1' values to element specific default values */
1241 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1243 for (act = 0; act < NUM_ACTIONS; act++)
1245 /* generic default action sound (defined by "[default]" directive) */
1246 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1248 /* look for special default action sound (classic game specific) */
1249 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1250 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1251 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1252 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1253 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1254 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1256 /* !!! there's no such thing as a "default action sound" !!! */
1258 /* look for element specific default sound (independent from action) */
1259 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1260 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1264 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1265 /* !!! make this better !!! */
1266 if (i == EL_EMPTY_SPACE)
1267 default_action_sound = element_info[EL_DEFAULT].sound[act];
1270 /* no sound for this specific action -- use default action sound */
1271 if (element_info[i].sound[act] == -1)
1272 element_info[i].sound[act] = default_action_sound;
1277 static void InitGameModeSoundInfo()
1281 /* set values to -1 to identify later as "uninitialized" values */
1282 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1285 /* initialize gamemode/sound mapping from static configuration */
1286 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1288 int gamemode = gamemode_to_sound[i].gamemode;
1289 int sound = gamemode_to_sound[i].sound;
1292 gamemode = GAME_MODE_DEFAULT;
1294 menu.sound[gamemode] = sound;
1297 /* now set all '-1' values to levelset specific default values */
1298 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1299 if (menu.sound[i] == -1)
1300 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1304 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1305 if (menu.sound[i] != -1)
1306 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1310 static void set_sound_parameters(int sound, char **parameter_raw)
1312 int parameter[NUM_SND_ARGS];
1315 /* get integer values from string parameters */
1316 for (i = 0; i < NUM_SND_ARGS; i++)
1318 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1319 sound_config_suffix[i].type);
1321 /* explicit loop mode setting in configuration overrides default value */
1322 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1323 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1325 /* sound volume to change the original volume when loading the sound file */
1326 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1328 /* sound priority to give certain sounds a higher or lower priority */
1329 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1332 static void InitSoundInfo()
1335 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1336 int num_property_mappings = getSoundListPropertyMappingSize();
1338 int *sound_effect_properties;
1339 int num_sounds = getSoundListSize();
1342 checked_free(sound_info);
1344 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1345 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1347 /* initialize sound effect for all elements to "no sound" */
1348 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1349 for (j = 0; j < NUM_ACTIONS; j++)
1350 element_info[i].sound[j] = SND_UNDEFINED;
1352 for (i = 0; i < num_sounds; i++)
1354 struct FileInfo *sound = getSoundListEntry(i);
1355 int len_effect_text = strlen(sound->token);
1357 sound_effect_properties[i] = ACTION_OTHER;
1358 sound_info[i].loop = FALSE; /* default: play sound only once */
1361 printf("::: sound %d: '%s'\n", i, sound->token);
1364 /* determine all loop sounds and identify certain sound classes */
1366 for (j = 0; element_action_info[j].suffix; j++)
1368 int len_action_text = strlen(element_action_info[j].suffix);
1370 if (len_action_text < len_effect_text &&
1371 strcmp(&sound->token[len_effect_text - len_action_text],
1372 element_action_info[j].suffix) == 0)
1374 sound_effect_properties[i] = element_action_info[j].value;
1375 sound_info[i].loop = element_action_info[j].is_loop_sound;
1382 if (strcmp(sound->token, "custom_42") == 0)
1383 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1386 /* associate elements and some selected sound actions */
1388 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1390 if (element_info[j].class_name)
1392 int len_class_text = strlen(element_info[j].class_name);
1394 if (len_class_text + 1 < len_effect_text &&
1395 strncmp(sound->token,
1396 element_info[j].class_name, len_class_text) == 0 &&
1397 sound->token[len_class_text] == '.')
1399 int sound_action_value = sound_effect_properties[i];
1401 element_info[j].sound[sound_action_value] = i;
1406 set_sound_parameters(i, sound->parameter);
1409 free(sound_effect_properties);
1412 /* !!! now handled in InitElementSoundInfo() !!! */
1413 /* initialize element/sound mapping from dynamic configuration */
1414 for (i = 0; i < num_property_mappings; i++)
1416 int element = property_mapping[i].base_index;
1417 int action = property_mapping[i].ext1_index;
1418 int sound = property_mapping[i].artwork_index;
1421 action = ACTION_DEFAULT;
1423 printf("::: %d: %d, %d, %d ['%s']\n",
1424 i, element, action, sound, element_info[element].token_name);
1426 element_info[element].sound[action] = sound;
1433 int element = EL_CUSTOM_11;
1436 while (element_action_info[j].suffix)
1438 printf("element %d, sound action '%s' == %d\n",
1439 element, element_action_info[j].suffix,
1440 element_info[element].sound[j]);
1445 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1451 int element = EL_SAND;
1452 int sound_action = ACTION_DIGGING;
1455 while (element_action_info[j].suffix)
1457 if (element_action_info[j].value == sound_action)
1458 printf("element %d, sound action '%s' == %d\n",
1459 element, element_action_info[j].suffix,
1460 element_info[element].sound[sound_action]);
1467 static void InitGameModeMusicInfo()
1469 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1470 int num_property_mappings = getMusicListPropertyMappingSize();
1471 int default_levelset_music = -1;
1474 /* set values to -1 to identify later as "uninitialized" values */
1475 for (i = 0; i < MAX_LEVELS; i++)
1476 levelset.music[i] = -1;
1477 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1480 /* initialize gamemode/music mapping from static configuration */
1481 for (i = 0; gamemode_to_music[i].music > -1; i++)
1483 int gamemode = gamemode_to_music[i].gamemode;
1484 int music = gamemode_to_music[i].music;
1487 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1491 gamemode = GAME_MODE_DEFAULT;
1493 menu.music[gamemode] = music;
1496 /* initialize gamemode/music mapping from dynamic configuration */
1497 for (i = 0; i < num_property_mappings; i++)
1499 int prefix = property_mapping[i].base_index;
1500 int gamemode = property_mapping[i].ext1_index;
1501 int level = property_mapping[i].ext2_index;
1502 int music = property_mapping[i].artwork_index;
1505 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1506 prefix, gamemode, level, music);
1509 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1513 gamemode = GAME_MODE_DEFAULT;
1515 /* level specific music only allowed for in-game music */
1516 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1517 gamemode = GAME_MODE_PLAYING;
1522 default_levelset_music = music;
1525 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1526 levelset.music[level] = music;
1527 if (gamemode != GAME_MODE_PLAYING)
1528 menu.music[gamemode] = music;
1531 /* now set all '-1' values to menu specific default values */
1532 /* (undefined values of "levelset.music[]" might stay at "-1" to
1533 allow dynamic selection of music files from music directory!) */
1534 for (i = 0; i < MAX_LEVELS; i++)
1535 if (levelset.music[i] == -1)
1536 levelset.music[i] = default_levelset_music;
1537 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1538 if (menu.music[i] == -1)
1539 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1543 for (i = 0; i < MAX_LEVELS; i++)
1544 if (levelset.music[i] != -1)
1545 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1546 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1547 if (menu.music[i] != -1)
1548 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1552 static void set_music_parameters(int music, char **parameter_raw)
1554 int parameter[NUM_MUS_ARGS];
1557 /* get integer values from string parameters */
1558 for (i = 0; i < NUM_MUS_ARGS; i++)
1560 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1561 music_config_suffix[i].type);
1563 /* explicit loop mode setting in configuration overrides default value */
1564 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1565 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1568 static void InitMusicInfo()
1570 int num_music = getMusicListSize();
1573 checked_free(music_info);
1575 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1577 for (i = 0; i < num_music; i++)
1579 struct FileInfo *music = getMusicListEntry(i);
1580 int len_music_text = strlen(music->token);
1582 music_info[i].loop = TRUE; /* default: play music in loop mode */
1584 /* determine all loop music */
1586 for (j = 0; music_prefix_info[j].prefix; j++)
1588 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1590 if (len_prefix_text < len_music_text &&
1591 strncmp(music->token,
1592 music_prefix_info[j].prefix, len_prefix_text) == 0)
1594 music_info[i].loop = music_prefix_info[j].is_loop_music;
1600 set_music_parameters(i, music->parameter);
1604 static void ReinitializeGraphics()
1606 InitGraphicInfo(); /* graphic properties mapping */
1607 InitElementGraphicInfo(); /* element game graphic mapping */
1608 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1610 InitElementSmallImages(); /* scale images to all needed sizes */
1611 InitFontGraphicInfo(); /* initialize text drawing functions */
1613 SetMainBackgroundImage(IMG_BACKGROUND);
1614 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1620 static void ReinitializeSounds()
1622 InitSoundInfo(); /* sound properties mapping */
1623 InitElementSoundInfo(); /* element game sound mapping */
1624 InitGameModeSoundInfo(); /* game mode sound mapping */
1626 InitPlayLevelSound(); /* internal game sound settings */
1629 static void ReinitializeMusic()
1631 InitMusicInfo(); /* music properties mapping */
1632 InitGameModeMusicInfo(); /* game mode music mapping */
1635 static int get_special_property_bit(int element, int property_bit_nr)
1637 struct PropertyBitInfo
1643 static struct PropertyBitInfo pb_can_move_into_acid[] =
1645 /* the player may be able fall into acid when gravity is activated */
1650 { EL_SP_MURPHY, 0 },
1651 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1653 /* all element that can move may be able to also move into acid */
1656 { EL_BUG_RIGHT, 1 },
1659 { EL_SPACESHIP, 2 },
1660 { EL_SPACESHIP_LEFT, 2 },
1661 { EL_SPACESHIP_RIGHT, 2 },
1662 { EL_SPACESHIP_UP, 2 },
1663 { EL_SPACESHIP_DOWN, 2 },
1664 { EL_BD_BUTTERFLY, 3 },
1665 { EL_BD_BUTTERFLY_LEFT, 3 },
1666 { EL_BD_BUTTERFLY_RIGHT, 3 },
1667 { EL_BD_BUTTERFLY_UP, 3 },
1668 { EL_BD_BUTTERFLY_DOWN, 3 },
1669 { EL_BD_FIREFLY, 4 },
1670 { EL_BD_FIREFLY_LEFT, 4 },
1671 { EL_BD_FIREFLY_RIGHT, 4 },
1672 { EL_BD_FIREFLY_UP, 4 },
1673 { EL_BD_FIREFLY_DOWN, 4 },
1675 { EL_DARK_YAMYAM, 6 },
1678 { EL_PACMAN_LEFT, 8 },
1679 { EL_PACMAN_RIGHT, 8 },
1680 { EL_PACMAN_UP, 8 },
1681 { EL_PACMAN_DOWN, 8 },
1683 { EL_MOLE_LEFT, 9 },
1684 { EL_MOLE_RIGHT, 9 },
1686 { EL_MOLE_DOWN, 9 },
1690 { EL_SATELLITE, 13 },
1691 { EL_SP_SNIKSNAK, 14 },
1692 { EL_SP_ELECTRON, 15 },
1699 static struct PropertyBitInfo pb_dont_collide_with[] =
1701 { EL_SP_SNIKSNAK, 0 },
1702 { EL_SP_ELECTRON, 1 },
1710 struct PropertyBitInfo *pb_info;
1713 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1714 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1719 struct PropertyBitInfo *pb_info = NULL;
1722 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1723 if (pb_definition[i].bit_nr == property_bit_nr)
1724 pb_info = pb_definition[i].pb_info;
1726 if (pb_info == NULL)
1729 for (i = 0; pb_info[i].element != -1; i++)
1730 if (pb_info[i].element == element)
1731 return pb_info[i].bit_nr;
1737 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1738 boolean property_value)
1740 int bit_nr = get_special_property_bit(element, property_bit_nr);
1745 *bitfield |= (1 << bit_nr);
1747 *bitfield &= ~(1 << bit_nr);
1751 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1753 int bit_nr = get_special_property_bit(element, property_bit_nr);
1756 return ((*bitfield & (1 << bit_nr)) != 0);
1763 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1765 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1769 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1772 level->can_move_into_acid_bits |= (1 << bit_nr);
1776 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1778 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1781 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1787 void InitElementPropertiesStatic()
1789 static int ep_diggable[] =
1794 EL_SP_BUGGY_BASE_ACTIVATING,
1797 EL_INVISIBLE_SAND_ACTIVE,
1799 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1800 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1804 EL_SP_BUGGY_BASE_ACTIVE,
1809 static int ep_collectible_only[] =
1826 EL_DYNABOMB_INCREASE_NUMBER,
1827 EL_DYNABOMB_INCREASE_SIZE,
1828 EL_DYNABOMB_INCREASE_POWER,
1845 static int ep_dont_run_into[] =
1847 /* same elements as in 'ep_dont_touch' */
1853 /* same elements as in 'ep_dont_collide_with' */
1865 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1869 EL_SP_BUGGY_BASE_ACTIVE,
1874 static int ep_dont_collide_with[] =
1876 /* same elements as in 'ep_dont_touch' */
1892 static int ep_dont_touch[] =
1901 static int ep_indestructible[] =
1905 EL_ACID_POOL_TOPLEFT,
1906 EL_ACID_POOL_TOPRIGHT,
1907 EL_ACID_POOL_BOTTOMLEFT,
1908 EL_ACID_POOL_BOTTOM,
1909 EL_ACID_POOL_BOTTOMRIGHT,
1910 EL_SP_HARDWARE_GRAY,
1911 EL_SP_HARDWARE_GREEN,
1912 EL_SP_HARDWARE_BLUE,
1914 EL_SP_HARDWARE_YELLOW,
1915 EL_SP_HARDWARE_BASE_1,
1916 EL_SP_HARDWARE_BASE_2,
1917 EL_SP_HARDWARE_BASE_3,
1918 EL_SP_HARDWARE_BASE_4,
1919 EL_SP_HARDWARE_BASE_5,
1920 EL_SP_HARDWARE_BASE_6,
1921 EL_INVISIBLE_STEELWALL,
1922 EL_INVISIBLE_STEELWALL_ACTIVE,
1923 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1924 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1925 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1926 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1927 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1928 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1929 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1930 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1931 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1932 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1933 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1934 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1936 EL_LIGHT_SWITCH_ACTIVE,
1937 EL_SIGN_EXCLAMATION,
1938 EL_SIGN_RADIOACTIVITY,
1949 EL_STEELWALL_SLIPPERY,
1972 EL_SWITCHGATE_OPENING,
1973 EL_SWITCHGATE_CLOSED,
1974 EL_SWITCHGATE_CLOSING,
1976 EL_SWITCHGATE_SWITCH_UP,
1977 EL_SWITCHGATE_SWITCH_DOWN,
1980 EL_TIMEGATE_OPENING,
1982 EL_TIMEGATE_CLOSING,
1985 EL_TIMEGATE_SWITCH_ACTIVE,
1990 EL_TUBE_VERTICAL_LEFT,
1991 EL_TUBE_VERTICAL_RIGHT,
1992 EL_TUBE_HORIZONTAL_UP,
1993 EL_TUBE_HORIZONTAL_DOWN,
2001 static int ep_slippery[] =
2015 EL_ROBOT_WHEEL_ACTIVE,
2021 EL_ACID_POOL_TOPLEFT,
2022 EL_ACID_POOL_TOPRIGHT,
2032 EL_STEELWALL_SLIPPERY,
2038 static int ep_can_change[] =
2043 static int ep_can_move[] =
2045 /* same elements as in 'pb_can_move_into_acid' */
2066 static int ep_can_fall[] =
2081 EL_BD_MAGIC_WALL_FULL,
2094 static int ep_can_smash_player[] =
2119 static int ep_can_smash_enemies[] =
2127 static int ep_can_smash_everything[] =
2135 static int ep_explodes_by_fire[] =
2137 /* same elements as in 'ep_explodes_impact' */
2142 /* same elements as in 'ep_explodes_smashed' */
2151 EL_DYNABOMB_PLAYER_1_ACTIVE,
2152 EL_DYNABOMB_PLAYER_2_ACTIVE,
2153 EL_DYNABOMB_PLAYER_3_ACTIVE,
2154 EL_DYNABOMB_PLAYER_4_ACTIVE,
2155 EL_DYNABOMB_INCREASE_NUMBER,
2156 EL_DYNABOMB_INCREASE_SIZE,
2157 EL_DYNABOMB_INCREASE_POWER,
2158 EL_SP_DISK_RED_ACTIVE,
2171 static int ep_explodes_smashed[] =
2173 /* same elements as in 'ep_explodes_impact' */
2186 static int ep_explodes_impact[] =
2194 static int ep_walkable_over[] =
2198 EL_SOKOBAN_FIELD_EMPTY,
2216 static int ep_walkable_inside[] =
2221 EL_TUBE_VERTICAL_LEFT,
2222 EL_TUBE_VERTICAL_RIGHT,
2223 EL_TUBE_HORIZONTAL_UP,
2224 EL_TUBE_HORIZONTAL_DOWN,
2232 static int ep_walkable_under[] =
2237 static int ep_passable_over[] =
2252 static int ep_passable_inside[] =
2258 EL_SP_PORT_HORIZONTAL,
2259 EL_SP_PORT_VERTICAL,
2261 EL_SP_GRAVITY_PORT_LEFT,
2262 EL_SP_GRAVITY_PORT_RIGHT,
2263 EL_SP_GRAVITY_PORT_UP,
2264 EL_SP_GRAVITY_PORT_DOWN,
2265 EL_SP_GRAVITY_ON_PORT_LEFT,
2266 EL_SP_GRAVITY_ON_PORT_RIGHT,
2267 EL_SP_GRAVITY_ON_PORT_UP,
2268 EL_SP_GRAVITY_ON_PORT_DOWN,
2269 EL_SP_GRAVITY_OFF_PORT_LEFT,
2270 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2271 EL_SP_GRAVITY_OFF_PORT_UP,
2272 EL_SP_GRAVITY_OFF_PORT_DOWN,
2276 static int ep_passable_under[] =
2281 static int ep_droppable[] =
2286 static int ep_explodes_1x1_old[] =
2291 static int ep_pushable[] =
2303 EL_SOKOBAN_FIELD_FULL,
2310 static int ep_explodes_cross_old[] =
2315 static int ep_protected[] =
2317 /* same elements as in 'ep_walkable_inside' */
2321 EL_TUBE_VERTICAL_LEFT,
2322 EL_TUBE_VERTICAL_RIGHT,
2323 EL_TUBE_HORIZONTAL_UP,
2324 EL_TUBE_HORIZONTAL_DOWN,
2330 /* same elements as in 'ep_passable_over' */
2342 /* same elements as in 'ep_passable_inside' */
2347 EL_SP_PORT_HORIZONTAL,
2348 EL_SP_PORT_VERTICAL,
2350 EL_SP_GRAVITY_PORT_LEFT,
2351 EL_SP_GRAVITY_PORT_RIGHT,
2352 EL_SP_GRAVITY_PORT_UP,
2353 EL_SP_GRAVITY_PORT_DOWN,
2354 EL_SP_GRAVITY_ON_PORT_LEFT,
2355 EL_SP_GRAVITY_ON_PORT_RIGHT,
2356 EL_SP_GRAVITY_ON_PORT_UP,
2357 EL_SP_GRAVITY_ON_PORT_DOWN,
2358 EL_SP_GRAVITY_OFF_PORT_LEFT,
2359 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2360 EL_SP_GRAVITY_OFF_PORT_UP,
2361 EL_SP_GRAVITY_OFF_PORT_DOWN,
2365 static int ep_throwable[] =
2370 static int ep_can_explode[] =
2372 /* same elements as in 'ep_explodes_impact' */
2377 /* same elements as in 'ep_explodes_smashed' */
2383 /* elements that can explode by explosion or by dragonfire */
2386 EL_DYNABOMB_PLAYER_1_ACTIVE,
2387 EL_DYNABOMB_PLAYER_2_ACTIVE,
2388 EL_DYNABOMB_PLAYER_3_ACTIVE,
2389 EL_DYNABOMB_PLAYER_4_ACTIVE,
2390 EL_DYNABOMB_INCREASE_NUMBER,
2391 EL_DYNABOMB_INCREASE_SIZE,
2392 EL_DYNABOMB_INCREASE_POWER,
2393 EL_SP_DISK_RED_ACTIVE,
2401 /* elements that can explode only by explosion */
2406 static int ep_gravity_reachable[] =
2412 EL_INVISIBLE_SAND_ACTIVE,
2417 EL_SP_PORT_HORIZONTAL,
2418 EL_SP_PORT_VERTICAL,
2420 EL_SP_GRAVITY_PORT_LEFT,
2421 EL_SP_GRAVITY_PORT_RIGHT,
2422 EL_SP_GRAVITY_PORT_UP,
2423 EL_SP_GRAVITY_PORT_DOWN,
2424 EL_SP_GRAVITY_ON_PORT_LEFT,
2425 EL_SP_GRAVITY_ON_PORT_RIGHT,
2426 EL_SP_GRAVITY_ON_PORT_UP,
2427 EL_SP_GRAVITY_ON_PORT_DOWN,
2428 EL_SP_GRAVITY_OFF_PORT_LEFT,
2429 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2430 EL_SP_GRAVITY_OFF_PORT_UP,
2431 EL_SP_GRAVITY_OFF_PORT_DOWN,
2435 static int ep_player[] =
2442 EL_SOKOBAN_FIELD_PLAYER,
2447 static int ep_can_pass_magic_wall[] =
2460 static int ep_switchable[] =
2464 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2465 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2466 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2467 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2468 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2469 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2470 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2471 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2472 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2473 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2474 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2475 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2476 EL_SWITCHGATE_SWITCH_UP,
2477 EL_SWITCHGATE_SWITCH_DOWN,
2479 EL_LIGHT_SWITCH_ACTIVE,
2481 EL_BALLOON_SWITCH_LEFT,
2482 EL_BALLOON_SWITCH_RIGHT,
2483 EL_BALLOON_SWITCH_UP,
2484 EL_BALLOON_SWITCH_DOWN,
2485 EL_BALLOON_SWITCH_ANY,
2491 static int ep_bd_element[] =
2524 static int ep_sp_element[] =
2526 /* should always be valid */
2529 /* standard classic Supaplex elements */
2536 EL_SP_HARDWARE_GRAY,
2544 EL_SP_GRAVITY_PORT_RIGHT,
2545 EL_SP_GRAVITY_PORT_DOWN,
2546 EL_SP_GRAVITY_PORT_LEFT,
2547 EL_SP_GRAVITY_PORT_UP,
2552 EL_SP_PORT_VERTICAL,
2553 EL_SP_PORT_HORIZONTAL,
2559 EL_SP_HARDWARE_BASE_1,
2560 EL_SP_HARDWARE_GREEN,
2561 EL_SP_HARDWARE_BLUE,
2563 EL_SP_HARDWARE_YELLOW,
2564 EL_SP_HARDWARE_BASE_2,
2565 EL_SP_HARDWARE_BASE_3,
2566 EL_SP_HARDWARE_BASE_4,
2567 EL_SP_HARDWARE_BASE_5,
2568 EL_SP_HARDWARE_BASE_6,
2572 /* additional elements that appeared in newer Supaplex levels */
2575 /* additional gravity port elements (not switching, but setting gravity) */
2576 EL_SP_GRAVITY_ON_PORT_LEFT,
2577 EL_SP_GRAVITY_ON_PORT_RIGHT,
2578 EL_SP_GRAVITY_ON_PORT_UP,
2579 EL_SP_GRAVITY_ON_PORT_DOWN,
2580 EL_SP_GRAVITY_OFF_PORT_LEFT,
2581 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2582 EL_SP_GRAVITY_OFF_PORT_UP,
2583 EL_SP_GRAVITY_OFF_PORT_DOWN,
2585 /* more than one Murphy in a level results in an inactive clone */
2588 /* runtime Supaplex elements */
2589 EL_SP_DISK_RED_ACTIVE,
2590 EL_SP_TERMINAL_ACTIVE,
2591 EL_SP_BUGGY_BASE_ACTIVATING,
2592 EL_SP_BUGGY_BASE_ACTIVE,
2598 static int ep_sb_element[] =
2603 EL_SOKOBAN_FIELD_EMPTY,
2604 EL_SOKOBAN_FIELD_FULL,
2605 EL_SOKOBAN_FIELD_PLAYER,
2610 EL_INVISIBLE_STEELWALL,
2614 static int ep_gem[] =
2625 static int ep_food_dark_yamyam[] =
2652 static int ep_food_penguin[] =
2665 static int ep_food_pig[] =
2676 static int ep_historic_wall[] =
2701 EL_EXPANDABLE_WALL_HORIZONTAL,
2702 EL_EXPANDABLE_WALL_VERTICAL,
2703 EL_EXPANDABLE_WALL_ANY,
2704 EL_EXPANDABLE_WALL_GROWING,
2711 EL_SP_HARDWARE_GRAY,
2712 EL_SP_HARDWARE_GREEN,
2713 EL_SP_HARDWARE_BLUE,
2715 EL_SP_HARDWARE_YELLOW,
2716 EL_SP_HARDWARE_BASE_1,
2717 EL_SP_HARDWARE_BASE_2,
2718 EL_SP_HARDWARE_BASE_3,
2719 EL_SP_HARDWARE_BASE_4,
2720 EL_SP_HARDWARE_BASE_5,
2721 EL_SP_HARDWARE_BASE_6,
2723 EL_SP_TERMINAL_ACTIVE,
2726 EL_INVISIBLE_STEELWALL,
2727 EL_INVISIBLE_STEELWALL_ACTIVE,
2729 EL_INVISIBLE_WALL_ACTIVE,
2730 EL_STEELWALL_SLIPPERY,
2746 static int ep_historic_solid[] =
2750 EL_EXPANDABLE_WALL_HORIZONTAL,
2751 EL_EXPANDABLE_WALL_VERTICAL,
2752 EL_EXPANDABLE_WALL_ANY,
2765 EL_QUICKSAND_FILLING,
2766 EL_QUICKSAND_EMPTYING,
2768 EL_MAGIC_WALL_ACTIVE,
2769 EL_MAGIC_WALL_EMPTYING,
2770 EL_MAGIC_WALL_FILLING,
2774 EL_BD_MAGIC_WALL_ACTIVE,
2775 EL_BD_MAGIC_WALL_EMPTYING,
2776 EL_BD_MAGIC_WALL_FULL,
2777 EL_BD_MAGIC_WALL_FILLING,
2778 EL_BD_MAGIC_WALL_DEAD,
2787 EL_SP_TERMINAL_ACTIVE,
2791 EL_INVISIBLE_WALL_ACTIVE,
2792 EL_SWITCHGATE_SWITCH_UP,
2793 EL_SWITCHGATE_SWITCH_DOWN,
2795 EL_TIMEGATE_SWITCH_ACTIVE,
2807 /* the following elements are a direct copy of "indestructible" elements,
2808 except "EL_ACID", which is "indestructible", but not "solid"! */
2813 EL_ACID_POOL_TOPLEFT,
2814 EL_ACID_POOL_TOPRIGHT,
2815 EL_ACID_POOL_BOTTOMLEFT,
2816 EL_ACID_POOL_BOTTOM,
2817 EL_ACID_POOL_BOTTOMRIGHT,
2818 EL_SP_HARDWARE_GRAY,
2819 EL_SP_HARDWARE_GREEN,
2820 EL_SP_HARDWARE_BLUE,
2822 EL_SP_HARDWARE_YELLOW,
2823 EL_SP_HARDWARE_BASE_1,
2824 EL_SP_HARDWARE_BASE_2,
2825 EL_SP_HARDWARE_BASE_3,
2826 EL_SP_HARDWARE_BASE_4,
2827 EL_SP_HARDWARE_BASE_5,
2828 EL_SP_HARDWARE_BASE_6,
2829 EL_INVISIBLE_STEELWALL,
2830 EL_INVISIBLE_STEELWALL_ACTIVE,
2831 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2832 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2833 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2834 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2835 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2836 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2837 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2838 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2839 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2840 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2841 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2842 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2844 EL_LIGHT_SWITCH_ACTIVE,
2845 EL_SIGN_EXCLAMATION,
2846 EL_SIGN_RADIOACTIVITY,
2857 EL_STEELWALL_SLIPPERY,
2880 EL_SWITCHGATE_OPENING,
2881 EL_SWITCHGATE_CLOSED,
2882 EL_SWITCHGATE_CLOSING,
2884 EL_TIMEGATE_OPENING,
2886 EL_TIMEGATE_CLOSING,
2890 EL_TUBE_VERTICAL_LEFT,
2891 EL_TUBE_VERTICAL_RIGHT,
2892 EL_TUBE_HORIZONTAL_UP,
2893 EL_TUBE_HORIZONTAL_DOWN,
2901 static int ep_classic_enemy[] =
2917 static int ep_belt[] =
2919 EL_CONVEYOR_BELT_1_LEFT,
2920 EL_CONVEYOR_BELT_1_MIDDLE,
2921 EL_CONVEYOR_BELT_1_RIGHT,
2922 EL_CONVEYOR_BELT_2_LEFT,
2923 EL_CONVEYOR_BELT_2_MIDDLE,
2924 EL_CONVEYOR_BELT_2_RIGHT,
2925 EL_CONVEYOR_BELT_3_LEFT,
2926 EL_CONVEYOR_BELT_3_MIDDLE,
2927 EL_CONVEYOR_BELT_3_RIGHT,
2928 EL_CONVEYOR_BELT_4_LEFT,
2929 EL_CONVEYOR_BELT_4_MIDDLE,
2930 EL_CONVEYOR_BELT_4_RIGHT,
2934 static int ep_belt_active[] =
2936 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2937 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2938 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2939 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2940 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2941 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2942 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2943 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2944 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2945 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2946 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2947 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2951 static int ep_belt_switch[] =
2953 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2954 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2955 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2956 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2957 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2958 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2959 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2960 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2961 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2962 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2963 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2964 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2968 static int ep_tube[] =
2975 EL_TUBE_HORIZONTAL_UP,
2976 EL_TUBE_HORIZONTAL_DOWN,
2978 EL_TUBE_VERTICAL_LEFT,
2979 EL_TUBE_VERTICAL_RIGHT,
2984 static int ep_keygate[] =
3005 static int ep_amoeboid[] =
3015 static int ep_amoebalive[] =
3024 static int ep_has_content[] =
3034 static int ep_can_turn_each_move[] =
3036 /* !!! do something with this one !!! */
3040 static int ep_can_grow[] =
3052 static int ep_active_bomb[] =
3055 EL_DYNABOMB_PLAYER_1_ACTIVE,
3056 EL_DYNABOMB_PLAYER_2_ACTIVE,
3057 EL_DYNABOMB_PLAYER_3_ACTIVE,
3058 EL_DYNABOMB_PLAYER_4_ACTIVE,
3059 EL_SP_DISK_RED_ACTIVE,
3063 static int ep_inactive[] =
3100 EL_INVISIBLE_STEELWALL,
3108 EL_WALL_EMERALD_YELLOW,
3109 EL_DYNABOMB_INCREASE_NUMBER,
3110 EL_DYNABOMB_INCREASE_SIZE,
3111 EL_DYNABOMB_INCREASE_POWER,
3115 EL_SOKOBAN_FIELD_EMPTY,
3116 EL_SOKOBAN_FIELD_FULL,
3117 EL_WALL_EMERALD_RED,
3118 EL_WALL_EMERALD_PURPLE,
3119 EL_ACID_POOL_TOPLEFT,
3120 EL_ACID_POOL_TOPRIGHT,
3121 EL_ACID_POOL_BOTTOMLEFT,
3122 EL_ACID_POOL_BOTTOM,
3123 EL_ACID_POOL_BOTTOMRIGHT,
3127 EL_BD_MAGIC_WALL_DEAD,
3128 EL_AMOEBA_TO_DIAMOND,
3136 EL_SP_GRAVITY_PORT_RIGHT,
3137 EL_SP_GRAVITY_PORT_DOWN,
3138 EL_SP_GRAVITY_PORT_LEFT,
3139 EL_SP_GRAVITY_PORT_UP,
3140 EL_SP_PORT_HORIZONTAL,
3141 EL_SP_PORT_VERTICAL,
3152 EL_SP_HARDWARE_GRAY,
3153 EL_SP_HARDWARE_GREEN,
3154 EL_SP_HARDWARE_BLUE,
3156 EL_SP_HARDWARE_YELLOW,
3157 EL_SP_HARDWARE_BASE_1,
3158 EL_SP_HARDWARE_BASE_2,
3159 EL_SP_HARDWARE_BASE_3,
3160 EL_SP_HARDWARE_BASE_4,
3161 EL_SP_HARDWARE_BASE_5,
3162 EL_SP_HARDWARE_BASE_6,
3163 EL_SP_GRAVITY_ON_PORT_LEFT,
3164 EL_SP_GRAVITY_ON_PORT_RIGHT,
3165 EL_SP_GRAVITY_ON_PORT_UP,
3166 EL_SP_GRAVITY_ON_PORT_DOWN,
3167 EL_SP_GRAVITY_OFF_PORT_LEFT,
3168 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3169 EL_SP_GRAVITY_OFF_PORT_UP,
3170 EL_SP_GRAVITY_OFF_PORT_DOWN,
3171 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3172 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3173 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3174 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3175 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3176 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3177 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3178 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3179 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3180 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3181 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3182 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3183 EL_SIGN_EXCLAMATION,
3184 EL_SIGN_RADIOACTIVITY,
3195 EL_STEELWALL_SLIPPERY,
3211 static int ep_em_slippery_wall[] =
3216 static int ep_gfx_crumbled[] =
3229 } element_properties[] =
3231 { ep_diggable, EP_DIGGABLE },
3232 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3233 { ep_dont_run_into, EP_DONT_RUN_INTO },
3234 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3235 { ep_dont_touch, EP_DONT_TOUCH },
3236 { ep_indestructible, EP_INDESTRUCTIBLE },
3237 { ep_slippery, EP_SLIPPERY },
3238 { ep_can_change, EP_CAN_CHANGE },
3239 { ep_can_move, EP_CAN_MOVE },
3240 { ep_can_fall, EP_CAN_FALL },
3241 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3242 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3243 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3244 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3245 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3246 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3247 { ep_walkable_over, EP_WALKABLE_OVER },
3248 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3249 { ep_walkable_under, EP_WALKABLE_UNDER },
3250 { ep_passable_over, EP_PASSABLE_OVER },
3251 { ep_passable_inside, EP_PASSABLE_INSIDE },
3252 { ep_passable_under, EP_PASSABLE_UNDER },
3253 { ep_droppable, EP_DROPPABLE },
3254 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3255 { ep_pushable, EP_PUSHABLE },
3256 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3257 { ep_protected, EP_PROTECTED },
3258 { ep_throwable, EP_THROWABLE },
3259 { ep_can_explode, EP_CAN_EXPLODE },
3260 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3262 { ep_player, EP_PLAYER },
3263 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3264 { ep_switchable, EP_SWITCHABLE },
3265 { ep_bd_element, EP_BD_ELEMENT },
3266 { ep_sp_element, EP_SP_ELEMENT },
3267 { ep_sb_element, EP_SB_ELEMENT },
3269 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3270 { ep_food_penguin, EP_FOOD_PENGUIN },
3271 { ep_food_pig, EP_FOOD_PIG },
3272 { ep_historic_wall, EP_HISTORIC_WALL },
3273 { ep_historic_solid, EP_HISTORIC_SOLID },
3274 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3275 { ep_belt, EP_BELT },
3276 { ep_belt_active, EP_BELT_ACTIVE },
3277 { ep_belt_switch, EP_BELT_SWITCH },
3278 { ep_tube, EP_TUBE },
3279 { ep_keygate, EP_KEYGATE },
3280 { ep_amoeboid, EP_AMOEBOID },
3281 { ep_amoebalive, EP_AMOEBALIVE },
3282 { ep_has_content, EP_HAS_CONTENT },
3283 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3284 { ep_can_grow, EP_CAN_GROW },
3285 { ep_active_bomb, EP_ACTIVE_BOMB },
3286 { ep_inactive, EP_INACTIVE },
3288 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3290 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3295 static int copy_properties[][5] =
3299 EL_BUG_LEFT, EL_BUG_RIGHT,
3300 EL_BUG_UP, EL_BUG_DOWN
3304 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3305 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3309 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3310 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3314 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3315 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3319 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3320 EL_PACMAN_UP, EL_PACMAN_DOWN
3324 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3325 EL_MOLE_UP, EL_MOLE_DOWN
3335 /* always start with reliable default values (element has no properties) */
3336 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3337 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3338 SET_PROPERTY(i, j, FALSE);
3340 /* set all base element properties from above array definitions */
3341 for (i = 0; element_properties[i].elements != NULL; i++)
3342 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3343 SET_PROPERTY((element_properties[i].elements)[j],
3344 element_properties[i].property, TRUE);
3346 /* copy properties to some elements that are only stored in level file */
3347 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3348 for (j = 0; copy_properties[j][0] != -1; j++)
3349 if (HAS_PROPERTY(copy_properties[j][0], i))
3350 for (k = 1; k <= 4; k++)
3351 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3354 void InitElementPropertiesEngine(int engine_version)
3357 static int active_properties[] =
3362 EP_DONT_COLLIDE_WITH,
3366 EP_CAN_PASS_MAGIC_WALL,
3371 EP_EXPLODES_BY_FIRE,
3384 EP_EM_SLIPPERY_WALL,
3388 static int no_wall_properties[] =
3391 EP_COLLECTIBLE_ONLY,
3393 EP_DONT_COLLIDE_WITH,
3396 EP_CAN_SMASH_PLAYER,
3397 EP_CAN_SMASH_ENEMIES,
3398 EP_CAN_SMASH_EVERYTHING,
3403 EP_FOOD_DARK_YAMYAM,
3420 InitElementPropertiesStatic();
3423 /* important: after initialization in InitElementPropertiesStatic(), the
3424 elements are not again initialized to a default value; therefore all
3425 changes have to make sure that they leave the element with a defined
3426 property (which means that conditional property changes must be set to
3427 a reliable default value before) */
3429 /* set all special, combined or engine dependent element properties */
3430 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3433 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3434 SET_PROPERTY(i, j, FALSE);
3437 /* ---------- INACTIVE ------------------------------------------------- */
3438 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3440 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3441 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3442 IS_WALKABLE_INSIDE(i) ||
3443 IS_WALKABLE_UNDER(i)));
3445 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3446 IS_PASSABLE_INSIDE(i) ||
3447 IS_PASSABLE_UNDER(i)));
3449 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3450 IS_PASSABLE_OVER(i)));
3452 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3453 IS_PASSABLE_INSIDE(i)));
3455 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3456 IS_PASSABLE_UNDER(i)));
3458 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3461 /* ---------- COLLECTIBLE ---------------------------------------------- */
3462 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3466 /* ---------- SNAPPABLE ------------------------------------------------ */
3467 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3468 IS_COLLECTIBLE(i) ||
3472 /* ---------- WALL ----------------------------------------------------- */
3473 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3475 for (j = 0; no_wall_properties[j] != -1; j++)
3476 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3477 i >= EL_FIRST_RUNTIME_UNREAL)
3478 SET_PROPERTY(i, EP_WALL, FALSE);
3480 if (IS_HISTORIC_WALL(i))
3481 SET_PROPERTY(i, EP_WALL, TRUE);
3483 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3484 if (engine_version < VERSION_IDENT(2,2,0,0))
3485 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3487 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3489 !IS_COLLECTIBLE(i)));
3492 /* ---------- PROTECTED ------------------------------------------------ */
3493 if (IS_ACCESSIBLE_INSIDE(i))
3494 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3497 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3499 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3500 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3502 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3503 IS_INDESTRUCTIBLE(i)));
3505 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3507 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3508 else if (engine_version < VERSION_IDENT(2,2,0,0))
3509 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3512 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3517 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3518 !IS_WALKABLE_OVER(i) &&
3519 !IS_WALKABLE_UNDER(i)));
3521 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3526 if (IS_CUSTOM_ELEMENT(i))
3528 /* these are additional properties which are initially false when set */
3530 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3532 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3533 if (DONT_COLLIDE_WITH(i))
3534 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3536 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3537 if (CAN_SMASH_EVERYTHING(i))
3538 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3539 if (CAN_SMASH_ENEMIES(i))
3540 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3543 /* ---------- CAN_SMASH ------------------------------------------------ */
3544 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3545 CAN_SMASH_ENEMIES(i) ||
3546 CAN_SMASH_EVERYTHING(i)));
3549 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3550 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3551 CAN_EXPLODE_SMASHED(i) ||
3552 CAN_EXPLODE_IMPACT(i)));
3556 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3558 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3559 !CAN_EXPLODE_CROSS(i)));
3561 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3562 !CAN_EXPLODE_1X1(i) &&
3563 !CAN_EXPLODE_CROSS(i)));
3567 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3568 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3569 EXPLODES_BY_FIRE(i)));
3571 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3572 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3573 EXPLODES_SMASHED(i)));
3575 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3576 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3577 EXPLODES_IMPACT(i)));
3579 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3580 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3582 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3583 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3584 i == EL_BLACK_ORB));
3586 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3587 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3589 IS_CUSTOM_ELEMENT(i)));
3591 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3592 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3593 i == EL_SP_ELECTRON));
3595 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3596 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3597 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3598 getMoveIntoAcidProperty(&level, i));
3600 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3601 if (MAYBE_DONT_COLLIDE_WITH(i))
3602 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3603 getDontCollideWithProperty(&level, i));
3605 /* ---------- SP_PORT -------------------------------------------------- */
3606 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3607 IS_PASSABLE_INSIDE(i)));
3609 /* ---------- CAN_CHANGE ----------------------------------------------- */
3610 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3611 for (j = 0; j < element_info[i].num_change_pages; j++)
3612 if (element_info[i].change_page[j].can_change)
3613 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3615 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3616 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3617 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3621 /* determine inactive elements (used for engine main loop optimization) */
3622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3624 boolean active = FALSE;
3626 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3628 if (HAS_PROPERTY(i, j))
3634 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3639 /* dynamically adjust element properties according to game engine version */
3641 static int ep_em_slippery_wall[] =
3646 EL_EXPANDABLE_WALL_HORIZONTAL,
3647 EL_EXPANDABLE_WALL_VERTICAL,
3648 EL_EXPANDABLE_WALL_ANY,
3652 /* special EM style gems behaviour */
3653 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3654 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3655 level.em_slippery_gems);
3657 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3658 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3659 (level.em_slippery_gems &&
3660 engine_version > VERSION_IDENT(2,0,1,0)));
3664 /* set default push delay values (corrected since version 3.0.7-1) */
3665 if (engine_version < VERSION_IDENT(3,0,7,1))
3667 game.default_push_delay_fixed = 2;
3668 game.default_push_delay_random = 8;
3672 game.default_push_delay_fixed = 8;
3673 game.default_push_delay_random = 8;
3676 /* set uninitialized push delay values of custom elements in older levels */
3677 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3679 int element = EL_CUSTOM_START + i;
3681 if (element_info[element].push_delay_fixed == -1)
3682 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3683 if (element_info[element].push_delay_random == -1)
3684 element_info[element].push_delay_random = game.default_push_delay_random;
3687 /* set some other uninitialized values of custom elements in older levels */
3688 if (engine_version < VERSION_IDENT(3,1,0,0))
3690 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3692 int element = EL_CUSTOM_START + i;
3694 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3696 element_info[element].explosion_delay = 17;
3697 element_info[element].ignition_delay = 8;
3702 /* set element properties that were handled incorrectly in older levels */
3703 if (engine_version < VERSION_IDENT(3,1,0,0))
3705 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3706 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3712 /* this is needed because some graphics depend on element properties */
3713 if (game_status == GAME_MODE_PLAYING)
3714 InitElementGraphicInfo();
3717 static void InitGlobal()
3721 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3723 /* check if element_name_info entry defined for each element in "main.h" */
3724 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3725 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3727 element_info[i].token_name = element_name_info[i].token_name;
3728 element_info[i].class_name = element_name_info[i].class_name;
3729 element_info[i].editor_description=element_name_info[i].editor_description;
3732 global.autoplay_leveldir = NULL;
3733 global.convert_leveldir = NULL;
3735 global.frames_per_second = 0;
3736 global.fps_slowdown = FALSE;
3737 global.fps_slowdown_factor = 1;
3740 void Execute_Command(char *command)
3744 if (strcmp(command, "print graphicsinfo.conf") == 0)
3746 printf("# You can configure additional/alternative image files here.\n");
3747 printf("# (The entries below are default and therefore commented out.)\n");
3749 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3751 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3754 for (i = 0; image_config[i].token != NULL; i++)
3755 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3756 image_config[i].value));
3760 else if (strcmp(command, "print soundsinfo.conf") == 0)
3762 printf("# You can configure additional/alternative sound files here.\n");
3763 printf("# (The entries below are default and therefore commented out.)\n");
3765 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3767 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3770 for (i = 0; sound_config[i].token != NULL; i++)
3771 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3772 sound_config[i].value));
3776 else if (strcmp(command, "print musicinfo.conf") == 0)
3778 printf("# You can configure additional/alternative music files here.\n");
3779 printf("# (The entries below are default and therefore commented out.)\n");
3781 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3783 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3786 for (i = 0; music_config[i].token != NULL; i++)
3787 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3788 music_config[i].value));
3792 else if (strcmp(command, "print editorsetup.conf") == 0)
3794 printf("# You can configure your personal editor element list here.\n");
3795 printf("# (The entries below are default and therefore commented out.)\n");
3798 PrintEditorElementList();
3802 else if (strcmp(command, "print helpanim.conf") == 0)
3804 printf("# You can configure different element help animations here.\n");
3805 printf("# (The entries below are default and therefore commented out.)\n");
3808 for (i = 0; helpanim_config[i].token != NULL; i++)
3810 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3811 helpanim_config[i].value));
3813 if (strcmp(helpanim_config[i].token, "end") == 0)
3819 else if (strcmp(command, "print helptext.conf") == 0)
3821 printf("# You can configure different element help text here.\n");
3822 printf("# (The entries below are default and therefore commented out.)\n");
3825 for (i = 0; helptext_config[i].token != NULL; i++)
3826 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3827 helptext_config[i].value));
3831 else if (strncmp(command, "dump level ", 11) == 0)
3833 char *filename = &command[11];
3835 if (access(filename, F_OK) != 0)
3836 Error(ERR_EXIT, "cannot open file '%s'", filename);
3838 LoadLevelFromFilename(&level, filename);
3843 else if (strncmp(command, "dump tape ", 10) == 0)
3845 char *filename = &command[10];
3847 if (access(filename, F_OK) != 0)
3848 Error(ERR_EXIT, "cannot open file '%s'", filename);
3850 LoadTapeFromFilename(filename);
3855 else if (strncmp(command, "autoplay ", 9) == 0)
3857 char *str_copy = getStringCopy(&command[9]);
3858 char *str_ptr = strchr(str_copy, ' ');
3860 global.autoplay_leveldir = str_copy;
3861 global.autoplay_level_nr = -1;
3863 if (str_ptr != NULL)
3865 *str_ptr++ = '\0'; /* terminate leveldir string */
3866 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3869 else if (strncmp(command, "convert ", 8) == 0)
3871 char *str_copy = getStringCopy(&command[8]);
3872 char *str_ptr = strchr(str_copy, ' ');
3874 global.convert_leveldir = str_copy;
3875 global.convert_level_nr = -1;
3877 if (str_ptr != NULL)
3879 *str_ptr++ = '\0'; /* terminate leveldir string */
3880 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3885 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3889 static void InitSetup()
3891 LoadSetup(); /* global setup info */
3893 /* set some options from setup file */
3895 if (setup.options.verbose)
3896 options.verbose = TRUE;
3899 static void InitPlayerInfo()
3903 /* choose default local player */
3904 local_player = &stored_player[0];
3906 for (i = 0; i < MAX_PLAYERS; i++)
3907 stored_player[i].connected = FALSE;
3909 local_player->connected = TRUE;
3912 static void InitArtworkInfo()
3917 static char *get_string_in_brackets(char *string)
3919 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3921 sprintf(string_in_brackets, "[%s]", string);
3923 return string_in_brackets;
3926 static char *get_level_id_suffix(int id_nr)
3928 char *id_suffix = checked_malloc(1 + 3 + 1);
3930 if (id_nr < 0 || id_nr > 999)
3933 sprintf(id_suffix, ".%03d", id_nr);
3939 static char *get_element_class_token(int element)
3941 char *element_class_name = element_info[element].class_name;
3942 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3944 sprintf(element_class_token, "[%s]", element_class_name);
3946 return element_class_token;
3949 static char *get_action_class_token(int action)
3951 char *action_class_name = &element_action_info[action].suffix[1];
3952 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3954 sprintf(action_class_token, "[%s]", action_class_name);
3956 return action_class_token;
3960 static void InitArtworkConfig()
3962 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3963 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3964 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3965 static char *action_id_suffix[NUM_ACTIONS + 1];
3966 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3967 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3968 static char *level_id_suffix[MAX_LEVELS + 1];
3969 static char *dummy[1] = { NULL };
3970 static char *ignore_generic_tokens[] =
3976 static char **ignore_image_tokens;
3977 static char **ignore_sound_tokens;
3978 static char **ignore_music_tokens;
3979 int num_ignore_generic_tokens;
3980 int num_ignore_image_tokens;
3981 int num_ignore_sound_tokens;
3982 int num_ignore_music_tokens;
3985 /* dynamically determine list of generic tokens to be ignored */
3986 num_ignore_generic_tokens = 0;
3987 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3988 num_ignore_generic_tokens++;
3990 /* dynamically determine list of image tokens to be ignored */
3991 num_ignore_image_tokens = num_ignore_generic_tokens;
3992 for (i = 0; image_config_vars[i].token != NULL; i++)
3993 num_ignore_image_tokens++;
3994 ignore_image_tokens =
3995 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3996 for (i = 0; i < num_ignore_generic_tokens; i++)
3997 ignore_image_tokens[i] = ignore_generic_tokens[i];
3998 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3999 ignore_image_tokens[num_ignore_generic_tokens + i] =
4000 image_config_vars[i].token;
4001 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4003 /* dynamically determine list of sound tokens to be ignored */
4004 num_ignore_sound_tokens = num_ignore_generic_tokens;
4005 ignore_sound_tokens =
4006 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4007 for (i = 0; i < num_ignore_generic_tokens; i++)
4008 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4009 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4011 /* dynamically determine list of music tokens to be ignored */
4012 num_ignore_music_tokens = num_ignore_generic_tokens;
4013 ignore_music_tokens =
4014 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4015 for (i = 0; i < num_ignore_generic_tokens; i++)
4016 ignore_music_tokens[i] = ignore_generic_tokens[i];
4017 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4019 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4020 image_id_prefix[i] = element_info[i].token_name;
4021 for (i = 0; i < NUM_FONTS; i++)
4022 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4023 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4025 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4026 sound_id_prefix[i] = element_info[i].token_name;
4027 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4028 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4029 get_string_in_brackets(element_info[i].class_name);
4030 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4032 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4033 music_id_prefix[i] = music_prefix_info[i].prefix;
4034 music_id_prefix[MAX_LEVELS] = NULL;
4036 for (i = 0; i < NUM_ACTIONS; i++)
4037 action_id_suffix[i] = element_action_info[i].suffix;
4038 action_id_suffix[NUM_ACTIONS] = NULL;
4040 for (i = 0; i < NUM_DIRECTIONS; i++)
4041 direction_id_suffix[i] = element_direction_info[i].suffix;
4042 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4044 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4045 special_id_suffix[i] = special_suffix_info[i].suffix;
4046 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4048 for (i = 0; i < MAX_LEVELS; i++)
4049 level_id_suffix[i] = get_level_id_suffix(i);
4050 level_id_suffix[MAX_LEVELS] = NULL;
4052 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4053 image_id_prefix, action_id_suffix, direction_id_suffix,
4054 special_id_suffix, ignore_image_tokens);
4055 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4056 sound_id_prefix, action_id_suffix, dummy,
4057 special_id_suffix, ignore_sound_tokens);
4058 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4059 music_id_prefix, special_id_suffix, level_id_suffix,
4060 dummy, ignore_music_tokens);
4063 static void InitMixer()
4071 char *filename_font_initial = NULL;
4072 Bitmap *bitmap_font_initial = NULL;
4075 /* determine settings for initial font (for displaying startup messages) */
4076 for (i = 0; image_config[i].token != NULL; i++)
4078 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4080 char font_token[128];
4083 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4084 len_font_token = strlen(font_token);
4086 if (strcmp(image_config[i].token, font_token) == 0)
4087 filename_font_initial = image_config[i].value;
4088 else if (strlen(image_config[i].token) > len_font_token &&
4089 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4091 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4092 font_initial[j].src_x = atoi(image_config[i].value);
4093 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4094 font_initial[j].src_y = atoi(image_config[i].value);
4095 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4096 font_initial[j].width = atoi(image_config[i].value);
4097 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4098 font_initial[j].height = atoi(image_config[i].value);
4103 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4105 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4106 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4109 if (filename_font_initial == NULL) /* should not happen */
4110 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4112 /* create additional image buffers for double-buffering */
4113 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4114 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4116 /* initialize screen properties */
4117 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4118 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4120 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4121 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4122 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4124 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4126 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4127 font_initial[j].bitmap = bitmap_font_initial;
4129 InitFontGraphicInfo();
4131 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4132 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4134 DrawInitText("Loading graphics:", 120, FC_GREEN);
4136 InitTileClipmasks();
4139 void InitGfxBackground()
4143 drawto = backbuffer;
4144 fieldbuffer = bitmap_db_field;
4145 SetDrawtoField(DRAW_BACKBUFFER);
4147 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4148 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4149 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4150 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4152 for (x = 0; x < MAX_BUF_XSIZE; x++)
4153 for (y = 0; y < MAX_BUF_YSIZE; y++)
4156 redraw_mask = REDRAW_ALL;
4159 static void InitLevelInfo()
4161 LoadLevelInfo(); /* global level info */
4162 LoadLevelSetup_LastSeries(); /* last played series info */
4163 LoadLevelSetup_SeriesInfo(); /* last played level info */
4166 void InitLevelArtworkInfo()
4168 LoadLevelArtworkInfo();
4171 static void InitImages()
4174 setLevelArtworkDir(artwork.gfx_first);
4178 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4179 leveldir_current->identifier,
4180 artwork.gfx_current_identifier,
4181 artwork.gfx_current->identifier,
4182 leveldir_current->graphics_set,
4183 leveldir_current->graphics_path);
4186 ReloadCustomImages();
4188 LoadCustomElementDescriptions();
4189 LoadSpecialMenuDesignSettings();
4191 ReinitializeGraphics();
4194 static void InitSound(char *identifier)
4196 if (identifier == NULL)
4197 identifier = artwork.snd_current->identifier;
4200 /* set artwork path to send it to the sound server process */
4201 setLevelArtworkDir(artwork.snd_first);
4204 InitReloadCustomSounds(identifier);
4205 ReinitializeSounds();
4208 static void InitMusic(char *identifier)
4210 if (identifier == NULL)
4211 identifier = artwork.mus_current->identifier;
4214 /* set artwork path to send it to the sound server process */
4215 setLevelArtworkDir(artwork.mus_first);
4218 InitReloadCustomMusic(identifier);
4219 ReinitializeMusic();
4222 void InitNetworkServer()
4224 #if defined(NETWORK_AVALIABLE)
4228 if (!options.network)
4231 #if defined(NETWORK_AVALIABLE)
4232 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4234 if (!ConnectToServer(options.server_host, options.server_port))
4235 Error(ERR_EXIT, "cannot connect to network game server");
4237 SendToServer_PlayerName(setup.player_name);
4238 SendToServer_ProtocolVersion();
4241 SendToServer_NrWanted(nr_wanted);
4245 static char *getNewArtworkIdentifier(int type)
4247 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4248 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4249 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4250 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4251 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4252 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4253 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4254 char *leveldir_identifier = leveldir_current->identifier;
4256 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4257 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4259 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4261 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4262 char *artwork_current_identifier;
4263 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4265 /* leveldir_current may be invalid (level group, parent link) */
4266 if (!validLevelSeries(leveldir_current))
4269 /* 1st step: determine artwork set to be activated in descending order:
4270 --------------------------------------------------------------------
4271 1. setup artwork (when configured to override everything else)
4272 2. artwork set configured in "levelinfo.conf" of current level set
4273 (artwork in level directory will have priority when loading later)
4274 3. artwork in level directory (stored in artwork sub-directory)
4275 4. setup artwork (currently configured in setup menu) */
4277 if (setup_override_artwork)
4278 artwork_current_identifier = setup_artwork_set;
4279 else if (leveldir_artwork_set != NULL)
4280 artwork_current_identifier = leveldir_artwork_set;
4281 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4282 artwork_current_identifier = leveldir_identifier;
4284 artwork_current_identifier = setup_artwork_set;
4287 /* 2nd step: check if it is really needed to reload artwork set
4288 ------------------------------------------------------------ */
4291 if (type == ARTWORK_TYPE_GRAPHICS)
4292 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4293 artwork_new_identifier,
4294 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4295 artwork_current_identifier,
4296 leveldir_current->graphics_set,
4297 leveldir_current->identifier);
4300 /* ---------- reload if level set and also artwork set has changed ------- */
4301 if (leveldir_current_identifier[type] != leveldir_identifier &&
4302 (last_has_level_artwork_set[type] || has_level_artwork_set))
4303 artwork_new_identifier = artwork_current_identifier;
4305 leveldir_current_identifier[type] = leveldir_identifier;
4306 last_has_level_artwork_set[type] = has_level_artwork_set;
4309 if (type == ARTWORK_TYPE_GRAPHICS)
4310 printf("::: 1: '%s'\n", artwork_new_identifier);
4313 /* ---------- reload if "override artwork" setting has changed ----------- */
4314 if (last_override_level_artwork[type] != setup_override_artwork)
4315 artwork_new_identifier = artwork_current_identifier;
4317 last_override_level_artwork[type] = setup_override_artwork;
4320 if (type == ARTWORK_TYPE_GRAPHICS)
4321 printf("::: 2: '%s'\n", artwork_new_identifier);
4324 /* ---------- reload if current artwork identifier has changed ----------- */
4325 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4326 artwork_current_identifier) != 0)
4327 artwork_new_identifier = artwork_current_identifier;
4329 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4332 if (type == ARTWORK_TYPE_GRAPHICS)
4333 printf("::: 3: '%s'\n", artwork_new_identifier);
4336 /* ---------- do not reload directly after starting ---------------------- */
4337 if (!initialized[type])
4338 artwork_new_identifier = NULL;
4340 initialized[type] = TRUE;
4343 if (type == ARTWORK_TYPE_GRAPHICS)
4344 printf("::: 4: '%s'\n", artwork_new_identifier);
4348 if (type == ARTWORK_TYPE_GRAPHICS)
4349 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4350 artwork.gfx_current_identifier, artwork_current_identifier,
4351 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4352 artwork_new_identifier);
4355 return artwork_new_identifier;
4358 void ReloadCustomArtwork(int force_reload)
4360 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4361 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4362 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4363 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4364 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4365 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4366 boolean redraw_screen = FALSE;
4368 if (gfx_new_identifier != NULL || force_reload_gfx)
4371 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4372 artwork.gfx_current_identifier,
4374 artwork.gfx_current->identifier,
4375 leveldir_current->graphics_set);
4378 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4383 printf("... '%s'\n",
4384 leveldir_current->graphics_set);
4387 FreeTileClipmasks();
4388 InitTileClipmasks();
4390 redraw_screen = TRUE;
4393 if (snd_new_identifier != NULL || force_reload_snd)
4395 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4397 InitSound(snd_new_identifier);
4399 redraw_screen = TRUE;
4402 if (mus_new_identifier != NULL || force_reload_mus)
4404 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4406 InitMusic(mus_new_identifier);
4408 redraw_screen = TRUE;
4413 InitGfxBackground();
4415 /* force redraw of (open or closed) door graphics */
4416 SetDoorState(DOOR_OPEN_ALL);
4417 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4421 void KeyboardAutoRepeatOffUnlessAutoplay()
4423 if (global.autoplay_leveldir == NULL)
4424 KeyboardAutoRepeatOff();
4428 /* ========================================================================= */
4430 /* ========================================================================= */
4434 InitGlobal(); /* initialize some global variables */
4436 if (options.execute_command)
4437 Execute_Command(options.execute_command);
4439 if (options.serveronly)
4441 #if defined(PLATFORM_UNIX)
4442 NetworkServer(options.server_port, options.serveronly);
4444 Error(ERR_WARN, "networking only supported in Unix version");
4446 exit(0); /* never reached */
4452 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4453 InitArtworkConfig(); /* needed before forking sound child process */
4458 InitRND(NEW_RANDOMIZE);
4459 InitSimpleRND(NEW_RANDOMIZE);
4464 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4467 InitEventFilter(FilterMouseMotionEvents);
4469 InitElementPropertiesStatic();
4470 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4475 InitLevelArtworkInfo();
4477 InitImages(); /* needs to know current level directory */
4478 InitSound(NULL); /* needs to know current level directory */
4479 InitMusic(NULL); /* needs to know current level directory */
4481 InitGfxBackground();
4483 if (global.autoplay_leveldir)
4488 else if (global.convert_leveldir)
4494 game_status = GAME_MODE_MAIN;
4502 InitNetworkServer();
4505 void CloseAllAndExit(int exit_value)
4510 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4517 FreeTileClipmasks();
4519 #if defined(TARGET_SDL)
4520 if (network_server) /* terminate network server */
4521 SDL_KillThread(server_thread);
4524 CloseVideoDisplay();
4525 ClosePlatformDependentStuff();