1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static void InitTileClipmasks()
46 #if defined(TARGET_X11)
47 XGCValues clip_gc_values;
48 unsigned long clip_gc_valuemask;
50 #if defined(TARGET_X11_NATIVE)
60 tile_needs_clipping[] =
62 { GFX_SPIELER1_UP, 4 },
63 { GFX_SPIELER1_DOWN, 4 },
64 { GFX_SPIELER1_LEFT, 4 },
65 { GFX_SPIELER1_RIGHT, 4 },
66 { GFX_SPIELER1_PUSH_LEFT, 4 },
67 { GFX_SPIELER1_PUSH_RIGHT, 4 },
68 { GFX_SPIELER2_UP, 4 },
69 { GFX_SPIELER2_DOWN, 4 },
70 { GFX_SPIELER2_LEFT, 4 },
71 { GFX_SPIELER2_RIGHT, 4 },
72 { GFX_SPIELER2_PUSH_LEFT, 4 },
73 { GFX_SPIELER2_PUSH_RIGHT, 4 },
74 { GFX_SPIELER3_UP, 4 },
75 { GFX_SPIELER3_DOWN, 4 },
76 { GFX_SPIELER3_LEFT, 4 },
77 { GFX_SPIELER3_RIGHT, 4 },
78 { GFX_SPIELER3_PUSH_LEFT, 4 },
79 { GFX_SPIELER3_PUSH_RIGHT, 4 },
80 { GFX_SPIELER4_UP, 4 },
81 { GFX_SPIELER4_DOWN, 4 },
82 { GFX_SPIELER4_LEFT, 4 },
83 { GFX_SPIELER4_RIGHT, 4 },
84 { GFX_SPIELER4_PUSH_LEFT, 4 },
85 { GFX_SPIELER4_PUSH_RIGHT, 4 },
87 { GFX_MURPHY_GO_LEFT, 3 },
88 { GFX_MURPHY_GO_RIGHT, 3 },
89 { GFX_MURPHY_SNAP_UP, 1 },
90 { GFX_MURPHY_SNAP_DOWN, 1 },
91 { GFX_MURPHY_SNAP_RIGHT, 1 },
92 { GFX_MURPHY_SNAP_LEFT, 1 },
93 { GFX_MURPHY_PUSH_RIGHT, 1 },
94 { GFX_MURPHY_PUSH_LEFT, 1 },
99 { GFX_SOKOBAN_OBJEKT, 1 },
100 { GFX_FUNKELN_BLAU, 3 },
101 { GFX_FUNKELN_WEISS, 3 },
102 { GFX2_SHIELD_PASSIVE, 3 },
103 { GFX2_SHIELD_ACTIVE, 3 },
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
113 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114 for (i = 0; i < NUM_TILES; i++)
115 tile_clipmask[i] = None;
117 #if defined(TARGET_X11)
118 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119 often very slow when preparing a masked XCopyArea() for big Pixmaps.
120 To prevent this, create small (tile-sized) mask Pixmaps which will then
121 be set much faster with XSetClipOrigin() and speed things up a lot. */
123 clip_gc_values.graphics_exposures = False;
124 clip_gc_valuemask = GCGraphicsExposures;
125 tile_clip_gc = XCreateGC(display, window->drawable,
126 clip_gc_valuemask, &clip_gc_values);
129 for (i = 0; i < NUM_BITMAPS; i++)
131 if (pix[i]->clip_mask)
133 clip_gc_values.graphics_exposures = False;
134 clip_gc_values.clip_mask = pix[i]->clip_mask;
135 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137 clip_gc_valuemask, &clip_gc_values);
142 #if defined(TARGET_X11_NATIVE)
145 /* create graphic context structures needed for clipping */
146 clip_gc_values.graphics_exposures = False;
147 clip_gc_valuemask = GCGraphicsExposures;
148 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149 clip_gc_valuemask, &clip_gc_values);
151 /* create only those clipping Pixmaps we really need */
152 for (i = 0; tile_needs_clipping[i].start >= 0; i++)
156 for (j = 0; j < tile_needs_clipping[i].count; j++)
158 int tile = tile_needs_clipping[i].start + j;
164 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165 src_pixmap = src_bitmap->clip_mask;
167 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
170 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171 src_x, src_y, TILEX, TILEY, 0, 0);
175 XFreeGC(display, copy_clipmask_gc);
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
183 void FreeTileClipmasks()
186 #if defined(TARGET_X11)
189 for (i = 0; i < NUM_TILES; i++)
191 if (tile_clipmask[i] != None)
193 XFreePixmap(display, tile_clipmask[i]);
194 tile_clipmask[i] = None;
199 XFreeGC(display, tile_clip_gc);
203 for (i = 0; i < NUM_BITMAPS; i++)
205 if (pix[i] != NULL && pix[i]->stored_clip_gc)
207 XFreeGC(display, pix[i]->stored_clip_gc);
208 pix[i]->stored_clip_gc = None;
213 #endif /* TARGET_X11 */
219 FreeLevelEditorGadgets();
228 static boolean gadgets_initialized = FALSE;
230 if (gadgets_initialized)
233 CreateLevelEditorGadgets();
237 CreateScreenGadgets();
239 gadgets_initialized = TRUE;
242 inline void InitElementSmallImagesScaledUp(int graphic)
244 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
247 void InitElementSmallImages()
249 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250 int num_property_mappings = getImageListPropertyMappingSize();
253 /* initialize normal images from static configuration */
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
257 /* initialize special images from static configuration */
258 for (i = 0; element_to_special_graphic[i].element > -1; i++)
259 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 /* initialize images from dynamic configuration */
262 for (i = 0; i < num_property_mappings; i++)
263 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
267 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
268 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
269 InitElementSmallImagesScaledUp(i);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 void SetBitmaps_EM(Bitmap **em_bitmap)
277 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
278 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
282 static int getFontBitmapID(int font_nr)
286 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
287 special = game_status;
288 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
289 special = GFX_SPECIAL_ARG_MAIN;
290 else if (game_status == GAME_MODE_PLAYING)
291 special = GFX_SPECIAL_ARG_DOOR;
294 return font_info[font_nr].special_bitmap_id[special];
299 void InitFontGraphicInfo()
301 static struct FontBitmapInfo *font_bitmap_info = NULL;
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
304 int num_font_bitmaps = NUM_FONTS;
307 if (graphic_info == NULL) /* still at startup phase */
309 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
314 /* ---------- initialize font graphic definitions ---------- */
316 /* always start with reliable default values (normal font graphics) */
318 for (i = 0; i < NUM_FONTS; i++)
319 font_info[i].graphic = IMG_FONT_INITIAL_1;
321 for (i = 0; i < NUM_FONTS; i++)
322 font_info[i].graphic = FONT_INITIAL_1;
325 /* initialize normal font/graphic mapping from static configuration */
326 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
335 font_info[font_nr].graphic = graphic;
338 /* always start with reliable default values (special font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
341 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
343 font_info[i].special_graphic[j] = font_info[i].graphic;
344 font_info[i].special_bitmap_id[j] = i;
348 /* initialize special font/graphic mapping from static configuration */
349 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
351 int font_nr = font_to_graphic[i].font_nr;
352 int special = font_to_graphic[i].special;
353 int graphic = font_to_graphic[i].graphic;
355 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
357 font_info[font_nr].special_graphic[special] = graphic;
358 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
363 /* initialize special element/graphic mapping from dynamic configuration */
364 for (i = 0; i < num_property_mappings; i++)
366 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
367 int special = property_mapping[i].ext3_index;
368 int graphic = property_mapping[i].artwork_index;
373 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
375 font_info[font_nr].special_graphic[special] = graphic;
376 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
381 /* ---------- initialize font bitmap array ---------- */
383 if (font_bitmap_info != NULL)
384 FreeFontInfo(font_bitmap_info);
387 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
389 /* ---------- initialize font bitmap definitions ---------- */
391 for (i = 0; i < NUM_FONTS; i++)
393 if (i < NUM_INITIAL_FONTS)
395 font_bitmap_info[i] = font_initial[i];
399 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
401 int font_bitmap_id = font_info[i].special_bitmap_id[j];
402 int graphic = font_info[i].special_graphic[j];
404 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
405 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
407 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
408 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
411 /* copy font relevant information from graphics information */
412 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
413 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
414 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
415 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
416 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
417 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
418 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
420 font_bitmap_info[font_bitmap_id].num_chars =
421 graphic_info[graphic].anim_frames;
422 font_bitmap_info[font_bitmap_id].num_chars_per_line =
423 graphic_info[graphic].anim_frames_per_line;
427 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
430 void InitElementGraphicInfo()
432 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
433 int num_property_mappings = getImageListPropertyMappingSize();
436 if (graphic_info == NULL) /* still at startup phase */
439 /* set values to -1 to identify later as "uninitialized" values */
440 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
442 for (act = 0; act < NUM_ACTIONS; act++)
444 element_info[i].graphic[act] = -1;
445 element_info[i].crumbled[act] = -1;
447 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
449 element_info[i].direction_graphic[act][dir] = -1;
450 element_info[i].direction_crumbled[act][dir] = -1;
455 /* initialize normal element/graphic mapping from static configuration */
456 for (i = 0; element_to_graphic[i].element > -1; i++)
458 int element = element_to_graphic[i].element;
459 int action = element_to_graphic[i].action;
460 int direction = element_to_graphic[i].direction;
461 boolean crumbled = element_to_graphic[i].crumbled;
462 int graphic = element_to_graphic[i].graphic;
463 int base_graphic = el2baseimg(element);
465 if (graphic_info[graphic].bitmap == NULL)
468 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
471 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
472 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
474 /* if the base graphic ("emerald", for example) has been redefined,
475 but not the action graphic ("emerald.falling", for example), do not
476 use an existing (in this case considered obsolete) action graphic
477 anymore, but use the automatically determined default graphic */
478 if (base_redefined && !act_dir_redefined)
483 action = ACTION_DEFAULT;
488 element_info[element].direction_crumbled[action][direction] = graphic;
490 element_info[element].crumbled[action] = graphic;
495 element_info[element].direction_graphic[action][direction] = graphic;
497 element_info[element].graphic[action] = graphic;
501 /* initialize normal element/graphic mapping from dynamic configuration */
502 for (i = 0; i < num_property_mappings; i++)
504 int element = property_mapping[i].base_index;
505 int action = property_mapping[i].ext1_index;
506 int direction = property_mapping[i].ext2_index;
507 int special = property_mapping[i].ext3_index;
508 int graphic = property_mapping[i].artwork_index;
509 boolean crumbled = FALSE;
511 if (special == GFX_SPECIAL_ARG_CRUMBLED)
517 if (graphic_info[graphic].bitmap == NULL)
520 if (element >= MAX_NUM_ELEMENTS || special != -1)
524 action = ACTION_DEFAULT;
529 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
530 element_info[element].direction_crumbled[action][dir] = -1;
533 element_info[element].direction_crumbled[action][direction] = graphic;
535 element_info[element].crumbled[action] = graphic;
540 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
541 element_info[element].direction_graphic[action][dir] = -1;
544 element_info[element].direction_graphic[action][direction] = graphic;
546 element_info[element].graphic[action] = graphic;
550 /* now copy all graphics that are defined to be cloned from other graphics */
551 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
553 int graphic = element_info[i].graphic[ACTION_DEFAULT];
554 int crumbled_like, diggable_like;
559 crumbled_like = graphic_info[graphic].crumbled_like;
560 diggable_like = graphic_info[graphic].diggable_like;
562 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
564 for (act = 0; act < NUM_ACTIONS; act++)
565 element_info[i].crumbled[act] =
566 element_info[crumbled_like].crumbled[act];
567 for (act = 0; act < NUM_ACTIONS; act++)
568 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
569 element_info[i].direction_crumbled[act][dir] =
570 element_info[crumbled_like].direction_crumbled[act][dir];
573 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
575 element_info[i].graphic[ACTION_DIGGING] =
576 element_info[diggable_like].graphic[ACTION_DIGGING];
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
579 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
584 /* set hardcoded definitions for some runtime elements without graphic */
585 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
589 /* now set all undefined/invalid graphics to -1 to set to default after it */
590 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
592 for (act = 0; act < NUM_ACTIONS; act++)
596 graphic = element_info[i].graphic[act];
597 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
598 element_info[i].graphic[act] = -1;
600 graphic = element_info[i].crumbled[act];
601 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
602 element_info[i].crumbled[act] = -1;
604 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
606 graphic = element_info[i].direction_graphic[act][dir];
607 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
608 element_info[i].direction_graphic[act][dir] = -1;
610 graphic = element_info[i].direction_crumbled[act][dir];
611 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
612 element_info[i].direction_crumbled[act][dir] = -1;
618 /* now set all '-1' values to element specific default values */
619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
621 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
622 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
623 int default_direction_graphic[NUM_DIRECTIONS];
624 int default_direction_crumbled[NUM_DIRECTIONS];
626 if (default_graphic == -1)
627 default_graphic = IMG_UNKNOWN;
628 if (default_crumbled == -1)
629 default_crumbled = IMG_EMPTY;
631 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
633 default_direction_graphic[dir] =
634 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
635 default_direction_crumbled[dir] =
636 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
638 if (default_direction_graphic[dir] == -1)
639 default_direction_graphic[dir] = default_graphic;
640 if (default_direction_crumbled[dir] == -1)
641 default_direction_crumbled[dir] = default_crumbled;
644 for (act = 0; act < NUM_ACTIONS; act++)
646 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
647 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
648 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
649 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
650 act == ACTION_TURNING_FROM_RIGHT ||
651 act == ACTION_TURNING_FROM_UP ||
652 act == ACTION_TURNING_FROM_DOWN);
654 /* generic default action graphic (defined by "[default]" directive) */
655 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
656 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
658 /* look for special default action graphic (classic game specific) */
659 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
660 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
661 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
662 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
663 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
664 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
666 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
667 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
668 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
669 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
670 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
671 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
674 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
675 /* !!! make this better !!! */
676 if (i == EL_EMPTY_SPACE)
678 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
683 if (default_action_graphic == -1)
684 default_action_graphic = default_graphic;
685 if (default_action_crumbled == -1)
686 default_action_crumbled = default_crumbled;
688 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
690 int default_action_direction_graphic = element_info[i].graphic[act];
691 int default_action_direction_crumbled = element_info[i].crumbled[act];
693 /* no graphic for current action -- use default direction graphic */
694 if (default_action_direction_graphic == -1)
695 default_action_direction_graphic =
696 (act_remove ? IMG_EMPTY :
698 element_info[i].direction_graphic[ACTION_TURNING][dir] :
699 default_direction_graphic[dir]);
700 if (default_action_direction_crumbled == -1)
701 default_action_direction_crumbled =
702 (act_remove ? IMG_EMPTY :
704 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
705 default_direction_crumbled[dir]);
707 if (element_info[i].direction_graphic[act][dir] == -1)
708 element_info[i].direction_graphic[act][dir] =
709 default_action_direction_graphic;
710 if (element_info[i].direction_crumbled[act][dir] == -1)
711 element_info[i].direction_crumbled[act][dir] =
712 default_action_direction_crumbled;
715 /* no graphic for this specific action -- use default action graphic */
716 if (element_info[i].graphic[act] == -1)
717 element_info[i].graphic[act] =
718 (act_remove ? IMG_EMPTY :
719 act_turning ? element_info[i].graphic[ACTION_TURNING] :
720 default_action_graphic);
721 if (element_info[i].crumbled[act] == -1)
722 element_info[i].crumbled[act] =
723 (act_remove ? IMG_EMPTY :
724 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
725 default_action_crumbled);
730 /* set animation mode to "none" for each graphic with only 1 frame */
731 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
733 for (act = 0; act < NUM_ACTIONS; act++)
735 int graphic = element_info[i].graphic[act];
736 int crumbled = element_info[i].crumbled[act];
738 if (graphic_info[graphic].anim_frames == 1)
739 graphic_info[graphic].anim_mode = ANIM_NONE;
740 if (graphic_info[crumbled].anim_frames == 1)
741 graphic_info[crumbled].anim_mode = ANIM_NONE;
743 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
745 graphic = element_info[i].direction_graphic[act][dir];
746 crumbled = element_info[i].direction_crumbled[act][dir];
748 if (graphic_info[graphic].anim_frames == 1)
749 graphic_info[graphic].anim_mode = ANIM_NONE;
750 if (graphic_info[crumbled].anim_frames == 1)
751 graphic_info[crumbled].anim_mode = ANIM_NONE;
761 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
762 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
764 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
765 element_info[i].token_name, i);
771 void InitElementSpecialGraphicInfo()
773 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
774 int num_property_mappings = getImageListPropertyMappingSize();
777 /* always start with reliable default values */
778 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
779 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
780 element_info[i].special_graphic[j] =
781 element_info[i].graphic[ACTION_DEFAULT];
783 /* initialize special element/graphic mapping from static configuration */
784 for (i = 0; element_to_special_graphic[i].element > -1; i++)
786 int element = element_to_special_graphic[i].element;
787 int special = element_to_special_graphic[i].special;
788 int graphic = element_to_special_graphic[i].graphic;
789 int base_graphic = el2baseimg(element);
790 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
791 boolean special_redefined = getImageListEntry(graphic)->redefined;
793 /* if the base graphic ("emerald", for example) has been redefined,
794 but not the special graphic ("emerald.EDITOR", for example), do not
795 use an existing (in this case considered obsolete) special graphic
796 anymore, but use the automatically created (down-scaled) graphic */
797 if (base_redefined && !special_redefined)
800 element_info[element].special_graphic[special] = graphic;
803 /* initialize special element/graphic mapping from dynamic configuration */
804 for (i = 0; i < num_property_mappings; i++)
806 int element = property_mapping[i].base_index;
807 int special = property_mapping[i].ext3_index;
808 int graphic = property_mapping[i].artwork_index;
810 if (element >= MAX_NUM_ELEMENTS)
813 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
814 element_info[element].special_graphic[special] = graphic;
818 /* now set all undefined/invalid graphics to default */
819 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
821 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
822 element_info[i].special_graphic[j] =
823 element_info[i].graphic[ACTION_DEFAULT];
827 static int get_element_from_token(char *token)
831 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832 if (strcmp(element_info[i].token_name, token) == 0)
838 static void set_graphic_parameters(int graphic, char **parameter_raw)
840 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
841 int parameter[NUM_GFX_ARGS];
842 int anim_frames_per_row = 1, anim_frames_per_col = 1;
843 int anim_frames_per_line = 1;
846 /* get integer values from string parameters */
847 for (i = 0; i < NUM_GFX_ARGS; i++)
850 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
851 image_config_suffix[i].type);
853 if (image_config_suffix[i].type == TYPE_TOKEN)
854 parameter[i] = get_element_from_token(parameter_raw[i]);
857 graphic_info[graphic].bitmap = src_bitmap;
859 /* start with reliable default values */
860 graphic_info[graphic].src_x = 0;
861 graphic_info[graphic].src_y = 0;
862 graphic_info[graphic].width = TILEX;
863 graphic_info[graphic].height = TILEY;
864 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
865 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
866 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
867 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
868 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
869 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
870 graphic_info[graphic].anim_delay_fixed = 0;
871 graphic_info[graphic].anim_delay_random = 0;
872 graphic_info[graphic].post_delay_fixed = 0;
873 graphic_info[graphic].post_delay_random = 0;
875 /* optional x and y tile position of animation frame sequence */
876 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
877 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
878 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
879 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
881 /* optional x and y pixel position of animation frame sequence */
882 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
883 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
884 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
887 /* optional width and height of each animation frame */
888 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
889 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
890 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
891 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
895 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
896 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
899 /* correct x or y offset dependent of vertical or horizontal frame order */
900 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
902 graphic_info[graphic].offset_y =
903 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
904 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
905 anim_frames_per_line = anim_frames_per_col;
907 else /* frames are ordered horizontally */
909 graphic_info[graphic].offset_x =
910 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
911 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
912 anim_frames_per_line = anim_frames_per_row;
915 /* optionally, the x and y offset of frames can be specified directly */
916 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
917 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
918 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
919 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
921 /* automatically determine correct number of frames, if not defined */
922 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
923 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
924 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
925 graphic_info[graphic].anim_frames = anim_frames_per_row;
926 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
927 graphic_info[graphic].anim_frames = anim_frames_per_col;
929 graphic_info[graphic].anim_frames = 1;
931 graphic_info[graphic].anim_frames_per_line =
932 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
933 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
935 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
936 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
937 graphic_info[graphic].anim_delay = 1;
939 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
941 if (graphic_info[graphic].anim_frames == 1)
942 graphic_info[graphic].anim_mode = ANIM_NONE;
945 /* automatically determine correct start frame, if not defined */
946 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
947 graphic_info[graphic].anim_start_frame = 0;
948 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
949 graphic_info[graphic].anim_start_frame =
950 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
952 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
954 /* animation synchronized with global frame counter, not move position */
955 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
957 /* optional element for cloning crumble graphics */
958 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
959 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
961 /* optional element for cloning digging graphics */
962 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
963 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
965 /* optional border size for "crumbling" diggable graphics */
966 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
967 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
969 /* optional zoom factor for scaling up the image to a larger size */
970 if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
971 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
972 if (graphic_info[graphic].scale_up_factor < 1)
973 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
975 /* this is only used for player "boring" and "sleeping" actions */
976 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
977 graphic_info[graphic].anim_delay_fixed =
978 parameter[GFX_ARG_ANIM_DELAY_FIXED];
979 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
980 graphic_info[graphic].anim_delay_random =
981 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
982 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
983 graphic_info[graphic].post_delay_fixed =
984 parameter[GFX_ARG_POST_DELAY_FIXED];
985 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
986 graphic_info[graphic].post_delay_random =
987 parameter[GFX_ARG_POST_DELAY_RANDOM];
989 /* this is only used for toon animations */
990 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
991 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
993 /* this is only used for drawing font characters */
994 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
995 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
997 /* this is only used for drawing envelope graphics */
998 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1001 static void InitGraphicInfo()
1003 int fallback_graphic = IMG_CHAR_EXCLAM;
1004 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1005 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1006 int num_images = getImageListSize();
1009 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1010 static boolean clipmasks_initialized = FALSE;
1012 XGCValues clip_gc_values;
1013 unsigned long clip_gc_valuemask;
1014 GC copy_clipmask_gc = None;
1017 checked_free(graphic_info);
1019 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1022 printf("::: graphic_info: %d entries\n", num_images);
1025 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1026 if (clipmasks_initialized)
1028 for (i = 0; i < num_images; i++)
1030 if (graphic_info[i].clip_mask)
1031 XFreePixmap(display, graphic_info[i].clip_mask);
1032 if (graphic_info[i].clip_gc)
1033 XFreeGC(display, graphic_info[i].clip_gc);
1035 graphic_info[i].clip_mask = None;
1036 graphic_info[i].clip_gc = None;
1041 for (i = 0; i < num_images; i++)
1043 struct FileInfo *image = getImageListEntry(i);
1046 int first_frame, last_frame;
1049 printf("::: image: '%s' [%d]\n", image->token, i);
1053 printf("::: image # %d: '%s' ['%s']\n",
1055 getTokenFromImageID(i));
1058 set_graphic_parameters(i, image->parameter);
1060 /* now check if no animation frames are outside of the loaded image */
1062 if (graphic_info[i].bitmap == NULL)
1063 continue; /* skip check for optional images that are undefined */
1066 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1067 if (src_x < 0 || src_y < 0 ||
1068 src_x + TILEX > src_bitmap->width ||
1069 src_y + TILEY > src_bitmap->height)
1071 Error(ERR_RETURN_LINE, "-");
1072 Error(ERR_RETURN, "warning: error found in config file:");
1073 Error(ERR_RETURN, "- config file: '%s'",
1074 getImageConfigFilename());
1075 Error(ERR_RETURN, "- config token: '%s'",
1076 getTokenFromImageID(i));
1077 Error(ERR_RETURN, "- image file: '%s'",
1078 src_bitmap->source_filename);
1080 "error: first animation frame out of bounds (%d, %d)",
1082 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1084 if (i == fallback_graphic)
1085 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1087 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1088 Error(ERR_RETURN_LINE, "-");
1090 set_graphic_parameters(i, fallback_image->default_parameter);
1091 graphic_info[i].bitmap = fallback_bitmap;
1094 last_frame = graphic_info[i].anim_frames - 1;
1095 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1096 if (src_x < 0 || src_y < 0 ||
1097 src_x + TILEX > src_bitmap->width ||
1098 src_y + TILEY > src_bitmap->height)
1100 Error(ERR_RETURN_LINE, "-");
1101 Error(ERR_RETURN, "warning: error found in config file:");
1102 Error(ERR_RETURN, "- config file: '%s'",
1103 getImageConfigFilename());
1104 Error(ERR_RETURN, "- config token: '%s'",
1105 getTokenFromImageID(i));
1106 Error(ERR_RETURN, "- image file: '%s'",
1107 src_bitmap->source_filename);
1109 "error: last animation frame (%d) out of bounds (%d, %d)",
1110 last_frame, src_x, src_y);
1111 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1113 if (i == fallback_graphic)
1114 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1116 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1117 Error(ERR_RETURN_LINE, "-");
1119 set_graphic_parameters(i, fallback_image->default_parameter);
1120 graphic_info[i].bitmap = fallback_bitmap;
1123 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1124 /* currently we need only a tile clip mask from the first frame */
1125 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1127 if (copy_clipmask_gc == None)
1129 clip_gc_values.graphics_exposures = False;
1130 clip_gc_valuemask = GCGraphicsExposures;
1131 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1132 clip_gc_valuemask, &clip_gc_values);
1135 graphic_info[i].clip_mask =
1136 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1138 src_pixmap = src_bitmap->clip_mask;
1139 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1140 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1142 clip_gc_values.graphics_exposures = False;
1143 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1144 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1146 graphic_info[i].clip_gc =
1147 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1151 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1152 if (copy_clipmask_gc)
1153 XFreeGC(display, copy_clipmask_gc);
1155 clipmasks_initialized = TRUE;
1159 static void InitElementSoundInfo()
1161 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1162 int num_property_mappings = getSoundListPropertyMappingSize();
1165 /* set values to -1 to identify later as "uninitialized" values */
1166 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1167 for (act = 0; act < NUM_ACTIONS; act++)
1168 element_info[i].sound[act] = -1;
1170 /* initialize element/sound mapping from static configuration */
1171 for (i = 0; element_to_sound[i].element > -1; i++)
1173 int element = element_to_sound[i].element;
1174 int action = element_to_sound[i].action;
1175 int sound = element_to_sound[i].sound;
1176 boolean is_class = element_to_sound[i].is_class;
1179 action = ACTION_DEFAULT;
1182 element_info[element].sound[action] = sound;
1184 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1185 if (strcmp(element_info[j].class_name,
1186 element_info[element].class_name) == 0)
1187 element_info[j].sound[action] = sound;
1190 /* initialize element class/sound mapping from dynamic configuration */
1191 for (i = 0; i < num_property_mappings; i++)
1193 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1194 int action = property_mapping[i].ext1_index;
1195 int sound = property_mapping[i].artwork_index;
1197 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1201 action = ACTION_DEFAULT;
1203 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1204 if (strcmp(element_info[j].class_name,
1205 element_info[element_class].class_name) == 0)
1206 element_info[j].sound[action] = sound;
1209 /* initialize element/sound mapping from dynamic configuration */
1210 for (i = 0; i < num_property_mappings; i++)
1212 int element = property_mapping[i].base_index;
1213 int action = property_mapping[i].ext1_index;
1214 int sound = property_mapping[i].artwork_index;
1216 if (element >= MAX_NUM_ELEMENTS)
1220 action = ACTION_DEFAULT;
1222 element_info[element].sound[action] = sound;
1225 /* now set all '-1' values to element specific default values */
1226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1228 for (act = 0; act < NUM_ACTIONS; act++)
1230 /* generic default action sound (defined by "[default]" directive) */
1231 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1233 /* look for special default action sound (classic game specific) */
1234 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1235 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1236 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1237 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1238 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1239 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1241 /* !!! there's no such thing as a "default action sound" !!! */
1243 /* look for element specific default sound (independent from action) */
1244 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1245 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1248 /* no sound for this specific action -- use default action sound */
1249 if (element_info[i].sound[act] == -1)
1250 element_info[i].sound[act] = default_action_sound;
1255 static void InitGameModeSoundInfo()
1259 /* set values to -1 to identify later as "uninitialized" values */
1260 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1263 /* initialize gamemode/sound mapping from static configuration */
1264 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1266 int gamemode = gamemode_to_sound[i].gamemode;
1267 int sound = gamemode_to_sound[i].sound;
1270 gamemode = GAME_MODE_DEFAULT;
1272 menu.sound[gamemode] = sound;
1275 /* now set all '-1' values to levelset specific default values */
1276 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1277 if (menu.sound[i] == -1)
1278 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1282 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1283 if (menu.sound[i] != -1)
1284 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1288 static void set_sound_parameters(int sound, char **parameter_raw)
1290 int parameter[NUM_SND_ARGS];
1293 /* get integer values from string parameters */
1294 for (i = 0; i < NUM_SND_ARGS; i++)
1296 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1297 sound_config_suffix[i].type);
1299 /* explicit loop mode setting in configuration overrides default value */
1300 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1301 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1304 static void InitSoundInfo()
1307 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1308 int num_property_mappings = getSoundListPropertyMappingSize();
1310 int *sound_effect_properties;
1311 int num_sounds = getSoundListSize();
1314 checked_free(sound_info);
1316 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1317 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1319 /* initialize sound effect for all elements to "no sound" */
1320 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1321 for (j = 0; j < NUM_ACTIONS; j++)
1322 element_info[i].sound[j] = SND_UNDEFINED;
1324 for (i = 0; i < num_sounds; i++)
1326 struct FileInfo *sound = getSoundListEntry(i);
1327 int len_effect_text = strlen(sound->token);
1329 sound_effect_properties[i] = ACTION_OTHER;
1330 sound_info[i].loop = FALSE; /* default: play sound only once */
1333 printf("::: sound %d: '%s'\n", i, sound->token);
1336 /* determine all loop sounds and identify certain sound classes */
1338 for (j = 0; element_action_info[j].suffix; j++)
1340 int len_action_text = strlen(element_action_info[j].suffix);
1342 if (len_action_text < len_effect_text &&
1343 strcmp(&sound->token[len_effect_text - len_action_text],
1344 element_action_info[j].suffix) == 0)
1346 sound_effect_properties[i] = element_action_info[j].value;
1347 sound_info[i].loop = element_action_info[j].is_loop_sound;
1354 if (strcmp(sound->token, "custom_42") == 0)
1355 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1358 /* associate elements and some selected sound actions */
1360 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1362 if (element_info[j].class_name)
1364 int len_class_text = strlen(element_info[j].class_name);
1366 if (len_class_text + 1 < len_effect_text &&
1367 strncmp(sound->token,
1368 element_info[j].class_name, len_class_text) == 0 &&
1369 sound->token[len_class_text] == '.')
1371 int sound_action_value = sound_effect_properties[i];
1373 element_info[j].sound[sound_action_value] = i;
1378 set_sound_parameters(i, sound->parameter);
1381 free(sound_effect_properties);
1384 /* !!! now handled in InitElementSoundInfo() !!! */
1385 /* initialize element/sound mapping from dynamic configuration */
1386 for (i = 0; i < num_property_mappings; i++)
1388 int element = property_mapping[i].base_index;
1389 int action = property_mapping[i].ext1_index;
1390 int sound = property_mapping[i].artwork_index;
1393 action = ACTION_DEFAULT;
1395 printf("::: %d: %d, %d, %d ['%s']\n",
1396 i, element, action, sound, element_info[element].token_name);
1398 element_info[element].sound[action] = sound;
1405 int element = EL_CUSTOM_11;
1408 while (element_action_info[j].suffix)
1410 printf("element %d, sound action '%s' == %d\n",
1411 element, element_action_info[j].suffix,
1412 element_info[element].sound[j]);
1417 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1423 int element = EL_SAND;
1424 int sound_action = ACTION_DIGGING;
1427 while (element_action_info[j].suffix)
1429 if (element_action_info[j].value == sound_action)
1430 printf("element %d, sound action '%s' == %d\n",
1431 element, element_action_info[j].suffix,
1432 element_info[element].sound[sound_action]);
1439 static void InitGameModeMusicInfo()
1441 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1442 int num_property_mappings = getMusicListPropertyMappingSize();
1443 int default_levelset_music = -1;
1446 /* set values to -1 to identify later as "uninitialized" values */
1447 for (i = 0; i < MAX_LEVELS; i++)
1448 levelset.music[i] = -1;
1449 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1452 /* initialize gamemode/music mapping from static configuration */
1453 for (i = 0; gamemode_to_music[i].music > -1; i++)
1455 int gamemode = gamemode_to_music[i].gamemode;
1456 int music = gamemode_to_music[i].music;
1459 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1463 gamemode = GAME_MODE_DEFAULT;
1465 menu.music[gamemode] = music;
1468 /* initialize gamemode/music mapping from dynamic configuration */
1469 for (i = 0; i < num_property_mappings; i++)
1471 int prefix = property_mapping[i].base_index;
1472 int gamemode = property_mapping[i].ext1_index;
1473 int level = property_mapping[i].ext2_index;
1474 int music = property_mapping[i].artwork_index;
1477 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1478 prefix, gamemode, level, music);
1481 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1485 gamemode = GAME_MODE_DEFAULT;
1487 /* level specific music only allowed for in-game music */
1488 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1489 gamemode = GAME_MODE_PLAYING;
1494 default_levelset_music = music;
1497 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1498 levelset.music[level] = music;
1499 if (gamemode != GAME_MODE_PLAYING)
1500 menu.music[gamemode] = music;
1503 /* now set all '-1' values to menu specific default values */
1504 /* (undefined values of "levelset.music[]" might stay at "-1" to
1505 allow dynamic selection of music files from music directory!) */
1506 for (i = 0; i < MAX_LEVELS; i++)
1507 if (levelset.music[i] == -1)
1508 levelset.music[i] = default_levelset_music;
1509 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1510 if (menu.music[i] == -1)
1511 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1515 for (i = 0; i < MAX_LEVELS; i++)
1516 if (levelset.music[i] != -1)
1517 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1518 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1519 if (menu.music[i] != -1)
1520 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1524 static void set_music_parameters(int music, char **parameter_raw)
1526 int parameter[NUM_MUS_ARGS];
1529 /* get integer values from string parameters */
1530 for (i = 0; i < NUM_MUS_ARGS; i++)
1532 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1533 music_config_suffix[i].type);
1535 /* explicit loop mode setting in configuration overrides default value */
1536 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1537 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1540 static void InitMusicInfo()
1542 int num_music = getMusicListSize();
1545 checked_free(music_info);
1547 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1549 for (i = 0; i < num_music; i++)
1551 struct FileInfo *music = getMusicListEntry(i);
1552 int len_music_text = strlen(music->token);
1554 music_info[i].loop = TRUE; /* default: play music in loop mode */
1556 /* determine all loop music */
1558 for (j = 0; music_prefix_info[j].prefix; j++)
1560 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1562 if (len_prefix_text < len_music_text &&
1563 strncmp(music->token,
1564 music_prefix_info[j].prefix, len_prefix_text) == 0)
1566 music_info[i].loop = music_prefix_info[j].is_loop_music;
1572 set_music_parameters(i, music->parameter);
1576 static void ReinitializeGraphics()
1578 InitGraphicInfo(); /* graphic properties mapping */
1579 InitElementGraphicInfo(); /* element game graphic mapping */
1580 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1582 InitElementSmallImages(); /* create editor and preview images */
1583 InitFontGraphicInfo(); /* initialize text drawing functions */
1585 SetMainBackgroundImage(IMG_BACKGROUND);
1586 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1592 static void ReinitializeSounds()
1594 InitSoundInfo(); /* sound properties mapping */
1595 InitElementSoundInfo(); /* element game sound mapping */
1596 InitGameModeSoundInfo(); /* game mode sound mapping */
1598 InitPlayLevelSound(); /* internal game sound settings */
1601 static void ReinitializeMusic()
1603 InitMusicInfo(); /* music properties mapping */
1604 InitGameModeMusicInfo(); /* game mode music mapping */
1607 static int get_special_property_bit(int element, int property_bit_nr)
1609 struct PropertyBitInfo
1615 static struct PropertyBitInfo pb_can_move_into_acid[] =
1617 /* the player may be able fall into acid when gravity is activated */
1622 { EL_SP_MURPHY, 0 },
1623 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1625 /* all element that can move may be able to also move into acid */
1628 { EL_BUG_RIGHT, 1 },
1631 { EL_SPACESHIP, 2 },
1632 { EL_SPACESHIP_LEFT, 2 },
1633 { EL_SPACESHIP_RIGHT, 2 },
1634 { EL_SPACESHIP_UP, 2 },
1635 { EL_SPACESHIP_DOWN, 2 },
1636 { EL_BD_BUTTERFLY, 3 },
1637 { EL_BD_BUTTERFLY_LEFT, 3 },
1638 { EL_BD_BUTTERFLY_RIGHT, 3 },
1639 { EL_BD_BUTTERFLY_UP, 3 },
1640 { EL_BD_BUTTERFLY_DOWN, 3 },
1641 { EL_BD_FIREFLY, 4 },
1642 { EL_BD_FIREFLY_LEFT, 4 },
1643 { EL_BD_FIREFLY_RIGHT, 4 },
1644 { EL_BD_FIREFLY_UP, 4 },
1645 { EL_BD_FIREFLY_DOWN, 4 },
1647 { EL_DARK_YAMYAM, 6 },
1650 { EL_PACMAN_LEFT, 8 },
1651 { EL_PACMAN_RIGHT, 8 },
1652 { EL_PACMAN_UP, 8 },
1653 { EL_PACMAN_DOWN, 8 },
1655 { EL_MOLE_LEFT, 9 },
1656 { EL_MOLE_RIGHT, 9 },
1658 { EL_MOLE_DOWN, 9 },
1662 { EL_SATELLITE, 13 },
1663 { EL_SP_SNIKSNAK, 14 },
1664 { EL_SP_ELECTRON, 15 },
1671 static struct PropertyBitInfo pb_dont_collide_with[] =
1673 { EL_SP_SNIKSNAK, 0 },
1674 { EL_SP_ELECTRON, 1 },
1682 struct PropertyBitInfo *pb_info;
1685 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1686 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1691 struct PropertyBitInfo *pb_info = NULL;
1694 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1695 if (pb_definition[i].bit_nr == property_bit_nr)
1696 pb_info = pb_definition[i].pb_info;
1698 if (pb_info == NULL)
1701 for (i = 0; pb_info[i].element != -1; i++)
1702 if (pb_info[i].element == element)
1703 return pb_info[i].bit_nr;
1709 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1710 boolean property_value)
1712 int bit_nr = get_special_property_bit(element, property_bit_nr);
1717 *bitfield |= (1 << bit_nr);
1719 *bitfield &= ~(1 << bit_nr);
1723 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1725 int bit_nr = get_special_property_bit(element, property_bit_nr);
1728 return ((*bitfield & (1 << bit_nr)) != 0);
1735 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1737 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1741 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1744 level->can_move_into_acid_bits |= (1 << bit_nr);
1748 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1750 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1753 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1759 void InitElementPropertiesStatic()
1761 static int ep_diggable[] =
1766 EL_SP_BUGGY_BASE_ACTIVATING,
1769 EL_INVISIBLE_SAND_ACTIVE,
1771 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1772 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1776 EL_SP_BUGGY_BASE_ACTIVE,
1781 static int ep_collectible_only[] =
1798 EL_DYNABOMB_INCREASE_NUMBER,
1799 EL_DYNABOMB_INCREASE_SIZE,
1800 EL_DYNABOMB_INCREASE_POWER,
1817 static int ep_dont_run_into[] =
1819 /* same elements as in 'ep_dont_touch' */
1825 /* same elements as in 'ep_dont_collide_with' */
1837 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1841 EL_SP_BUGGY_BASE_ACTIVE,
1846 static int ep_dont_collide_with[] =
1848 /* same elements as in 'ep_dont_touch' */
1864 static int ep_dont_touch[] =
1873 static int ep_indestructible[] =
1877 EL_ACID_POOL_TOPLEFT,
1878 EL_ACID_POOL_TOPRIGHT,
1879 EL_ACID_POOL_BOTTOMLEFT,
1880 EL_ACID_POOL_BOTTOM,
1881 EL_ACID_POOL_BOTTOMRIGHT,
1882 EL_SP_HARDWARE_GRAY,
1883 EL_SP_HARDWARE_GREEN,
1884 EL_SP_HARDWARE_BLUE,
1886 EL_SP_HARDWARE_YELLOW,
1887 EL_SP_HARDWARE_BASE_1,
1888 EL_SP_HARDWARE_BASE_2,
1889 EL_SP_HARDWARE_BASE_3,
1890 EL_SP_HARDWARE_BASE_4,
1891 EL_SP_HARDWARE_BASE_5,
1892 EL_SP_HARDWARE_BASE_6,
1893 EL_INVISIBLE_STEELWALL,
1894 EL_INVISIBLE_STEELWALL_ACTIVE,
1895 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1896 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1897 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1898 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1899 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1900 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1901 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1902 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1903 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1904 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1905 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1906 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1908 EL_LIGHT_SWITCH_ACTIVE,
1909 EL_SIGN_EXCLAMATION,
1910 EL_SIGN_RADIOACTIVITY,
1921 EL_STEELWALL_SLIPPERY,
1944 EL_SWITCHGATE_OPENING,
1945 EL_SWITCHGATE_CLOSED,
1946 EL_SWITCHGATE_CLOSING,
1948 EL_SWITCHGATE_SWITCH_UP,
1949 EL_SWITCHGATE_SWITCH_DOWN,
1952 EL_TIMEGATE_OPENING,
1954 EL_TIMEGATE_CLOSING,
1957 EL_TIMEGATE_SWITCH_ACTIVE,
1962 EL_TUBE_VERTICAL_LEFT,
1963 EL_TUBE_VERTICAL_RIGHT,
1964 EL_TUBE_HORIZONTAL_UP,
1965 EL_TUBE_HORIZONTAL_DOWN,
1973 static int ep_slippery[] =
1987 EL_ROBOT_WHEEL_ACTIVE,
1993 EL_ACID_POOL_TOPLEFT,
1994 EL_ACID_POOL_TOPRIGHT,
2004 EL_STEELWALL_SLIPPERY,
2010 static int ep_can_change[] =
2015 static int ep_can_move[] =
2017 /* same elements as in 'pb_can_move_into_acid' */
2038 static int ep_can_fall[] =
2053 EL_BD_MAGIC_WALL_FULL,
2066 static int ep_can_smash_player[] =
2091 static int ep_can_smash_enemies[] =
2099 static int ep_can_smash_everything[] =
2107 static int ep_explodes_by_fire[] =
2109 /* same elements as in 'ep_explodes_impact' */
2114 /* same elements as in 'ep_explodes_smashed' */
2123 EL_DYNABOMB_PLAYER_1_ACTIVE,
2124 EL_DYNABOMB_PLAYER_2_ACTIVE,
2125 EL_DYNABOMB_PLAYER_3_ACTIVE,
2126 EL_DYNABOMB_PLAYER_4_ACTIVE,
2127 EL_DYNABOMB_INCREASE_NUMBER,
2128 EL_DYNABOMB_INCREASE_SIZE,
2129 EL_DYNABOMB_INCREASE_POWER,
2130 EL_SP_DISK_RED_ACTIVE,
2143 static int ep_explodes_smashed[] =
2145 /* same elements as in 'ep_explodes_impact' */
2158 static int ep_explodes_impact[] =
2166 static int ep_walkable_over[] =
2170 EL_SOKOBAN_FIELD_EMPTY,
2188 static int ep_walkable_inside[] =
2193 EL_TUBE_VERTICAL_LEFT,
2194 EL_TUBE_VERTICAL_RIGHT,
2195 EL_TUBE_HORIZONTAL_UP,
2196 EL_TUBE_HORIZONTAL_DOWN,
2204 static int ep_walkable_under[] =
2209 static int ep_passable_over[] =
2224 static int ep_passable_inside[] =
2230 EL_SP_PORT_HORIZONTAL,
2231 EL_SP_PORT_VERTICAL,
2233 EL_SP_GRAVITY_PORT_LEFT,
2234 EL_SP_GRAVITY_PORT_RIGHT,
2235 EL_SP_GRAVITY_PORT_UP,
2236 EL_SP_GRAVITY_PORT_DOWN,
2237 EL_SP_GRAVITY_ON_PORT_LEFT,
2238 EL_SP_GRAVITY_ON_PORT_RIGHT,
2239 EL_SP_GRAVITY_ON_PORT_UP,
2240 EL_SP_GRAVITY_ON_PORT_DOWN,
2241 EL_SP_GRAVITY_OFF_PORT_LEFT,
2242 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2243 EL_SP_GRAVITY_OFF_PORT_UP,
2244 EL_SP_GRAVITY_OFF_PORT_DOWN,
2248 static int ep_passable_under[] =
2253 static int ep_droppable[] =
2258 static int ep_explodes_1x1_old[] =
2263 static int ep_pushable[] =
2275 EL_SOKOBAN_FIELD_FULL,
2282 static int ep_explodes_cross_old[] =
2287 static int ep_protected[] =
2289 /* same elements as in 'ep_walkable_inside' */
2293 EL_TUBE_VERTICAL_LEFT,
2294 EL_TUBE_VERTICAL_RIGHT,
2295 EL_TUBE_HORIZONTAL_UP,
2296 EL_TUBE_HORIZONTAL_DOWN,
2302 /* same elements as in 'ep_passable_over' */
2314 /* same elements as in 'ep_passable_inside' */
2319 EL_SP_PORT_HORIZONTAL,
2320 EL_SP_PORT_VERTICAL,
2322 EL_SP_GRAVITY_PORT_LEFT,
2323 EL_SP_GRAVITY_PORT_RIGHT,
2324 EL_SP_GRAVITY_PORT_UP,
2325 EL_SP_GRAVITY_PORT_DOWN,
2326 EL_SP_GRAVITY_ON_PORT_LEFT,
2327 EL_SP_GRAVITY_ON_PORT_RIGHT,
2328 EL_SP_GRAVITY_ON_PORT_UP,
2329 EL_SP_GRAVITY_ON_PORT_DOWN,
2330 EL_SP_GRAVITY_OFF_PORT_LEFT,
2331 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2332 EL_SP_GRAVITY_OFF_PORT_UP,
2333 EL_SP_GRAVITY_OFF_PORT_DOWN,
2337 static int ep_throwable[] =
2342 static int ep_can_explode[] =
2344 /* same elements as in 'ep_explodes_impact' */
2349 /* same elements as in 'ep_explodes_smashed' */
2355 /* elements that can explode by explosion or by dragonfire */
2358 EL_DYNABOMB_PLAYER_1_ACTIVE,
2359 EL_DYNABOMB_PLAYER_2_ACTIVE,
2360 EL_DYNABOMB_PLAYER_3_ACTIVE,
2361 EL_DYNABOMB_PLAYER_4_ACTIVE,
2362 EL_DYNABOMB_INCREASE_NUMBER,
2363 EL_DYNABOMB_INCREASE_SIZE,
2364 EL_DYNABOMB_INCREASE_POWER,
2365 EL_SP_DISK_RED_ACTIVE,
2373 /* elements that can explode only by explosion */
2378 static int ep_gravity_reachable[] =
2384 EL_INVISIBLE_SAND_ACTIVE,
2389 EL_SP_PORT_HORIZONTAL,
2390 EL_SP_PORT_VERTICAL,
2392 EL_SP_GRAVITY_PORT_LEFT,
2393 EL_SP_GRAVITY_PORT_RIGHT,
2394 EL_SP_GRAVITY_PORT_UP,
2395 EL_SP_GRAVITY_PORT_DOWN,
2396 EL_SP_GRAVITY_ON_PORT_LEFT,
2397 EL_SP_GRAVITY_ON_PORT_RIGHT,
2398 EL_SP_GRAVITY_ON_PORT_UP,
2399 EL_SP_GRAVITY_ON_PORT_DOWN,
2400 EL_SP_GRAVITY_OFF_PORT_LEFT,
2401 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2402 EL_SP_GRAVITY_OFF_PORT_UP,
2403 EL_SP_GRAVITY_OFF_PORT_DOWN,
2407 static int ep_player[] =
2414 EL_SOKOBAN_FIELD_PLAYER,
2419 static int ep_can_pass_magic_wall[] =
2432 static int ep_switchable[] =
2436 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2437 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2438 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2439 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2440 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2441 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2442 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2443 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2444 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2445 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2446 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2447 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2448 EL_SWITCHGATE_SWITCH_UP,
2449 EL_SWITCHGATE_SWITCH_DOWN,
2451 EL_LIGHT_SWITCH_ACTIVE,
2453 EL_BALLOON_SWITCH_LEFT,
2454 EL_BALLOON_SWITCH_RIGHT,
2455 EL_BALLOON_SWITCH_UP,
2456 EL_BALLOON_SWITCH_DOWN,
2457 EL_BALLOON_SWITCH_ANY,
2463 static int ep_bd_element[] =
2496 static int ep_sp_element[] =
2498 /* should always be valid */
2501 /* standard classic Supaplex elements */
2508 EL_SP_HARDWARE_GRAY,
2516 EL_SP_GRAVITY_PORT_RIGHT,
2517 EL_SP_GRAVITY_PORT_DOWN,
2518 EL_SP_GRAVITY_PORT_LEFT,
2519 EL_SP_GRAVITY_PORT_UP,
2524 EL_SP_PORT_VERTICAL,
2525 EL_SP_PORT_HORIZONTAL,
2531 EL_SP_HARDWARE_BASE_1,
2532 EL_SP_HARDWARE_GREEN,
2533 EL_SP_HARDWARE_BLUE,
2535 EL_SP_HARDWARE_YELLOW,
2536 EL_SP_HARDWARE_BASE_2,
2537 EL_SP_HARDWARE_BASE_3,
2538 EL_SP_HARDWARE_BASE_4,
2539 EL_SP_HARDWARE_BASE_5,
2540 EL_SP_HARDWARE_BASE_6,
2544 /* additional elements that appeared in newer Supaplex levels */
2547 /* additional gravity port elements (not switching, but setting gravity) */
2548 EL_SP_GRAVITY_ON_PORT_LEFT,
2549 EL_SP_GRAVITY_ON_PORT_RIGHT,
2550 EL_SP_GRAVITY_ON_PORT_UP,
2551 EL_SP_GRAVITY_ON_PORT_DOWN,
2552 EL_SP_GRAVITY_OFF_PORT_LEFT,
2553 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2554 EL_SP_GRAVITY_OFF_PORT_UP,
2555 EL_SP_GRAVITY_OFF_PORT_DOWN,
2557 /* more than one Murphy in a level results in an inactive clone */
2560 /* runtime Supaplex elements */
2561 EL_SP_DISK_RED_ACTIVE,
2562 EL_SP_TERMINAL_ACTIVE,
2563 EL_SP_BUGGY_BASE_ACTIVATING,
2564 EL_SP_BUGGY_BASE_ACTIVE,
2570 static int ep_sb_element[] =
2575 EL_SOKOBAN_FIELD_EMPTY,
2576 EL_SOKOBAN_FIELD_FULL,
2577 EL_SOKOBAN_FIELD_PLAYER,
2582 EL_INVISIBLE_STEELWALL,
2586 static int ep_gem[] =
2597 static int ep_food_dark_yamyam[] =
2624 static int ep_food_penguin[] =
2637 static int ep_food_pig[] =
2648 static int ep_historic_wall[] =
2673 EL_EXPANDABLE_WALL_HORIZONTAL,
2674 EL_EXPANDABLE_WALL_VERTICAL,
2675 EL_EXPANDABLE_WALL_ANY,
2676 EL_EXPANDABLE_WALL_GROWING,
2683 EL_SP_HARDWARE_GRAY,
2684 EL_SP_HARDWARE_GREEN,
2685 EL_SP_HARDWARE_BLUE,
2687 EL_SP_HARDWARE_YELLOW,
2688 EL_SP_HARDWARE_BASE_1,
2689 EL_SP_HARDWARE_BASE_2,
2690 EL_SP_HARDWARE_BASE_3,
2691 EL_SP_HARDWARE_BASE_4,
2692 EL_SP_HARDWARE_BASE_5,
2693 EL_SP_HARDWARE_BASE_6,
2695 EL_SP_TERMINAL_ACTIVE,
2698 EL_INVISIBLE_STEELWALL,
2699 EL_INVISIBLE_STEELWALL_ACTIVE,
2701 EL_INVISIBLE_WALL_ACTIVE,
2702 EL_STEELWALL_SLIPPERY,
2718 static int ep_historic_solid[] =
2722 EL_EXPANDABLE_WALL_HORIZONTAL,
2723 EL_EXPANDABLE_WALL_VERTICAL,
2724 EL_EXPANDABLE_WALL_ANY,
2737 EL_QUICKSAND_FILLING,
2738 EL_QUICKSAND_EMPTYING,
2740 EL_MAGIC_WALL_ACTIVE,
2741 EL_MAGIC_WALL_EMPTYING,
2742 EL_MAGIC_WALL_FILLING,
2746 EL_BD_MAGIC_WALL_ACTIVE,
2747 EL_BD_MAGIC_WALL_EMPTYING,
2748 EL_BD_MAGIC_WALL_FULL,
2749 EL_BD_MAGIC_WALL_FILLING,
2750 EL_BD_MAGIC_WALL_DEAD,
2759 EL_SP_TERMINAL_ACTIVE,
2763 EL_INVISIBLE_WALL_ACTIVE,
2764 EL_SWITCHGATE_SWITCH_UP,
2765 EL_SWITCHGATE_SWITCH_DOWN,
2767 EL_TIMEGATE_SWITCH_ACTIVE,
2779 /* the following elements are a direct copy of "indestructible" elements,
2780 except "EL_ACID", which is "indestructible", but not "solid"! */
2785 EL_ACID_POOL_TOPLEFT,
2786 EL_ACID_POOL_TOPRIGHT,
2787 EL_ACID_POOL_BOTTOMLEFT,
2788 EL_ACID_POOL_BOTTOM,
2789 EL_ACID_POOL_BOTTOMRIGHT,
2790 EL_SP_HARDWARE_GRAY,
2791 EL_SP_HARDWARE_GREEN,
2792 EL_SP_HARDWARE_BLUE,
2794 EL_SP_HARDWARE_YELLOW,
2795 EL_SP_HARDWARE_BASE_1,
2796 EL_SP_HARDWARE_BASE_2,
2797 EL_SP_HARDWARE_BASE_3,
2798 EL_SP_HARDWARE_BASE_4,
2799 EL_SP_HARDWARE_BASE_5,
2800 EL_SP_HARDWARE_BASE_6,
2801 EL_INVISIBLE_STEELWALL,
2802 EL_INVISIBLE_STEELWALL_ACTIVE,
2803 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2804 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2805 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2806 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2807 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2808 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2809 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2810 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2811 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2812 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2813 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2814 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2816 EL_LIGHT_SWITCH_ACTIVE,
2817 EL_SIGN_EXCLAMATION,
2818 EL_SIGN_RADIOACTIVITY,
2829 EL_STEELWALL_SLIPPERY,
2852 EL_SWITCHGATE_OPENING,
2853 EL_SWITCHGATE_CLOSED,
2854 EL_SWITCHGATE_CLOSING,
2856 EL_TIMEGATE_OPENING,
2858 EL_TIMEGATE_CLOSING,
2862 EL_TUBE_VERTICAL_LEFT,
2863 EL_TUBE_VERTICAL_RIGHT,
2864 EL_TUBE_HORIZONTAL_UP,
2865 EL_TUBE_HORIZONTAL_DOWN,
2873 static int ep_classic_enemy[] =
2889 static int ep_belt[] =
2891 EL_CONVEYOR_BELT_1_LEFT,
2892 EL_CONVEYOR_BELT_1_MIDDLE,
2893 EL_CONVEYOR_BELT_1_RIGHT,
2894 EL_CONVEYOR_BELT_2_LEFT,
2895 EL_CONVEYOR_BELT_2_MIDDLE,
2896 EL_CONVEYOR_BELT_2_RIGHT,
2897 EL_CONVEYOR_BELT_3_LEFT,
2898 EL_CONVEYOR_BELT_3_MIDDLE,
2899 EL_CONVEYOR_BELT_3_RIGHT,
2900 EL_CONVEYOR_BELT_4_LEFT,
2901 EL_CONVEYOR_BELT_4_MIDDLE,
2902 EL_CONVEYOR_BELT_4_RIGHT,
2906 static int ep_belt_active[] =
2908 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2909 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2910 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2911 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2912 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2913 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2914 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2915 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2916 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2917 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2918 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2919 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2923 static int ep_belt_switch[] =
2925 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2926 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2927 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2928 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2929 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2930 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2931 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2932 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2933 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2934 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2935 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2936 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2940 static int ep_tube[] =
2947 EL_TUBE_HORIZONTAL_UP,
2948 EL_TUBE_HORIZONTAL_DOWN,
2950 EL_TUBE_VERTICAL_LEFT,
2951 EL_TUBE_VERTICAL_RIGHT,
2956 static int ep_keygate[] =
2977 static int ep_amoeboid[] =
2987 static int ep_amoebalive[] =
2996 static int ep_has_content[] =
3006 static int ep_can_turn_each_move[] =
3008 /* !!! do something with this one !!! */
3012 static int ep_can_grow[] =
3024 static int ep_active_bomb[] =
3027 EL_DYNABOMB_PLAYER_1_ACTIVE,
3028 EL_DYNABOMB_PLAYER_2_ACTIVE,
3029 EL_DYNABOMB_PLAYER_3_ACTIVE,
3030 EL_DYNABOMB_PLAYER_4_ACTIVE,
3031 EL_SP_DISK_RED_ACTIVE,
3035 static int ep_inactive[] =
3072 EL_INVISIBLE_STEELWALL,
3080 EL_WALL_EMERALD_YELLOW,
3081 EL_DYNABOMB_INCREASE_NUMBER,
3082 EL_DYNABOMB_INCREASE_SIZE,
3083 EL_DYNABOMB_INCREASE_POWER,
3087 EL_SOKOBAN_FIELD_EMPTY,
3088 EL_SOKOBAN_FIELD_FULL,
3089 EL_WALL_EMERALD_RED,
3090 EL_WALL_EMERALD_PURPLE,
3091 EL_ACID_POOL_TOPLEFT,
3092 EL_ACID_POOL_TOPRIGHT,
3093 EL_ACID_POOL_BOTTOMLEFT,
3094 EL_ACID_POOL_BOTTOM,
3095 EL_ACID_POOL_BOTTOMRIGHT,
3099 EL_BD_MAGIC_WALL_DEAD,
3100 EL_AMOEBA_TO_DIAMOND,
3108 EL_SP_GRAVITY_PORT_RIGHT,
3109 EL_SP_GRAVITY_PORT_DOWN,
3110 EL_SP_GRAVITY_PORT_LEFT,
3111 EL_SP_GRAVITY_PORT_UP,
3112 EL_SP_PORT_HORIZONTAL,
3113 EL_SP_PORT_VERTICAL,
3124 EL_SP_HARDWARE_GRAY,
3125 EL_SP_HARDWARE_GREEN,
3126 EL_SP_HARDWARE_BLUE,
3128 EL_SP_HARDWARE_YELLOW,
3129 EL_SP_HARDWARE_BASE_1,
3130 EL_SP_HARDWARE_BASE_2,
3131 EL_SP_HARDWARE_BASE_3,
3132 EL_SP_HARDWARE_BASE_4,
3133 EL_SP_HARDWARE_BASE_5,
3134 EL_SP_HARDWARE_BASE_6,
3135 EL_SP_GRAVITY_ON_PORT_LEFT,
3136 EL_SP_GRAVITY_ON_PORT_RIGHT,
3137 EL_SP_GRAVITY_ON_PORT_UP,
3138 EL_SP_GRAVITY_ON_PORT_DOWN,
3139 EL_SP_GRAVITY_OFF_PORT_LEFT,
3140 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3141 EL_SP_GRAVITY_OFF_PORT_UP,
3142 EL_SP_GRAVITY_OFF_PORT_DOWN,
3143 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3144 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3145 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3146 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3147 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3148 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3149 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3150 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3151 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3152 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3153 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3154 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3155 EL_SIGN_EXCLAMATION,
3156 EL_SIGN_RADIOACTIVITY,
3167 EL_STEELWALL_SLIPPERY,
3183 static int ep_em_slippery_wall[] =
3188 static int ep_gfx_crumbled[] =
3201 } element_properties[] =
3203 { ep_diggable, EP_DIGGABLE },
3204 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3205 { ep_dont_run_into, EP_DONT_RUN_INTO },
3206 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3207 { ep_dont_touch, EP_DONT_TOUCH },
3208 { ep_indestructible, EP_INDESTRUCTIBLE },
3209 { ep_slippery, EP_SLIPPERY },
3210 { ep_can_change, EP_CAN_CHANGE },
3211 { ep_can_move, EP_CAN_MOVE },
3212 { ep_can_fall, EP_CAN_FALL },
3213 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3214 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3215 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3216 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3217 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3218 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3219 { ep_walkable_over, EP_WALKABLE_OVER },
3220 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3221 { ep_walkable_under, EP_WALKABLE_UNDER },
3222 { ep_passable_over, EP_PASSABLE_OVER },
3223 { ep_passable_inside, EP_PASSABLE_INSIDE },
3224 { ep_passable_under, EP_PASSABLE_UNDER },
3225 { ep_droppable, EP_DROPPABLE },
3226 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3227 { ep_pushable, EP_PUSHABLE },
3228 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3229 { ep_protected, EP_PROTECTED },
3230 { ep_throwable, EP_THROWABLE },
3231 { ep_can_explode, EP_CAN_EXPLODE },
3232 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3234 { ep_player, EP_PLAYER },
3235 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3236 { ep_switchable, EP_SWITCHABLE },
3237 { ep_bd_element, EP_BD_ELEMENT },
3238 { ep_sp_element, EP_SP_ELEMENT },
3239 { ep_sb_element, EP_SB_ELEMENT },
3241 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3242 { ep_food_penguin, EP_FOOD_PENGUIN },
3243 { ep_food_pig, EP_FOOD_PIG },
3244 { ep_historic_wall, EP_HISTORIC_WALL },
3245 { ep_historic_solid, EP_HISTORIC_SOLID },
3246 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3247 { ep_belt, EP_BELT },
3248 { ep_belt_active, EP_BELT_ACTIVE },
3249 { ep_belt_switch, EP_BELT_SWITCH },
3250 { ep_tube, EP_TUBE },
3251 { ep_keygate, EP_KEYGATE },
3252 { ep_amoeboid, EP_AMOEBOID },
3253 { ep_amoebalive, EP_AMOEBALIVE },
3254 { ep_has_content, EP_HAS_CONTENT },
3255 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3256 { ep_can_grow, EP_CAN_GROW },
3257 { ep_active_bomb, EP_ACTIVE_BOMB },
3258 { ep_inactive, EP_INACTIVE },
3260 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3262 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3267 static int copy_properties[][5] =
3271 EL_BUG_LEFT, EL_BUG_RIGHT,
3272 EL_BUG_UP, EL_BUG_DOWN
3276 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3277 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3281 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3282 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3286 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3287 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3291 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3292 EL_PACMAN_UP, EL_PACMAN_DOWN
3296 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3297 EL_MOLE_UP, EL_MOLE_DOWN
3307 /* always start with reliable default values (element has no properties) */
3308 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3309 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3310 SET_PROPERTY(i, j, FALSE);
3312 /* set all base element properties from above array definitions */
3313 for (i = 0; element_properties[i].elements != NULL; i++)
3314 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3315 SET_PROPERTY((element_properties[i].elements)[j],
3316 element_properties[i].property, TRUE);
3318 /* copy properties to some elements that are only stored in level file */
3319 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3320 for (j = 0; copy_properties[j][0] != -1; j++)
3321 if (HAS_PROPERTY(copy_properties[j][0], i))
3322 for (k = 1; k <= 4; k++)
3323 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3326 void InitElementPropertiesEngine(int engine_version)
3329 static int active_properties[] =
3334 EP_DONT_COLLIDE_WITH,
3338 EP_CAN_PASS_MAGIC_WALL,
3343 EP_EXPLODES_BY_FIRE,
3356 EP_EM_SLIPPERY_WALL,
3360 static int no_wall_properties[] =
3363 EP_COLLECTIBLE_ONLY,
3365 EP_DONT_COLLIDE_WITH,
3368 EP_CAN_SMASH_PLAYER,
3369 EP_CAN_SMASH_ENEMIES,
3370 EP_CAN_SMASH_EVERYTHING,
3375 EP_FOOD_DARK_YAMYAM,
3392 InitElementPropertiesStatic();
3395 /* important: after initialization in InitElementPropertiesStatic(), the
3396 elements are not again initialized to a default value; therefore all
3397 changes have to make sure that they leave the element with a defined
3398 property (which means that conditional property changes must be set to
3399 a reliable default value before) */
3401 /* set all special, combined or engine dependent element properties */
3402 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3405 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3406 SET_PROPERTY(i, j, FALSE);
3409 /* ---------- INACTIVE ------------------------------------------------- */
3410 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3412 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3413 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3414 IS_WALKABLE_INSIDE(i) ||
3415 IS_WALKABLE_UNDER(i)));
3417 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3418 IS_PASSABLE_INSIDE(i) ||
3419 IS_PASSABLE_UNDER(i)));
3421 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3422 IS_PASSABLE_OVER(i)));
3424 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3425 IS_PASSABLE_INSIDE(i)));
3427 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3428 IS_PASSABLE_UNDER(i)));
3430 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3433 /* ---------- COLLECTIBLE ---------------------------------------------- */
3434 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3438 /* ---------- SNAPPABLE ------------------------------------------------ */
3439 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3440 IS_COLLECTIBLE(i) ||
3444 /* ---------- WALL ----------------------------------------------------- */
3445 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3447 for (j = 0; no_wall_properties[j] != -1; j++)
3448 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3449 i >= EL_FIRST_RUNTIME_UNREAL)
3450 SET_PROPERTY(i, EP_WALL, FALSE);
3452 if (IS_HISTORIC_WALL(i))
3453 SET_PROPERTY(i, EP_WALL, TRUE);
3455 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3456 if (engine_version < VERSION_IDENT(2,2,0,0))
3457 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3459 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3461 !IS_COLLECTIBLE(i)));
3464 /* ---------- PROTECTED ------------------------------------------------ */
3465 if (IS_ACCESSIBLE_INSIDE(i))
3466 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3469 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3471 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3472 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3474 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3475 IS_INDESTRUCTIBLE(i)));
3477 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3479 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3480 else if (engine_version < VERSION_IDENT(2,2,0,0))
3481 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3484 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3489 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3490 !IS_WALKABLE_OVER(i) &&
3491 !IS_WALKABLE_UNDER(i)));
3493 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3498 if (IS_CUSTOM_ELEMENT(i))
3500 /* these are additional properties which are initially false when set */
3502 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3504 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3505 if (DONT_COLLIDE_WITH(i))
3506 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3508 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3509 if (CAN_SMASH_EVERYTHING(i))
3510 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3511 if (CAN_SMASH_ENEMIES(i))
3512 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3515 /* ---------- CAN_SMASH ------------------------------------------------ */
3516 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3517 CAN_SMASH_ENEMIES(i) ||
3518 CAN_SMASH_EVERYTHING(i)));
3521 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3522 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3523 CAN_EXPLODE_SMASHED(i) ||
3524 CAN_EXPLODE_IMPACT(i)));
3528 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3530 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3531 !CAN_EXPLODE_CROSS(i)));
3533 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3534 !CAN_EXPLODE_1X1(i) &&
3535 !CAN_EXPLODE_CROSS(i)));
3539 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3540 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3541 EXPLODES_BY_FIRE(i)));
3543 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3544 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3545 EXPLODES_SMASHED(i)));
3547 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3548 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3549 EXPLODES_IMPACT(i)));
3551 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3552 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3554 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3555 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3556 i == EL_BLACK_ORB));
3558 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3559 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3561 IS_CUSTOM_ELEMENT(i)));
3563 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3564 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3565 i == EL_SP_ELECTRON));
3567 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3568 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3569 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3570 getMoveIntoAcidProperty(&level, i));
3572 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3573 if (MAYBE_DONT_COLLIDE_WITH(i))
3574 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3575 getDontCollideWithProperty(&level, i));
3577 /* ---------- SP_PORT -------------------------------------------------- */
3578 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3579 IS_PASSABLE_INSIDE(i)));
3581 /* ---------- CAN_CHANGE ----------------------------------------------- */
3582 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3583 for (j = 0; j < element_info[i].num_change_pages; j++)
3584 if (element_info[i].change_page[j].can_change)
3585 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3587 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3588 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3589 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3593 /* determine inactive elements (used for engine main loop optimization) */
3594 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3596 boolean active = FALSE;
3598 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3600 if (HAS_PROPERTY(i, j))
3606 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3611 /* dynamically adjust element properties according to game engine version */
3613 static int ep_em_slippery_wall[] =
3618 EL_EXPANDABLE_WALL_HORIZONTAL,
3619 EL_EXPANDABLE_WALL_VERTICAL,
3620 EL_EXPANDABLE_WALL_ANY,
3624 /* special EM style gems behaviour */
3625 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3626 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3627 level.em_slippery_gems);
3629 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3630 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3631 (level.em_slippery_gems &&
3632 engine_version > VERSION_IDENT(2,0,1,0)));
3636 /* set default push delay values (corrected since version 3.0.7-1) */
3637 if (engine_version < VERSION_IDENT(3,0,7,1))
3639 game.default_push_delay_fixed = 2;
3640 game.default_push_delay_random = 8;
3644 game.default_push_delay_fixed = 8;
3645 game.default_push_delay_random = 8;
3648 /* set uninitialized push delay values of custom elements in older levels */
3649 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3651 int element = EL_CUSTOM_START + i;
3653 if (element_info[element].push_delay_fixed == -1)
3654 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3655 if (element_info[element].push_delay_random == -1)
3656 element_info[element].push_delay_random = game.default_push_delay_random;
3659 /* set some other uninitialized values of custom elements in older levels */
3660 if (engine_version < VERSION_IDENT(3,1,0,0))
3662 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3664 int element = EL_CUSTOM_START + i;
3666 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3668 element_info[element].explosion_delay = 17;
3669 element_info[element].ignition_delay = 8;
3674 /* set element properties that were handled incorrectly in older levels */
3675 if (engine_version < VERSION_IDENT(3,1,0,0))
3677 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3678 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3684 /* this is needed because some graphics depend on element properties */
3685 if (game_status == GAME_MODE_PLAYING)
3686 InitElementGraphicInfo();
3689 static void InitGlobal()
3693 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3695 element_info[i].token_name = element_name_info[i].token_name;
3696 element_info[i].class_name = element_name_info[i].class_name;
3697 element_info[i].editor_description=element_name_info[i].editor_description;
3700 global.autoplay_leveldir = NULL;
3701 global.convert_leveldir = NULL;
3703 global.frames_per_second = 0;
3704 global.fps_slowdown = FALSE;
3705 global.fps_slowdown_factor = 1;
3708 void Execute_Command(char *command)
3712 if (strcmp(command, "print graphicsinfo.conf") == 0)
3714 printf("# You can configure additional/alternative image files here.\n");
3715 printf("# (The entries below are default and therefore commented out.)\n");
3717 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3719 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3722 for (i = 0; image_config[i].token != NULL; i++)
3723 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3724 image_config[i].value));
3728 else if (strcmp(command, "print soundsinfo.conf") == 0)
3730 printf("# You can configure additional/alternative sound files here.\n");
3731 printf("# (The entries below are default and therefore commented out.)\n");
3733 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3735 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3738 for (i = 0; sound_config[i].token != NULL; i++)
3739 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3740 sound_config[i].value));
3744 else if (strcmp(command, "print musicinfo.conf") == 0)
3746 printf("# You can configure additional/alternative music files here.\n");
3747 printf("# (The entries below are default and therefore commented out.)\n");
3749 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3751 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3754 for (i = 0; music_config[i].token != NULL; i++)
3755 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3756 music_config[i].value));
3760 else if (strcmp(command, "print editorsetup.conf") == 0)
3762 printf("# You can configure your personal editor element list here.\n");
3763 printf("# (The entries below are default and therefore commented out.)\n");
3766 PrintEditorElementList();
3770 else if (strcmp(command, "print helpanim.conf") == 0)
3772 printf("# You can configure different element help animations here.\n");
3773 printf("# (The entries below are default and therefore commented out.)\n");
3776 for (i = 0; helpanim_config[i].token != NULL; i++)
3778 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3779 helpanim_config[i].value));
3781 if (strcmp(helpanim_config[i].token, "end") == 0)
3787 else if (strcmp(command, "print helptext.conf") == 0)
3789 printf("# You can configure different element help text here.\n");
3790 printf("# (The entries below are default and therefore commented out.)\n");
3793 for (i = 0; helptext_config[i].token != NULL; i++)
3794 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3795 helptext_config[i].value));
3799 else if (strncmp(command, "dump level ", 11) == 0)
3801 char *filename = &command[11];
3803 if (access(filename, F_OK) != 0)
3804 Error(ERR_EXIT, "cannot open file '%s'", filename);
3806 LoadLevelFromFilename(&level, filename);
3811 else if (strncmp(command, "dump tape ", 10) == 0)
3813 char *filename = &command[10];
3815 if (access(filename, F_OK) != 0)
3816 Error(ERR_EXIT, "cannot open file '%s'", filename);
3818 LoadTapeFromFilename(filename);
3823 else if (strncmp(command, "autoplay ", 9) == 0)
3825 char *str_copy = getStringCopy(&command[9]);
3826 char *str_ptr = strchr(str_copy, ' ');
3828 global.autoplay_leveldir = str_copy;
3829 global.autoplay_level_nr = -1;
3831 if (str_ptr != NULL)
3833 *str_ptr++ = '\0'; /* terminate leveldir string */
3834 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3837 else if (strncmp(command, "convert ", 8) == 0)
3839 char *str_copy = getStringCopy(&command[8]);
3840 char *str_ptr = strchr(str_copy, ' ');
3842 global.convert_leveldir = str_copy;
3843 global.convert_level_nr = -1;
3845 if (str_ptr != NULL)
3847 *str_ptr++ = '\0'; /* terminate leveldir string */
3848 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3853 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3857 static void InitSetup()
3859 LoadSetup(); /* global setup info */
3861 /* set some options from setup file */
3863 if (setup.options.verbose)
3864 options.verbose = TRUE;
3867 static void InitPlayerInfo()
3871 /* choose default local player */
3872 local_player = &stored_player[0];
3874 for (i = 0; i < MAX_PLAYERS; i++)
3875 stored_player[i].connected = FALSE;
3877 local_player->connected = TRUE;
3880 static void InitArtworkInfo()
3885 static char *get_string_in_brackets(char *string)
3887 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3889 sprintf(string_in_brackets, "[%s]", string);
3891 return string_in_brackets;
3894 static char *get_level_id_suffix(int id_nr)
3896 char *id_suffix = checked_malloc(1 + 3 + 1);
3898 if (id_nr < 0 || id_nr > 999)
3901 sprintf(id_suffix, ".%03d", id_nr);
3907 static char *get_element_class_token(int element)
3909 char *element_class_name = element_info[element].class_name;
3910 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3912 sprintf(element_class_token, "[%s]", element_class_name);
3914 return element_class_token;
3917 static char *get_action_class_token(int action)
3919 char *action_class_name = &element_action_info[action].suffix[1];
3920 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3922 sprintf(action_class_token, "[%s]", action_class_name);
3924 return action_class_token;
3928 static void InitArtworkConfig()
3930 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3931 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3932 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3933 static char *action_id_suffix[NUM_ACTIONS + 1];
3934 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3935 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3936 static char *level_id_suffix[MAX_LEVELS + 1];
3937 static char *dummy[1] = { NULL };
3938 static char *ignore_generic_tokens[] =
3944 static char **ignore_image_tokens;
3945 static char **ignore_sound_tokens;
3946 static char **ignore_music_tokens;
3947 int num_ignore_generic_tokens;
3948 int num_ignore_image_tokens;
3949 int num_ignore_sound_tokens;
3950 int num_ignore_music_tokens;
3953 /* dynamically determine list of generic tokens to be ignored */
3954 num_ignore_generic_tokens = 0;
3955 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3956 num_ignore_generic_tokens++;
3958 /* dynamically determine list of image tokens to be ignored */
3959 num_ignore_image_tokens = num_ignore_generic_tokens;
3960 for (i = 0; image_config_vars[i].token != NULL; i++)
3961 num_ignore_image_tokens++;
3962 ignore_image_tokens =
3963 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3964 for (i = 0; i < num_ignore_generic_tokens; i++)
3965 ignore_image_tokens[i] = ignore_generic_tokens[i];
3966 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3967 ignore_image_tokens[num_ignore_generic_tokens + i] =
3968 image_config_vars[i].token;
3969 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3971 /* dynamically determine list of sound tokens to be ignored */
3972 num_ignore_sound_tokens = num_ignore_generic_tokens;
3973 ignore_sound_tokens =
3974 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3975 for (i = 0; i < num_ignore_generic_tokens; i++)
3976 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3977 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3979 /* dynamically determine list of music tokens to be ignored */
3980 num_ignore_music_tokens = num_ignore_generic_tokens;
3981 ignore_music_tokens =
3982 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3983 for (i = 0; i < num_ignore_generic_tokens; i++)
3984 ignore_music_tokens[i] = ignore_generic_tokens[i];
3985 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3987 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3988 image_id_prefix[i] = element_info[i].token_name;
3989 for (i = 0; i < NUM_FONTS; i++)
3990 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3991 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3993 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3994 sound_id_prefix[i] = element_info[i].token_name;
3995 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3996 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3997 get_string_in_brackets(element_info[i].class_name);
3998 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4000 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4001 music_id_prefix[i] = music_prefix_info[i].prefix;
4002 music_id_prefix[MAX_LEVELS] = NULL;
4004 for (i = 0; i < NUM_ACTIONS; i++)
4005 action_id_suffix[i] = element_action_info[i].suffix;
4006 action_id_suffix[NUM_ACTIONS] = NULL;
4008 for (i = 0; i < NUM_DIRECTIONS; i++)
4009 direction_id_suffix[i] = element_direction_info[i].suffix;
4010 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4012 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4013 special_id_suffix[i] = special_suffix_info[i].suffix;
4014 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4016 for (i = 0; i < MAX_LEVELS; i++)
4017 level_id_suffix[i] = get_level_id_suffix(i);
4018 level_id_suffix[MAX_LEVELS] = NULL;
4020 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4021 image_id_prefix, action_id_suffix, direction_id_suffix,
4022 special_id_suffix, ignore_image_tokens);
4023 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4024 sound_id_prefix, action_id_suffix, dummy,
4025 special_id_suffix, ignore_sound_tokens);
4026 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4027 music_id_prefix, special_id_suffix, level_id_suffix,
4028 dummy, ignore_music_tokens);
4031 static void InitMixer()
4039 char *filename_font_initial = NULL;
4040 Bitmap *bitmap_font_initial = NULL;
4043 /* determine settings for initial font (for displaying startup messages) */
4044 for (i = 0; image_config[i].token != NULL; i++)
4046 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4048 char font_token[128];
4051 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4052 len_font_token = strlen(font_token);
4054 if (strcmp(image_config[i].token, font_token) == 0)
4055 filename_font_initial = image_config[i].value;
4056 else if (strlen(image_config[i].token) > len_font_token &&
4057 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4059 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4060 font_initial[j].src_x = atoi(image_config[i].value);
4061 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4062 font_initial[j].src_y = atoi(image_config[i].value);
4063 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4064 font_initial[j].width = atoi(image_config[i].value);
4065 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4066 font_initial[j].height = atoi(image_config[i].value);
4071 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4073 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4074 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4077 if (filename_font_initial == NULL) /* should not happen */
4078 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4080 /* create additional image buffers for double-buffering */
4081 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4082 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4084 /* initialize screen properties */
4085 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4086 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4088 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4089 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4090 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4092 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4094 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4095 font_initial[j].bitmap = bitmap_font_initial;
4097 InitFontGraphicInfo();
4099 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4100 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4102 DrawInitText("Loading graphics:", 120, FC_GREEN);
4104 InitTileClipmasks();
4107 void InitGfxBackground()
4111 drawto = backbuffer;
4112 fieldbuffer = bitmap_db_field;
4113 SetDrawtoField(DRAW_BACKBUFFER);
4115 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4116 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4117 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4118 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4120 for (x = 0; x < MAX_BUF_XSIZE; x++)
4121 for (y = 0; y < MAX_BUF_YSIZE; y++)
4124 redraw_mask = REDRAW_ALL;
4127 static void InitLevelInfo()
4129 LoadLevelInfo(); /* global level info */
4130 LoadLevelSetup_LastSeries(); /* last played series info */
4131 LoadLevelSetup_SeriesInfo(); /* last played level info */
4134 void InitLevelArtworkInfo()
4136 LoadLevelArtworkInfo();
4139 static void InitImages()
4142 setLevelArtworkDir(artwork.gfx_first);
4146 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4147 leveldir_current->identifier,
4148 artwork.gfx_current_identifier,
4149 artwork.gfx_current->identifier,
4150 leveldir_current->graphics_set,
4151 leveldir_current->graphics_path);
4154 ReloadCustomImages();
4156 LoadCustomElementDescriptions();
4157 LoadSpecialMenuDesignSettings();
4159 ReinitializeGraphics();
4162 static void InitSound(char *identifier)
4164 if (identifier == NULL)
4165 identifier = artwork.snd_current->identifier;
4168 /* set artwork path to send it to the sound server process */
4169 setLevelArtworkDir(artwork.snd_first);
4172 InitReloadCustomSounds(identifier);
4173 ReinitializeSounds();
4176 static void InitMusic(char *identifier)
4178 if (identifier == NULL)
4179 identifier = artwork.mus_current->identifier;
4182 /* set artwork path to send it to the sound server process */
4183 setLevelArtworkDir(artwork.mus_first);
4186 InitReloadCustomMusic(identifier);
4187 ReinitializeMusic();
4190 void InitNetworkServer()
4192 #if defined(NETWORK_AVALIABLE)
4196 if (!options.network)
4199 #if defined(NETWORK_AVALIABLE)
4200 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4202 if (!ConnectToServer(options.server_host, options.server_port))
4203 Error(ERR_EXIT, "cannot connect to network game server");
4205 SendToServer_PlayerName(setup.player_name);
4206 SendToServer_ProtocolVersion();
4209 SendToServer_NrWanted(nr_wanted);
4213 static char *getNewArtworkIdentifier(int type)
4215 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4216 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4217 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4218 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4219 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4220 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4221 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4222 char *leveldir_identifier = leveldir_current->identifier;
4224 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4225 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4227 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4229 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4230 char *artwork_current_identifier;
4231 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4233 /* leveldir_current may be invalid (level group, parent link) */
4234 if (!validLevelSeries(leveldir_current))
4237 /* 1st step: determine artwork set to be activated in descending order:
4238 --------------------------------------------------------------------
4239 1. setup artwork (when configured to override everything else)
4240 2. artwork set configured in "levelinfo.conf" of current level set
4241 (artwork in level directory will have priority when loading later)
4242 3. artwork in level directory (stored in artwork sub-directory)
4243 4. setup artwork (currently configured in setup menu) */
4245 if (setup_override_artwork)
4246 artwork_current_identifier = setup_artwork_set;
4247 else if (leveldir_artwork_set != NULL)
4248 artwork_current_identifier = leveldir_artwork_set;
4249 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4250 artwork_current_identifier = leveldir_identifier;
4252 artwork_current_identifier = setup_artwork_set;
4255 /* 2nd step: check if it is really needed to reload artwork set
4256 ------------------------------------------------------------ */
4259 if (type == ARTWORK_TYPE_GRAPHICS)
4260 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4261 artwork_new_identifier,
4262 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4263 artwork_current_identifier,
4264 leveldir_current->graphics_set,
4265 leveldir_current->identifier);
4268 /* ---------- reload if level set and also artwork set has changed ------- */
4269 if (leveldir_current_identifier[type] != leveldir_identifier &&
4270 (last_has_level_artwork_set[type] || has_level_artwork_set))
4271 artwork_new_identifier = artwork_current_identifier;
4273 leveldir_current_identifier[type] = leveldir_identifier;
4274 last_has_level_artwork_set[type] = has_level_artwork_set;
4277 if (type == ARTWORK_TYPE_GRAPHICS)
4278 printf("::: 1: '%s'\n", artwork_new_identifier);
4281 /* ---------- reload if "override artwork" setting has changed ----------- */
4282 if (last_override_level_artwork[type] != setup_override_artwork)
4283 artwork_new_identifier = artwork_current_identifier;
4285 last_override_level_artwork[type] = setup_override_artwork;
4288 if (type == ARTWORK_TYPE_GRAPHICS)
4289 printf("::: 2: '%s'\n", artwork_new_identifier);
4292 /* ---------- reload if current artwork identifier has changed ----------- */
4293 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4294 artwork_current_identifier) != 0)
4295 artwork_new_identifier = artwork_current_identifier;
4297 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4300 if (type == ARTWORK_TYPE_GRAPHICS)
4301 printf("::: 3: '%s'\n", artwork_new_identifier);
4304 /* ---------- do not reload directly after starting ---------------------- */
4305 if (!initialized[type])
4306 artwork_new_identifier = NULL;
4308 initialized[type] = TRUE;
4311 if (type == ARTWORK_TYPE_GRAPHICS)
4312 printf("::: 4: '%s'\n", artwork_new_identifier);
4316 if (type == ARTWORK_TYPE_GRAPHICS)
4317 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4318 artwork.gfx_current_identifier, artwork_current_identifier,
4319 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4320 artwork_new_identifier);
4323 return artwork_new_identifier;
4326 void ReloadCustomArtwork(int force_reload)
4328 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4329 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4330 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4331 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4332 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4333 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4334 boolean redraw_screen = FALSE;
4336 if (gfx_new_identifier != NULL || force_reload_gfx)
4339 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4340 artwork.gfx_current_identifier,
4342 artwork.gfx_current->identifier,
4343 leveldir_current->graphics_set);
4346 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4351 printf("... '%s'\n",
4352 leveldir_current->graphics_set);
4355 FreeTileClipmasks();
4356 InitTileClipmasks();
4358 redraw_screen = TRUE;
4361 if (snd_new_identifier != NULL || force_reload_snd)
4363 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4365 InitSound(snd_new_identifier);
4367 redraw_screen = TRUE;
4370 if (mus_new_identifier != NULL || force_reload_mus)
4372 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4374 InitMusic(mus_new_identifier);
4376 redraw_screen = TRUE;
4381 InitGfxBackground();
4383 /* force redraw of (open or closed) door graphics */
4384 SetDoorState(DOOR_OPEN_ALL);
4385 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4389 void KeyboardAutoRepeatOffUnlessAutoplay()
4391 if (global.autoplay_leveldir == NULL)
4392 KeyboardAutoRepeatOff();
4396 /* ========================================================================= */
4398 /* ========================================================================= */
4402 InitGlobal(); /* initialize some global variables */
4404 if (options.execute_command)
4405 Execute_Command(options.execute_command);
4407 if (options.serveronly)
4409 #if defined(PLATFORM_UNIX)
4410 NetworkServer(options.server_port, options.serveronly);
4412 Error(ERR_WARN, "networking only supported in Unix version");
4414 exit(0); /* never reached */
4420 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4421 InitArtworkConfig(); /* needed before forking sound child process */
4426 InitRND(NEW_RANDOMIZE);
4427 InitSimpleRND(NEW_RANDOMIZE);
4432 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4435 InitEventFilter(FilterMouseMotionEvents);
4437 InitElementPropertiesStatic();
4438 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4443 InitLevelArtworkInfo();
4445 InitImages(); /* needs to know current level directory */
4446 InitSound(NULL); /* needs to know current level directory */
4447 InitMusic(NULL); /* needs to know current level directory */
4449 InitGfxBackground();
4451 if (global.autoplay_leveldir)
4456 else if (global.convert_leveldir)
4462 game_status = GAME_MODE_MAIN;
4470 InitNetworkServer();
4473 void CloseAllAndExit(int exit_value)
4478 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4485 FreeTileClipmasks();
4487 #if defined(TARGET_SDL)
4488 if (network_server) /* terminate network server */
4489 SDL_KillThread(server_thread);
4492 CloseVideoDisplay();
4493 ClosePlatformDependentStuff();