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);
266 /* !!! FIX ME (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
268 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_TITLE; i++)
269 InitElementSmallImagesScaledUp(i);
273 void SetBitmaps_EM(Bitmap **em_bitmap)
275 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
276 em_bitmap[1] = graphic_info[IMG_EMC_SCORE].bitmap;
277 em_bitmap[2] = graphic_info[IMG_EMC_SPRITE].bitmap;
278 em_bitmap[3] = graphic_info[IMG_EMC_TITLE].bitmap;
281 static int getFontBitmapID(int font_nr)
285 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
286 special = game_status;
287 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
288 special = GFX_SPECIAL_ARG_MAIN;
289 else if (game_status == GAME_MODE_PLAYING)
290 special = GFX_SPECIAL_ARG_DOOR;
293 return font_info[font_nr].special_bitmap_id[special];
298 void InitFontGraphicInfo()
300 static struct FontBitmapInfo *font_bitmap_info = NULL;
301 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
302 int num_property_mappings = getImageListPropertyMappingSize();
303 int num_font_bitmaps = NUM_FONTS;
306 if (graphic_info == NULL) /* still at startup phase */
308 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
313 /* ---------- initialize font graphic definitions ---------- */
315 /* always start with reliable default values (normal font graphics) */
317 for (i = 0; i < NUM_FONTS; i++)
318 font_info[i].graphic = IMG_FONT_INITIAL_1;
320 for (i = 0; i < NUM_FONTS; i++)
321 font_info[i].graphic = FONT_INITIAL_1;
324 /* initialize normal font/graphic mapping from static configuration */
325 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
327 int font_nr = font_to_graphic[i].font_nr;
328 int special = font_to_graphic[i].special;
329 int graphic = font_to_graphic[i].graphic;
334 font_info[font_nr].graphic = graphic;
337 /* always start with reliable default values (special font graphics) */
338 for (i = 0; i < NUM_FONTS; i++)
340 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
342 font_info[i].special_graphic[j] = font_info[i].graphic;
343 font_info[i].special_bitmap_id[j] = i;
347 /* initialize special font/graphic mapping from static configuration */
348 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
350 int font_nr = font_to_graphic[i].font_nr;
351 int special = font_to_graphic[i].special;
352 int graphic = font_to_graphic[i].graphic;
354 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
356 font_info[font_nr].special_graphic[special] = graphic;
357 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
362 /* initialize special element/graphic mapping from dynamic configuration */
363 for (i = 0; i < num_property_mappings; i++)
365 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
366 int special = property_mapping[i].ext3_index;
367 int graphic = property_mapping[i].artwork_index;
372 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
374 font_info[font_nr].special_graphic[special] = graphic;
375 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
380 /* ---------- initialize font bitmap array ---------- */
382 if (font_bitmap_info != NULL)
383 FreeFontInfo(font_bitmap_info);
386 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
388 /* ---------- initialize font bitmap definitions ---------- */
390 for (i = 0; i < NUM_FONTS; i++)
392 if (i < NUM_INITIAL_FONTS)
394 font_bitmap_info[i] = font_initial[i];
398 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
400 int font_bitmap_id = font_info[i].special_bitmap_id[j];
401 int graphic = font_info[i].special_graphic[j];
403 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
404 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
406 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
407 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
410 /* copy font relevant information from graphics information */
411 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
412 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
413 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
414 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
415 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
416 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
417 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
419 font_bitmap_info[font_bitmap_id].num_chars =
420 graphic_info[graphic].anim_frames;
421 font_bitmap_info[font_bitmap_id].num_chars_per_line =
422 graphic_info[graphic].anim_frames_per_line;
426 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
429 void InitElementGraphicInfo()
431 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
432 int num_property_mappings = getImageListPropertyMappingSize();
435 if (graphic_info == NULL) /* still at startup phase */
438 /* set values to -1 to identify later as "uninitialized" values */
439 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
441 for (act = 0; act < NUM_ACTIONS; act++)
443 element_info[i].graphic[act] = -1;
444 element_info[i].crumbled[act] = -1;
446 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
448 element_info[i].direction_graphic[act][dir] = -1;
449 element_info[i].direction_crumbled[act][dir] = -1;
454 /* initialize normal element/graphic mapping from static configuration */
455 for (i = 0; element_to_graphic[i].element > -1; i++)
457 int element = element_to_graphic[i].element;
458 int action = element_to_graphic[i].action;
459 int direction = element_to_graphic[i].direction;
460 boolean crumbled = element_to_graphic[i].crumbled;
461 int graphic = element_to_graphic[i].graphic;
462 int base_graphic = el2baseimg(element);
464 if (graphic_info[graphic].bitmap == NULL)
467 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
470 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
471 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
473 /* if the base graphic ("emerald", for example) has been redefined,
474 but not the action graphic ("emerald.falling", for example), do not
475 use an existing (in this case considered obsolete) action graphic
476 anymore, but use the automatically determined default graphic */
477 if (base_redefined && !act_dir_redefined)
482 action = ACTION_DEFAULT;
487 element_info[element].direction_crumbled[action][direction] = graphic;
489 element_info[element].crumbled[action] = graphic;
494 element_info[element].direction_graphic[action][direction] = graphic;
496 element_info[element].graphic[action] = graphic;
500 /* initialize normal element/graphic mapping from dynamic configuration */
501 for (i = 0; i < num_property_mappings; i++)
503 int element = property_mapping[i].base_index;
504 int action = property_mapping[i].ext1_index;
505 int direction = property_mapping[i].ext2_index;
506 int special = property_mapping[i].ext3_index;
507 int graphic = property_mapping[i].artwork_index;
508 boolean crumbled = FALSE;
510 if (special == GFX_SPECIAL_ARG_CRUMBLED)
516 if (graphic_info[graphic].bitmap == NULL)
519 if (element >= MAX_NUM_ELEMENTS || special != -1)
523 action = ACTION_DEFAULT;
528 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
529 element_info[element].direction_crumbled[action][dir] = -1;
532 element_info[element].direction_crumbled[action][direction] = graphic;
534 element_info[element].crumbled[action] = graphic;
539 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
540 element_info[element].direction_graphic[action][dir] = -1;
543 element_info[element].direction_graphic[action][direction] = graphic;
545 element_info[element].graphic[action] = graphic;
549 /* now copy all graphics that are defined to be cloned from other graphics */
550 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
552 int graphic = element_info[i].graphic[ACTION_DEFAULT];
553 int crumbled_like, diggable_like;
558 crumbled_like = graphic_info[graphic].crumbled_like;
559 diggable_like = graphic_info[graphic].diggable_like;
561 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
563 for (act = 0; act < NUM_ACTIONS; act++)
564 element_info[i].crumbled[act] =
565 element_info[crumbled_like].crumbled[act];
566 for (act = 0; act < NUM_ACTIONS; act++)
567 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
568 element_info[i].direction_crumbled[act][dir] =
569 element_info[crumbled_like].direction_crumbled[act][dir];
572 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
574 element_info[i].graphic[ACTION_DIGGING] =
575 element_info[diggable_like].graphic[ACTION_DIGGING];
576 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
577 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
578 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
583 /* set hardcoded definitions for some runtime elements without graphic */
584 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
588 /* now set all undefined/invalid graphics to -1 to set to default after it */
589 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
591 for (act = 0; act < NUM_ACTIONS; act++)
595 graphic = element_info[i].graphic[act];
596 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
597 element_info[i].graphic[act] = -1;
599 graphic = element_info[i].crumbled[act];
600 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
601 element_info[i].crumbled[act] = -1;
603 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
605 graphic = element_info[i].direction_graphic[act][dir];
606 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
607 element_info[i].direction_graphic[act][dir] = -1;
609 graphic = element_info[i].direction_crumbled[act][dir];
610 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
611 element_info[i].direction_crumbled[act][dir] = -1;
617 /* now set all '-1' values to element specific default values */
618 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
620 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
621 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
622 int default_direction_graphic[NUM_DIRECTIONS];
623 int default_direction_crumbled[NUM_DIRECTIONS];
625 if (default_graphic == -1)
626 default_graphic = IMG_UNKNOWN;
627 if (default_crumbled == -1)
628 default_crumbled = IMG_EMPTY;
630 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
632 default_direction_graphic[dir] =
633 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
634 default_direction_crumbled[dir] =
635 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
637 if (default_direction_graphic[dir] == -1)
638 default_direction_graphic[dir] = default_graphic;
639 if (default_direction_crumbled[dir] == -1)
640 default_direction_crumbled[dir] = default_crumbled;
643 for (act = 0; act < NUM_ACTIONS; act++)
645 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
646 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
647 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
648 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
649 act == ACTION_TURNING_FROM_RIGHT ||
650 act == ACTION_TURNING_FROM_UP ||
651 act == ACTION_TURNING_FROM_DOWN);
653 /* generic default action graphic (defined by "[default]" directive) */
654 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
655 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
657 /* look for special default action graphic (classic game specific) */
658 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
659 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
660 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
661 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
662 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
663 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
665 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
666 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
667 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
668 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
669 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
670 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
673 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
674 /* !!! make this better !!! */
675 if (i == EL_EMPTY_SPACE)
677 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
678 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
682 if (default_action_graphic == -1)
683 default_action_graphic = default_graphic;
684 if (default_action_crumbled == -1)
685 default_action_crumbled = default_crumbled;
687 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
689 int default_action_direction_graphic = element_info[i].graphic[act];
690 int default_action_direction_crumbled = element_info[i].crumbled[act];
692 /* no graphic for current action -- use default direction graphic */
693 if (default_action_direction_graphic == -1)
694 default_action_direction_graphic =
695 (act_remove ? IMG_EMPTY :
697 element_info[i].direction_graphic[ACTION_TURNING][dir] :
698 default_direction_graphic[dir]);
699 if (default_action_direction_crumbled == -1)
700 default_action_direction_crumbled =
701 (act_remove ? IMG_EMPTY :
703 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
704 default_direction_crumbled[dir]);
706 if (element_info[i].direction_graphic[act][dir] == -1)
707 element_info[i].direction_graphic[act][dir] =
708 default_action_direction_graphic;
709 if (element_info[i].direction_crumbled[act][dir] == -1)
710 element_info[i].direction_crumbled[act][dir] =
711 default_action_direction_crumbled;
714 /* no graphic for this specific action -- use default action graphic */
715 if (element_info[i].graphic[act] == -1)
716 element_info[i].graphic[act] =
717 (act_remove ? IMG_EMPTY :
718 act_turning ? element_info[i].graphic[ACTION_TURNING] :
719 default_action_graphic);
720 if (element_info[i].crumbled[act] == -1)
721 element_info[i].crumbled[act] =
722 (act_remove ? IMG_EMPTY :
723 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
724 default_action_crumbled);
729 /* set animation mode to "none" for each graphic with only 1 frame */
730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
732 for (act = 0; act < NUM_ACTIONS; act++)
734 int graphic = element_info[i].graphic[act];
735 int crumbled = element_info[i].crumbled[act];
737 if (graphic_info[graphic].anim_frames == 1)
738 graphic_info[graphic].anim_mode = ANIM_NONE;
739 if (graphic_info[crumbled].anim_frames == 1)
740 graphic_info[crumbled].anim_mode = ANIM_NONE;
742 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
744 graphic = element_info[i].direction_graphic[act][dir];
745 crumbled = element_info[i].direction_crumbled[act][dir];
747 if (graphic_info[graphic].anim_frames == 1)
748 graphic_info[graphic].anim_mode = ANIM_NONE;
749 if (graphic_info[crumbled].anim_frames == 1)
750 graphic_info[crumbled].anim_mode = ANIM_NONE;
760 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
761 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
763 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
764 element_info[i].token_name, i);
770 void InitElementSpecialGraphicInfo()
772 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
773 int num_property_mappings = getImageListPropertyMappingSize();
776 /* always start with reliable default values */
777 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
778 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
779 element_info[i].special_graphic[j] =
780 element_info[i].graphic[ACTION_DEFAULT];
782 /* initialize special element/graphic mapping from static configuration */
783 for (i = 0; element_to_special_graphic[i].element > -1; i++)
785 int element = element_to_special_graphic[i].element;
786 int special = element_to_special_graphic[i].special;
787 int graphic = element_to_special_graphic[i].graphic;
788 int base_graphic = el2baseimg(element);
789 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
790 boolean special_redefined = getImageListEntry(graphic)->redefined;
792 /* if the base graphic ("emerald", for example) has been redefined,
793 but not the special graphic ("emerald.EDITOR", for example), do not
794 use an existing (in this case considered obsolete) special graphic
795 anymore, but use the automatically created (down-scaled) graphic */
796 if (base_redefined && !special_redefined)
799 element_info[element].special_graphic[special] = graphic;
802 /* initialize special element/graphic mapping from dynamic configuration */
803 for (i = 0; i < num_property_mappings; i++)
805 int element = property_mapping[i].base_index;
806 int special = property_mapping[i].ext3_index;
807 int graphic = property_mapping[i].artwork_index;
809 if (element >= MAX_NUM_ELEMENTS)
812 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
813 element_info[element].special_graphic[special] = graphic;
817 /* now set all undefined/invalid graphics to default */
818 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
819 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
820 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
821 element_info[i].special_graphic[j] =
822 element_info[i].graphic[ACTION_DEFAULT];
826 static int get_element_from_token(char *token)
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831 if (strcmp(element_info[i].token_name, token) == 0)
837 static void set_graphic_parameters(int graphic, char **parameter_raw)
839 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
840 int parameter[NUM_GFX_ARGS];
841 int anim_frames_per_row = 1, anim_frames_per_col = 1;
842 int anim_frames_per_line = 1;
845 /* get integer values from string parameters */
846 for (i = 0; i < NUM_GFX_ARGS; i++)
849 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
850 image_config_suffix[i].type);
852 if (image_config_suffix[i].type == TYPE_TOKEN)
853 parameter[i] = get_element_from_token(parameter_raw[i]);
856 graphic_info[graphic].bitmap = src_bitmap;
858 /* start with reliable default values */
859 graphic_info[graphic].src_x = 0;
860 graphic_info[graphic].src_y = 0;
861 graphic_info[graphic].width = TILEX;
862 graphic_info[graphic].height = TILEY;
863 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
864 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
865 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
866 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
867 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
868 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
869 graphic_info[graphic].anim_delay_fixed = 0;
870 graphic_info[graphic].anim_delay_random = 0;
871 graphic_info[graphic].post_delay_fixed = 0;
872 graphic_info[graphic].post_delay_random = 0;
874 /* optional x and y tile position of animation frame sequence */
875 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
876 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
877 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
878 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
880 /* optional x and y pixel position of animation frame sequence */
881 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
882 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
883 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
884 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
886 /* optional width and height of each animation frame */
887 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
888 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
889 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
890 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
894 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
895 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
898 /* correct x or y offset dependent of vertical or horizontal frame order */
899 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
901 graphic_info[graphic].offset_y =
902 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
903 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
904 anim_frames_per_line = anim_frames_per_col;
906 else /* frames are ordered horizontally */
908 graphic_info[graphic].offset_x =
909 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
910 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
911 anim_frames_per_line = anim_frames_per_row;
914 /* optionally, the x and y offset of frames can be specified directly */
915 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
916 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
917 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
918 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
920 /* automatically determine correct number of frames, if not defined */
921 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
922 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
923 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
924 graphic_info[graphic].anim_frames = anim_frames_per_row;
925 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
926 graphic_info[graphic].anim_frames = anim_frames_per_col;
928 graphic_info[graphic].anim_frames = 1;
930 graphic_info[graphic].anim_frames_per_line =
931 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
932 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
934 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
935 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
936 graphic_info[graphic].anim_delay = 1;
938 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
940 if (graphic_info[graphic].anim_frames == 1)
941 graphic_info[graphic].anim_mode = ANIM_NONE;
944 /* automatically determine correct start frame, if not defined */
945 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].anim_start_frame = 0;
947 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
948 graphic_info[graphic].anim_start_frame =
949 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
951 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
953 /* animation synchronized with global frame counter, not move position */
954 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
956 /* optional element for cloning crumble graphics */
957 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
958 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
960 /* optional element for cloning digging graphics */
961 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
962 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
964 /* optional border size for "crumbling" diggable graphics */
965 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
966 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
968 /* optional zoom factor for scaling up the image to a larger size */
969 if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
971 if (graphic_info[graphic].scale_up_factor < 1)
972 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
974 /* this is only used for player "boring" and "sleeping" actions */
975 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
976 graphic_info[graphic].anim_delay_fixed =
977 parameter[GFX_ARG_ANIM_DELAY_FIXED];
978 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
979 graphic_info[graphic].anim_delay_random =
980 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
981 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].post_delay_fixed =
983 parameter[GFX_ARG_POST_DELAY_FIXED];
984 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
985 graphic_info[graphic].post_delay_random =
986 parameter[GFX_ARG_POST_DELAY_RANDOM];
988 /* this is only used for toon animations */
989 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
990 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
992 /* this is only used for drawing font characters */
993 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
994 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
996 /* this is only used for drawing envelope graphics */
997 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1000 static void InitGraphicInfo()
1002 int fallback_graphic = IMG_CHAR_EXCLAM;
1003 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1004 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1005 int num_images = getImageListSize();
1008 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1009 static boolean clipmasks_initialized = FALSE;
1011 XGCValues clip_gc_values;
1012 unsigned long clip_gc_valuemask;
1013 GC copy_clipmask_gc = None;
1016 checked_free(graphic_info);
1018 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1021 printf("::: graphic_info: %d entries\n", num_images);
1024 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1025 if (clipmasks_initialized)
1027 for (i = 0; i < num_images; i++)
1029 if (graphic_info[i].clip_mask)
1030 XFreePixmap(display, graphic_info[i].clip_mask);
1031 if (graphic_info[i].clip_gc)
1032 XFreeGC(display, graphic_info[i].clip_gc);
1034 graphic_info[i].clip_mask = None;
1035 graphic_info[i].clip_gc = None;
1040 for (i = 0; i < num_images; i++)
1042 struct FileInfo *image = getImageListEntry(i);
1045 int first_frame, last_frame;
1048 printf("::: image: '%s' [%d]\n", image->token, i);
1052 printf("::: image # %d: '%s' ['%s']\n",
1054 getTokenFromImageID(i));
1057 set_graphic_parameters(i, image->parameter);
1059 /* now check if no animation frames are outside of the loaded image */
1061 if (graphic_info[i].bitmap == NULL)
1062 continue; /* skip check for optional images that are undefined */
1065 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1066 if (src_x < 0 || src_y < 0 ||
1067 src_x + TILEX > src_bitmap->width ||
1068 src_y + TILEY > src_bitmap->height)
1070 Error(ERR_RETURN_LINE, "-");
1071 Error(ERR_RETURN, "warning: error found in config file:");
1072 Error(ERR_RETURN, "- config file: '%s'",
1073 getImageConfigFilename());
1074 Error(ERR_RETURN, "- config token: '%s'",
1075 getTokenFromImageID(i));
1076 Error(ERR_RETURN, "- image file: '%s'",
1077 src_bitmap->source_filename);
1079 "error: first animation frame out of bounds (%d, %d)",
1081 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1083 if (i == fallback_graphic)
1084 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1086 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1087 Error(ERR_RETURN_LINE, "-");
1089 set_graphic_parameters(i, fallback_image->default_parameter);
1090 graphic_info[i].bitmap = fallback_bitmap;
1093 last_frame = graphic_info[i].anim_frames - 1;
1094 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1095 if (src_x < 0 || src_y < 0 ||
1096 src_x + TILEX > src_bitmap->width ||
1097 src_y + TILEY > src_bitmap->height)
1099 Error(ERR_RETURN_LINE, "-");
1100 Error(ERR_RETURN, "warning: error found in config file:");
1101 Error(ERR_RETURN, "- config file: '%s'",
1102 getImageConfigFilename());
1103 Error(ERR_RETURN, "- config token: '%s'",
1104 getTokenFromImageID(i));
1105 Error(ERR_RETURN, "- image file: '%s'",
1106 src_bitmap->source_filename);
1108 "error: last animation frame (%d) out of bounds (%d, %d)",
1109 last_frame, src_x, src_y);
1110 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1112 if (i == fallback_graphic)
1113 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1115 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1116 Error(ERR_RETURN_LINE, "-");
1118 set_graphic_parameters(i, fallback_image->default_parameter);
1119 graphic_info[i].bitmap = fallback_bitmap;
1122 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1123 /* currently we need only a tile clip mask from the first frame */
1124 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1126 if (copy_clipmask_gc == None)
1128 clip_gc_values.graphics_exposures = False;
1129 clip_gc_valuemask = GCGraphicsExposures;
1130 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1131 clip_gc_valuemask, &clip_gc_values);
1134 graphic_info[i].clip_mask =
1135 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1137 src_pixmap = src_bitmap->clip_mask;
1138 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1139 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1141 clip_gc_values.graphics_exposures = False;
1142 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1143 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1145 graphic_info[i].clip_gc =
1146 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1150 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1151 if (copy_clipmask_gc)
1152 XFreeGC(display, copy_clipmask_gc);
1154 clipmasks_initialized = TRUE;
1158 static void InitElementSoundInfo()
1160 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1161 int num_property_mappings = getSoundListPropertyMappingSize();
1164 /* set values to -1 to identify later as "uninitialized" values */
1165 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1166 for (act = 0; act < NUM_ACTIONS; act++)
1167 element_info[i].sound[act] = -1;
1169 /* initialize element/sound mapping from static configuration */
1170 for (i = 0; element_to_sound[i].element > -1; i++)
1172 int element = element_to_sound[i].element;
1173 int action = element_to_sound[i].action;
1174 int sound = element_to_sound[i].sound;
1175 boolean is_class = element_to_sound[i].is_class;
1178 action = ACTION_DEFAULT;
1181 element_info[element].sound[action] = sound;
1183 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1184 if (strcmp(element_info[j].class_name,
1185 element_info[element].class_name) == 0)
1186 element_info[j].sound[action] = sound;
1189 /* initialize element class/sound mapping from dynamic configuration */
1190 for (i = 0; i < num_property_mappings; i++)
1192 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1193 int action = property_mapping[i].ext1_index;
1194 int sound = property_mapping[i].artwork_index;
1196 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1200 action = ACTION_DEFAULT;
1202 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1203 if (strcmp(element_info[j].class_name,
1204 element_info[element_class].class_name) == 0)
1205 element_info[j].sound[action] = sound;
1208 /* initialize element/sound mapping from dynamic configuration */
1209 for (i = 0; i < num_property_mappings; i++)
1211 int element = property_mapping[i].base_index;
1212 int action = property_mapping[i].ext1_index;
1213 int sound = property_mapping[i].artwork_index;
1215 if (element >= MAX_NUM_ELEMENTS)
1219 action = ACTION_DEFAULT;
1221 element_info[element].sound[action] = sound;
1224 /* now set all '-1' values to element specific default values */
1225 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1227 for (act = 0; act < NUM_ACTIONS; act++)
1229 /* generic default action sound (defined by "[default]" directive) */
1230 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1232 /* look for special default action sound (classic game specific) */
1233 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1234 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1235 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1236 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1237 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1238 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1240 /* !!! there's no such thing as a "default action sound" !!! */
1242 /* look for element specific default sound (independent from action) */
1243 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1244 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1247 /* no sound for this specific action -- use default action sound */
1248 if (element_info[i].sound[act] == -1)
1249 element_info[i].sound[act] = default_action_sound;
1254 static void InitGameModeSoundInfo()
1258 /* set values to -1 to identify later as "uninitialized" values */
1259 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1262 /* initialize gamemode/sound mapping from static configuration */
1263 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1265 int gamemode = gamemode_to_sound[i].gamemode;
1266 int sound = gamemode_to_sound[i].sound;
1269 gamemode = GAME_MODE_DEFAULT;
1271 menu.sound[gamemode] = sound;
1274 /* now set all '-1' values to levelset specific default values */
1275 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1276 if (menu.sound[i] == -1)
1277 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1281 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1282 if (menu.sound[i] != -1)
1283 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1287 static void set_sound_parameters(int sound, char **parameter_raw)
1289 int parameter[NUM_SND_ARGS];
1292 /* get integer values from string parameters */
1293 for (i = 0; i < NUM_SND_ARGS; i++)
1295 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1296 sound_config_suffix[i].type);
1298 /* explicit loop mode setting in configuration overrides default value */
1299 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1300 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1303 static void InitSoundInfo()
1306 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1307 int num_property_mappings = getSoundListPropertyMappingSize();
1309 int *sound_effect_properties;
1310 int num_sounds = getSoundListSize();
1313 checked_free(sound_info);
1315 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1316 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1318 /* initialize sound effect for all elements to "no sound" */
1319 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1320 for (j = 0; j < NUM_ACTIONS; j++)
1321 element_info[i].sound[j] = SND_UNDEFINED;
1323 for (i = 0; i < num_sounds; i++)
1325 struct FileInfo *sound = getSoundListEntry(i);
1326 int len_effect_text = strlen(sound->token);
1328 sound_effect_properties[i] = ACTION_OTHER;
1329 sound_info[i].loop = FALSE; /* default: play sound only once */
1332 printf("::: sound %d: '%s'\n", i, sound->token);
1335 /* determine all loop sounds and identify certain sound classes */
1337 for (j = 0; element_action_info[j].suffix; j++)
1339 int len_action_text = strlen(element_action_info[j].suffix);
1341 if (len_action_text < len_effect_text &&
1342 strcmp(&sound->token[len_effect_text - len_action_text],
1343 element_action_info[j].suffix) == 0)
1345 sound_effect_properties[i] = element_action_info[j].value;
1346 sound_info[i].loop = element_action_info[j].is_loop_sound;
1353 if (strcmp(sound->token, "custom_42") == 0)
1354 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1357 /* associate elements and some selected sound actions */
1359 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1361 if (element_info[j].class_name)
1363 int len_class_text = strlen(element_info[j].class_name);
1365 if (len_class_text + 1 < len_effect_text &&
1366 strncmp(sound->token,
1367 element_info[j].class_name, len_class_text) == 0 &&
1368 sound->token[len_class_text] == '.')
1370 int sound_action_value = sound_effect_properties[i];
1372 element_info[j].sound[sound_action_value] = i;
1377 set_sound_parameters(i, sound->parameter);
1380 free(sound_effect_properties);
1383 /* !!! now handled in InitElementSoundInfo() !!! */
1384 /* initialize element/sound mapping from dynamic configuration */
1385 for (i = 0; i < num_property_mappings; i++)
1387 int element = property_mapping[i].base_index;
1388 int action = property_mapping[i].ext1_index;
1389 int sound = property_mapping[i].artwork_index;
1392 action = ACTION_DEFAULT;
1394 printf("::: %d: %d, %d, %d ['%s']\n",
1395 i, element, action, sound, element_info[element].token_name);
1397 element_info[element].sound[action] = sound;
1404 int element = EL_CUSTOM_11;
1407 while (element_action_info[j].suffix)
1409 printf("element %d, sound action '%s' == %d\n",
1410 element, element_action_info[j].suffix,
1411 element_info[element].sound[j]);
1416 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1422 int element = EL_SAND;
1423 int sound_action = ACTION_DIGGING;
1426 while (element_action_info[j].suffix)
1428 if (element_action_info[j].value == sound_action)
1429 printf("element %d, sound action '%s' == %d\n",
1430 element, element_action_info[j].suffix,
1431 element_info[element].sound[sound_action]);
1438 static void InitGameModeMusicInfo()
1440 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1441 int num_property_mappings = getMusicListPropertyMappingSize();
1442 int default_levelset_music = -1;
1445 /* set values to -1 to identify later as "uninitialized" values */
1446 for (i = 0; i < MAX_LEVELS; i++)
1447 levelset.music[i] = -1;
1448 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1451 /* initialize gamemode/music mapping from static configuration */
1452 for (i = 0; gamemode_to_music[i].music > -1; i++)
1454 int gamemode = gamemode_to_music[i].gamemode;
1455 int music = gamemode_to_music[i].music;
1458 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1462 gamemode = GAME_MODE_DEFAULT;
1464 menu.music[gamemode] = music;
1467 /* initialize gamemode/music mapping from dynamic configuration */
1468 for (i = 0; i < num_property_mappings; i++)
1470 int prefix = property_mapping[i].base_index;
1471 int gamemode = property_mapping[i].ext1_index;
1472 int level = property_mapping[i].ext2_index;
1473 int music = property_mapping[i].artwork_index;
1476 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1477 prefix, gamemode, level, music);
1480 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1484 gamemode = GAME_MODE_DEFAULT;
1486 /* level specific music only allowed for in-game music */
1487 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1488 gamemode = GAME_MODE_PLAYING;
1493 default_levelset_music = music;
1496 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1497 levelset.music[level] = music;
1498 if (gamemode != GAME_MODE_PLAYING)
1499 menu.music[gamemode] = music;
1502 /* now set all '-1' values to menu specific default values */
1503 /* (undefined values of "levelset.music[]" might stay at "-1" to
1504 allow dynamic selection of music files from music directory!) */
1505 for (i = 0; i < MAX_LEVELS; i++)
1506 if (levelset.music[i] == -1)
1507 levelset.music[i] = default_levelset_music;
1508 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1509 if (menu.music[i] == -1)
1510 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1514 for (i = 0; i < MAX_LEVELS; i++)
1515 if (levelset.music[i] != -1)
1516 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1517 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1518 if (menu.music[i] != -1)
1519 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1523 static void set_music_parameters(int music, char **parameter_raw)
1525 int parameter[NUM_MUS_ARGS];
1528 /* get integer values from string parameters */
1529 for (i = 0; i < NUM_MUS_ARGS; i++)
1531 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1532 music_config_suffix[i].type);
1534 /* explicit loop mode setting in configuration overrides default value */
1535 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1536 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1539 static void InitMusicInfo()
1541 int num_music = getMusicListSize();
1544 checked_free(music_info);
1546 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1548 for (i = 0; i < num_music; i++)
1550 struct FileInfo *music = getMusicListEntry(i);
1551 int len_music_text = strlen(music->token);
1553 music_info[i].loop = TRUE; /* default: play music in loop mode */
1555 /* determine all loop music */
1557 for (j = 0; music_prefix_info[j].prefix; j++)
1559 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1561 if (len_prefix_text < len_music_text &&
1562 strncmp(music->token,
1563 music_prefix_info[j].prefix, len_prefix_text) == 0)
1565 music_info[i].loop = music_prefix_info[j].is_loop_music;
1571 set_music_parameters(i, music->parameter);
1575 static void ReinitializeGraphics()
1577 InitGraphicInfo(); /* graphic properties mapping */
1578 InitElementGraphicInfo(); /* element game graphic mapping */
1579 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1581 InitElementSmallImages(); /* create editor and preview images */
1582 InitFontGraphicInfo(); /* initialize text drawing functions */
1584 SetMainBackgroundImage(IMG_BACKGROUND);
1585 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1591 static void ReinitializeSounds()
1593 InitSoundInfo(); /* sound properties mapping */
1594 InitElementSoundInfo(); /* element game sound mapping */
1595 InitGameModeSoundInfo(); /* game mode sound mapping */
1597 InitPlayLevelSound(); /* internal game sound settings */
1600 static void ReinitializeMusic()
1602 InitMusicInfo(); /* music properties mapping */
1603 InitGameModeMusicInfo(); /* game mode music mapping */
1606 static int get_special_property_bit(int element, int property_bit_nr)
1608 struct PropertyBitInfo
1614 static struct PropertyBitInfo pb_can_move_into_acid[] =
1616 /* the player may be able fall into acid when gravity is activated */
1621 { EL_SP_MURPHY, 0 },
1622 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1624 /* all element that can move may be able to also move into acid */
1627 { EL_BUG_RIGHT, 1 },
1630 { EL_SPACESHIP, 2 },
1631 { EL_SPACESHIP_LEFT, 2 },
1632 { EL_SPACESHIP_RIGHT, 2 },
1633 { EL_SPACESHIP_UP, 2 },
1634 { EL_SPACESHIP_DOWN, 2 },
1635 { EL_BD_BUTTERFLY, 3 },
1636 { EL_BD_BUTTERFLY_LEFT, 3 },
1637 { EL_BD_BUTTERFLY_RIGHT, 3 },
1638 { EL_BD_BUTTERFLY_UP, 3 },
1639 { EL_BD_BUTTERFLY_DOWN, 3 },
1640 { EL_BD_FIREFLY, 4 },
1641 { EL_BD_FIREFLY_LEFT, 4 },
1642 { EL_BD_FIREFLY_RIGHT, 4 },
1643 { EL_BD_FIREFLY_UP, 4 },
1644 { EL_BD_FIREFLY_DOWN, 4 },
1646 { EL_DARK_YAMYAM, 6 },
1649 { EL_PACMAN_LEFT, 8 },
1650 { EL_PACMAN_RIGHT, 8 },
1651 { EL_PACMAN_UP, 8 },
1652 { EL_PACMAN_DOWN, 8 },
1654 { EL_MOLE_LEFT, 9 },
1655 { EL_MOLE_RIGHT, 9 },
1657 { EL_MOLE_DOWN, 9 },
1661 { EL_SATELLITE, 13 },
1662 { EL_SP_SNIKSNAK, 14 },
1663 { EL_SP_ELECTRON, 15 },
1670 static struct PropertyBitInfo pb_dont_collide_with[] =
1672 { EL_SP_SNIKSNAK, 0 },
1673 { EL_SP_ELECTRON, 1 },
1681 struct PropertyBitInfo *pb_info;
1684 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1685 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1690 struct PropertyBitInfo *pb_info = NULL;
1693 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1694 if (pb_definition[i].bit_nr == property_bit_nr)
1695 pb_info = pb_definition[i].pb_info;
1697 if (pb_info == NULL)
1700 for (i = 0; pb_info[i].element != -1; i++)
1701 if (pb_info[i].element == element)
1702 return pb_info[i].bit_nr;
1708 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1709 boolean property_value)
1711 int bit_nr = get_special_property_bit(element, property_bit_nr);
1716 *bitfield |= (1 << bit_nr);
1718 *bitfield &= ~(1 << bit_nr);
1722 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1724 int bit_nr = get_special_property_bit(element, property_bit_nr);
1727 return ((*bitfield & (1 << bit_nr)) != 0);
1734 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1736 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1740 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1743 level->can_move_into_acid_bits |= (1 << bit_nr);
1747 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1749 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1752 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1758 void InitElementPropertiesStatic()
1760 static int ep_diggable[] =
1765 EL_SP_BUGGY_BASE_ACTIVATING,
1768 EL_INVISIBLE_SAND_ACTIVE,
1770 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1771 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1775 EL_SP_BUGGY_BASE_ACTIVE,
1780 static int ep_collectible_only[] =
1797 EL_DYNABOMB_INCREASE_NUMBER,
1798 EL_DYNABOMB_INCREASE_SIZE,
1799 EL_DYNABOMB_INCREASE_POWER,
1816 static int ep_dont_run_into[] =
1818 /* same elements as in 'ep_dont_touch' */
1824 /* same elements as in 'ep_dont_collide_with' */
1836 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1840 EL_SP_BUGGY_BASE_ACTIVE,
1845 static int ep_dont_collide_with[] =
1847 /* same elements as in 'ep_dont_touch' */
1863 static int ep_dont_touch[] =
1872 static int ep_indestructible[] =
1876 EL_ACID_POOL_TOPLEFT,
1877 EL_ACID_POOL_TOPRIGHT,
1878 EL_ACID_POOL_BOTTOMLEFT,
1879 EL_ACID_POOL_BOTTOM,
1880 EL_ACID_POOL_BOTTOMRIGHT,
1881 EL_SP_HARDWARE_GRAY,
1882 EL_SP_HARDWARE_GREEN,
1883 EL_SP_HARDWARE_BLUE,
1885 EL_SP_HARDWARE_YELLOW,
1886 EL_SP_HARDWARE_BASE_1,
1887 EL_SP_HARDWARE_BASE_2,
1888 EL_SP_HARDWARE_BASE_3,
1889 EL_SP_HARDWARE_BASE_4,
1890 EL_SP_HARDWARE_BASE_5,
1891 EL_SP_HARDWARE_BASE_6,
1892 EL_INVISIBLE_STEELWALL,
1893 EL_INVISIBLE_STEELWALL_ACTIVE,
1894 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1895 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1896 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1897 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1898 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1899 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1900 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1901 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1902 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1903 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1904 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1905 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1907 EL_LIGHT_SWITCH_ACTIVE,
1908 EL_SIGN_EXCLAMATION,
1909 EL_SIGN_RADIOACTIVITY,
1920 EL_STEELWALL_SLIPPERY,
1943 EL_SWITCHGATE_OPENING,
1944 EL_SWITCHGATE_CLOSED,
1945 EL_SWITCHGATE_CLOSING,
1947 EL_SWITCHGATE_SWITCH_UP,
1948 EL_SWITCHGATE_SWITCH_DOWN,
1951 EL_TIMEGATE_OPENING,
1953 EL_TIMEGATE_CLOSING,
1956 EL_TIMEGATE_SWITCH_ACTIVE,
1961 EL_TUBE_VERTICAL_LEFT,
1962 EL_TUBE_VERTICAL_RIGHT,
1963 EL_TUBE_HORIZONTAL_UP,
1964 EL_TUBE_HORIZONTAL_DOWN,
1972 static int ep_slippery[] =
1986 EL_ROBOT_WHEEL_ACTIVE,
1992 EL_ACID_POOL_TOPLEFT,
1993 EL_ACID_POOL_TOPRIGHT,
2003 EL_STEELWALL_SLIPPERY,
2009 static int ep_can_change[] =
2014 static int ep_can_move[] =
2016 /* same elements as in 'pb_can_move_into_acid' */
2037 static int ep_can_fall[] =
2052 EL_BD_MAGIC_WALL_FULL,
2065 static int ep_can_smash_player[] =
2090 static int ep_can_smash_enemies[] =
2098 static int ep_can_smash_everything[] =
2106 static int ep_explodes_by_fire[] =
2108 /* same elements as in 'ep_explodes_impact' */
2113 /* same elements as in 'ep_explodes_smashed' */
2122 EL_DYNABOMB_PLAYER_1_ACTIVE,
2123 EL_DYNABOMB_PLAYER_2_ACTIVE,
2124 EL_DYNABOMB_PLAYER_3_ACTIVE,
2125 EL_DYNABOMB_PLAYER_4_ACTIVE,
2126 EL_DYNABOMB_INCREASE_NUMBER,
2127 EL_DYNABOMB_INCREASE_SIZE,
2128 EL_DYNABOMB_INCREASE_POWER,
2129 EL_SP_DISK_RED_ACTIVE,
2142 static int ep_explodes_smashed[] =
2144 /* same elements as in 'ep_explodes_impact' */
2157 static int ep_explodes_impact[] =
2165 static int ep_walkable_over[] =
2169 EL_SOKOBAN_FIELD_EMPTY,
2187 static int ep_walkable_inside[] =
2192 EL_TUBE_VERTICAL_LEFT,
2193 EL_TUBE_VERTICAL_RIGHT,
2194 EL_TUBE_HORIZONTAL_UP,
2195 EL_TUBE_HORIZONTAL_DOWN,
2203 static int ep_walkable_under[] =
2208 static int ep_passable_over[] =
2223 static int ep_passable_inside[] =
2229 EL_SP_PORT_HORIZONTAL,
2230 EL_SP_PORT_VERTICAL,
2232 EL_SP_GRAVITY_PORT_LEFT,
2233 EL_SP_GRAVITY_PORT_RIGHT,
2234 EL_SP_GRAVITY_PORT_UP,
2235 EL_SP_GRAVITY_PORT_DOWN,
2236 EL_SP_GRAVITY_ON_PORT_LEFT,
2237 EL_SP_GRAVITY_ON_PORT_RIGHT,
2238 EL_SP_GRAVITY_ON_PORT_UP,
2239 EL_SP_GRAVITY_ON_PORT_DOWN,
2240 EL_SP_GRAVITY_OFF_PORT_LEFT,
2241 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2242 EL_SP_GRAVITY_OFF_PORT_UP,
2243 EL_SP_GRAVITY_OFF_PORT_DOWN,
2247 static int ep_passable_under[] =
2252 static int ep_droppable[] =
2257 static int ep_explodes_1x1_old[] =
2262 static int ep_pushable[] =
2274 EL_SOKOBAN_FIELD_FULL,
2281 static int ep_explodes_cross_old[] =
2286 static int ep_protected[] =
2288 /* same elements as in 'ep_walkable_inside' */
2292 EL_TUBE_VERTICAL_LEFT,
2293 EL_TUBE_VERTICAL_RIGHT,
2294 EL_TUBE_HORIZONTAL_UP,
2295 EL_TUBE_HORIZONTAL_DOWN,
2301 /* same elements as in 'ep_passable_over' */
2313 /* same elements as in 'ep_passable_inside' */
2318 EL_SP_PORT_HORIZONTAL,
2319 EL_SP_PORT_VERTICAL,
2321 EL_SP_GRAVITY_PORT_LEFT,
2322 EL_SP_GRAVITY_PORT_RIGHT,
2323 EL_SP_GRAVITY_PORT_UP,
2324 EL_SP_GRAVITY_PORT_DOWN,
2325 EL_SP_GRAVITY_ON_PORT_LEFT,
2326 EL_SP_GRAVITY_ON_PORT_RIGHT,
2327 EL_SP_GRAVITY_ON_PORT_UP,
2328 EL_SP_GRAVITY_ON_PORT_DOWN,
2329 EL_SP_GRAVITY_OFF_PORT_LEFT,
2330 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2331 EL_SP_GRAVITY_OFF_PORT_UP,
2332 EL_SP_GRAVITY_OFF_PORT_DOWN,
2336 static int ep_throwable[] =
2341 static int ep_can_explode[] =
2343 /* same elements as in 'ep_explodes_impact' */
2348 /* same elements as in 'ep_explodes_smashed' */
2354 /* elements that can explode by explosion or by dragonfire */
2357 EL_DYNABOMB_PLAYER_1_ACTIVE,
2358 EL_DYNABOMB_PLAYER_2_ACTIVE,
2359 EL_DYNABOMB_PLAYER_3_ACTIVE,
2360 EL_DYNABOMB_PLAYER_4_ACTIVE,
2361 EL_DYNABOMB_INCREASE_NUMBER,
2362 EL_DYNABOMB_INCREASE_SIZE,
2363 EL_DYNABOMB_INCREASE_POWER,
2364 EL_SP_DISK_RED_ACTIVE,
2372 /* elements that can explode only by explosion */
2377 static int ep_gravity_reachable[] =
2383 EL_INVISIBLE_SAND_ACTIVE,
2388 EL_SP_PORT_HORIZONTAL,
2389 EL_SP_PORT_VERTICAL,
2391 EL_SP_GRAVITY_PORT_LEFT,
2392 EL_SP_GRAVITY_PORT_RIGHT,
2393 EL_SP_GRAVITY_PORT_UP,
2394 EL_SP_GRAVITY_PORT_DOWN,
2395 EL_SP_GRAVITY_ON_PORT_LEFT,
2396 EL_SP_GRAVITY_ON_PORT_RIGHT,
2397 EL_SP_GRAVITY_ON_PORT_UP,
2398 EL_SP_GRAVITY_ON_PORT_DOWN,
2399 EL_SP_GRAVITY_OFF_PORT_LEFT,
2400 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2401 EL_SP_GRAVITY_OFF_PORT_UP,
2402 EL_SP_GRAVITY_OFF_PORT_DOWN,
2406 static int ep_player[] =
2413 EL_SOKOBAN_FIELD_PLAYER,
2418 static int ep_can_pass_magic_wall[] =
2431 static int ep_switchable[] =
2435 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2436 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2437 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2438 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2439 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2440 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2441 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2442 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2443 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2444 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2445 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2446 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2447 EL_SWITCHGATE_SWITCH_UP,
2448 EL_SWITCHGATE_SWITCH_DOWN,
2450 EL_LIGHT_SWITCH_ACTIVE,
2452 EL_BALLOON_SWITCH_LEFT,
2453 EL_BALLOON_SWITCH_RIGHT,
2454 EL_BALLOON_SWITCH_UP,
2455 EL_BALLOON_SWITCH_DOWN,
2456 EL_BALLOON_SWITCH_ANY,
2462 static int ep_bd_element[] =
2495 static int ep_sp_element[] =
2497 /* should always be valid */
2500 /* standard classic Supaplex elements */
2507 EL_SP_HARDWARE_GRAY,
2515 EL_SP_GRAVITY_PORT_RIGHT,
2516 EL_SP_GRAVITY_PORT_DOWN,
2517 EL_SP_GRAVITY_PORT_LEFT,
2518 EL_SP_GRAVITY_PORT_UP,
2523 EL_SP_PORT_VERTICAL,
2524 EL_SP_PORT_HORIZONTAL,
2530 EL_SP_HARDWARE_BASE_1,
2531 EL_SP_HARDWARE_GREEN,
2532 EL_SP_HARDWARE_BLUE,
2534 EL_SP_HARDWARE_YELLOW,
2535 EL_SP_HARDWARE_BASE_2,
2536 EL_SP_HARDWARE_BASE_3,
2537 EL_SP_HARDWARE_BASE_4,
2538 EL_SP_HARDWARE_BASE_5,
2539 EL_SP_HARDWARE_BASE_6,
2543 /* additional elements that appeared in newer Supaplex levels */
2546 /* additional gravity port elements (not switching, but setting gravity) */
2547 EL_SP_GRAVITY_ON_PORT_LEFT,
2548 EL_SP_GRAVITY_ON_PORT_RIGHT,
2549 EL_SP_GRAVITY_ON_PORT_UP,
2550 EL_SP_GRAVITY_ON_PORT_DOWN,
2551 EL_SP_GRAVITY_OFF_PORT_LEFT,
2552 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2553 EL_SP_GRAVITY_OFF_PORT_UP,
2554 EL_SP_GRAVITY_OFF_PORT_DOWN,
2556 /* more than one Murphy in a level results in an inactive clone */
2559 /* runtime Supaplex elements */
2560 EL_SP_DISK_RED_ACTIVE,
2561 EL_SP_TERMINAL_ACTIVE,
2562 EL_SP_BUGGY_BASE_ACTIVATING,
2563 EL_SP_BUGGY_BASE_ACTIVE,
2569 static int ep_sb_element[] =
2574 EL_SOKOBAN_FIELD_EMPTY,
2575 EL_SOKOBAN_FIELD_FULL,
2576 EL_SOKOBAN_FIELD_PLAYER,
2581 EL_INVISIBLE_STEELWALL,
2585 static int ep_gem[] =
2596 static int ep_food_dark_yamyam[] =
2623 static int ep_food_penguin[] =
2636 static int ep_food_pig[] =
2647 static int ep_historic_wall[] =
2672 EL_EXPANDABLE_WALL_HORIZONTAL,
2673 EL_EXPANDABLE_WALL_VERTICAL,
2674 EL_EXPANDABLE_WALL_ANY,
2675 EL_EXPANDABLE_WALL_GROWING,
2682 EL_SP_HARDWARE_GRAY,
2683 EL_SP_HARDWARE_GREEN,
2684 EL_SP_HARDWARE_BLUE,
2686 EL_SP_HARDWARE_YELLOW,
2687 EL_SP_HARDWARE_BASE_1,
2688 EL_SP_HARDWARE_BASE_2,
2689 EL_SP_HARDWARE_BASE_3,
2690 EL_SP_HARDWARE_BASE_4,
2691 EL_SP_HARDWARE_BASE_5,
2692 EL_SP_HARDWARE_BASE_6,
2694 EL_SP_TERMINAL_ACTIVE,
2697 EL_INVISIBLE_STEELWALL,
2698 EL_INVISIBLE_STEELWALL_ACTIVE,
2700 EL_INVISIBLE_WALL_ACTIVE,
2701 EL_STEELWALL_SLIPPERY,
2717 static int ep_historic_solid[] =
2721 EL_EXPANDABLE_WALL_HORIZONTAL,
2722 EL_EXPANDABLE_WALL_VERTICAL,
2723 EL_EXPANDABLE_WALL_ANY,
2736 EL_QUICKSAND_FILLING,
2737 EL_QUICKSAND_EMPTYING,
2739 EL_MAGIC_WALL_ACTIVE,
2740 EL_MAGIC_WALL_EMPTYING,
2741 EL_MAGIC_WALL_FILLING,
2745 EL_BD_MAGIC_WALL_ACTIVE,
2746 EL_BD_MAGIC_WALL_EMPTYING,
2747 EL_BD_MAGIC_WALL_FULL,
2748 EL_BD_MAGIC_WALL_FILLING,
2749 EL_BD_MAGIC_WALL_DEAD,
2758 EL_SP_TERMINAL_ACTIVE,
2762 EL_INVISIBLE_WALL_ACTIVE,
2763 EL_SWITCHGATE_SWITCH_UP,
2764 EL_SWITCHGATE_SWITCH_DOWN,
2766 EL_TIMEGATE_SWITCH_ACTIVE,
2778 /* the following elements are a direct copy of "indestructible" elements,
2779 except "EL_ACID", which is "indestructible", but not "solid"! */
2784 EL_ACID_POOL_TOPLEFT,
2785 EL_ACID_POOL_TOPRIGHT,
2786 EL_ACID_POOL_BOTTOMLEFT,
2787 EL_ACID_POOL_BOTTOM,
2788 EL_ACID_POOL_BOTTOMRIGHT,
2789 EL_SP_HARDWARE_GRAY,
2790 EL_SP_HARDWARE_GREEN,
2791 EL_SP_HARDWARE_BLUE,
2793 EL_SP_HARDWARE_YELLOW,
2794 EL_SP_HARDWARE_BASE_1,
2795 EL_SP_HARDWARE_BASE_2,
2796 EL_SP_HARDWARE_BASE_3,
2797 EL_SP_HARDWARE_BASE_4,
2798 EL_SP_HARDWARE_BASE_5,
2799 EL_SP_HARDWARE_BASE_6,
2800 EL_INVISIBLE_STEELWALL,
2801 EL_INVISIBLE_STEELWALL_ACTIVE,
2802 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2803 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2804 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2805 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2806 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2807 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2808 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2811 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2812 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2813 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2815 EL_LIGHT_SWITCH_ACTIVE,
2816 EL_SIGN_EXCLAMATION,
2817 EL_SIGN_RADIOACTIVITY,
2828 EL_STEELWALL_SLIPPERY,
2851 EL_SWITCHGATE_OPENING,
2852 EL_SWITCHGATE_CLOSED,
2853 EL_SWITCHGATE_CLOSING,
2855 EL_TIMEGATE_OPENING,
2857 EL_TIMEGATE_CLOSING,
2861 EL_TUBE_VERTICAL_LEFT,
2862 EL_TUBE_VERTICAL_RIGHT,
2863 EL_TUBE_HORIZONTAL_UP,
2864 EL_TUBE_HORIZONTAL_DOWN,
2872 static int ep_classic_enemy[] =
2888 static int ep_belt[] =
2890 EL_CONVEYOR_BELT_1_LEFT,
2891 EL_CONVEYOR_BELT_1_MIDDLE,
2892 EL_CONVEYOR_BELT_1_RIGHT,
2893 EL_CONVEYOR_BELT_2_LEFT,
2894 EL_CONVEYOR_BELT_2_MIDDLE,
2895 EL_CONVEYOR_BELT_2_RIGHT,
2896 EL_CONVEYOR_BELT_3_LEFT,
2897 EL_CONVEYOR_BELT_3_MIDDLE,
2898 EL_CONVEYOR_BELT_3_RIGHT,
2899 EL_CONVEYOR_BELT_4_LEFT,
2900 EL_CONVEYOR_BELT_4_MIDDLE,
2901 EL_CONVEYOR_BELT_4_RIGHT,
2905 static int ep_belt_active[] =
2907 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2908 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2909 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2910 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2911 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2912 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2913 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2914 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2915 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2916 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2917 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2918 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2922 static int ep_belt_switch[] =
2924 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2925 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2926 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2927 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2928 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2929 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2930 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2931 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2932 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2933 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2934 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2935 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2939 static int ep_tube[] =
2946 EL_TUBE_HORIZONTAL_UP,
2947 EL_TUBE_HORIZONTAL_DOWN,
2949 EL_TUBE_VERTICAL_LEFT,
2950 EL_TUBE_VERTICAL_RIGHT,
2955 static int ep_keygate[] =
2976 static int ep_amoeboid[] =
2986 static int ep_amoebalive[] =
2995 static int ep_has_content[] =
3005 static int ep_can_turn_each_move[] =
3007 /* !!! do something with this one !!! */
3011 static int ep_can_grow[] =
3023 static int ep_active_bomb[] =
3026 EL_DYNABOMB_PLAYER_1_ACTIVE,
3027 EL_DYNABOMB_PLAYER_2_ACTIVE,
3028 EL_DYNABOMB_PLAYER_3_ACTIVE,
3029 EL_DYNABOMB_PLAYER_4_ACTIVE,
3030 EL_SP_DISK_RED_ACTIVE,
3034 static int ep_inactive[] =
3071 EL_INVISIBLE_STEELWALL,
3079 EL_WALL_EMERALD_YELLOW,
3080 EL_DYNABOMB_INCREASE_NUMBER,
3081 EL_DYNABOMB_INCREASE_SIZE,
3082 EL_DYNABOMB_INCREASE_POWER,
3086 EL_SOKOBAN_FIELD_EMPTY,
3087 EL_SOKOBAN_FIELD_FULL,
3088 EL_WALL_EMERALD_RED,
3089 EL_WALL_EMERALD_PURPLE,
3090 EL_ACID_POOL_TOPLEFT,
3091 EL_ACID_POOL_TOPRIGHT,
3092 EL_ACID_POOL_BOTTOMLEFT,
3093 EL_ACID_POOL_BOTTOM,
3094 EL_ACID_POOL_BOTTOMRIGHT,
3098 EL_BD_MAGIC_WALL_DEAD,
3099 EL_AMOEBA_TO_DIAMOND,
3107 EL_SP_GRAVITY_PORT_RIGHT,
3108 EL_SP_GRAVITY_PORT_DOWN,
3109 EL_SP_GRAVITY_PORT_LEFT,
3110 EL_SP_GRAVITY_PORT_UP,
3111 EL_SP_PORT_HORIZONTAL,
3112 EL_SP_PORT_VERTICAL,
3123 EL_SP_HARDWARE_GRAY,
3124 EL_SP_HARDWARE_GREEN,
3125 EL_SP_HARDWARE_BLUE,
3127 EL_SP_HARDWARE_YELLOW,
3128 EL_SP_HARDWARE_BASE_1,
3129 EL_SP_HARDWARE_BASE_2,
3130 EL_SP_HARDWARE_BASE_3,
3131 EL_SP_HARDWARE_BASE_4,
3132 EL_SP_HARDWARE_BASE_5,
3133 EL_SP_HARDWARE_BASE_6,
3134 EL_SP_GRAVITY_ON_PORT_LEFT,
3135 EL_SP_GRAVITY_ON_PORT_RIGHT,
3136 EL_SP_GRAVITY_ON_PORT_UP,
3137 EL_SP_GRAVITY_ON_PORT_DOWN,
3138 EL_SP_GRAVITY_OFF_PORT_LEFT,
3139 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3140 EL_SP_GRAVITY_OFF_PORT_UP,
3141 EL_SP_GRAVITY_OFF_PORT_DOWN,
3142 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3143 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3144 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3145 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3146 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3147 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3148 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3149 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3150 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3151 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3152 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3153 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3154 EL_SIGN_EXCLAMATION,
3155 EL_SIGN_RADIOACTIVITY,
3166 EL_STEELWALL_SLIPPERY,
3182 static int ep_em_slippery_wall[] =
3187 static int ep_gfx_crumbled[] =
3200 } element_properties[] =
3202 { ep_diggable, EP_DIGGABLE },
3203 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3204 { ep_dont_run_into, EP_DONT_RUN_INTO },
3205 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3206 { ep_dont_touch, EP_DONT_TOUCH },
3207 { ep_indestructible, EP_INDESTRUCTIBLE },
3208 { ep_slippery, EP_SLIPPERY },
3209 { ep_can_change, EP_CAN_CHANGE },
3210 { ep_can_move, EP_CAN_MOVE },
3211 { ep_can_fall, EP_CAN_FALL },
3212 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3213 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3214 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3215 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3216 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3217 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3218 { ep_walkable_over, EP_WALKABLE_OVER },
3219 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3220 { ep_walkable_under, EP_WALKABLE_UNDER },
3221 { ep_passable_over, EP_PASSABLE_OVER },
3222 { ep_passable_inside, EP_PASSABLE_INSIDE },
3223 { ep_passable_under, EP_PASSABLE_UNDER },
3224 { ep_droppable, EP_DROPPABLE },
3225 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3226 { ep_pushable, EP_PUSHABLE },
3227 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3228 { ep_protected, EP_PROTECTED },
3229 { ep_throwable, EP_THROWABLE },
3230 { ep_can_explode, EP_CAN_EXPLODE },
3231 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3233 { ep_player, EP_PLAYER },
3234 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3235 { ep_switchable, EP_SWITCHABLE },
3236 { ep_bd_element, EP_BD_ELEMENT },
3237 { ep_sp_element, EP_SP_ELEMENT },
3238 { ep_sb_element, EP_SB_ELEMENT },
3240 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3241 { ep_food_penguin, EP_FOOD_PENGUIN },
3242 { ep_food_pig, EP_FOOD_PIG },
3243 { ep_historic_wall, EP_HISTORIC_WALL },
3244 { ep_historic_solid, EP_HISTORIC_SOLID },
3245 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3246 { ep_belt, EP_BELT },
3247 { ep_belt_active, EP_BELT_ACTIVE },
3248 { ep_belt_switch, EP_BELT_SWITCH },
3249 { ep_tube, EP_TUBE },
3250 { ep_keygate, EP_KEYGATE },
3251 { ep_amoeboid, EP_AMOEBOID },
3252 { ep_amoebalive, EP_AMOEBALIVE },
3253 { ep_has_content, EP_HAS_CONTENT },
3254 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3255 { ep_can_grow, EP_CAN_GROW },
3256 { ep_active_bomb, EP_ACTIVE_BOMB },
3257 { ep_inactive, EP_INACTIVE },
3259 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3261 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3266 static int copy_properties[][5] =
3270 EL_BUG_LEFT, EL_BUG_RIGHT,
3271 EL_BUG_UP, EL_BUG_DOWN
3275 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3276 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3280 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3281 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3285 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3286 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3290 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3291 EL_PACMAN_UP, EL_PACMAN_DOWN
3295 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3296 EL_MOLE_UP, EL_MOLE_DOWN
3306 /* always start with reliable default values (element has no properties) */
3307 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3308 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3309 SET_PROPERTY(i, j, FALSE);
3311 /* set all base element properties from above array definitions */
3312 for (i = 0; element_properties[i].elements != NULL; i++)
3313 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3314 SET_PROPERTY((element_properties[i].elements)[j],
3315 element_properties[i].property, TRUE);
3317 /* copy properties to some elements that are only stored in level file */
3318 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3319 for (j = 0; copy_properties[j][0] != -1; j++)
3320 if (HAS_PROPERTY(copy_properties[j][0], i))
3321 for (k = 1; k <= 4; k++)
3322 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3325 void InitElementPropertiesEngine(int engine_version)
3328 static int active_properties[] =
3333 EP_DONT_COLLIDE_WITH,
3337 EP_CAN_PASS_MAGIC_WALL,
3342 EP_EXPLODES_BY_FIRE,
3355 EP_EM_SLIPPERY_WALL,
3359 static int no_wall_properties[] =
3362 EP_COLLECTIBLE_ONLY,
3364 EP_DONT_COLLIDE_WITH,
3367 EP_CAN_SMASH_PLAYER,
3368 EP_CAN_SMASH_ENEMIES,
3369 EP_CAN_SMASH_EVERYTHING,
3374 EP_FOOD_DARK_YAMYAM,
3391 InitElementPropertiesStatic();
3394 /* important: after initialization in InitElementPropertiesStatic(), the
3395 elements are not again initialized to a default value; therefore all
3396 changes have to make sure that they leave the element with a defined
3397 property (which means that conditional property changes must be set to
3398 a reliable default value before) */
3400 /* set all special, combined or engine dependent element properties */
3401 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3404 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3405 SET_PROPERTY(i, j, FALSE);
3408 /* ---------- INACTIVE ------------------------------------------------- */
3409 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3411 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3412 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3413 IS_WALKABLE_INSIDE(i) ||
3414 IS_WALKABLE_UNDER(i)));
3416 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3417 IS_PASSABLE_INSIDE(i) ||
3418 IS_PASSABLE_UNDER(i)));
3420 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3421 IS_PASSABLE_OVER(i)));
3423 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3424 IS_PASSABLE_INSIDE(i)));
3426 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3427 IS_PASSABLE_UNDER(i)));
3429 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3432 /* ---------- COLLECTIBLE ---------------------------------------------- */
3433 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3437 /* ---------- SNAPPABLE ------------------------------------------------ */
3438 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3439 IS_COLLECTIBLE(i) ||
3443 /* ---------- WALL ----------------------------------------------------- */
3444 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3446 for (j = 0; no_wall_properties[j] != -1; j++)
3447 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3448 i >= EL_FIRST_RUNTIME_UNREAL)
3449 SET_PROPERTY(i, EP_WALL, FALSE);
3451 if (IS_HISTORIC_WALL(i))
3452 SET_PROPERTY(i, EP_WALL, TRUE);
3454 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3455 if (engine_version < VERSION_IDENT(2,2,0,0))
3456 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3458 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3460 !IS_COLLECTIBLE(i)));
3463 /* ---------- PROTECTED ------------------------------------------------ */
3464 if (IS_ACCESSIBLE_INSIDE(i))
3465 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3468 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3470 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3471 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3473 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3474 IS_INDESTRUCTIBLE(i)));
3476 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3478 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3479 else if (engine_version < VERSION_IDENT(2,2,0,0))
3480 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3483 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3488 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3489 !IS_WALKABLE_OVER(i) &&
3490 !IS_WALKABLE_UNDER(i)));
3492 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3497 if (IS_CUSTOM_ELEMENT(i))
3499 /* these are additional properties which are initially false when set */
3501 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3503 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3504 if (DONT_COLLIDE_WITH(i))
3505 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3507 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3508 if (CAN_SMASH_EVERYTHING(i))
3509 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3510 if (CAN_SMASH_ENEMIES(i))
3511 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3514 /* ---------- CAN_SMASH ------------------------------------------------ */
3515 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3516 CAN_SMASH_ENEMIES(i) ||
3517 CAN_SMASH_EVERYTHING(i)));
3520 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3521 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3522 CAN_EXPLODE_SMASHED(i) ||
3523 CAN_EXPLODE_IMPACT(i)));
3527 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3529 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3530 !CAN_EXPLODE_CROSS(i)));
3532 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3533 !CAN_EXPLODE_1X1(i) &&
3534 !CAN_EXPLODE_CROSS(i)));
3538 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3539 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3540 EXPLODES_BY_FIRE(i)));
3542 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3543 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3544 EXPLODES_SMASHED(i)));
3546 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3547 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3548 EXPLODES_IMPACT(i)));
3550 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3551 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3553 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3554 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3555 i == EL_BLACK_ORB));
3557 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3558 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3560 IS_CUSTOM_ELEMENT(i)));
3562 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3563 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3564 i == EL_SP_ELECTRON));
3566 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3567 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3568 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3569 getMoveIntoAcidProperty(&level, i));
3571 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3572 if (MAYBE_DONT_COLLIDE_WITH(i))
3573 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3574 getDontCollideWithProperty(&level, i));
3576 /* ---------- SP_PORT -------------------------------------------------- */
3577 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3578 IS_PASSABLE_INSIDE(i)));
3580 /* ---------- CAN_CHANGE ----------------------------------------------- */
3581 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3582 for (j = 0; j < element_info[i].num_change_pages; j++)
3583 if (element_info[i].change_page[j].can_change)
3584 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3586 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3587 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3588 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3592 /* determine inactive elements (used for engine main loop optimization) */
3593 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3595 boolean active = FALSE;
3597 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3599 if (HAS_PROPERTY(i, j))
3605 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3610 /* dynamically adjust element properties according to game engine version */
3612 static int ep_em_slippery_wall[] =
3617 EL_EXPANDABLE_WALL_HORIZONTAL,
3618 EL_EXPANDABLE_WALL_VERTICAL,
3619 EL_EXPANDABLE_WALL_ANY,
3623 /* special EM style gems behaviour */
3624 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3625 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3626 level.em_slippery_gems);
3628 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3629 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3630 (level.em_slippery_gems &&
3631 engine_version > VERSION_IDENT(2,0,1,0)));
3635 /* set default push delay values (corrected since version 3.0.7-1) */
3636 if (engine_version < VERSION_IDENT(3,0,7,1))
3638 game.default_push_delay_fixed = 2;
3639 game.default_push_delay_random = 8;
3643 game.default_push_delay_fixed = 8;
3644 game.default_push_delay_random = 8;
3647 /* set uninitialized push delay values of custom elements in older levels */
3648 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3650 int element = EL_CUSTOM_START + i;
3652 if (element_info[element].push_delay_fixed == -1)
3653 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3654 if (element_info[element].push_delay_random == -1)
3655 element_info[element].push_delay_random = game.default_push_delay_random;
3658 /* set some other uninitialized values of custom elements in older levels */
3659 if (engine_version < VERSION_IDENT(3,1,0,0))
3661 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3663 int element = EL_CUSTOM_START + i;
3665 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3667 element_info[element].explosion_delay = 17;
3668 element_info[element].ignition_delay = 8;
3673 /* set element properties that were handled incorrectly in older levels */
3674 if (engine_version < VERSION_IDENT(3,1,0,0))
3676 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3677 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3683 /* this is needed because some graphics depend on element properties */
3684 if (game_status == GAME_MODE_PLAYING)
3685 InitElementGraphicInfo();
3688 static void InitGlobal()
3692 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3694 element_info[i].token_name = element_name_info[i].token_name;
3695 element_info[i].class_name = element_name_info[i].class_name;
3696 element_info[i].editor_description=element_name_info[i].editor_description;
3699 global.autoplay_leveldir = NULL;
3700 global.convert_leveldir = NULL;
3702 global.frames_per_second = 0;
3703 global.fps_slowdown = FALSE;
3704 global.fps_slowdown_factor = 1;
3707 void Execute_Command(char *command)
3711 if (strcmp(command, "print graphicsinfo.conf") == 0)
3713 printf("# You can configure additional/alternative image files here.\n");
3714 printf("# (The entries below are default and therefore commented out.)\n");
3716 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3718 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3721 for (i = 0; image_config[i].token != NULL; i++)
3722 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3723 image_config[i].value));
3727 else if (strcmp(command, "print soundsinfo.conf") == 0)
3729 printf("# You can configure additional/alternative sound files here.\n");
3730 printf("# (The entries below are default and therefore commented out.)\n");
3732 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3734 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3737 for (i = 0; sound_config[i].token != NULL; i++)
3738 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3739 sound_config[i].value));
3743 else if (strcmp(command, "print musicinfo.conf") == 0)
3745 printf("# You can configure additional/alternative music files here.\n");
3746 printf("# (The entries below are default and therefore commented out.)\n");
3748 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3750 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3753 for (i = 0; music_config[i].token != NULL; i++)
3754 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3755 music_config[i].value));
3759 else if (strcmp(command, "print editorsetup.conf") == 0)
3761 printf("# You can configure your personal editor element list here.\n");
3762 printf("# (The entries below are default and therefore commented out.)\n");
3765 PrintEditorElementList();
3769 else if (strcmp(command, "print helpanim.conf") == 0)
3771 printf("# You can configure different element help animations here.\n");
3772 printf("# (The entries below are default and therefore commented out.)\n");
3775 for (i = 0; helpanim_config[i].token != NULL; i++)
3777 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3778 helpanim_config[i].value));
3780 if (strcmp(helpanim_config[i].token, "end") == 0)
3786 else if (strcmp(command, "print helptext.conf") == 0)
3788 printf("# You can configure different element help text here.\n");
3789 printf("# (The entries below are default and therefore commented out.)\n");
3792 for (i = 0; helptext_config[i].token != NULL; i++)
3793 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3794 helptext_config[i].value));
3798 else if (strncmp(command, "dump level ", 11) == 0)
3800 char *filename = &command[11];
3802 if (access(filename, F_OK) != 0)
3803 Error(ERR_EXIT, "cannot open file '%s'", filename);
3805 LoadLevelFromFilename(&level, filename);
3810 else if (strncmp(command, "dump tape ", 10) == 0)
3812 char *filename = &command[10];
3814 if (access(filename, F_OK) != 0)
3815 Error(ERR_EXIT, "cannot open file '%s'", filename);
3817 LoadTapeFromFilename(filename);
3822 else if (strncmp(command, "autoplay ", 9) == 0)
3824 char *str_copy = getStringCopy(&command[9]);
3825 char *str_ptr = strchr(str_copy, ' ');
3827 global.autoplay_leveldir = str_copy;
3828 global.autoplay_level_nr = -1;
3830 if (str_ptr != NULL)
3832 *str_ptr++ = '\0'; /* terminate leveldir string */
3833 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3836 else if (strncmp(command, "convert ", 8) == 0)
3838 char *str_copy = getStringCopy(&command[8]);
3839 char *str_ptr = strchr(str_copy, ' ');
3841 global.convert_leveldir = str_copy;
3842 global.convert_level_nr = -1;
3844 if (str_ptr != NULL)
3846 *str_ptr++ = '\0'; /* terminate leveldir string */
3847 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3852 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3856 static void InitSetup()
3858 LoadSetup(); /* global setup info */
3860 /* set some options from setup file */
3862 if (setup.options.verbose)
3863 options.verbose = TRUE;
3866 static void InitPlayerInfo()
3870 /* choose default local player */
3871 local_player = &stored_player[0];
3873 for (i = 0; i < MAX_PLAYERS; i++)
3874 stored_player[i].connected = FALSE;
3876 local_player->connected = TRUE;
3879 static void InitArtworkInfo()
3884 static char *get_string_in_brackets(char *string)
3886 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3888 sprintf(string_in_brackets, "[%s]", string);
3890 return string_in_brackets;
3893 static char *get_level_id_suffix(int id_nr)
3895 char *id_suffix = checked_malloc(1 + 3 + 1);
3897 if (id_nr < 0 || id_nr > 999)
3900 sprintf(id_suffix, ".%03d", id_nr);
3906 static char *get_element_class_token(int element)
3908 char *element_class_name = element_info[element].class_name;
3909 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3911 sprintf(element_class_token, "[%s]", element_class_name);
3913 return element_class_token;
3916 static char *get_action_class_token(int action)
3918 char *action_class_name = &element_action_info[action].suffix[1];
3919 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3921 sprintf(action_class_token, "[%s]", action_class_name);
3923 return action_class_token;
3927 static void InitArtworkConfig()
3929 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3930 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3931 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3932 static char *action_id_suffix[NUM_ACTIONS + 1];
3933 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3934 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3935 static char *level_id_suffix[MAX_LEVELS + 1];
3936 static char *dummy[1] = { NULL };
3937 static char *ignore_generic_tokens[] =
3943 static char **ignore_image_tokens;
3944 static char **ignore_sound_tokens;
3945 static char **ignore_music_tokens;
3946 int num_ignore_generic_tokens;
3947 int num_ignore_image_tokens;
3948 int num_ignore_sound_tokens;
3949 int num_ignore_music_tokens;
3952 /* dynamically determine list of generic tokens to be ignored */
3953 num_ignore_generic_tokens = 0;
3954 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3955 num_ignore_generic_tokens++;
3957 /* dynamically determine list of image tokens to be ignored */
3958 num_ignore_image_tokens = num_ignore_generic_tokens;
3959 for (i = 0; image_config_vars[i].token != NULL; i++)
3960 num_ignore_image_tokens++;
3961 ignore_image_tokens =
3962 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3963 for (i = 0; i < num_ignore_generic_tokens; i++)
3964 ignore_image_tokens[i] = ignore_generic_tokens[i];
3965 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3966 ignore_image_tokens[num_ignore_generic_tokens + i] =
3967 image_config_vars[i].token;
3968 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3970 /* dynamically determine list of sound tokens to be ignored */
3971 num_ignore_sound_tokens = num_ignore_generic_tokens;
3972 ignore_sound_tokens =
3973 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3974 for (i = 0; i < num_ignore_generic_tokens; i++)
3975 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3976 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3978 /* dynamically determine list of music tokens to be ignored */
3979 num_ignore_music_tokens = num_ignore_generic_tokens;
3980 ignore_music_tokens =
3981 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3982 for (i = 0; i < num_ignore_generic_tokens; i++)
3983 ignore_music_tokens[i] = ignore_generic_tokens[i];
3984 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3986 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3987 image_id_prefix[i] = element_info[i].token_name;
3988 for (i = 0; i < NUM_FONTS; i++)
3989 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3990 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3992 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3993 sound_id_prefix[i] = element_info[i].token_name;
3994 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3995 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3996 get_string_in_brackets(element_info[i].class_name);
3997 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3999 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4000 music_id_prefix[i] = music_prefix_info[i].prefix;
4001 music_id_prefix[MAX_LEVELS] = NULL;
4003 for (i = 0; i < NUM_ACTIONS; i++)
4004 action_id_suffix[i] = element_action_info[i].suffix;
4005 action_id_suffix[NUM_ACTIONS] = NULL;
4007 for (i = 0; i < NUM_DIRECTIONS; i++)
4008 direction_id_suffix[i] = element_direction_info[i].suffix;
4009 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4011 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4012 special_id_suffix[i] = special_suffix_info[i].suffix;
4013 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4015 for (i = 0; i < MAX_LEVELS; i++)
4016 level_id_suffix[i] = get_level_id_suffix(i);
4017 level_id_suffix[MAX_LEVELS] = NULL;
4019 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4020 image_id_prefix, action_id_suffix, direction_id_suffix,
4021 special_id_suffix, ignore_image_tokens);
4022 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4023 sound_id_prefix, action_id_suffix, dummy,
4024 special_id_suffix, ignore_sound_tokens);
4025 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4026 music_id_prefix, special_id_suffix, level_id_suffix,
4027 dummy, ignore_music_tokens);
4030 static void InitMixer()
4038 char *filename_font_initial = NULL;
4039 Bitmap *bitmap_font_initial = NULL;
4042 /* determine settings for initial font (for displaying startup messages) */
4043 for (i = 0; image_config[i].token != NULL; i++)
4045 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4047 char font_token[128];
4050 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4051 len_font_token = strlen(font_token);
4053 if (strcmp(image_config[i].token, font_token) == 0)
4054 filename_font_initial = image_config[i].value;
4055 else if (strlen(image_config[i].token) > len_font_token &&
4056 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4058 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4059 font_initial[j].src_x = atoi(image_config[i].value);
4060 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4061 font_initial[j].src_y = atoi(image_config[i].value);
4062 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4063 font_initial[j].width = atoi(image_config[i].value);
4064 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4065 font_initial[j].height = atoi(image_config[i].value);
4070 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4072 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4073 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4076 if (filename_font_initial == NULL) /* should not happen */
4077 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4079 /* create additional image buffers for double-buffering */
4080 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4081 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4083 /* initialize screen properties */
4084 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4085 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4087 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4088 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4089 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4091 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4093 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4094 font_initial[j].bitmap = bitmap_font_initial;
4096 InitFontGraphicInfo();
4098 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4099 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4101 DrawInitText("Loading graphics:", 120, FC_GREEN);
4103 InitTileClipmasks();
4106 void InitGfxBackground()
4110 drawto = backbuffer;
4111 fieldbuffer = bitmap_db_field;
4112 SetDrawtoField(DRAW_BACKBUFFER);
4114 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4115 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4116 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4117 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4119 for (x = 0; x < MAX_BUF_XSIZE; x++)
4120 for (y = 0; y < MAX_BUF_YSIZE; y++)
4123 redraw_mask = REDRAW_ALL;
4126 static void InitLevelInfo()
4128 LoadLevelInfo(); /* global level info */
4129 LoadLevelSetup_LastSeries(); /* last played series info */
4130 LoadLevelSetup_SeriesInfo(); /* last played level info */
4133 void InitLevelArtworkInfo()
4135 LoadLevelArtworkInfo();
4138 static void InitImages()
4141 setLevelArtworkDir(artwork.gfx_first);
4145 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4146 leveldir_current->identifier,
4147 artwork.gfx_current_identifier,
4148 artwork.gfx_current->identifier,
4149 leveldir_current->graphics_set,
4150 leveldir_current->graphics_path);
4153 ReloadCustomImages();
4155 LoadCustomElementDescriptions();
4156 LoadSpecialMenuDesignSettings();
4158 ReinitializeGraphics();
4161 static void InitSound(char *identifier)
4163 if (identifier == NULL)
4164 identifier = artwork.snd_current->identifier;
4167 /* set artwork path to send it to the sound server process */
4168 setLevelArtworkDir(artwork.snd_first);
4171 InitReloadCustomSounds(identifier);
4172 ReinitializeSounds();
4175 static void InitMusic(char *identifier)
4177 if (identifier == NULL)
4178 identifier = artwork.mus_current->identifier;
4181 /* set artwork path to send it to the sound server process */
4182 setLevelArtworkDir(artwork.mus_first);
4185 InitReloadCustomMusic(identifier);
4186 ReinitializeMusic();
4189 void InitNetworkServer()
4191 #if defined(NETWORK_AVALIABLE)
4195 if (!options.network)
4198 #if defined(NETWORK_AVALIABLE)
4199 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4201 if (!ConnectToServer(options.server_host, options.server_port))
4202 Error(ERR_EXIT, "cannot connect to network game server");
4204 SendToServer_PlayerName(setup.player_name);
4205 SendToServer_ProtocolVersion();
4208 SendToServer_NrWanted(nr_wanted);
4212 static char *getNewArtworkIdentifier(int type)
4214 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4215 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4216 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4217 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4218 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4219 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4220 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4221 char *leveldir_identifier = leveldir_current->identifier;
4223 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4224 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4226 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4228 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4229 char *artwork_current_identifier;
4230 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4232 /* leveldir_current may be invalid (level group, parent link) */
4233 if (!validLevelSeries(leveldir_current))
4236 /* 1st step: determine artwork set to be activated in descending order:
4237 --------------------------------------------------------------------
4238 1. setup artwork (when configured to override everything else)
4239 2. artwork set configured in "levelinfo.conf" of current level set
4240 (artwork in level directory will have priority when loading later)
4241 3. artwork in level directory (stored in artwork sub-directory)
4242 4. setup artwork (currently configured in setup menu) */
4244 if (setup_override_artwork)
4245 artwork_current_identifier = setup_artwork_set;
4246 else if (leveldir_artwork_set != NULL)
4247 artwork_current_identifier = leveldir_artwork_set;
4248 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4249 artwork_current_identifier = leveldir_identifier;
4251 artwork_current_identifier = setup_artwork_set;
4254 /* 2nd step: check if it is really needed to reload artwork set
4255 ------------------------------------------------------------ */
4258 if (type == ARTWORK_TYPE_GRAPHICS)
4259 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4260 artwork_new_identifier,
4261 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4262 artwork_current_identifier,
4263 leveldir_current->graphics_set,
4264 leveldir_current->identifier);
4267 /* ---------- reload if level set and also artwork set has changed ------- */
4268 if (leveldir_current_identifier[type] != leveldir_identifier &&
4269 (last_has_level_artwork_set[type] || has_level_artwork_set))
4270 artwork_new_identifier = artwork_current_identifier;
4272 leveldir_current_identifier[type] = leveldir_identifier;
4273 last_has_level_artwork_set[type] = has_level_artwork_set;
4276 if (type == ARTWORK_TYPE_GRAPHICS)
4277 printf("::: 1: '%s'\n", artwork_new_identifier);
4280 /* ---------- reload if "override artwork" setting has changed ----------- */
4281 if (last_override_level_artwork[type] != setup_override_artwork)
4282 artwork_new_identifier = artwork_current_identifier;
4284 last_override_level_artwork[type] = setup_override_artwork;
4287 if (type == ARTWORK_TYPE_GRAPHICS)
4288 printf("::: 2: '%s'\n", artwork_new_identifier);
4291 /* ---------- reload if current artwork identifier has changed ----------- */
4292 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4293 artwork_current_identifier) != 0)
4294 artwork_new_identifier = artwork_current_identifier;
4296 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4299 if (type == ARTWORK_TYPE_GRAPHICS)
4300 printf("::: 3: '%s'\n", artwork_new_identifier);
4303 /* ---------- do not reload directly after starting ---------------------- */
4304 if (!initialized[type])
4305 artwork_new_identifier = NULL;
4307 initialized[type] = TRUE;
4310 if (type == ARTWORK_TYPE_GRAPHICS)
4311 printf("::: 4: '%s'\n", artwork_new_identifier);
4315 if (type == ARTWORK_TYPE_GRAPHICS)
4316 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4317 artwork.gfx_current_identifier, artwork_current_identifier,
4318 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4319 artwork_new_identifier);
4322 return artwork_new_identifier;
4325 void ReloadCustomArtwork(int force_reload)
4327 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4328 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4329 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4330 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4331 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4332 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4333 boolean redraw_screen = FALSE;
4335 if (gfx_new_identifier != NULL || force_reload_gfx)
4338 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4339 artwork.gfx_current_identifier,
4341 artwork.gfx_current->identifier,
4342 leveldir_current->graphics_set);
4345 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4350 printf("... '%s'\n",
4351 leveldir_current->graphics_set);
4354 FreeTileClipmasks();
4355 InitTileClipmasks();
4357 redraw_screen = TRUE;
4360 if (snd_new_identifier != NULL || force_reload_snd)
4362 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4364 InitSound(snd_new_identifier);
4366 redraw_screen = TRUE;
4369 if (mus_new_identifier != NULL || force_reload_mus)
4371 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4373 InitMusic(mus_new_identifier);
4375 redraw_screen = TRUE;
4380 InitGfxBackground();
4382 /* force redraw of (open or closed) door graphics */
4383 SetDoorState(DOOR_OPEN_ALL);
4384 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4388 void KeyboardAutoRepeatOffUnlessAutoplay()
4390 if (global.autoplay_leveldir == NULL)
4391 KeyboardAutoRepeatOff();
4395 /* ========================================================================= */
4397 /* ========================================================================= */
4401 InitGlobal(); /* initialize some global variables */
4403 if (options.execute_command)
4404 Execute_Command(options.execute_command);
4406 if (options.serveronly)
4408 #if defined(PLATFORM_UNIX)
4409 NetworkServer(options.server_port, options.serveronly);
4411 Error(ERR_WARN, "networking only supported in Unix version");
4413 exit(0); /* never reached */
4419 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4420 InitArtworkConfig(); /* needed before forking sound child process */
4425 InitRND(NEW_RANDOMIZE);
4426 InitSimpleRND(NEW_RANDOMIZE);
4431 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4434 InitEventFilter(FilterMouseMotionEvents);
4436 InitElementPropertiesStatic();
4437 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4442 InitLevelArtworkInfo();
4444 InitImages(); /* needs to know current level directory */
4445 InitSound(NULL); /* needs to know current level directory */
4446 InitMusic(NULL); /* needs to know current level directory */
4448 InitGfxBackground();
4450 if (global.autoplay_leveldir)
4455 else if (global.convert_leveldir)
4461 game_status = GAME_MODE_MAIN;
4469 InitNetworkServer();
4472 void CloseAllAndExit(int exit_value)
4477 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4484 FreeTileClipmasks();
4486 #if defined(TARGET_SDL)
4487 if (network_server) /* terminate network server */
4488 SDL_KillThread(server_thread);
4491 CloseVideoDisplay();
4492 ClosePlatformDependentStuff();