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,
1800 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1801 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1805 EL_SP_BUGGY_BASE_ACTIVE,
1811 static int ep_collectible_only[] =
1832 EL_DYNABOMB_INCREASE_NUMBER,
1833 EL_DYNABOMB_INCREASE_SIZE,
1834 EL_DYNABOMB_INCREASE_POWER,
1853 static int ep_dont_run_into[] =
1855 /* same elements as in 'ep_dont_touch' */
1861 /* same elements as in 'ep_dont_collide_with' */
1873 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1877 EL_SP_BUGGY_BASE_ACTIVE,
1883 static int ep_dont_collide_with[] =
1885 /* same elements as in 'ep_dont_touch' */
1901 static int ep_dont_touch[] =
1910 static int ep_indestructible[] =
1914 EL_ACID_POOL_TOPLEFT,
1915 EL_ACID_POOL_TOPRIGHT,
1916 EL_ACID_POOL_BOTTOMLEFT,
1917 EL_ACID_POOL_BOTTOM,
1918 EL_ACID_POOL_BOTTOMRIGHT,
1919 EL_SP_HARDWARE_GRAY,
1920 EL_SP_HARDWARE_GREEN,
1921 EL_SP_HARDWARE_BLUE,
1923 EL_SP_HARDWARE_YELLOW,
1924 EL_SP_HARDWARE_BASE_1,
1925 EL_SP_HARDWARE_BASE_2,
1926 EL_SP_HARDWARE_BASE_3,
1927 EL_SP_HARDWARE_BASE_4,
1928 EL_SP_HARDWARE_BASE_5,
1929 EL_SP_HARDWARE_BASE_6,
1930 EL_INVISIBLE_STEELWALL,
1931 EL_INVISIBLE_STEELWALL_ACTIVE,
1932 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1933 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1934 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1935 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1936 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1937 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1938 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1939 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1940 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1941 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1942 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1943 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1945 EL_LIGHT_SWITCH_ACTIVE,
1946 EL_SIGN_EXCLAMATION,
1947 EL_SIGN_RADIOACTIVITY,
1958 EL_STEELWALL_SLIPPERY,
1981 EL_SWITCHGATE_OPENING,
1982 EL_SWITCHGATE_CLOSED,
1983 EL_SWITCHGATE_CLOSING,
1985 EL_SWITCHGATE_SWITCH_UP,
1986 EL_SWITCHGATE_SWITCH_DOWN,
1989 EL_TIMEGATE_OPENING,
1991 EL_TIMEGATE_CLOSING,
1994 EL_TIMEGATE_SWITCH_ACTIVE,
1999 EL_TUBE_VERTICAL_LEFT,
2000 EL_TUBE_VERTICAL_RIGHT,
2001 EL_TUBE_HORIZONTAL_UP,
2002 EL_TUBE_HORIZONTAL_DOWN,
2010 static int ep_slippery[] =
2024 EL_ROBOT_WHEEL_ACTIVE,
2030 EL_ACID_POOL_TOPLEFT,
2031 EL_ACID_POOL_TOPRIGHT,
2041 EL_STEELWALL_SLIPPERY,
2044 EL_EMC_WALL_SLIPPERY_1,
2045 EL_EMC_WALL_SLIPPERY_2,
2046 EL_EMC_WALL_SLIPPERY_3,
2047 EL_EMC_WALL_SLIPPERY_4,
2051 static int ep_can_change[] =
2056 static int ep_can_move[] =
2058 /* same elements as in 'pb_can_move_into_acid' */
2080 static int ep_can_fall[] =
2095 EL_BD_MAGIC_WALL_FULL,
2108 static int ep_can_smash_player[] =
2133 static int ep_can_smash_enemies[] =
2141 static int ep_can_smash_everything[] =
2149 static int ep_explodes_by_fire[] =
2151 /* same elements as in 'ep_explodes_impact' */
2156 /* same elements as in 'ep_explodes_smashed' */
2165 EL_DYNABOMB_PLAYER_1_ACTIVE,
2166 EL_DYNABOMB_PLAYER_2_ACTIVE,
2167 EL_DYNABOMB_PLAYER_3_ACTIVE,
2168 EL_DYNABOMB_PLAYER_4_ACTIVE,
2169 EL_DYNABOMB_INCREASE_NUMBER,
2170 EL_DYNABOMB_INCREASE_SIZE,
2171 EL_DYNABOMB_INCREASE_POWER,
2172 EL_SP_DISK_RED_ACTIVE,
2185 static int ep_explodes_smashed[] =
2187 /* same elements as in 'ep_explodes_impact' */
2200 static int ep_explodes_impact[] =
2208 static int ep_walkable_over[] =
2212 EL_SOKOBAN_FIELD_EMPTY,
2230 static int ep_walkable_inside[] =
2235 EL_TUBE_VERTICAL_LEFT,
2236 EL_TUBE_VERTICAL_RIGHT,
2237 EL_TUBE_HORIZONTAL_UP,
2238 EL_TUBE_HORIZONTAL_DOWN,
2246 static int ep_walkable_under[] =
2251 static int ep_passable_over[] =
2274 static int ep_passable_inside[] =
2280 EL_SP_PORT_HORIZONTAL,
2281 EL_SP_PORT_VERTICAL,
2283 EL_SP_GRAVITY_PORT_LEFT,
2284 EL_SP_GRAVITY_PORT_RIGHT,
2285 EL_SP_GRAVITY_PORT_UP,
2286 EL_SP_GRAVITY_PORT_DOWN,
2287 EL_SP_GRAVITY_ON_PORT_LEFT,
2288 EL_SP_GRAVITY_ON_PORT_RIGHT,
2289 EL_SP_GRAVITY_ON_PORT_UP,
2290 EL_SP_GRAVITY_ON_PORT_DOWN,
2291 EL_SP_GRAVITY_OFF_PORT_LEFT,
2292 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2293 EL_SP_GRAVITY_OFF_PORT_UP,
2294 EL_SP_GRAVITY_OFF_PORT_DOWN,
2298 static int ep_passable_under[] =
2303 static int ep_droppable[] =
2308 static int ep_explodes_1x1_old[] =
2313 static int ep_pushable[] =
2325 EL_SOKOBAN_FIELD_FULL,
2333 static int ep_explodes_cross_old[] =
2338 static int ep_protected[] =
2340 /* same elements as in 'ep_walkable_inside' */
2344 EL_TUBE_VERTICAL_LEFT,
2345 EL_TUBE_VERTICAL_RIGHT,
2346 EL_TUBE_HORIZONTAL_UP,
2347 EL_TUBE_HORIZONTAL_DOWN,
2353 /* same elements as in 'ep_passable_over' */
2373 /* same elements as in 'ep_passable_inside' */
2378 EL_SP_PORT_HORIZONTAL,
2379 EL_SP_PORT_VERTICAL,
2381 EL_SP_GRAVITY_PORT_LEFT,
2382 EL_SP_GRAVITY_PORT_RIGHT,
2383 EL_SP_GRAVITY_PORT_UP,
2384 EL_SP_GRAVITY_PORT_DOWN,
2385 EL_SP_GRAVITY_ON_PORT_LEFT,
2386 EL_SP_GRAVITY_ON_PORT_RIGHT,
2387 EL_SP_GRAVITY_ON_PORT_UP,
2388 EL_SP_GRAVITY_ON_PORT_DOWN,
2389 EL_SP_GRAVITY_OFF_PORT_LEFT,
2390 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2391 EL_SP_GRAVITY_OFF_PORT_UP,
2392 EL_SP_GRAVITY_OFF_PORT_DOWN,
2396 static int ep_throwable[] =
2401 static int ep_can_explode[] =
2403 /* same elements as in 'ep_explodes_impact' */
2408 /* same elements as in 'ep_explodes_smashed' */
2414 /* elements that can explode by explosion or by dragonfire */
2417 EL_DYNABOMB_PLAYER_1_ACTIVE,
2418 EL_DYNABOMB_PLAYER_2_ACTIVE,
2419 EL_DYNABOMB_PLAYER_3_ACTIVE,
2420 EL_DYNABOMB_PLAYER_4_ACTIVE,
2421 EL_DYNABOMB_INCREASE_NUMBER,
2422 EL_DYNABOMB_INCREASE_SIZE,
2423 EL_DYNABOMB_INCREASE_POWER,
2424 EL_SP_DISK_RED_ACTIVE,
2432 /* elements that can explode only by explosion */
2437 static int ep_gravity_reachable[] =
2443 EL_INVISIBLE_SAND_ACTIVE,
2448 EL_SP_PORT_HORIZONTAL,
2449 EL_SP_PORT_VERTICAL,
2451 EL_SP_GRAVITY_PORT_LEFT,
2452 EL_SP_GRAVITY_PORT_RIGHT,
2453 EL_SP_GRAVITY_PORT_UP,
2454 EL_SP_GRAVITY_PORT_DOWN,
2455 EL_SP_GRAVITY_ON_PORT_LEFT,
2456 EL_SP_GRAVITY_ON_PORT_RIGHT,
2457 EL_SP_GRAVITY_ON_PORT_UP,
2458 EL_SP_GRAVITY_ON_PORT_DOWN,
2459 EL_SP_GRAVITY_OFF_PORT_LEFT,
2460 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2461 EL_SP_GRAVITY_OFF_PORT_UP,
2462 EL_SP_GRAVITY_OFF_PORT_DOWN,
2467 static int ep_player[] =
2474 EL_SOKOBAN_FIELD_PLAYER,
2479 static int ep_can_pass_magic_wall[] =
2492 static int ep_switchable[] =
2496 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2497 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2498 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2499 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2500 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2501 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2502 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2503 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2504 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2505 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2506 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2507 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2508 EL_SWITCHGATE_SWITCH_UP,
2509 EL_SWITCHGATE_SWITCH_DOWN,
2511 EL_LIGHT_SWITCH_ACTIVE,
2513 EL_BALLOON_SWITCH_LEFT,
2514 EL_BALLOON_SWITCH_RIGHT,
2515 EL_BALLOON_SWITCH_UP,
2516 EL_BALLOON_SWITCH_DOWN,
2517 EL_BALLOON_SWITCH_ANY,
2520 EL_EMC_MAGIC_BALL_SWITCH,
2524 static int ep_bd_element[] =
2557 static int ep_sp_element[] =
2559 /* should always be valid */
2562 /* standard classic Supaplex elements */
2569 EL_SP_HARDWARE_GRAY,
2577 EL_SP_GRAVITY_PORT_RIGHT,
2578 EL_SP_GRAVITY_PORT_DOWN,
2579 EL_SP_GRAVITY_PORT_LEFT,
2580 EL_SP_GRAVITY_PORT_UP,
2585 EL_SP_PORT_VERTICAL,
2586 EL_SP_PORT_HORIZONTAL,
2592 EL_SP_HARDWARE_BASE_1,
2593 EL_SP_HARDWARE_GREEN,
2594 EL_SP_HARDWARE_BLUE,
2596 EL_SP_HARDWARE_YELLOW,
2597 EL_SP_HARDWARE_BASE_2,
2598 EL_SP_HARDWARE_BASE_3,
2599 EL_SP_HARDWARE_BASE_4,
2600 EL_SP_HARDWARE_BASE_5,
2601 EL_SP_HARDWARE_BASE_6,
2605 /* additional elements that appeared in newer Supaplex levels */
2608 /* additional gravity port elements (not switching, but setting gravity) */
2609 EL_SP_GRAVITY_ON_PORT_LEFT,
2610 EL_SP_GRAVITY_ON_PORT_RIGHT,
2611 EL_SP_GRAVITY_ON_PORT_UP,
2612 EL_SP_GRAVITY_ON_PORT_DOWN,
2613 EL_SP_GRAVITY_OFF_PORT_LEFT,
2614 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2615 EL_SP_GRAVITY_OFF_PORT_UP,
2616 EL_SP_GRAVITY_OFF_PORT_DOWN,
2618 /* more than one Murphy in a level results in an inactive clone */
2621 /* runtime Supaplex elements */
2622 EL_SP_DISK_RED_ACTIVE,
2623 EL_SP_TERMINAL_ACTIVE,
2624 EL_SP_BUGGY_BASE_ACTIVATING,
2625 EL_SP_BUGGY_BASE_ACTIVE,
2631 static int ep_sb_element[] =
2636 EL_SOKOBAN_FIELD_EMPTY,
2637 EL_SOKOBAN_FIELD_FULL,
2638 EL_SOKOBAN_FIELD_PLAYER,
2643 EL_INVISIBLE_STEELWALL,
2647 static int ep_gem[] =
2658 static int ep_food_dark_yamyam[] =
2685 static int ep_food_penguin[] =
2698 static int ep_food_pig[] =
2709 static int ep_historic_wall[] =
2734 EL_EXPANDABLE_WALL_HORIZONTAL,
2735 EL_EXPANDABLE_WALL_VERTICAL,
2736 EL_EXPANDABLE_WALL_ANY,
2737 EL_EXPANDABLE_WALL_GROWING,
2744 EL_SP_HARDWARE_GRAY,
2745 EL_SP_HARDWARE_GREEN,
2746 EL_SP_HARDWARE_BLUE,
2748 EL_SP_HARDWARE_YELLOW,
2749 EL_SP_HARDWARE_BASE_1,
2750 EL_SP_HARDWARE_BASE_2,
2751 EL_SP_HARDWARE_BASE_3,
2752 EL_SP_HARDWARE_BASE_4,
2753 EL_SP_HARDWARE_BASE_5,
2754 EL_SP_HARDWARE_BASE_6,
2756 EL_SP_TERMINAL_ACTIVE,
2759 EL_INVISIBLE_STEELWALL,
2760 EL_INVISIBLE_STEELWALL_ACTIVE,
2762 EL_INVISIBLE_WALL_ACTIVE,
2763 EL_STEELWALL_SLIPPERY,
2779 static int ep_historic_solid[] =
2783 EL_EXPANDABLE_WALL_HORIZONTAL,
2784 EL_EXPANDABLE_WALL_VERTICAL,
2785 EL_EXPANDABLE_WALL_ANY,
2798 EL_QUICKSAND_FILLING,
2799 EL_QUICKSAND_EMPTYING,
2801 EL_MAGIC_WALL_ACTIVE,
2802 EL_MAGIC_WALL_EMPTYING,
2803 EL_MAGIC_WALL_FILLING,
2807 EL_BD_MAGIC_WALL_ACTIVE,
2808 EL_BD_MAGIC_WALL_EMPTYING,
2809 EL_BD_MAGIC_WALL_FULL,
2810 EL_BD_MAGIC_WALL_FILLING,
2811 EL_BD_MAGIC_WALL_DEAD,
2820 EL_SP_TERMINAL_ACTIVE,
2824 EL_INVISIBLE_WALL_ACTIVE,
2825 EL_SWITCHGATE_SWITCH_UP,
2826 EL_SWITCHGATE_SWITCH_DOWN,
2828 EL_TIMEGATE_SWITCH_ACTIVE,
2840 /* the following elements are a direct copy of "indestructible" elements,
2841 except "EL_ACID", which is "indestructible", but not "solid"! */
2846 EL_ACID_POOL_TOPLEFT,
2847 EL_ACID_POOL_TOPRIGHT,
2848 EL_ACID_POOL_BOTTOMLEFT,
2849 EL_ACID_POOL_BOTTOM,
2850 EL_ACID_POOL_BOTTOMRIGHT,
2851 EL_SP_HARDWARE_GRAY,
2852 EL_SP_HARDWARE_GREEN,
2853 EL_SP_HARDWARE_BLUE,
2855 EL_SP_HARDWARE_YELLOW,
2856 EL_SP_HARDWARE_BASE_1,
2857 EL_SP_HARDWARE_BASE_2,
2858 EL_SP_HARDWARE_BASE_3,
2859 EL_SP_HARDWARE_BASE_4,
2860 EL_SP_HARDWARE_BASE_5,
2861 EL_SP_HARDWARE_BASE_6,
2862 EL_INVISIBLE_STEELWALL,
2863 EL_INVISIBLE_STEELWALL_ACTIVE,
2864 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2865 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2866 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2867 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2868 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2869 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2870 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2871 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2872 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2873 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2874 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2875 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2877 EL_LIGHT_SWITCH_ACTIVE,
2878 EL_SIGN_EXCLAMATION,
2879 EL_SIGN_RADIOACTIVITY,
2890 EL_STEELWALL_SLIPPERY,
2913 EL_SWITCHGATE_OPENING,
2914 EL_SWITCHGATE_CLOSED,
2915 EL_SWITCHGATE_CLOSING,
2917 EL_TIMEGATE_OPENING,
2919 EL_TIMEGATE_CLOSING,
2923 EL_TUBE_VERTICAL_LEFT,
2924 EL_TUBE_VERTICAL_RIGHT,
2925 EL_TUBE_HORIZONTAL_UP,
2926 EL_TUBE_HORIZONTAL_DOWN,
2934 static int ep_classic_enemy[] =
2950 static int ep_belt[] =
2952 EL_CONVEYOR_BELT_1_LEFT,
2953 EL_CONVEYOR_BELT_1_MIDDLE,
2954 EL_CONVEYOR_BELT_1_RIGHT,
2955 EL_CONVEYOR_BELT_2_LEFT,
2956 EL_CONVEYOR_BELT_2_MIDDLE,
2957 EL_CONVEYOR_BELT_2_RIGHT,
2958 EL_CONVEYOR_BELT_3_LEFT,
2959 EL_CONVEYOR_BELT_3_MIDDLE,
2960 EL_CONVEYOR_BELT_3_RIGHT,
2961 EL_CONVEYOR_BELT_4_LEFT,
2962 EL_CONVEYOR_BELT_4_MIDDLE,
2963 EL_CONVEYOR_BELT_4_RIGHT,
2967 static int ep_belt_active[] =
2969 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2970 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2971 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2972 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2973 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2974 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2975 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2976 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2977 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2978 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2979 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2980 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2984 static int ep_belt_switch[] =
2986 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2987 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2988 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2989 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2990 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2991 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2992 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2993 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2994 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2995 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2996 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2997 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3001 static int ep_tube[] =
3008 EL_TUBE_HORIZONTAL_UP,
3009 EL_TUBE_HORIZONTAL_DOWN,
3011 EL_TUBE_VERTICAL_LEFT,
3012 EL_TUBE_VERTICAL_RIGHT,
3017 static int ep_keygate[] =
3046 static int ep_amoeboid[] =
3056 static int ep_amoebalive[] =
3065 static int ep_has_content[] =
3075 static int ep_can_turn_each_move[] =
3077 /* !!! do something with this one !!! */
3081 static int ep_can_grow[] =
3093 static int ep_active_bomb[] =
3096 EL_DYNABOMB_PLAYER_1_ACTIVE,
3097 EL_DYNABOMB_PLAYER_2_ACTIVE,
3098 EL_DYNABOMB_PLAYER_3_ACTIVE,
3099 EL_DYNABOMB_PLAYER_4_ACTIVE,
3100 EL_SP_DISK_RED_ACTIVE,
3104 static int ep_inactive[] =
3153 EL_INVISIBLE_STEELWALL,
3161 EL_WALL_EMERALD_YELLOW,
3162 EL_DYNABOMB_INCREASE_NUMBER,
3163 EL_DYNABOMB_INCREASE_SIZE,
3164 EL_DYNABOMB_INCREASE_POWER,
3168 EL_SOKOBAN_FIELD_EMPTY,
3169 EL_SOKOBAN_FIELD_FULL,
3170 EL_WALL_EMERALD_RED,
3171 EL_WALL_EMERALD_PURPLE,
3172 EL_ACID_POOL_TOPLEFT,
3173 EL_ACID_POOL_TOPRIGHT,
3174 EL_ACID_POOL_BOTTOMLEFT,
3175 EL_ACID_POOL_BOTTOM,
3176 EL_ACID_POOL_BOTTOMRIGHT,
3180 EL_BD_MAGIC_WALL_DEAD,
3181 EL_AMOEBA_TO_DIAMOND,
3189 EL_SP_GRAVITY_PORT_RIGHT,
3190 EL_SP_GRAVITY_PORT_DOWN,
3191 EL_SP_GRAVITY_PORT_LEFT,
3192 EL_SP_GRAVITY_PORT_UP,
3193 EL_SP_PORT_HORIZONTAL,
3194 EL_SP_PORT_VERTICAL,
3205 EL_SP_HARDWARE_GRAY,
3206 EL_SP_HARDWARE_GREEN,
3207 EL_SP_HARDWARE_BLUE,
3209 EL_SP_HARDWARE_YELLOW,
3210 EL_SP_HARDWARE_BASE_1,
3211 EL_SP_HARDWARE_BASE_2,
3212 EL_SP_HARDWARE_BASE_3,
3213 EL_SP_HARDWARE_BASE_4,
3214 EL_SP_HARDWARE_BASE_5,
3215 EL_SP_HARDWARE_BASE_6,
3216 EL_SP_GRAVITY_ON_PORT_LEFT,
3217 EL_SP_GRAVITY_ON_PORT_RIGHT,
3218 EL_SP_GRAVITY_ON_PORT_UP,
3219 EL_SP_GRAVITY_ON_PORT_DOWN,
3220 EL_SP_GRAVITY_OFF_PORT_LEFT,
3221 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3222 EL_SP_GRAVITY_OFF_PORT_UP,
3223 EL_SP_GRAVITY_OFF_PORT_DOWN,
3224 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3225 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3226 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3227 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3228 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3229 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3230 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3231 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3232 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3233 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3234 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3235 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3236 EL_SIGN_EXCLAMATION,
3237 EL_SIGN_RADIOACTIVITY,
3248 EL_STEELWALL_SLIPPERY,
3253 EL_EMC_WALL_SLIPPERY_1,
3254 EL_EMC_WALL_SLIPPERY_2,
3255 EL_EMC_WALL_SLIPPERY_3,
3256 EL_EMC_WALL_SLIPPERY_4,
3276 static int ep_em_slippery_wall[] =
3281 static int ep_gfx_crumbled[] =
3294 } element_properties[] =
3296 { ep_diggable, EP_DIGGABLE },
3297 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3298 { ep_dont_run_into, EP_DONT_RUN_INTO },
3299 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3300 { ep_dont_touch, EP_DONT_TOUCH },
3301 { ep_indestructible, EP_INDESTRUCTIBLE },
3302 { ep_slippery, EP_SLIPPERY },
3303 { ep_can_change, EP_CAN_CHANGE },
3304 { ep_can_move, EP_CAN_MOVE },
3305 { ep_can_fall, EP_CAN_FALL },
3306 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3307 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3308 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3309 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3310 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3311 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3312 { ep_walkable_over, EP_WALKABLE_OVER },
3313 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3314 { ep_walkable_under, EP_WALKABLE_UNDER },
3315 { ep_passable_over, EP_PASSABLE_OVER },
3316 { ep_passable_inside, EP_PASSABLE_INSIDE },
3317 { ep_passable_under, EP_PASSABLE_UNDER },
3318 { ep_droppable, EP_DROPPABLE },
3319 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3320 { ep_pushable, EP_PUSHABLE },
3321 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3322 { ep_protected, EP_PROTECTED },
3323 { ep_throwable, EP_THROWABLE },
3324 { ep_can_explode, EP_CAN_EXPLODE },
3325 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3327 { ep_player, EP_PLAYER },
3328 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3329 { ep_switchable, EP_SWITCHABLE },
3330 { ep_bd_element, EP_BD_ELEMENT },
3331 { ep_sp_element, EP_SP_ELEMENT },
3332 { ep_sb_element, EP_SB_ELEMENT },
3334 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3335 { ep_food_penguin, EP_FOOD_PENGUIN },
3336 { ep_food_pig, EP_FOOD_PIG },
3337 { ep_historic_wall, EP_HISTORIC_WALL },
3338 { ep_historic_solid, EP_HISTORIC_SOLID },
3339 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3340 { ep_belt, EP_BELT },
3341 { ep_belt_active, EP_BELT_ACTIVE },
3342 { ep_belt_switch, EP_BELT_SWITCH },
3343 { ep_tube, EP_TUBE },
3344 { ep_keygate, EP_KEYGATE },
3345 { ep_amoeboid, EP_AMOEBOID },
3346 { ep_amoebalive, EP_AMOEBALIVE },
3347 { ep_has_content, EP_HAS_CONTENT },
3348 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3349 { ep_can_grow, EP_CAN_GROW },
3350 { ep_active_bomb, EP_ACTIVE_BOMB },
3351 { ep_inactive, EP_INACTIVE },
3353 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3355 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3360 static int copy_properties[][5] =
3364 EL_BUG_LEFT, EL_BUG_RIGHT,
3365 EL_BUG_UP, EL_BUG_DOWN
3369 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3370 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3374 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3375 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3379 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3380 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3384 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3385 EL_PACMAN_UP, EL_PACMAN_DOWN
3389 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3390 EL_MOLE_UP, EL_MOLE_DOWN
3400 /* always start with reliable default values (element has no properties) */
3401 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3402 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3403 SET_PROPERTY(i, j, FALSE);
3405 /* set all base element properties from above array definitions */
3406 for (i = 0; element_properties[i].elements != NULL; i++)
3407 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3408 SET_PROPERTY((element_properties[i].elements)[j],
3409 element_properties[i].property, TRUE);
3411 /* copy properties to some elements that are only stored in level file */
3412 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3413 for (j = 0; copy_properties[j][0] != -1; j++)
3414 if (HAS_PROPERTY(copy_properties[j][0], i))
3415 for (k = 1; k <= 4; k++)
3416 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3419 void InitElementPropertiesEngine(int engine_version)
3422 static int active_properties[] =
3427 EP_DONT_COLLIDE_WITH,
3431 EP_CAN_PASS_MAGIC_WALL,
3436 EP_EXPLODES_BY_FIRE,
3449 EP_EM_SLIPPERY_WALL,
3453 static int no_wall_properties[] =
3456 EP_COLLECTIBLE_ONLY,
3458 EP_DONT_COLLIDE_WITH,
3461 EP_CAN_SMASH_PLAYER,
3462 EP_CAN_SMASH_ENEMIES,
3463 EP_CAN_SMASH_EVERYTHING,
3468 EP_FOOD_DARK_YAMYAM,
3485 InitElementPropertiesStatic();
3488 /* important: after initialization in InitElementPropertiesStatic(), the
3489 elements are not again initialized to a default value; therefore all
3490 changes have to make sure that they leave the element with a defined
3491 property (which means that conditional property changes must be set to
3492 a reliable default value before) */
3494 /* set all special, combined or engine dependent element properties */
3495 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3498 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3499 SET_PROPERTY(i, j, FALSE);
3502 /* ---------- INACTIVE ------------------------------------------------- */
3503 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3505 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3506 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3507 IS_WALKABLE_INSIDE(i) ||
3508 IS_WALKABLE_UNDER(i)));
3510 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3511 IS_PASSABLE_INSIDE(i) ||
3512 IS_PASSABLE_UNDER(i)));
3514 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3515 IS_PASSABLE_OVER(i)));
3517 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3518 IS_PASSABLE_INSIDE(i)));
3520 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3521 IS_PASSABLE_UNDER(i)));
3523 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3526 /* ---------- COLLECTIBLE ---------------------------------------------- */
3527 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3531 /* ---------- SNAPPABLE ------------------------------------------------ */
3532 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3533 IS_COLLECTIBLE(i) ||
3537 /* ---------- WALL ----------------------------------------------------- */
3538 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3540 for (j = 0; no_wall_properties[j] != -1; j++)
3541 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3542 i >= EL_FIRST_RUNTIME_UNREAL)
3543 SET_PROPERTY(i, EP_WALL, FALSE);
3545 if (IS_HISTORIC_WALL(i))
3546 SET_PROPERTY(i, EP_WALL, TRUE);
3548 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3549 if (engine_version < VERSION_IDENT(2,2,0,0))
3550 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3552 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3554 !IS_COLLECTIBLE(i)));
3557 /* ---------- PROTECTED ------------------------------------------------ */
3558 if (IS_ACCESSIBLE_INSIDE(i))
3559 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3562 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3564 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3565 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3567 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3568 IS_INDESTRUCTIBLE(i)));
3570 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3572 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3573 else if (engine_version < VERSION_IDENT(2,2,0,0))
3574 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3577 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3582 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3583 !IS_WALKABLE_OVER(i) &&
3584 !IS_WALKABLE_UNDER(i)));
3586 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3591 if (IS_CUSTOM_ELEMENT(i))
3593 /* these are additional properties which are initially false when set */
3595 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3597 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3598 if (DONT_COLLIDE_WITH(i))
3599 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3601 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3602 if (CAN_SMASH_EVERYTHING(i))
3603 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3604 if (CAN_SMASH_ENEMIES(i))
3605 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3608 /* ---------- CAN_SMASH ------------------------------------------------ */
3609 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3610 CAN_SMASH_ENEMIES(i) ||
3611 CAN_SMASH_EVERYTHING(i)));
3614 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3615 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3616 CAN_EXPLODE_SMASHED(i) ||
3617 CAN_EXPLODE_IMPACT(i)));
3621 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3623 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3624 !CAN_EXPLODE_CROSS(i)));
3626 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3627 !CAN_EXPLODE_1X1(i) &&
3628 !CAN_EXPLODE_CROSS(i)));
3632 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3633 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3634 EXPLODES_BY_FIRE(i)));
3636 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3637 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3638 EXPLODES_SMASHED(i)));
3640 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3641 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3642 EXPLODES_IMPACT(i)));
3644 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3645 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3647 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3648 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3649 i == EL_BLACK_ORB));
3651 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3652 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3654 IS_CUSTOM_ELEMENT(i)));
3656 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3657 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3658 i == EL_SP_ELECTRON));
3660 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3661 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3662 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3663 getMoveIntoAcidProperty(&level, i));
3665 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3666 if (MAYBE_DONT_COLLIDE_WITH(i))
3667 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3668 getDontCollideWithProperty(&level, i));
3670 /* ---------- SP_PORT -------------------------------------------------- */
3671 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3672 IS_PASSABLE_INSIDE(i)));
3674 /* ---------- CAN_CHANGE ----------------------------------------------- */
3675 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3676 for (j = 0; j < element_info[i].num_change_pages; j++)
3677 if (element_info[i].change_page[j].can_change)
3678 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3680 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3681 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3682 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3686 /* determine inactive elements (used for engine main loop optimization) */
3687 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3689 boolean active = FALSE;
3691 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3693 if (HAS_PROPERTY(i, j))
3699 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3704 /* dynamically adjust element properties according to game engine version */
3706 static int ep_em_slippery_wall[] =
3711 EL_EXPANDABLE_WALL_HORIZONTAL,
3712 EL_EXPANDABLE_WALL_VERTICAL,
3713 EL_EXPANDABLE_WALL_ANY,
3717 /* special EM style gems behaviour */
3718 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3719 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3720 level.em_slippery_gems);
3722 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3723 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3724 (level.em_slippery_gems &&
3725 engine_version > VERSION_IDENT(2,0,1,0)));
3729 /* set default push delay values (corrected since version 3.0.7-1) */
3730 if (engine_version < VERSION_IDENT(3,0,7,1))
3732 game.default_push_delay_fixed = 2;
3733 game.default_push_delay_random = 8;
3737 game.default_push_delay_fixed = 8;
3738 game.default_push_delay_random = 8;
3741 /* set uninitialized push delay values of custom elements in older levels */
3742 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3744 int element = EL_CUSTOM_START + i;
3746 if (element_info[element].push_delay_fixed == -1)
3747 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3748 if (element_info[element].push_delay_random == -1)
3749 element_info[element].push_delay_random = game.default_push_delay_random;
3752 /* set some other uninitialized values of custom elements in older levels */
3753 if (engine_version < VERSION_IDENT(3,1,0,0))
3755 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3757 int element = EL_CUSTOM_START + i;
3759 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3761 element_info[element].explosion_delay = 17;
3762 element_info[element].ignition_delay = 8;
3767 /* set element properties that were handled incorrectly in older levels */
3768 if (engine_version < VERSION_IDENT(3,1,0,0))
3770 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3771 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3777 /* this is needed because some graphics depend on element properties */
3778 if (game_status == GAME_MODE_PLAYING)
3779 InitElementGraphicInfo();
3782 static void InitGlobal()
3786 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3788 /* check if element_name_info entry defined for each element in "main.h" */
3789 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3790 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3792 element_info[i].token_name = element_name_info[i].token_name;
3793 element_info[i].class_name = element_name_info[i].class_name;
3794 element_info[i].editor_description=element_name_info[i].editor_description;
3797 global.autoplay_leveldir = NULL;
3798 global.convert_leveldir = NULL;
3800 global.frames_per_second = 0;
3801 global.fps_slowdown = FALSE;
3802 global.fps_slowdown_factor = 1;
3805 void Execute_Command(char *command)
3809 if (strcmp(command, "print graphicsinfo.conf") == 0)
3811 printf("# You can configure additional/alternative image files here.\n");
3812 printf("# (The entries below are default and therefore commented out.)\n");
3814 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3816 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3819 for (i = 0; image_config[i].token != NULL; i++)
3820 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3821 image_config[i].value));
3825 else if (strcmp(command, "print soundsinfo.conf") == 0)
3827 printf("# You can configure additional/alternative sound files here.\n");
3828 printf("# (The entries below are default and therefore commented out.)\n");
3830 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3832 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3835 for (i = 0; sound_config[i].token != NULL; i++)
3836 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3837 sound_config[i].value));
3841 else if (strcmp(command, "print musicinfo.conf") == 0)
3843 printf("# You can configure additional/alternative music files here.\n");
3844 printf("# (The entries below are default and therefore commented out.)\n");
3846 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3848 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3851 for (i = 0; music_config[i].token != NULL; i++)
3852 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3853 music_config[i].value));
3857 else if (strcmp(command, "print editorsetup.conf") == 0)
3859 printf("# You can configure your personal editor element list here.\n");
3860 printf("# (The entries below are default and therefore commented out.)\n");
3863 PrintEditorElementList();
3867 else if (strcmp(command, "print helpanim.conf") == 0)
3869 printf("# You can configure different element help animations here.\n");
3870 printf("# (The entries below are default and therefore commented out.)\n");
3873 for (i = 0; helpanim_config[i].token != NULL; i++)
3875 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3876 helpanim_config[i].value));
3878 if (strcmp(helpanim_config[i].token, "end") == 0)
3884 else if (strcmp(command, "print helptext.conf") == 0)
3886 printf("# You can configure different element help text here.\n");
3887 printf("# (The entries below are default and therefore commented out.)\n");
3890 for (i = 0; helptext_config[i].token != NULL; i++)
3891 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3892 helptext_config[i].value));
3896 else if (strncmp(command, "dump level ", 11) == 0)
3898 char *filename = &command[11];
3900 if (access(filename, F_OK) != 0)
3901 Error(ERR_EXIT, "cannot open file '%s'", filename);
3903 LoadLevelFromFilename(&level, filename);
3908 else if (strncmp(command, "dump tape ", 10) == 0)
3910 char *filename = &command[10];
3912 if (access(filename, F_OK) != 0)
3913 Error(ERR_EXIT, "cannot open file '%s'", filename);
3915 LoadTapeFromFilename(filename);
3920 else if (strncmp(command, "autoplay ", 9) == 0)
3922 char *str_copy = getStringCopy(&command[9]);
3923 char *str_ptr = strchr(str_copy, ' ');
3925 global.autoplay_leveldir = str_copy;
3926 global.autoplay_level_nr = -1;
3928 if (str_ptr != NULL)
3930 *str_ptr++ = '\0'; /* terminate leveldir string */
3931 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3934 else if (strncmp(command, "convert ", 8) == 0)
3936 char *str_copy = getStringCopy(&command[8]);
3937 char *str_ptr = strchr(str_copy, ' ');
3939 global.convert_leveldir = str_copy;
3940 global.convert_level_nr = -1;
3942 if (str_ptr != NULL)
3944 *str_ptr++ = '\0'; /* terminate leveldir string */
3945 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3950 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3954 static void InitSetup()
3956 LoadSetup(); /* global setup info */
3958 /* set some options from setup file */
3960 if (setup.options.verbose)
3961 options.verbose = TRUE;
3964 static void InitPlayerInfo()
3968 /* choose default local player */
3969 local_player = &stored_player[0];
3971 for (i = 0; i < MAX_PLAYERS; i++)
3972 stored_player[i].connected = FALSE;
3974 local_player->connected = TRUE;
3977 static void InitArtworkInfo()
3982 static char *get_string_in_brackets(char *string)
3984 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3986 sprintf(string_in_brackets, "[%s]", string);
3988 return string_in_brackets;
3991 static char *get_level_id_suffix(int id_nr)
3993 char *id_suffix = checked_malloc(1 + 3 + 1);
3995 if (id_nr < 0 || id_nr > 999)
3998 sprintf(id_suffix, ".%03d", id_nr);
4004 static char *get_element_class_token(int element)
4006 char *element_class_name = element_info[element].class_name;
4007 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4009 sprintf(element_class_token, "[%s]", element_class_name);
4011 return element_class_token;
4014 static char *get_action_class_token(int action)
4016 char *action_class_name = &element_action_info[action].suffix[1];
4017 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4019 sprintf(action_class_token, "[%s]", action_class_name);
4021 return action_class_token;
4025 static void InitArtworkConfig()
4027 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4028 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4029 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4030 static char *action_id_suffix[NUM_ACTIONS + 1];
4031 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4032 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4033 static char *level_id_suffix[MAX_LEVELS + 1];
4034 static char *dummy[1] = { NULL };
4035 static char *ignore_generic_tokens[] =
4041 static char **ignore_image_tokens;
4042 static char **ignore_sound_tokens;
4043 static char **ignore_music_tokens;
4044 int num_ignore_generic_tokens;
4045 int num_ignore_image_tokens;
4046 int num_ignore_sound_tokens;
4047 int num_ignore_music_tokens;
4050 /* dynamically determine list of generic tokens to be ignored */
4051 num_ignore_generic_tokens = 0;
4052 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4053 num_ignore_generic_tokens++;
4055 /* dynamically determine list of image tokens to be ignored */
4056 num_ignore_image_tokens = num_ignore_generic_tokens;
4057 for (i = 0; image_config_vars[i].token != NULL; i++)
4058 num_ignore_image_tokens++;
4059 ignore_image_tokens =
4060 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4061 for (i = 0; i < num_ignore_generic_tokens; i++)
4062 ignore_image_tokens[i] = ignore_generic_tokens[i];
4063 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4064 ignore_image_tokens[num_ignore_generic_tokens + i] =
4065 image_config_vars[i].token;
4066 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4068 /* dynamically determine list of sound tokens to be ignored */
4069 num_ignore_sound_tokens = num_ignore_generic_tokens;
4070 ignore_sound_tokens =
4071 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4072 for (i = 0; i < num_ignore_generic_tokens; i++)
4073 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4074 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4076 /* dynamically determine list of music tokens to be ignored */
4077 num_ignore_music_tokens = num_ignore_generic_tokens;
4078 ignore_music_tokens =
4079 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4080 for (i = 0; i < num_ignore_generic_tokens; i++)
4081 ignore_music_tokens[i] = ignore_generic_tokens[i];
4082 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4084 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4085 image_id_prefix[i] = element_info[i].token_name;
4086 for (i = 0; i < NUM_FONTS; i++)
4087 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4088 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4090 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4091 sound_id_prefix[i] = element_info[i].token_name;
4092 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4093 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4094 get_string_in_brackets(element_info[i].class_name);
4095 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4097 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4098 music_id_prefix[i] = music_prefix_info[i].prefix;
4099 music_id_prefix[MAX_LEVELS] = NULL;
4101 for (i = 0; i < NUM_ACTIONS; i++)
4102 action_id_suffix[i] = element_action_info[i].suffix;
4103 action_id_suffix[NUM_ACTIONS] = NULL;
4105 for (i = 0; i < NUM_DIRECTIONS; i++)
4106 direction_id_suffix[i] = element_direction_info[i].suffix;
4107 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4109 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4110 special_id_suffix[i] = special_suffix_info[i].suffix;
4111 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4113 for (i = 0; i < MAX_LEVELS; i++)
4114 level_id_suffix[i] = get_level_id_suffix(i);
4115 level_id_suffix[MAX_LEVELS] = NULL;
4117 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4118 image_id_prefix, action_id_suffix, direction_id_suffix,
4119 special_id_suffix, ignore_image_tokens);
4120 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4121 sound_id_prefix, action_id_suffix, dummy,
4122 special_id_suffix, ignore_sound_tokens);
4123 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4124 music_id_prefix, special_id_suffix, level_id_suffix,
4125 dummy, ignore_music_tokens);
4128 static void InitMixer()
4136 char *filename_font_initial = NULL;
4137 Bitmap *bitmap_font_initial = NULL;
4140 /* determine settings for initial font (for displaying startup messages) */
4141 for (i = 0; image_config[i].token != NULL; i++)
4143 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4145 char font_token[128];
4148 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4149 len_font_token = strlen(font_token);
4151 if (strcmp(image_config[i].token, font_token) == 0)
4152 filename_font_initial = image_config[i].value;
4153 else if (strlen(image_config[i].token) > len_font_token &&
4154 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4156 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4157 font_initial[j].src_x = atoi(image_config[i].value);
4158 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4159 font_initial[j].src_y = atoi(image_config[i].value);
4160 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4161 font_initial[j].width = atoi(image_config[i].value);
4162 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4163 font_initial[j].height = atoi(image_config[i].value);
4168 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4170 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4171 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4174 if (filename_font_initial == NULL) /* should not happen */
4175 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4177 /* create additional image buffers for double-buffering */
4178 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4179 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4181 /* initialize screen properties */
4182 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4183 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4185 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4186 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4187 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4189 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4191 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4192 font_initial[j].bitmap = bitmap_font_initial;
4194 InitFontGraphicInfo();
4196 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4197 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4199 DrawInitText("Loading graphics:", 120, FC_GREEN);
4201 InitTileClipmasks();
4204 void InitGfxBackground()
4208 drawto = backbuffer;
4209 fieldbuffer = bitmap_db_field;
4210 SetDrawtoField(DRAW_BACKBUFFER);
4212 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4213 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4214 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4215 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4217 for (x = 0; x < MAX_BUF_XSIZE; x++)
4218 for (y = 0; y < MAX_BUF_YSIZE; y++)
4221 redraw_mask = REDRAW_ALL;
4224 static void InitLevelInfo()
4226 LoadLevelInfo(); /* global level info */
4227 LoadLevelSetup_LastSeries(); /* last played series info */
4228 LoadLevelSetup_SeriesInfo(); /* last played level info */
4231 void InitLevelArtworkInfo()
4233 LoadLevelArtworkInfo();
4236 static void InitImages()
4239 setLevelArtworkDir(artwork.gfx_first);
4243 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4244 leveldir_current->identifier,
4245 artwork.gfx_current_identifier,
4246 artwork.gfx_current->identifier,
4247 leveldir_current->graphics_set,
4248 leveldir_current->graphics_path);
4251 ReloadCustomImages();
4253 LoadCustomElementDescriptions();
4254 LoadSpecialMenuDesignSettings();
4256 ReinitializeGraphics();
4259 static void InitSound(char *identifier)
4261 if (identifier == NULL)
4262 identifier = artwork.snd_current->identifier;
4265 /* set artwork path to send it to the sound server process */
4266 setLevelArtworkDir(artwork.snd_first);
4269 InitReloadCustomSounds(identifier);
4270 ReinitializeSounds();
4273 static void InitMusic(char *identifier)
4275 if (identifier == NULL)
4276 identifier = artwork.mus_current->identifier;
4279 /* set artwork path to send it to the sound server process */
4280 setLevelArtworkDir(artwork.mus_first);
4283 InitReloadCustomMusic(identifier);
4284 ReinitializeMusic();
4287 void InitNetworkServer()
4289 #if defined(NETWORK_AVALIABLE)
4293 if (!options.network)
4296 #if defined(NETWORK_AVALIABLE)
4297 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4299 if (!ConnectToServer(options.server_host, options.server_port))
4300 Error(ERR_EXIT, "cannot connect to network game server");
4302 SendToServer_PlayerName(setup.player_name);
4303 SendToServer_ProtocolVersion();
4306 SendToServer_NrWanted(nr_wanted);
4310 static char *getNewArtworkIdentifier(int type)
4312 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4313 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4314 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4315 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4316 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4317 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4318 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4319 char *leveldir_identifier = leveldir_current->identifier;
4321 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4322 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4324 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4326 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4327 char *artwork_current_identifier;
4328 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4330 /* leveldir_current may be invalid (level group, parent link) */
4331 if (!validLevelSeries(leveldir_current))
4334 /* 1st step: determine artwork set to be activated in descending order:
4335 --------------------------------------------------------------------
4336 1. setup artwork (when configured to override everything else)
4337 2. artwork set configured in "levelinfo.conf" of current level set
4338 (artwork in level directory will have priority when loading later)
4339 3. artwork in level directory (stored in artwork sub-directory)
4340 4. setup artwork (currently configured in setup menu) */
4342 if (setup_override_artwork)
4343 artwork_current_identifier = setup_artwork_set;
4344 else if (leveldir_artwork_set != NULL)
4345 artwork_current_identifier = leveldir_artwork_set;
4346 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4347 artwork_current_identifier = leveldir_identifier;
4349 artwork_current_identifier = setup_artwork_set;
4352 /* 2nd step: check if it is really needed to reload artwork set
4353 ------------------------------------------------------------ */
4356 if (type == ARTWORK_TYPE_GRAPHICS)
4357 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4358 artwork_new_identifier,
4359 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4360 artwork_current_identifier,
4361 leveldir_current->graphics_set,
4362 leveldir_current->identifier);
4365 /* ---------- reload if level set and also artwork set has changed ------- */
4366 if (leveldir_current_identifier[type] != leveldir_identifier &&
4367 (last_has_level_artwork_set[type] || has_level_artwork_set))
4368 artwork_new_identifier = artwork_current_identifier;
4370 leveldir_current_identifier[type] = leveldir_identifier;
4371 last_has_level_artwork_set[type] = has_level_artwork_set;
4374 if (type == ARTWORK_TYPE_GRAPHICS)
4375 printf("::: 1: '%s'\n", artwork_new_identifier);
4378 /* ---------- reload if "override artwork" setting has changed ----------- */
4379 if (last_override_level_artwork[type] != setup_override_artwork)
4380 artwork_new_identifier = artwork_current_identifier;
4382 last_override_level_artwork[type] = setup_override_artwork;
4385 if (type == ARTWORK_TYPE_GRAPHICS)
4386 printf("::: 2: '%s'\n", artwork_new_identifier);
4389 /* ---------- reload if current artwork identifier has changed ----------- */
4390 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4391 artwork_current_identifier) != 0)
4392 artwork_new_identifier = artwork_current_identifier;
4394 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4397 if (type == ARTWORK_TYPE_GRAPHICS)
4398 printf("::: 3: '%s'\n", artwork_new_identifier);
4401 /* ---------- do not reload directly after starting ---------------------- */
4402 if (!initialized[type])
4403 artwork_new_identifier = NULL;
4405 initialized[type] = TRUE;
4408 if (type == ARTWORK_TYPE_GRAPHICS)
4409 printf("::: 4: '%s'\n", artwork_new_identifier);
4413 if (type == ARTWORK_TYPE_GRAPHICS)
4414 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4415 artwork.gfx_current_identifier, artwork_current_identifier,
4416 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4417 artwork_new_identifier);
4420 return artwork_new_identifier;
4423 void ReloadCustomArtwork(int force_reload)
4425 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4426 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4427 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4428 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4429 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4430 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4431 boolean redraw_screen = FALSE;
4433 if (gfx_new_identifier != NULL || force_reload_gfx)
4436 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4437 artwork.gfx_current_identifier,
4439 artwork.gfx_current->identifier,
4440 leveldir_current->graphics_set);
4443 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4448 printf("... '%s'\n",
4449 leveldir_current->graphics_set);
4452 FreeTileClipmasks();
4453 InitTileClipmasks();
4455 redraw_screen = TRUE;
4458 if (snd_new_identifier != NULL || force_reload_snd)
4460 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4462 InitSound(snd_new_identifier);
4464 redraw_screen = TRUE;
4467 if (mus_new_identifier != NULL || force_reload_mus)
4469 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4471 InitMusic(mus_new_identifier);
4473 redraw_screen = TRUE;
4478 InitGfxBackground();
4480 /* force redraw of (open or closed) door graphics */
4481 SetDoorState(DOOR_OPEN_ALL);
4482 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4486 void KeyboardAutoRepeatOffUnlessAutoplay()
4488 if (global.autoplay_leveldir == NULL)
4489 KeyboardAutoRepeatOff();
4493 /* ========================================================================= */
4495 /* ========================================================================= */
4499 InitGlobal(); /* initialize some global variables */
4501 if (options.execute_command)
4502 Execute_Command(options.execute_command);
4504 if (options.serveronly)
4506 #if defined(PLATFORM_UNIX)
4507 NetworkServer(options.server_port, options.serveronly);
4509 Error(ERR_WARN, "networking only supported in Unix version");
4511 exit(0); /* never reached */
4517 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4518 InitArtworkConfig(); /* needed before forking sound child process */
4523 InitRND(NEW_RANDOMIZE);
4524 InitSimpleRND(NEW_RANDOMIZE);
4529 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4532 InitEventFilter(FilterMouseMotionEvents);
4534 InitElementPropertiesStatic();
4535 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4540 InitLevelArtworkInfo();
4542 InitImages(); /* needs to know current level directory */
4543 InitSound(NULL); /* needs to know current level directory */
4544 InitMusic(NULL); /* needs to know current level directory */
4546 InitGfxBackground();
4548 if (global.autoplay_leveldir)
4553 else if (global.convert_leveldir)
4559 game_status = GAME_MODE_MAIN;
4567 InitNetworkServer();
4570 void CloseAllAndExit(int exit_value)
4575 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4582 FreeTileClipmasks();
4584 #if defined(TARGET_SDL)
4585 if (network_server) /* terminate network server */
4586 SDL_KillThread(server_thread);
4589 CloseVideoDisplay();
4590 ClosePlatformDependentStuff();