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];
1263 /* no sound for this specific action -- use default action sound */
1264 if (element_info[i].sound[act] == -1)
1265 element_info[i].sound[act] = default_action_sound;
1270 static void InitGameModeSoundInfo()
1274 /* set values to -1 to identify later as "uninitialized" values */
1275 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1278 /* initialize gamemode/sound mapping from static configuration */
1279 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1281 int gamemode = gamemode_to_sound[i].gamemode;
1282 int sound = gamemode_to_sound[i].sound;
1285 gamemode = GAME_MODE_DEFAULT;
1287 menu.sound[gamemode] = sound;
1290 /* now set all '-1' values to levelset specific default values */
1291 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1292 if (menu.sound[i] == -1)
1293 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1297 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1298 if (menu.sound[i] != -1)
1299 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1303 static void set_sound_parameters(int sound, char **parameter_raw)
1305 int parameter[NUM_SND_ARGS];
1308 /* get integer values from string parameters */
1309 for (i = 0; i < NUM_SND_ARGS; i++)
1311 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1312 sound_config_suffix[i].type);
1314 /* explicit loop mode setting in configuration overrides default value */
1315 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1316 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1318 /* sound volume to change the original volume when loading the sound file */
1319 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1321 /* sound priority to give certain sounds a higher or lower priority */
1322 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1325 static void InitSoundInfo()
1328 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1329 int num_property_mappings = getSoundListPropertyMappingSize();
1331 int *sound_effect_properties;
1332 int num_sounds = getSoundListSize();
1335 checked_free(sound_info);
1337 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1338 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1340 /* initialize sound effect for all elements to "no sound" */
1341 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1342 for (j = 0; j < NUM_ACTIONS; j++)
1343 element_info[i].sound[j] = SND_UNDEFINED;
1345 for (i = 0; i < num_sounds; i++)
1347 struct FileInfo *sound = getSoundListEntry(i);
1348 int len_effect_text = strlen(sound->token);
1350 sound_effect_properties[i] = ACTION_OTHER;
1351 sound_info[i].loop = FALSE; /* default: play sound only once */
1354 printf("::: sound %d: '%s'\n", i, sound->token);
1357 /* determine all loop sounds and identify certain sound classes */
1359 for (j = 0; element_action_info[j].suffix; j++)
1361 int len_action_text = strlen(element_action_info[j].suffix);
1363 if (len_action_text < len_effect_text &&
1364 strcmp(&sound->token[len_effect_text - len_action_text],
1365 element_action_info[j].suffix) == 0)
1367 sound_effect_properties[i] = element_action_info[j].value;
1368 sound_info[i].loop = element_action_info[j].is_loop_sound;
1375 if (strcmp(sound->token, "custom_42") == 0)
1376 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1379 /* associate elements and some selected sound actions */
1381 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1383 if (element_info[j].class_name)
1385 int len_class_text = strlen(element_info[j].class_name);
1387 if (len_class_text + 1 < len_effect_text &&
1388 strncmp(sound->token,
1389 element_info[j].class_name, len_class_text) == 0 &&
1390 sound->token[len_class_text] == '.')
1392 int sound_action_value = sound_effect_properties[i];
1394 element_info[j].sound[sound_action_value] = i;
1399 set_sound_parameters(i, sound->parameter);
1402 free(sound_effect_properties);
1405 /* !!! now handled in InitElementSoundInfo() !!! */
1406 /* initialize element/sound mapping from dynamic configuration */
1407 for (i = 0; i < num_property_mappings; i++)
1409 int element = property_mapping[i].base_index;
1410 int action = property_mapping[i].ext1_index;
1411 int sound = property_mapping[i].artwork_index;
1414 action = ACTION_DEFAULT;
1416 printf("::: %d: %d, %d, %d ['%s']\n",
1417 i, element, action, sound, element_info[element].token_name);
1419 element_info[element].sound[action] = sound;
1426 int element = EL_CUSTOM_11;
1429 while (element_action_info[j].suffix)
1431 printf("element %d, sound action '%s' == %d\n",
1432 element, element_action_info[j].suffix,
1433 element_info[element].sound[j]);
1438 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1444 int element = EL_SAND;
1445 int sound_action = ACTION_DIGGING;
1448 while (element_action_info[j].suffix)
1450 if (element_action_info[j].value == sound_action)
1451 printf("element %d, sound action '%s' == %d\n",
1452 element, element_action_info[j].suffix,
1453 element_info[element].sound[sound_action]);
1460 static void InitGameModeMusicInfo()
1462 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1463 int num_property_mappings = getMusicListPropertyMappingSize();
1464 int default_levelset_music = -1;
1467 /* set values to -1 to identify later as "uninitialized" values */
1468 for (i = 0; i < MAX_LEVELS; i++)
1469 levelset.music[i] = -1;
1470 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1473 /* initialize gamemode/music mapping from static configuration */
1474 for (i = 0; gamemode_to_music[i].music > -1; i++)
1476 int gamemode = gamemode_to_music[i].gamemode;
1477 int music = gamemode_to_music[i].music;
1480 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1484 gamemode = GAME_MODE_DEFAULT;
1486 menu.music[gamemode] = music;
1489 /* initialize gamemode/music mapping from dynamic configuration */
1490 for (i = 0; i < num_property_mappings; i++)
1492 int prefix = property_mapping[i].base_index;
1493 int gamemode = property_mapping[i].ext1_index;
1494 int level = property_mapping[i].ext2_index;
1495 int music = property_mapping[i].artwork_index;
1498 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1499 prefix, gamemode, level, music);
1502 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1506 gamemode = GAME_MODE_DEFAULT;
1508 /* level specific music only allowed for in-game music */
1509 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1510 gamemode = GAME_MODE_PLAYING;
1515 default_levelset_music = music;
1518 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1519 levelset.music[level] = music;
1520 if (gamemode != GAME_MODE_PLAYING)
1521 menu.music[gamemode] = music;
1524 /* now set all '-1' values to menu specific default values */
1525 /* (undefined values of "levelset.music[]" might stay at "-1" to
1526 allow dynamic selection of music files from music directory!) */
1527 for (i = 0; i < MAX_LEVELS; i++)
1528 if (levelset.music[i] == -1)
1529 levelset.music[i] = default_levelset_music;
1530 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1531 if (menu.music[i] == -1)
1532 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1536 for (i = 0; i < MAX_LEVELS; i++)
1537 if (levelset.music[i] != -1)
1538 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1539 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1540 if (menu.music[i] != -1)
1541 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1545 static void set_music_parameters(int music, char **parameter_raw)
1547 int parameter[NUM_MUS_ARGS];
1550 /* get integer values from string parameters */
1551 for (i = 0; i < NUM_MUS_ARGS; i++)
1553 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1554 music_config_suffix[i].type);
1556 /* explicit loop mode setting in configuration overrides default value */
1557 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1558 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1561 static void InitMusicInfo()
1563 int num_music = getMusicListSize();
1566 checked_free(music_info);
1568 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1570 for (i = 0; i < num_music; i++)
1572 struct FileInfo *music = getMusicListEntry(i);
1573 int len_music_text = strlen(music->token);
1575 music_info[i].loop = TRUE; /* default: play music in loop mode */
1577 /* determine all loop music */
1579 for (j = 0; music_prefix_info[j].prefix; j++)
1581 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1583 if (len_prefix_text < len_music_text &&
1584 strncmp(music->token,
1585 music_prefix_info[j].prefix, len_prefix_text) == 0)
1587 music_info[i].loop = music_prefix_info[j].is_loop_music;
1593 set_music_parameters(i, music->parameter);
1597 static void ReinitializeGraphics()
1599 InitGraphicInfo(); /* graphic properties mapping */
1600 InitElementGraphicInfo(); /* element game graphic mapping */
1601 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1603 InitElementSmallImages(); /* scale images to all needed sizes */
1604 InitFontGraphicInfo(); /* initialize text drawing functions */
1606 SetMainBackgroundImage(IMG_BACKGROUND);
1607 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1613 static void ReinitializeSounds()
1615 InitSoundInfo(); /* sound properties mapping */
1616 InitElementSoundInfo(); /* element game sound mapping */
1617 InitGameModeSoundInfo(); /* game mode sound mapping */
1619 InitPlayLevelSound(); /* internal game sound settings */
1622 static void ReinitializeMusic()
1624 InitMusicInfo(); /* music properties mapping */
1625 InitGameModeMusicInfo(); /* game mode music mapping */
1628 static int get_special_property_bit(int element, int property_bit_nr)
1630 struct PropertyBitInfo
1636 static struct PropertyBitInfo pb_can_move_into_acid[] =
1638 /* the player may be able fall into acid when gravity is activated */
1643 { EL_SP_MURPHY, 0 },
1644 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1646 /* all element that can move may be able to also move into acid */
1649 { EL_BUG_RIGHT, 1 },
1652 { EL_SPACESHIP, 2 },
1653 { EL_SPACESHIP_LEFT, 2 },
1654 { EL_SPACESHIP_RIGHT, 2 },
1655 { EL_SPACESHIP_UP, 2 },
1656 { EL_SPACESHIP_DOWN, 2 },
1657 { EL_BD_BUTTERFLY, 3 },
1658 { EL_BD_BUTTERFLY_LEFT, 3 },
1659 { EL_BD_BUTTERFLY_RIGHT, 3 },
1660 { EL_BD_BUTTERFLY_UP, 3 },
1661 { EL_BD_BUTTERFLY_DOWN, 3 },
1662 { EL_BD_FIREFLY, 4 },
1663 { EL_BD_FIREFLY_LEFT, 4 },
1664 { EL_BD_FIREFLY_RIGHT, 4 },
1665 { EL_BD_FIREFLY_UP, 4 },
1666 { EL_BD_FIREFLY_DOWN, 4 },
1668 { EL_DARK_YAMYAM, 6 },
1671 { EL_PACMAN_LEFT, 8 },
1672 { EL_PACMAN_RIGHT, 8 },
1673 { EL_PACMAN_UP, 8 },
1674 { EL_PACMAN_DOWN, 8 },
1676 { EL_MOLE_LEFT, 9 },
1677 { EL_MOLE_RIGHT, 9 },
1679 { EL_MOLE_DOWN, 9 },
1683 { EL_SATELLITE, 13 },
1684 { EL_SP_SNIKSNAK, 14 },
1685 { EL_SP_ELECTRON, 15 },
1692 static struct PropertyBitInfo pb_dont_collide_with[] =
1694 { EL_SP_SNIKSNAK, 0 },
1695 { EL_SP_ELECTRON, 1 },
1703 struct PropertyBitInfo *pb_info;
1706 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1707 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1712 struct PropertyBitInfo *pb_info = NULL;
1715 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1716 if (pb_definition[i].bit_nr == property_bit_nr)
1717 pb_info = pb_definition[i].pb_info;
1719 if (pb_info == NULL)
1722 for (i = 0; pb_info[i].element != -1; i++)
1723 if (pb_info[i].element == element)
1724 return pb_info[i].bit_nr;
1730 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1731 boolean property_value)
1733 int bit_nr = get_special_property_bit(element, property_bit_nr);
1738 *bitfield |= (1 << bit_nr);
1740 *bitfield &= ~(1 << bit_nr);
1744 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1746 int bit_nr = get_special_property_bit(element, property_bit_nr);
1749 return ((*bitfield & (1 << bit_nr)) != 0);
1756 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1758 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1762 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1765 level->can_move_into_acid_bits |= (1 << bit_nr);
1769 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1771 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1774 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1780 void InitElementPropertiesStatic()
1782 static int ep_diggable[] =
1787 EL_SP_BUGGY_BASE_ACTIVATING,
1790 EL_INVISIBLE_SAND_ACTIVE,
1792 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1793 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1797 EL_SP_BUGGY_BASE_ACTIVE,
1802 static int ep_collectible_only[] =
1819 EL_DYNABOMB_INCREASE_NUMBER,
1820 EL_DYNABOMB_INCREASE_SIZE,
1821 EL_DYNABOMB_INCREASE_POWER,
1838 static int ep_dont_run_into[] =
1840 /* same elements as in 'ep_dont_touch' */
1846 /* same elements as in 'ep_dont_collide_with' */
1858 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1862 EL_SP_BUGGY_BASE_ACTIVE,
1867 static int ep_dont_collide_with[] =
1869 /* same elements as in 'ep_dont_touch' */
1885 static int ep_dont_touch[] =
1894 static int ep_indestructible[] =
1898 EL_ACID_POOL_TOPLEFT,
1899 EL_ACID_POOL_TOPRIGHT,
1900 EL_ACID_POOL_BOTTOMLEFT,
1901 EL_ACID_POOL_BOTTOM,
1902 EL_ACID_POOL_BOTTOMRIGHT,
1903 EL_SP_HARDWARE_GRAY,
1904 EL_SP_HARDWARE_GREEN,
1905 EL_SP_HARDWARE_BLUE,
1907 EL_SP_HARDWARE_YELLOW,
1908 EL_SP_HARDWARE_BASE_1,
1909 EL_SP_HARDWARE_BASE_2,
1910 EL_SP_HARDWARE_BASE_3,
1911 EL_SP_HARDWARE_BASE_4,
1912 EL_SP_HARDWARE_BASE_5,
1913 EL_SP_HARDWARE_BASE_6,
1914 EL_INVISIBLE_STEELWALL,
1915 EL_INVISIBLE_STEELWALL_ACTIVE,
1916 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1917 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1918 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1919 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1920 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1921 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1922 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1923 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1924 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1925 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1926 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1927 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1929 EL_LIGHT_SWITCH_ACTIVE,
1930 EL_SIGN_EXCLAMATION,
1931 EL_SIGN_RADIOACTIVITY,
1942 EL_STEELWALL_SLIPPERY,
1965 EL_SWITCHGATE_OPENING,
1966 EL_SWITCHGATE_CLOSED,
1967 EL_SWITCHGATE_CLOSING,
1969 EL_SWITCHGATE_SWITCH_UP,
1970 EL_SWITCHGATE_SWITCH_DOWN,
1973 EL_TIMEGATE_OPENING,
1975 EL_TIMEGATE_CLOSING,
1978 EL_TIMEGATE_SWITCH_ACTIVE,
1983 EL_TUBE_VERTICAL_LEFT,
1984 EL_TUBE_VERTICAL_RIGHT,
1985 EL_TUBE_HORIZONTAL_UP,
1986 EL_TUBE_HORIZONTAL_DOWN,
1994 static int ep_slippery[] =
2008 EL_ROBOT_WHEEL_ACTIVE,
2014 EL_ACID_POOL_TOPLEFT,
2015 EL_ACID_POOL_TOPRIGHT,
2025 EL_STEELWALL_SLIPPERY,
2031 static int ep_can_change[] =
2036 static int ep_can_move[] =
2038 /* same elements as in 'pb_can_move_into_acid' */
2059 static int ep_can_fall[] =
2074 EL_BD_MAGIC_WALL_FULL,
2087 static int ep_can_smash_player[] =
2112 static int ep_can_smash_enemies[] =
2120 static int ep_can_smash_everything[] =
2128 static int ep_explodes_by_fire[] =
2130 /* same elements as in 'ep_explodes_impact' */
2135 /* same elements as in 'ep_explodes_smashed' */
2144 EL_DYNABOMB_PLAYER_1_ACTIVE,
2145 EL_DYNABOMB_PLAYER_2_ACTIVE,
2146 EL_DYNABOMB_PLAYER_3_ACTIVE,
2147 EL_DYNABOMB_PLAYER_4_ACTIVE,
2148 EL_DYNABOMB_INCREASE_NUMBER,
2149 EL_DYNABOMB_INCREASE_SIZE,
2150 EL_DYNABOMB_INCREASE_POWER,
2151 EL_SP_DISK_RED_ACTIVE,
2164 static int ep_explodes_smashed[] =
2166 /* same elements as in 'ep_explodes_impact' */
2179 static int ep_explodes_impact[] =
2187 static int ep_walkable_over[] =
2191 EL_SOKOBAN_FIELD_EMPTY,
2209 static int ep_walkable_inside[] =
2214 EL_TUBE_VERTICAL_LEFT,
2215 EL_TUBE_VERTICAL_RIGHT,
2216 EL_TUBE_HORIZONTAL_UP,
2217 EL_TUBE_HORIZONTAL_DOWN,
2225 static int ep_walkable_under[] =
2230 static int ep_passable_over[] =
2245 static int ep_passable_inside[] =
2251 EL_SP_PORT_HORIZONTAL,
2252 EL_SP_PORT_VERTICAL,
2254 EL_SP_GRAVITY_PORT_LEFT,
2255 EL_SP_GRAVITY_PORT_RIGHT,
2256 EL_SP_GRAVITY_PORT_UP,
2257 EL_SP_GRAVITY_PORT_DOWN,
2258 EL_SP_GRAVITY_ON_PORT_LEFT,
2259 EL_SP_GRAVITY_ON_PORT_RIGHT,
2260 EL_SP_GRAVITY_ON_PORT_UP,
2261 EL_SP_GRAVITY_ON_PORT_DOWN,
2262 EL_SP_GRAVITY_OFF_PORT_LEFT,
2263 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2264 EL_SP_GRAVITY_OFF_PORT_UP,
2265 EL_SP_GRAVITY_OFF_PORT_DOWN,
2269 static int ep_passable_under[] =
2274 static int ep_droppable[] =
2279 static int ep_explodes_1x1_old[] =
2284 static int ep_pushable[] =
2296 EL_SOKOBAN_FIELD_FULL,
2303 static int ep_explodes_cross_old[] =
2308 static int ep_protected[] =
2310 /* same elements as in 'ep_walkable_inside' */
2314 EL_TUBE_VERTICAL_LEFT,
2315 EL_TUBE_VERTICAL_RIGHT,
2316 EL_TUBE_HORIZONTAL_UP,
2317 EL_TUBE_HORIZONTAL_DOWN,
2323 /* same elements as in 'ep_passable_over' */
2335 /* same elements as in 'ep_passable_inside' */
2340 EL_SP_PORT_HORIZONTAL,
2341 EL_SP_PORT_VERTICAL,
2343 EL_SP_GRAVITY_PORT_LEFT,
2344 EL_SP_GRAVITY_PORT_RIGHT,
2345 EL_SP_GRAVITY_PORT_UP,
2346 EL_SP_GRAVITY_PORT_DOWN,
2347 EL_SP_GRAVITY_ON_PORT_LEFT,
2348 EL_SP_GRAVITY_ON_PORT_RIGHT,
2349 EL_SP_GRAVITY_ON_PORT_UP,
2350 EL_SP_GRAVITY_ON_PORT_DOWN,
2351 EL_SP_GRAVITY_OFF_PORT_LEFT,
2352 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2353 EL_SP_GRAVITY_OFF_PORT_UP,
2354 EL_SP_GRAVITY_OFF_PORT_DOWN,
2358 static int ep_throwable[] =
2363 static int ep_can_explode[] =
2365 /* same elements as in 'ep_explodes_impact' */
2370 /* same elements as in 'ep_explodes_smashed' */
2376 /* elements that can explode by explosion or by dragonfire */
2379 EL_DYNABOMB_PLAYER_1_ACTIVE,
2380 EL_DYNABOMB_PLAYER_2_ACTIVE,
2381 EL_DYNABOMB_PLAYER_3_ACTIVE,
2382 EL_DYNABOMB_PLAYER_4_ACTIVE,
2383 EL_DYNABOMB_INCREASE_NUMBER,
2384 EL_DYNABOMB_INCREASE_SIZE,
2385 EL_DYNABOMB_INCREASE_POWER,
2386 EL_SP_DISK_RED_ACTIVE,
2394 /* elements that can explode only by explosion */
2399 static int ep_gravity_reachable[] =
2405 EL_INVISIBLE_SAND_ACTIVE,
2410 EL_SP_PORT_HORIZONTAL,
2411 EL_SP_PORT_VERTICAL,
2413 EL_SP_GRAVITY_PORT_LEFT,
2414 EL_SP_GRAVITY_PORT_RIGHT,
2415 EL_SP_GRAVITY_PORT_UP,
2416 EL_SP_GRAVITY_PORT_DOWN,
2417 EL_SP_GRAVITY_ON_PORT_LEFT,
2418 EL_SP_GRAVITY_ON_PORT_RIGHT,
2419 EL_SP_GRAVITY_ON_PORT_UP,
2420 EL_SP_GRAVITY_ON_PORT_DOWN,
2421 EL_SP_GRAVITY_OFF_PORT_LEFT,
2422 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2423 EL_SP_GRAVITY_OFF_PORT_UP,
2424 EL_SP_GRAVITY_OFF_PORT_DOWN,
2428 static int ep_player[] =
2435 EL_SOKOBAN_FIELD_PLAYER,
2440 static int ep_can_pass_magic_wall[] =
2453 static int ep_switchable[] =
2457 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2458 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2459 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2460 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2461 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2462 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2463 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2464 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2465 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2466 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2467 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2468 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2469 EL_SWITCHGATE_SWITCH_UP,
2470 EL_SWITCHGATE_SWITCH_DOWN,
2472 EL_LIGHT_SWITCH_ACTIVE,
2474 EL_BALLOON_SWITCH_LEFT,
2475 EL_BALLOON_SWITCH_RIGHT,
2476 EL_BALLOON_SWITCH_UP,
2477 EL_BALLOON_SWITCH_DOWN,
2478 EL_BALLOON_SWITCH_ANY,
2484 static int ep_bd_element[] =
2517 static int ep_sp_element[] =
2519 /* should always be valid */
2522 /* standard classic Supaplex elements */
2529 EL_SP_HARDWARE_GRAY,
2537 EL_SP_GRAVITY_PORT_RIGHT,
2538 EL_SP_GRAVITY_PORT_DOWN,
2539 EL_SP_GRAVITY_PORT_LEFT,
2540 EL_SP_GRAVITY_PORT_UP,
2545 EL_SP_PORT_VERTICAL,
2546 EL_SP_PORT_HORIZONTAL,
2552 EL_SP_HARDWARE_BASE_1,
2553 EL_SP_HARDWARE_GREEN,
2554 EL_SP_HARDWARE_BLUE,
2556 EL_SP_HARDWARE_YELLOW,
2557 EL_SP_HARDWARE_BASE_2,
2558 EL_SP_HARDWARE_BASE_3,
2559 EL_SP_HARDWARE_BASE_4,
2560 EL_SP_HARDWARE_BASE_5,
2561 EL_SP_HARDWARE_BASE_6,
2565 /* additional elements that appeared in newer Supaplex levels */
2568 /* additional gravity port elements (not switching, but setting gravity) */
2569 EL_SP_GRAVITY_ON_PORT_LEFT,
2570 EL_SP_GRAVITY_ON_PORT_RIGHT,
2571 EL_SP_GRAVITY_ON_PORT_UP,
2572 EL_SP_GRAVITY_ON_PORT_DOWN,
2573 EL_SP_GRAVITY_OFF_PORT_LEFT,
2574 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2575 EL_SP_GRAVITY_OFF_PORT_UP,
2576 EL_SP_GRAVITY_OFF_PORT_DOWN,
2578 /* more than one Murphy in a level results in an inactive clone */
2581 /* runtime Supaplex elements */
2582 EL_SP_DISK_RED_ACTIVE,
2583 EL_SP_TERMINAL_ACTIVE,
2584 EL_SP_BUGGY_BASE_ACTIVATING,
2585 EL_SP_BUGGY_BASE_ACTIVE,
2591 static int ep_sb_element[] =
2596 EL_SOKOBAN_FIELD_EMPTY,
2597 EL_SOKOBAN_FIELD_FULL,
2598 EL_SOKOBAN_FIELD_PLAYER,
2603 EL_INVISIBLE_STEELWALL,
2607 static int ep_gem[] =
2618 static int ep_food_dark_yamyam[] =
2645 static int ep_food_penguin[] =
2658 static int ep_food_pig[] =
2669 static int ep_historic_wall[] =
2694 EL_EXPANDABLE_WALL_HORIZONTAL,
2695 EL_EXPANDABLE_WALL_VERTICAL,
2696 EL_EXPANDABLE_WALL_ANY,
2697 EL_EXPANDABLE_WALL_GROWING,
2704 EL_SP_HARDWARE_GRAY,
2705 EL_SP_HARDWARE_GREEN,
2706 EL_SP_HARDWARE_BLUE,
2708 EL_SP_HARDWARE_YELLOW,
2709 EL_SP_HARDWARE_BASE_1,
2710 EL_SP_HARDWARE_BASE_2,
2711 EL_SP_HARDWARE_BASE_3,
2712 EL_SP_HARDWARE_BASE_4,
2713 EL_SP_HARDWARE_BASE_5,
2714 EL_SP_HARDWARE_BASE_6,
2716 EL_SP_TERMINAL_ACTIVE,
2719 EL_INVISIBLE_STEELWALL,
2720 EL_INVISIBLE_STEELWALL_ACTIVE,
2722 EL_INVISIBLE_WALL_ACTIVE,
2723 EL_STEELWALL_SLIPPERY,
2739 static int ep_historic_solid[] =
2743 EL_EXPANDABLE_WALL_HORIZONTAL,
2744 EL_EXPANDABLE_WALL_VERTICAL,
2745 EL_EXPANDABLE_WALL_ANY,
2758 EL_QUICKSAND_FILLING,
2759 EL_QUICKSAND_EMPTYING,
2761 EL_MAGIC_WALL_ACTIVE,
2762 EL_MAGIC_WALL_EMPTYING,
2763 EL_MAGIC_WALL_FILLING,
2767 EL_BD_MAGIC_WALL_ACTIVE,
2768 EL_BD_MAGIC_WALL_EMPTYING,
2769 EL_BD_MAGIC_WALL_FULL,
2770 EL_BD_MAGIC_WALL_FILLING,
2771 EL_BD_MAGIC_WALL_DEAD,
2780 EL_SP_TERMINAL_ACTIVE,
2784 EL_INVISIBLE_WALL_ACTIVE,
2785 EL_SWITCHGATE_SWITCH_UP,
2786 EL_SWITCHGATE_SWITCH_DOWN,
2788 EL_TIMEGATE_SWITCH_ACTIVE,
2800 /* the following elements are a direct copy of "indestructible" elements,
2801 except "EL_ACID", which is "indestructible", but not "solid"! */
2806 EL_ACID_POOL_TOPLEFT,
2807 EL_ACID_POOL_TOPRIGHT,
2808 EL_ACID_POOL_BOTTOMLEFT,
2809 EL_ACID_POOL_BOTTOM,
2810 EL_ACID_POOL_BOTTOMRIGHT,
2811 EL_SP_HARDWARE_GRAY,
2812 EL_SP_HARDWARE_GREEN,
2813 EL_SP_HARDWARE_BLUE,
2815 EL_SP_HARDWARE_YELLOW,
2816 EL_SP_HARDWARE_BASE_1,
2817 EL_SP_HARDWARE_BASE_2,
2818 EL_SP_HARDWARE_BASE_3,
2819 EL_SP_HARDWARE_BASE_4,
2820 EL_SP_HARDWARE_BASE_5,
2821 EL_SP_HARDWARE_BASE_6,
2822 EL_INVISIBLE_STEELWALL,
2823 EL_INVISIBLE_STEELWALL_ACTIVE,
2824 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2825 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2826 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2827 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2828 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2829 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2830 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2831 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2832 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2833 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2834 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2835 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2837 EL_LIGHT_SWITCH_ACTIVE,
2838 EL_SIGN_EXCLAMATION,
2839 EL_SIGN_RADIOACTIVITY,
2850 EL_STEELWALL_SLIPPERY,
2873 EL_SWITCHGATE_OPENING,
2874 EL_SWITCHGATE_CLOSED,
2875 EL_SWITCHGATE_CLOSING,
2877 EL_TIMEGATE_OPENING,
2879 EL_TIMEGATE_CLOSING,
2883 EL_TUBE_VERTICAL_LEFT,
2884 EL_TUBE_VERTICAL_RIGHT,
2885 EL_TUBE_HORIZONTAL_UP,
2886 EL_TUBE_HORIZONTAL_DOWN,
2894 static int ep_classic_enemy[] =
2910 static int ep_belt[] =
2912 EL_CONVEYOR_BELT_1_LEFT,
2913 EL_CONVEYOR_BELT_1_MIDDLE,
2914 EL_CONVEYOR_BELT_1_RIGHT,
2915 EL_CONVEYOR_BELT_2_LEFT,
2916 EL_CONVEYOR_BELT_2_MIDDLE,
2917 EL_CONVEYOR_BELT_2_RIGHT,
2918 EL_CONVEYOR_BELT_3_LEFT,
2919 EL_CONVEYOR_BELT_3_MIDDLE,
2920 EL_CONVEYOR_BELT_3_RIGHT,
2921 EL_CONVEYOR_BELT_4_LEFT,
2922 EL_CONVEYOR_BELT_4_MIDDLE,
2923 EL_CONVEYOR_BELT_4_RIGHT,
2927 static int ep_belt_active[] =
2929 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2930 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2931 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2932 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2933 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2934 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2935 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2936 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2937 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2938 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2939 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2940 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2944 static int ep_belt_switch[] =
2946 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2947 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2948 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2949 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2950 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2951 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2952 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2953 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2954 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2955 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2956 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2957 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2961 static int ep_tube[] =
2968 EL_TUBE_HORIZONTAL_UP,
2969 EL_TUBE_HORIZONTAL_DOWN,
2971 EL_TUBE_VERTICAL_LEFT,
2972 EL_TUBE_VERTICAL_RIGHT,
2977 static int ep_keygate[] =
2998 static int ep_amoeboid[] =
3008 static int ep_amoebalive[] =
3017 static int ep_has_content[] =
3027 static int ep_can_turn_each_move[] =
3029 /* !!! do something with this one !!! */
3033 static int ep_can_grow[] =
3045 static int ep_active_bomb[] =
3048 EL_DYNABOMB_PLAYER_1_ACTIVE,
3049 EL_DYNABOMB_PLAYER_2_ACTIVE,
3050 EL_DYNABOMB_PLAYER_3_ACTIVE,
3051 EL_DYNABOMB_PLAYER_4_ACTIVE,
3052 EL_SP_DISK_RED_ACTIVE,
3056 static int ep_inactive[] =
3093 EL_INVISIBLE_STEELWALL,
3101 EL_WALL_EMERALD_YELLOW,
3102 EL_DYNABOMB_INCREASE_NUMBER,
3103 EL_DYNABOMB_INCREASE_SIZE,
3104 EL_DYNABOMB_INCREASE_POWER,
3108 EL_SOKOBAN_FIELD_EMPTY,
3109 EL_SOKOBAN_FIELD_FULL,
3110 EL_WALL_EMERALD_RED,
3111 EL_WALL_EMERALD_PURPLE,
3112 EL_ACID_POOL_TOPLEFT,
3113 EL_ACID_POOL_TOPRIGHT,
3114 EL_ACID_POOL_BOTTOMLEFT,
3115 EL_ACID_POOL_BOTTOM,
3116 EL_ACID_POOL_BOTTOMRIGHT,
3120 EL_BD_MAGIC_WALL_DEAD,
3121 EL_AMOEBA_TO_DIAMOND,
3129 EL_SP_GRAVITY_PORT_RIGHT,
3130 EL_SP_GRAVITY_PORT_DOWN,
3131 EL_SP_GRAVITY_PORT_LEFT,
3132 EL_SP_GRAVITY_PORT_UP,
3133 EL_SP_PORT_HORIZONTAL,
3134 EL_SP_PORT_VERTICAL,
3145 EL_SP_HARDWARE_GRAY,
3146 EL_SP_HARDWARE_GREEN,
3147 EL_SP_HARDWARE_BLUE,
3149 EL_SP_HARDWARE_YELLOW,
3150 EL_SP_HARDWARE_BASE_1,
3151 EL_SP_HARDWARE_BASE_2,
3152 EL_SP_HARDWARE_BASE_3,
3153 EL_SP_HARDWARE_BASE_4,
3154 EL_SP_HARDWARE_BASE_5,
3155 EL_SP_HARDWARE_BASE_6,
3156 EL_SP_GRAVITY_ON_PORT_LEFT,
3157 EL_SP_GRAVITY_ON_PORT_RIGHT,
3158 EL_SP_GRAVITY_ON_PORT_UP,
3159 EL_SP_GRAVITY_ON_PORT_DOWN,
3160 EL_SP_GRAVITY_OFF_PORT_LEFT,
3161 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3162 EL_SP_GRAVITY_OFF_PORT_UP,
3163 EL_SP_GRAVITY_OFF_PORT_DOWN,
3164 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3165 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3166 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3167 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3168 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3169 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3170 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3171 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3172 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3173 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3174 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3175 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3176 EL_SIGN_EXCLAMATION,
3177 EL_SIGN_RADIOACTIVITY,
3188 EL_STEELWALL_SLIPPERY,
3204 static int ep_em_slippery_wall[] =
3209 static int ep_gfx_crumbled[] =
3222 } element_properties[] =
3224 { ep_diggable, EP_DIGGABLE },
3225 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3226 { ep_dont_run_into, EP_DONT_RUN_INTO },
3227 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3228 { ep_dont_touch, EP_DONT_TOUCH },
3229 { ep_indestructible, EP_INDESTRUCTIBLE },
3230 { ep_slippery, EP_SLIPPERY },
3231 { ep_can_change, EP_CAN_CHANGE },
3232 { ep_can_move, EP_CAN_MOVE },
3233 { ep_can_fall, EP_CAN_FALL },
3234 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3235 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3236 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3237 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3238 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3239 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3240 { ep_walkable_over, EP_WALKABLE_OVER },
3241 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3242 { ep_walkable_under, EP_WALKABLE_UNDER },
3243 { ep_passable_over, EP_PASSABLE_OVER },
3244 { ep_passable_inside, EP_PASSABLE_INSIDE },
3245 { ep_passable_under, EP_PASSABLE_UNDER },
3246 { ep_droppable, EP_DROPPABLE },
3247 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3248 { ep_pushable, EP_PUSHABLE },
3249 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3250 { ep_protected, EP_PROTECTED },
3251 { ep_throwable, EP_THROWABLE },
3252 { ep_can_explode, EP_CAN_EXPLODE },
3253 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3255 { ep_player, EP_PLAYER },
3256 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3257 { ep_switchable, EP_SWITCHABLE },
3258 { ep_bd_element, EP_BD_ELEMENT },
3259 { ep_sp_element, EP_SP_ELEMENT },
3260 { ep_sb_element, EP_SB_ELEMENT },
3262 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3263 { ep_food_penguin, EP_FOOD_PENGUIN },
3264 { ep_food_pig, EP_FOOD_PIG },
3265 { ep_historic_wall, EP_HISTORIC_WALL },
3266 { ep_historic_solid, EP_HISTORIC_SOLID },
3267 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3268 { ep_belt, EP_BELT },
3269 { ep_belt_active, EP_BELT_ACTIVE },
3270 { ep_belt_switch, EP_BELT_SWITCH },
3271 { ep_tube, EP_TUBE },
3272 { ep_keygate, EP_KEYGATE },
3273 { ep_amoeboid, EP_AMOEBOID },
3274 { ep_amoebalive, EP_AMOEBALIVE },
3275 { ep_has_content, EP_HAS_CONTENT },
3276 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3277 { ep_can_grow, EP_CAN_GROW },
3278 { ep_active_bomb, EP_ACTIVE_BOMB },
3279 { ep_inactive, EP_INACTIVE },
3281 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3283 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3288 static int copy_properties[][5] =
3292 EL_BUG_LEFT, EL_BUG_RIGHT,
3293 EL_BUG_UP, EL_BUG_DOWN
3297 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3298 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3302 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3303 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3307 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3308 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3312 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3313 EL_PACMAN_UP, EL_PACMAN_DOWN
3317 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3318 EL_MOLE_UP, EL_MOLE_DOWN
3328 /* always start with reliable default values (element has no properties) */
3329 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3330 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3331 SET_PROPERTY(i, j, FALSE);
3333 /* set all base element properties from above array definitions */
3334 for (i = 0; element_properties[i].elements != NULL; i++)
3335 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3336 SET_PROPERTY((element_properties[i].elements)[j],
3337 element_properties[i].property, TRUE);
3339 /* copy properties to some elements that are only stored in level file */
3340 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3341 for (j = 0; copy_properties[j][0] != -1; j++)
3342 if (HAS_PROPERTY(copy_properties[j][0], i))
3343 for (k = 1; k <= 4; k++)
3344 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3347 void InitElementPropertiesEngine(int engine_version)
3350 static int active_properties[] =
3355 EP_DONT_COLLIDE_WITH,
3359 EP_CAN_PASS_MAGIC_WALL,
3364 EP_EXPLODES_BY_FIRE,
3377 EP_EM_SLIPPERY_WALL,
3381 static int no_wall_properties[] =
3384 EP_COLLECTIBLE_ONLY,
3386 EP_DONT_COLLIDE_WITH,
3389 EP_CAN_SMASH_PLAYER,
3390 EP_CAN_SMASH_ENEMIES,
3391 EP_CAN_SMASH_EVERYTHING,
3396 EP_FOOD_DARK_YAMYAM,
3413 InitElementPropertiesStatic();
3416 /* important: after initialization in InitElementPropertiesStatic(), the
3417 elements are not again initialized to a default value; therefore all
3418 changes have to make sure that they leave the element with a defined
3419 property (which means that conditional property changes must be set to
3420 a reliable default value before) */
3422 /* set all special, combined or engine dependent element properties */
3423 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3426 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3427 SET_PROPERTY(i, j, FALSE);
3430 /* ---------- INACTIVE ------------------------------------------------- */
3431 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3433 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3434 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3435 IS_WALKABLE_INSIDE(i) ||
3436 IS_WALKABLE_UNDER(i)));
3438 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3439 IS_PASSABLE_INSIDE(i) ||
3440 IS_PASSABLE_UNDER(i)));
3442 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3443 IS_PASSABLE_OVER(i)));
3445 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3446 IS_PASSABLE_INSIDE(i)));
3448 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3449 IS_PASSABLE_UNDER(i)));
3451 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3454 /* ---------- COLLECTIBLE ---------------------------------------------- */
3455 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3459 /* ---------- SNAPPABLE ------------------------------------------------ */
3460 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3461 IS_COLLECTIBLE(i) ||
3465 /* ---------- WALL ----------------------------------------------------- */
3466 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3468 for (j = 0; no_wall_properties[j] != -1; j++)
3469 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3470 i >= EL_FIRST_RUNTIME_UNREAL)
3471 SET_PROPERTY(i, EP_WALL, FALSE);
3473 if (IS_HISTORIC_WALL(i))
3474 SET_PROPERTY(i, EP_WALL, TRUE);
3476 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3477 if (engine_version < VERSION_IDENT(2,2,0,0))
3478 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3480 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3482 !IS_COLLECTIBLE(i)));
3485 /* ---------- PROTECTED ------------------------------------------------ */
3486 if (IS_ACCESSIBLE_INSIDE(i))
3487 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3490 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3492 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3493 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3495 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3496 IS_INDESTRUCTIBLE(i)));
3498 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3500 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3501 else if (engine_version < VERSION_IDENT(2,2,0,0))
3502 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3505 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3510 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3511 !IS_WALKABLE_OVER(i) &&
3512 !IS_WALKABLE_UNDER(i)));
3514 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3519 if (IS_CUSTOM_ELEMENT(i))
3521 /* these are additional properties which are initially false when set */
3523 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3525 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3526 if (DONT_COLLIDE_WITH(i))
3527 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3529 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3530 if (CAN_SMASH_EVERYTHING(i))
3531 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3532 if (CAN_SMASH_ENEMIES(i))
3533 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3536 /* ---------- CAN_SMASH ------------------------------------------------ */
3537 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3538 CAN_SMASH_ENEMIES(i) ||
3539 CAN_SMASH_EVERYTHING(i)));
3542 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3543 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3544 CAN_EXPLODE_SMASHED(i) ||
3545 CAN_EXPLODE_IMPACT(i)));
3549 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3551 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3552 !CAN_EXPLODE_CROSS(i)));
3554 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3555 !CAN_EXPLODE_1X1(i) &&
3556 !CAN_EXPLODE_CROSS(i)));
3560 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3561 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3562 EXPLODES_BY_FIRE(i)));
3564 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3565 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3566 EXPLODES_SMASHED(i)));
3568 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3569 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3570 EXPLODES_IMPACT(i)));
3572 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3573 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3575 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3576 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3577 i == EL_BLACK_ORB));
3579 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3580 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3582 IS_CUSTOM_ELEMENT(i)));
3584 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3585 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3586 i == EL_SP_ELECTRON));
3588 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3589 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3590 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3591 getMoveIntoAcidProperty(&level, i));
3593 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3594 if (MAYBE_DONT_COLLIDE_WITH(i))
3595 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3596 getDontCollideWithProperty(&level, i));
3598 /* ---------- SP_PORT -------------------------------------------------- */
3599 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3600 IS_PASSABLE_INSIDE(i)));
3602 /* ---------- CAN_CHANGE ----------------------------------------------- */
3603 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3604 for (j = 0; j < element_info[i].num_change_pages; j++)
3605 if (element_info[i].change_page[j].can_change)
3606 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3608 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3609 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3610 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3614 /* determine inactive elements (used for engine main loop optimization) */
3615 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3617 boolean active = FALSE;
3619 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3621 if (HAS_PROPERTY(i, j))
3627 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3632 /* dynamically adjust element properties according to game engine version */
3634 static int ep_em_slippery_wall[] =
3639 EL_EXPANDABLE_WALL_HORIZONTAL,
3640 EL_EXPANDABLE_WALL_VERTICAL,
3641 EL_EXPANDABLE_WALL_ANY,
3645 /* special EM style gems behaviour */
3646 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3647 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3648 level.em_slippery_gems);
3650 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3651 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3652 (level.em_slippery_gems &&
3653 engine_version > VERSION_IDENT(2,0,1,0)));
3657 /* set default push delay values (corrected since version 3.0.7-1) */
3658 if (engine_version < VERSION_IDENT(3,0,7,1))
3660 game.default_push_delay_fixed = 2;
3661 game.default_push_delay_random = 8;
3665 game.default_push_delay_fixed = 8;
3666 game.default_push_delay_random = 8;
3669 /* set uninitialized push delay values of custom elements in older levels */
3670 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3672 int element = EL_CUSTOM_START + i;
3674 if (element_info[element].push_delay_fixed == -1)
3675 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3676 if (element_info[element].push_delay_random == -1)
3677 element_info[element].push_delay_random = game.default_push_delay_random;
3680 /* set some other uninitialized values of custom elements in older levels */
3681 if (engine_version < VERSION_IDENT(3,1,0,0))
3683 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3685 int element = EL_CUSTOM_START + i;
3687 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3689 element_info[element].explosion_delay = 17;
3690 element_info[element].ignition_delay = 8;
3695 /* set element properties that were handled incorrectly in older levels */
3696 if (engine_version < VERSION_IDENT(3,1,0,0))
3698 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3699 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3705 /* this is needed because some graphics depend on element properties */
3706 if (game_status == GAME_MODE_PLAYING)
3707 InitElementGraphicInfo();
3710 static void InitGlobal()
3714 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3716 /* check if element_name_info entry defined for each element in "main.h" */
3717 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3718 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3720 element_info[i].token_name = element_name_info[i].token_name;
3721 element_info[i].class_name = element_name_info[i].class_name;
3722 element_info[i].editor_description=element_name_info[i].editor_description;
3725 global.autoplay_leveldir = NULL;
3726 global.convert_leveldir = NULL;
3728 global.frames_per_second = 0;
3729 global.fps_slowdown = FALSE;
3730 global.fps_slowdown_factor = 1;
3733 void Execute_Command(char *command)
3737 if (strcmp(command, "print graphicsinfo.conf") == 0)
3739 printf("# You can configure additional/alternative image files here.\n");
3740 printf("# (The entries below are default and therefore commented out.)\n");
3742 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3744 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3747 for (i = 0; image_config[i].token != NULL; i++)
3748 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3749 image_config[i].value));
3753 else if (strcmp(command, "print soundsinfo.conf") == 0)
3755 printf("# You can configure additional/alternative sound files here.\n");
3756 printf("# (The entries below are default and therefore commented out.)\n");
3758 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3760 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3763 for (i = 0; sound_config[i].token != NULL; i++)
3764 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3765 sound_config[i].value));
3769 else if (strcmp(command, "print musicinfo.conf") == 0)
3771 printf("# You can configure additional/alternative music files here.\n");
3772 printf("# (The entries below are default and therefore commented out.)\n");
3774 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3776 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3779 for (i = 0; music_config[i].token != NULL; i++)
3780 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3781 music_config[i].value));
3785 else if (strcmp(command, "print editorsetup.conf") == 0)
3787 printf("# You can configure your personal editor element list here.\n");
3788 printf("# (The entries below are default and therefore commented out.)\n");
3791 PrintEditorElementList();
3795 else if (strcmp(command, "print helpanim.conf") == 0)
3797 printf("# You can configure different element help animations here.\n");
3798 printf("# (The entries below are default and therefore commented out.)\n");
3801 for (i = 0; helpanim_config[i].token != NULL; i++)
3803 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3804 helpanim_config[i].value));
3806 if (strcmp(helpanim_config[i].token, "end") == 0)
3812 else if (strcmp(command, "print helptext.conf") == 0)
3814 printf("# You can configure different element help text here.\n");
3815 printf("# (The entries below are default and therefore commented out.)\n");
3818 for (i = 0; helptext_config[i].token != NULL; i++)
3819 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3820 helptext_config[i].value));
3824 else if (strncmp(command, "dump level ", 11) == 0)
3826 char *filename = &command[11];
3828 if (access(filename, F_OK) != 0)
3829 Error(ERR_EXIT, "cannot open file '%s'", filename);
3831 LoadLevelFromFilename(&level, filename);
3836 else if (strncmp(command, "dump tape ", 10) == 0)
3838 char *filename = &command[10];
3840 if (access(filename, F_OK) != 0)
3841 Error(ERR_EXIT, "cannot open file '%s'", filename);
3843 LoadTapeFromFilename(filename);
3848 else if (strncmp(command, "autoplay ", 9) == 0)
3850 char *str_copy = getStringCopy(&command[9]);
3851 char *str_ptr = strchr(str_copy, ' ');
3853 global.autoplay_leveldir = str_copy;
3854 global.autoplay_level_nr = -1;
3856 if (str_ptr != NULL)
3858 *str_ptr++ = '\0'; /* terminate leveldir string */
3859 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3862 else if (strncmp(command, "convert ", 8) == 0)
3864 char *str_copy = getStringCopy(&command[8]);
3865 char *str_ptr = strchr(str_copy, ' ');
3867 global.convert_leveldir = str_copy;
3868 global.convert_level_nr = -1;
3870 if (str_ptr != NULL)
3872 *str_ptr++ = '\0'; /* terminate leveldir string */
3873 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3878 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3882 static void InitSetup()
3884 LoadSetup(); /* global setup info */
3886 /* set some options from setup file */
3888 if (setup.options.verbose)
3889 options.verbose = TRUE;
3892 static void InitPlayerInfo()
3896 /* choose default local player */
3897 local_player = &stored_player[0];
3899 for (i = 0; i < MAX_PLAYERS; i++)
3900 stored_player[i].connected = FALSE;
3902 local_player->connected = TRUE;
3905 static void InitArtworkInfo()
3910 static char *get_string_in_brackets(char *string)
3912 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3914 sprintf(string_in_brackets, "[%s]", string);
3916 return string_in_brackets;
3919 static char *get_level_id_suffix(int id_nr)
3921 char *id_suffix = checked_malloc(1 + 3 + 1);
3923 if (id_nr < 0 || id_nr > 999)
3926 sprintf(id_suffix, ".%03d", id_nr);
3932 static char *get_element_class_token(int element)
3934 char *element_class_name = element_info[element].class_name;
3935 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3937 sprintf(element_class_token, "[%s]", element_class_name);
3939 return element_class_token;
3942 static char *get_action_class_token(int action)
3944 char *action_class_name = &element_action_info[action].suffix[1];
3945 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3947 sprintf(action_class_token, "[%s]", action_class_name);
3949 return action_class_token;
3953 static void InitArtworkConfig()
3955 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3956 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3957 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3958 static char *action_id_suffix[NUM_ACTIONS + 1];
3959 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3960 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3961 static char *level_id_suffix[MAX_LEVELS + 1];
3962 static char *dummy[1] = { NULL };
3963 static char *ignore_generic_tokens[] =
3969 static char **ignore_image_tokens;
3970 static char **ignore_sound_tokens;
3971 static char **ignore_music_tokens;
3972 int num_ignore_generic_tokens;
3973 int num_ignore_image_tokens;
3974 int num_ignore_sound_tokens;
3975 int num_ignore_music_tokens;
3978 /* dynamically determine list of generic tokens to be ignored */
3979 num_ignore_generic_tokens = 0;
3980 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3981 num_ignore_generic_tokens++;
3983 /* dynamically determine list of image tokens to be ignored */
3984 num_ignore_image_tokens = num_ignore_generic_tokens;
3985 for (i = 0; image_config_vars[i].token != NULL; i++)
3986 num_ignore_image_tokens++;
3987 ignore_image_tokens =
3988 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3989 for (i = 0; i < num_ignore_generic_tokens; i++)
3990 ignore_image_tokens[i] = ignore_generic_tokens[i];
3991 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3992 ignore_image_tokens[num_ignore_generic_tokens + i] =
3993 image_config_vars[i].token;
3994 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3996 /* dynamically determine list of sound tokens to be ignored */
3997 num_ignore_sound_tokens = num_ignore_generic_tokens;
3998 ignore_sound_tokens =
3999 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4000 for (i = 0; i < num_ignore_generic_tokens; i++)
4001 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4002 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4004 /* dynamically determine list of music tokens to be ignored */
4005 num_ignore_music_tokens = num_ignore_generic_tokens;
4006 ignore_music_tokens =
4007 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4008 for (i = 0; i < num_ignore_generic_tokens; i++)
4009 ignore_music_tokens[i] = ignore_generic_tokens[i];
4010 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4012 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4013 image_id_prefix[i] = element_info[i].token_name;
4014 for (i = 0; i < NUM_FONTS; i++)
4015 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4016 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4018 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4019 sound_id_prefix[i] = element_info[i].token_name;
4020 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4021 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4022 get_string_in_brackets(element_info[i].class_name);
4023 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4025 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4026 music_id_prefix[i] = music_prefix_info[i].prefix;
4027 music_id_prefix[MAX_LEVELS] = NULL;
4029 for (i = 0; i < NUM_ACTIONS; i++)
4030 action_id_suffix[i] = element_action_info[i].suffix;
4031 action_id_suffix[NUM_ACTIONS] = NULL;
4033 for (i = 0; i < NUM_DIRECTIONS; i++)
4034 direction_id_suffix[i] = element_direction_info[i].suffix;
4035 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4037 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4038 special_id_suffix[i] = special_suffix_info[i].suffix;
4039 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4041 for (i = 0; i < MAX_LEVELS; i++)
4042 level_id_suffix[i] = get_level_id_suffix(i);
4043 level_id_suffix[MAX_LEVELS] = NULL;
4045 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4046 image_id_prefix, action_id_suffix, direction_id_suffix,
4047 special_id_suffix, ignore_image_tokens);
4048 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4049 sound_id_prefix, action_id_suffix, dummy,
4050 special_id_suffix, ignore_sound_tokens);
4051 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4052 music_id_prefix, special_id_suffix, level_id_suffix,
4053 dummy, ignore_music_tokens);
4056 static void InitMixer()
4064 char *filename_font_initial = NULL;
4065 Bitmap *bitmap_font_initial = NULL;
4068 /* determine settings for initial font (for displaying startup messages) */
4069 for (i = 0; image_config[i].token != NULL; i++)
4071 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4073 char font_token[128];
4076 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4077 len_font_token = strlen(font_token);
4079 if (strcmp(image_config[i].token, font_token) == 0)
4080 filename_font_initial = image_config[i].value;
4081 else if (strlen(image_config[i].token) > len_font_token &&
4082 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4084 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4085 font_initial[j].src_x = atoi(image_config[i].value);
4086 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4087 font_initial[j].src_y = atoi(image_config[i].value);
4088 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4089 font_initial[j].width = atoi(image_config[i].value);
4090 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4091 font_initial[j].height = atoi(image_config[i].value);
4096 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4098 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4099 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4102 if (filename_font_initial == NULL) /* should not happen */
4103 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4105 /* create additional image buffers for double-buffering */
4106 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4107 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4109 /* initialize screen properties */
4110 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4111 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4113 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4114 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4115 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4117 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4119 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4120 font_initial[j].bitmap = bitmap_font_initial;
4122 InitFontGraphicInfo();
4124 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4125 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4127 DrawInitText("Loading graphics:", 120, FC_GREEN);
4129 InitTileClipmasks();
4132 void InitGfxBackground()
4136 drawto = backbuffer;
4137 fieldbuffer = bitmap_db_field;
4138 SetDrawtoField(DRAW_BACKBUFFER);
4140 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4141 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4142 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4143 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4145 for (x = 0; x < MAX_BUF_XSIZE; x++)
4146 for (y = 0; y < MAX_BUF_YSIZE; y++)
4149 redraw_mask = REDRAW_ALL;
4152 static void InitLevelInfo()
4154 LoadLevelInfo(); /* global level info */
4155 LoadLevelSetup_LastSeries(); /* last played series info */
4156 LoadLevelSetup_SeriesInfo(); /* last played level info */
4159 void InitLevelArtworkInfo()
4161 LoadLevelArtworkInfo();
4164 static void InitImages()
4167 setLevelArtworkDir(artwork.gfx_first);
4171 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4172 leveldir_current->identifier,
4173 artwork.gfx_current_identifier,
4174 artwork.gfx_current->identifier,
4175 leveldir_current->graphics_set,
4176 leveldir_current->graphics_path);
4179 ReloadCustomImages();
4181 LoadCustomElementDescriptions();
4182 LoadSpecialMenuDesignSettings();
4184 ReinitializeGraphics();
4187 static void InitSound(char *identifier)
4189 if (identifier == NULL)
4190 identifier = artwork.snd_current->identifier;
4193 /* set artwork path to send it to the sound server process */
4194 setLevelArtworkDir(artwork.snd_first);
4197 InitReloadCustomSounds(identifier);
4198 ReinitializeSounds();
4201 static void InitMusic(char *identifier)
4203 if (identifier == NULL)
4204 identifier = artwork.mus_current->identifier;
4207 /* set artwork path to send it to the sound server process */
4208 setLevelArtworkDir(artwork.mus_first);
4211 InitReloadCustomMusic(identifier);
4212 ReinitializeMusic();
4215 void InitNetworkServer()
4217 #if defined(NETWORK_AVALIABLE)
4221 if (!options.network)
4224 #if defined(NETWORK_AVALIABLE)
4225 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4227 if (!ConnectToServer(options.server_host, options.server_port))
4228 Error(ERR_EXIT, "cannot connect to network game server");
4230 SendToServer_PlayerName(setup.player_name);
4231 SendToServer_ProtocolVersion();
4234 SendToServer_NrWanted(nr_wanted);
4238 static char *getNewArtworkIdentifier(int type)
4240 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4241 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4242 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4243 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4244 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4245 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4246 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4247 char *leveldir_identifier = leveldir_current->identifier;
4249 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4250 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4252 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4254 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4255 char *artwork_current_identifier;
4256 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4258 /* leveldir_current may be invalid (level group, parent link) */
4259 if (!validLevelSeries(leveldir_current))
4262 /* 1st step: determine artwork set to be activated in descending order:
4263 --------------------------------------------------------------------
4264 1. setup artwork (when configured to override everything else)
4265 2. artwork set configured in "levelinfo.conf" of current level set
4266 (artwork in level directory will have priority when loading later)
4267 3. artwork in level directory (stored in artwork sub-directory)
4268 4. setup artwork (currently configured in setup menu) */
4270 if (setup_override_artwork)
4271 artwork_current_identifier = setup_artwork_set;
4272 else if (leveldir_artwork_set != NULL)
4273 artwork_current_identifier = leveldir_artwork_set;
4274 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4275 artwork_current_identifier = leveldir_identifier;
4277 artwork_current_identifier = setup_artwork_set;
4280 /* 2nd step: check if it is really needed to reload artwork set
4281 ------------------------------------------------------------ */
4284 if (type == ARTWORK_TYPE_GRAPHICS)
4285 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4286 artwork_new_identifier,
4287 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4288 artwork_current_identifier,
4289 leveldir_current->graphics_set,
4290 leveldir_current->identifier);
4293 /* ---------- reload if level set and also artwork set has changed ------- */
4294 if (leveldir_current_identifier[type] != leveldir_identifier &&
4295 (last_has_level_artwork_set[type] || has_level_artwork_set))
4296 artwork_new_identifier = artwork_current_identifier;
4298 leveldir_current_identifier[type] = leveldir_identifier;
4299 last_has_level_artwork_set[type] = has_level_artwork_set;
4302 if (type == ARTWORK_TYPE_GRAPHICS)
4303 printf("::: 1: '%s'\n", artwork_new_identifier);
4306 /* ---------- reload if "override artwork" setting has changed ----------- */
4307 if (last_override_level_artwork[type] != setup_override_artwork)
4308 artwork_new_identifier = artwork_current_identifier;
4310 last_override_level_artwork[type] = setup_override_artwork;
4313 if (type == ARTWORK_TYPE_GRAPHICS)
4314 printf("::: 2: '%s'\n", artwork_new_identifier);
4317 /* ---------- reload if current artwork identifier has changed ----------- */
4318 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4319 artwork_current_identifier) != 0)
4320 artwork_new_identifier = artwork_current_identifier;
4322 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4325 if (type == ARTWORK_TYPE_GRAPHICS)
4326 printf("::: 3: '%s'\n", artwork_new_identifier);
4329 /* ---------- do not reload directly after starting ---------------------- */
4330 if (!initialized[type])
4331 artwork_new_identifier = NULL;
4333 initialized[type] = TRUE;
4336 if (type == ARTWORK_TYPE_GRAPHICS)
4337 printf("::: 4: '%s'\n", artwork_new_identifier);
4341 if (type == ARTWORK_TYPE_GRAPHICS)
4342 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4343 artwork.gfx_current_identifier, artwork_current_identifier,
4344 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4345 artwork_new_identifier);
4348 return artwork_new_identifier;
4351 void ReloadCustomArtwork(int force_reload)
4353 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4354 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4355 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4356 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4357 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4358 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4359 boolean redraw_screen = FALSE;
4361 if (gfx_new_identifier != NULL || force_reload_gfx)
4364 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4365 artwork.gfx_current_identifier,
4367 artwork.gfx_current->identifier,
4368 leveldir_current->graphics_set);
4371 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4376 printf("... '%s'\n",
4377 leveldir_current->graphics_set);
4380 FreeTileClipmasks();
4381 InitTileClipmasks();
4383 redraw_screen = TRUE;
4386 if (snd_new_identifier != NULL || force_reload_snd)
4388 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4390 InitSound(snd_new_identifier);
4392 redraw_screen = TRUE;
4395 if (mus_new_identifier != NULL || force_reload_mus)
4397 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4399 InitMusic(mus_new_identifier);
4401 redraw_screen = TRUE;
4406 InitGfxBackground();
4408 /* force redraw of (open or closed) door graphics */
4409 SetDoorState(DOOR_OPEN_ALL);
4410 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4414 void KeyboardAutoRepeatOffUnlessAutoplay()
4416 if (global.autoplay_leveldir == NULL)
4417 KeyboardAutoRepeatOff();
4421 /* ========================================================================= */
4423 /* ========================================================================= */
4427 InitGlobal(); /* initialize some global variables */
4429 if (options.execute_command)
4430 Execute_Command(options.execute_command);
4432 if (options.serveronly)
4434 #if defined(PLATFORM_UNIX)
4435 NetworkServer(options.server_port, options.serveronly);
4437 Error(ERR_WARN, "networking only supported in Unix version");
4439 exit(0); /* never reached */
4445 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4446 InitArtworkConfig(); /* needed before forking sound child process */
4451 InitRND(NEW_RANDOMIZE);
4452 InitSimpleRND(NEW_RANDOMIZE);
4457 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4460 InitEventFilter(FilterMouseMotionEvents);
4462 InitElementPropertiesStatic();
4463 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4468 InitLevelArtworkInfo();
4470 InitImages(); /* needs to know current level directory */
4471 InitSound(NULL); /* needs to know current level directory */
4472 InitMusic(NULL); /* needs to know current level directory */
4474 InitGfxBackground();
4476 if (global.autoplay_leveldir)
4481 else if (global.convert_leveldir)
4487 game_status = GAME_MODE_MAIN;
4495 InitNetworkServer();
4498 void CloseAllAndExit(int exit_value)
4503 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4510 FreeTileClipmasks();
4512 #if defined(TARGET_SDL)
4513 if (network_server) /* terminate network server */
4514 SDL_KillThread(server_thread);
4517 CloseVideoDisplay();
4518 ClosePlatformDependentStuff();