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 void InitElementSmallImages()
244 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
245 int num_property_mappings = getImageListPropertyMappingSize();
248 /* initialize normal images from static configuration */
249 for (i = 0; element_to_graphic[i].element > -1; i++)
250 CreateImageWithSmallImages(element_to_graphic[i].graphic);
252 /* initialize special images from static configuration */
253 for (i = 0; element_to_special_graphic[i].element > -1; i++)
254 CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
256 /* initialize images from dynamic configuration */
257 for (i = 0; i < num_property_mappings; i++)
258 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
259 CreateImageWithSmallImages(property_mapping[i].artwork_index);
262 static int getFontBitmapID(int font_nr)
266 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
267 special = game_status;
268 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
269 special = GFX_SPECIAL_ARG_MAIN;
270 else if (game_status == GAME_MODE_PLAYING)
271 special = GFX_SPECIAL_ARG_DOOR;
274 return font_info[font_nr].special_bitmap_id[special];
279 void InitFontGraphicInfo()
281 static struct FontBitmapInfo *font_bitmap_info = NULL;
282 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
283 int num_property_mappings = getImageListPropertyMappingSize();
284 int num_font_bitmaps = NUM_FONTS;
287 if (graphic_info == NULL) /* still at startup phase */
289 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
294 /* ---------- initialize font graphic definitions ---------- */
296 /* always start with reliable default values (normal font graphics) */
298 for (i = 0; i < NUM_FONTS; i++)
299 font_info[i].graphic = IMG_FONT_INITIAL_1;
301 for (i = 0; i < NUM_FONTS; i++)
302 font_info[i].graphic = FONT_INITIAL_1;
305 /* initialize normal font/graphic mapping from static configuration */
306 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
308 int font_nr = font_to_graphic[i].font_nr;
309 int special = font_to_graphic[i].special;
310 int graphic = font_to_graphic[i].graphic;
315 font_info[font_nr].graphic = graphic;
318 /* always start with reliable default values (special font graphics) */
319 for (i = 0; i < NUM_FONTS; i++)
321 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
323 font_info[i].special_graphic[j] = font_info[i].graphic;
324 font_info[i].special_bitmap_id[j] = i;
328 /* initialize special font/graphic mapping from static configuration */
329 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
331 int font_nr = font_to_graphic[i].font_nr;
332 int special = font_to_graphic[i].special;
333 int graphic = font_to_graphic[i].graphic;
335 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
337 font_info[font_nr].special_graphic[special] = graphic;
338 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
343 /* initialize special element/graphic mapping from dynamic configuration */
344 for (i = 0; i < num_property_mappings; i++)
346 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
347 int special = property_mapping[i].ext3_index;
348 int graphic = property_mapping[i].artwork_index;
353 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
355 font_info[font_nr].special_graphic[special] = graphic;
356 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
361 /* ---------- initialize font bitmap array ---------- */
363 if (font_bitmap_info != NULL)
364 FreeFontInfo(font_bitmap_info);
367 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
369 /* ---------- initialize font bitmap definitions ---------- */
371 for (i = 0; i < NUM_FONTS; i++)
373 if (i < NUM_INITIAL_FONTS)
375 font_bitmap_info[i] = font_initial[i];
379 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
381 int font_bitmap_id = font_info[i].special_bitmap_id[j];
382 int graphic = font_info[i].special_graphic[j];
384 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
385 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
387 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
388 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
391 /* copy font relevant information from graphics information */
392 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
393 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
394 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
395 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
396 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
397 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
398 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
400 font_bitmap_info[font_bitmap_id].num_chars =
401 graphic_info[graphic].anim_frames;
402 font_bitmap_info[font_bitmap_id].num_chars_per_line =
403 graphic_info[graphic].anim_frames_per_line;
407 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
410 void InitElementGraphicInfo()
412 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
413 int num_property_mappings = getImageListPropertyMappingSize();
416 if (graphic_info == NULL) /* still at startup phase */
419 /* set values to -1 to identify later as "uninitialized" values */
420 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
422 for (act = 0; act < NUM_ACTIONS; act++)
424 element_info[i].graphic[act] = -1;
425 element_info[i].crumbled[act] = -1;
427 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
429 element_info[i].direction_graphic[act][dir] = -1;
430 element_info[i].direction_crumbled[act][dir] = -1;
435 /* initialize normal element/graphic mapping from static configuration */
436 for (i = 0; element_to_graphic[i].element > -1; i++)
438 int element = element_to_graphic[i].element;
439 int action = element_to_graphic[i].action;
440 int direction = element_to_graphic[i].direction;
441 boolean crumbled = element_to_graphic[i].crumbled;
442 int graphic = element_to_graphic[i].graphic;
443 int base_graphic = el2baseimg(element);
445 if (graphic_info[graphic].bitmap == NULL)
448 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
451 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
452 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
454 /* if the base graphic ("emerald", for example) has been redefined,
455 but not the action graphic ("emerald.falling", for example), do not
456 use an existing (in this case considered obsolete) action graphic
457 anymore, but use the automatically determined default graphic */
458 if (base_redefined && !act_dir_redefined)
463 action = ACTION_DEFAULT;
468 element_info[element].direction_crumbled[action][direction] = graphic;
470 element_info[element].crumbled[action] = graphic;
475 element_info[element].direction_graphic[action][direction] = graphic;
477 element_info[element].graphic[action] = graphic;
481 /* initialize normal element/graphic mapping from dynamic configuration */
482 for (i = 0; i < num_property_mappings; i++)
484 int element = property_mapping[i].base_index;
485 int action = property_mapping[i].ext1_index;
486 int direction = property_mapping[i].ext2_index;
487 int special = property_mapping[i].ext3_index;
488 int graphic = property_mapping[i].artwork_index;
489 boolean crumbled = FALSE;
491 if (special == GFX_SPECIAL_ARG_CRUMBLED)
497 if (graphic_info[graphic].bitmap == NULL)
500 if (element >= MAX_NUM_ELEMENTS || special != -1)
504 action = ACTION_DEFAULT;
509 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
510 element_info[element].direction_crumbled[action][dir] = -1;
513 element_info[element].direction_crumbled[action][direction] = graphic;
515 element_info[element].crumbled[action] = graphic;
520 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
521 element_info[element].direction_graphic[action][dir] = -1;
524 element_info[element].direction_graphic[action][direction] = graphic;
526 element_info[element].graphic[action] = graphic;
530 /* now copy all graphics that are defined to be cloned from other graphics */
531 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
533 int graphic = element_info[i].graphic[ACTION_DEFAULT];
534 int crumbled_like, diggable_like;
539 crumbled_like = graphic_info[graphic].crumbled_like;
540 diggable_like = graphic_info[graphic].diggable_like;
542 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
544 for (act = 0; act < NUM_ACTIONS; act++)
545 element_info[i].crumbled[act] =
546 element_info[crumbled_like].crumbled[act];
547 for (act = 0; act < NUM_ACTIONS; act++)
548 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
549 element_info[i].direction_crumbled[act][dir] =
550 element_info[crumbled_like].direction_crumbled[act][dir];
553 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
555 element_info[i].graphic[ACTION_DIGGING] =
556 element_info[diggable_like].graphic[ACTION_DIGGING];
557 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
558 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
559 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
564 /* set hardcoded definitions for some runtime elements without graphic */
565 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
569 /* now set all undefined/invalid graphics to -1 to set to default after it */
570 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
572 for (act = 0; act < NUM_ACTIONS; act++)
576 graphic = element_info[i].graphic[act];
577 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
578 element_info[i].graphic[act] = -1;
580 graphic = element_info[i].crumbled[act];
581 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
582 element_info[i].crumbled[act] = -1;
584 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
586 graphic = element_info[i].direction_graphic[act][dir];
587 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
588 element_info[i].direction_graphic[act][dir] = -1;
590 graphic = element_info[i].direction_crumbled[act][dir];
591 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
592 element_info[i].direction_crumbled[act][dir] = -1;
598 /* now set all '-1' values to element specific default values */
599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
602 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
603 int default_direction_graphic[NUM_DIRECTIONS];
604 int default_direction_crumbled[NUM_DIRECTIONS];
606 if (default_graphic == -1)
607 default_graphic = IMG_UNKNOWN;
608 if (default_crumbled == -1)
609 default_crumbled = IMG_EMPTY;
611 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
613 default_direction_graphic[dir] =
614 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
615 default_direction_crumbled[dir] =
616 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
618 if (default_direction_graphic[dir] == -1)
619 default_direction_graphic[dir] = default_graphic;
620 if (default_direction_crumbled[dir] == -1)
621 default_direction_crumbled[dir] = default_crumbled;
624 for (act = 0; act < NUM_ACTIONS; act++)
626 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
627 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
628 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
629 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
630 act == ACTION_TURNING_FROM_RIGHT ||
631 act == ACTION_TURNING_FROM_UP ||
632 act == ACTION_TURNING_FROM_DOWN);
634 /* generic default action graphic (defined by "[default]" directive) */
635 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
636 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
638 /* look for special default action graphic (classic game specific) */
639 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
640 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
641 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
642 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
643 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
644 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
646 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
647 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
648 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
649 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
650 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
651 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
654 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
655 /* !!! make this better !!! */
656 if (i == EL_EMPTY_SPACE)
658 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
659 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
663 if (default_action_graphic == -1)
664 default_action_graphic = default_graphic;
665 if (default_action_crumbled == -1)
666 default_action_crumbled = default_crumbled;
668 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
670 int default_action_direction_graphic = element_info[i].graphic[act];
671 int default_action_direction_crumbled = element_info[i].crumbled[act];
673 /* no graphic for current action -- use default direction graphic */
674 if (default_action_direction_graphic == -1)
675 default_action_direction_graphic =
676 (act_remove ? IMG_EMPTY :
678 element_info[i].direction_graphic[ACTION_TURNING][dir] :
679 default_direction_graphic[dir]);
680 if (default_action_direction_crumbled == -1)
681 default_action_direction_crumbled =
682 (act_remove ? IMG_EMPTY :
684 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
685 default_direction_crumbled[dir]);
687 if (element_info[i].direction_graphic[act][dir] == -1)
688 element_info[i].direction_graphic[act][dir] =
689 default_action_direction_graphic;
690 if (element_info[i].direction_crumbled[act][dir] == -1)
691 element_info[i].direction_crumbled[act][dir] =
692 default_action_direction_crumbled;
695 /* no graphic for this specific action -- use default action graphic */
696 if (element_info[i].graphic[act] == -1)
697 element_info[i].graphic[act] =
698 (act_remove ? IMG_EMPTY :
699 act_turning ? element_info[i].graphic[ACTION_TURNING] :
700 default_action_graphic);
701 if (element_info[i].crumbled[act] == -1)
702 element_info[i].crumbled[act] =
703 (act_remove ? IMG_EMPTY :
704 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
705 default_action_crumbled);
710 /* set animation mode to "none" for each graphic with only 1 frame */
711 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
713 for (act = 0; act < NUM_ACTIONS; act++)
715 int graphic = element_info[i].graphic[act];
716 int crumbled = element_info[i].crumbled[act];
718 if (graphic_info[graphic].anim_frames == 1)
719 graphic_info[graphic].anim_mode = ANIM_NONE;
720 if (graphic_info[crumbled].anim_frames == 1)
721 graphic_info[crumbled].anim_mode = ANIM_NONE;
723 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
725 graphic = element_info[i].direction_graphic[act][dir];
726 crumbled = element_info[i].direction_crumbled[act][dir];
728 if (graphic_info[graphic].anim_frames == 1)
729 graphic_info[graphic].anim_mode = ANIM_NONE;
730 if (graphic_info[crumbled].anim_frames == 1)
731 graphic_info[crumbled].anim_mode = ANIM_NONE;
741 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
742 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
744 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
745 element_info[i].token_name, i);
751 void InitElementSpecialGraphicInfo()
753 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
754 int num_property_mappings = getImageListPropertyMappingSize();
757 /* always start with reliable default values */
758 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
759 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
760 element_info[i].special_graphic[j] =
761 element_info[i].graphic[ACTION_DEFAULT];
763 /* initialize special element/graphic mapping from static configuration */
764 for (i = 0; element_to_special_graphic[i].element > -1; i++)
766 int element = element_to_special_graphic[i].element;
767 int special = element_to_special_graphic[i].special;
768 int graphic = element_to_special_graphic[i].graphic;
769 int base_graphic = el2baseimg(element);
770 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
771 boolean special_redefined = getImageListEntry(graphic)->redefined;
773 /* if the base graphic ("emerald", for example) has been redefined,
774 but not the special graphic ("emerald.EDITOR", for example), do not
775 use an existing (in this case considered obsolete) special graphic
776 anymore, but use the automatically created (down-scaled) graphic */
777 if (base_redefined && !special_redefined)
780 element_info[element].special_graphic[special] = graphic;
783 /* initialize special element/graphic mapping from dynamic configuration */
784 for (i = 0; i < num_property_mappings; i++)
786 int element = property_mapping[i].base_index;
787 int special = property_mapping[i].ext3_index;
788 int graphic = property_mapping[i].artwork_index;
790 if (element >= MAX_NUM_ELEMENTS)
793 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
794 element_info[element].special_graphic[special] = graphic;
798 /* now set all undefined/invalid graphics to default */
799 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
800 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
801 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
802 element_info[i].special_graphic[j] =
803 element_info[i].graphic[ACTION_DEFAULT];
807 static int get_element_from_token(char *token)
811 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
812 if (strcmp(element_info[i].token_name, token) == 0)
818 static void set_graphic_parameters(int graphic, char **parameter_raw)
820 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
821 int parameter[NUM_GFX_ARGS];
822 int anim_frames_per_row = 1, anim_frames_per_col = 1;
823 int anim_frames_per_line = 1;
826 /* get integer values from string parameters */
827 for (i = 0; i < NUM_GFX_ARGS; i++)
830 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
831 image_config_suffix[i].type);
833 if (image_config_suffix[i].type == TYPE_TOKEN)
834 parameter[i] = get_element_from_token(parameter_raw[i]);
837 graphic_info[graphic].bitmap = src_bitmap;
839 /* start with reliable default values */
840 graphic_info[graphic].src_x = 0;
841 graphic_info[graphic].src_y = 0;
842 graphic_info[graphic].width = TILEX;
843 graphic_info[graphic].height = TILEY;
844 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
845 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
846 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
847 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
848 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
849 graphic_info[graphic].anim_delay_fixed = 0;
850 graphic_info[graphic].anim_delay_random = 0;
851 graphic_info[graphic].post_delay_fixed = 0;
852 graphic_info[graphic].post_delay_random = 0;
854 /* optional x and y tile position of animation frame sequence */
855 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
856 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
857 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
858 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
860 /* optional x and y pixel position of animation frame sequence */
861 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
862 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
863 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
864 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
866 /* optional width and height of each animation frame */
867 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
868 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
869 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
870 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
874 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
875 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
878 /* correct x or y offset dependent of vertical or horizontal frame order */
879 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
881 graphic_info[graphic].offset_y =
882 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
883 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
884 anim_frames_per_line = anim_frames_per_col;
886 else /* frames are ordered horizontally */
888 graphic_info[graphic].offset_x =
889 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
890 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
891 anim_frames_per_line = anim_frames_per_row;
894 /* optionally, the x and y offset of frames can be specified directly */
895 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
896 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
897 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
898 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
900 /* automatically determine correct number of frames, if not defined */
901 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
902 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
903 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
904 graphic_info[graphic].anim_frames = anim_frames_per_row;
905 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
906 graphic_info[graphic].anim_frames = anim_frames_per_col;
908 graphic_info[graphic].anim_frames = 1;
910 graphic_info[graphic].anim_frames_per_line =
911 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
912 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
914 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
915 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
916 graphic_info[graphic].anim_delay = 1;
918 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
920 if (graphic_info[graphic].anim_frames == 1)
921 graphic_info[graphic].anim_mode = ANIM_NONE;
924 /* automatically determine correct start frame, if not defined */
925 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
926 graphic_info[graphic].anim_start_frame = 0;
927 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
928 graphic_info[graphic].anim_start_frame =
929 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
931 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
933 /* animation synchronized with global frame counter, not move position */
934 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
936 /* optional element for cloning crumble graphics */
937 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
938 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
940 /* optional element for cloning digging graphics */
941 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
942 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
944 /* optional border size for "crumbling" diggable graphics */
945 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
948 /* this is only used for player "boring" and "sleeping" actions */
949 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
950 graphic_info[graphic].anim_delay_fixed =
951 parameter[GFX_ARG_ANIM_DELAY_FIXED];
952 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
953 graphic_info[graphic].anim_delay_random =
954 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
955 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
956 graphic_info[graphic].post_delay_fixed =
957 parameter[GFX_ARG_POST_DELAY_FIXED];
958 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
959 graphic_info[graphic].post_delay_random =
960 parameter[GFX_ARG_POST_DELAY_RANDOM];
962 /* this is only used for toon animations */
963 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
964 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
966 /* this is only used for drawing font characters */
967 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
968 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
970 /* this is only used for drawing envelope graphics */
971 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
974 static void InitGraphicInfo()
976 int fallback_graphic = IMG_CHAR_EXCLAM;
977 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
978 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
979 int num_images = getImageListSize();
982 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
983 static boolean clipmasks_initialized = FALSE;
985 XGCValues clip_gc_values;
986 unsigned long clip_gc_valuemask;
987 GC copy_clipmask_gc = None;
990 checked_free(graphic_info);
992 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
995 printf("::: graphic_info: %d entries\n", num_images);
998 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
999 if (clipmasks_initialized)
1001 for (i = 0; i < num_images; i++)
1003 if (graphic_info[i].clip_mask)
1004 XFreePixmap(display, graphic_info[i].clip_mask);
1005 if (graphic_info[i].clip_gc)
1006 XFreeGC(display, graphic_info[i].clip_gc);
1008 graphic_info[i].clip_mask = None;
1009 graphic_info[i].clip_gc = None;
1014 for (i = 0; i < num_images; i++)
1016 struct FileInfo *image = getImageListEntry(i);
1019 int first_frame, last_frame;
1022 printf("::: image: '%s' [%d]\n", image->token, i);
1026 printf("::: image # %d: '%s' ['%s']\n",
1028 getTokenFromImageID(i));
1031 set_graphic_parameters(i, image->parameter);
1033 /* now check if no animation frames are outside of the loaded image */
1035 if (graphic_info[i].bitmap == NULL)
1036 continue; /* skip check for optional images that are undefined */
1039 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1040 if (src_x < 0 || src_y < 0 ||
1041 src_x + TILEX > src_bitmap->width ||
1042 src_y + TILEY > src_bitmap->height)
1044 Error(ERR_RETURN_LINE, "-");
1045 Error(ERR_RETURN, "warning: error found in config file:");
1046 Error(ERR_RETURN, "- config file: '%s'",
1047 getImageConfigFilename());
1048 Error(ERR_RETURN, "- config token: '%s'",
1049 getTokenFromImageID(i));
1050 Error(ERR_RETURN, "- image file: '%s'",
1051 src_bitmap->source_filename);
1053 "error: first animation frame out of bounds (%d, %d)",
1055 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1057 if (i == fallback_graphic)
1058 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1060 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1061 Error(ERR_RETURN_LINE, "-");
1063 set_graphic_parameters(i, fallback_image->default_parameter);
1064 graphic_info[i].bitmap = fallback_bitmap;
1067 last_frame = graphic_info[i].anim_frames - 1;
1068 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1069 if (src_x < 0 || src_y < 0 ||
1070 src_x + TILEX > src_bitmap->width ||
1071 src_y + TILEY > src_bitmap->height)
1073 Error(ERR_RETURN_LINE, "-");
1074 Error(ERR_RETURN, "warning: error found in config file:");
1075 Error(ERR_RETURN, "- config file: '%s'",
1076 getImageConfigFilename());
1077 Error(ERR_RETURN, "- config token: '%s'",
1078 getTokenFromImageID(i));
1079 Error(ERR_RETURN, "- image file: '%s'",
1080 src_bitmap->source_filename);
1082 "error: last animation frame (%d) out of bounds (%d, %d)",
1083 last_frame, src_x, src_y);
1084 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1086 if (i == fallback_graphic)
1087 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1089 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1090 Error(ERR_RETURN_LINE, "-");
1092 set_graphic_parameters(i, fallback_image->default_parameter);
1093 graphic_info[i].bitmap = fallback_bitmap;
1096 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1097 /* currently we need only a tile clip mask from the first frame */
1098 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1100 if (copy_clipmask_gc == None)
1102 clip_gc_values.graphics_exposures = False;
1103 clip_gc_valuemask = GCGraphicsExposures;
1104 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1105 clip_gc_valuemask, &clip_gc_values);
1108 graphic_info[i].clip_mask =
1109 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1111 src_pixmap = src_bitmap->clip_mask;
1112 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1113 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1115 clip_gc_values.graphics_exposures = False;
1116 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1117 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1119 graphic_info[i].clip_gc =
1120 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1124 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1125 if (copy_clipmask_gc)
1126 XFreeGC(display, copy_clipmask_gc);
1128 clipmasks_initialized = TRUE;
1132 static void InitElementSoundInfo()
1134 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1135 int num_property_mappings = getSoundListPropertyMappingSize();
1138 /* set values to -1 to identify later as "uninitialized" values */
1139 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1140 for (act = 0; act < NUM_ACTIONS; act++)
1141 element_info[i].sound[act] = -1;
1143 /* initialize element/sound mapping from static configuration */
1144 for (i = 0; element_to_sound[i].element > -1; i++)
1146 int element = element_to_sound[i].element;
1147 int action = element_to_sound[i].action;
1148 int sound = element_to_sound[i].sound;
1149 boolean is_class = element_to_sound[i].is_class;
1152 action = ACTION_DEFAULT;
1155 element_info[element].sound[action] = sound;
1157 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1158 if (strcmp(element_info[j].class_name,
1159 element_info[element].class_name) == 0)
1160 element_info[j].sound[action] = sound;
1163 /* initialize element class/sound mapping from dynamic configuration */
1164 for (i = 0; i < num_property_mappings; i++)
1166 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1167 int action = property_mapping[i].ext1_index;
1168 int sound = property_mapping[i].artwork_index;
1170 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1174 action = ACTION_DEFAULT;
1176 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1177 if (strcmp(element_info[j].class_name,
1178 element_info[element_class].class_name) == 0)
1179 element_info[j].sound[action] = sound;
1182 /* initialize element/sound mapping from dynamic configuration */
1183 for (i = 0; i < num_property_mappings; i++)
1185 int element = property_mapping[i].base_index;
1186 int action = property_mapping[i].ext1_index;
1187 int sound = property_mapping[i].artwork_index;
1189 if (element >= MAX_NUM_ELEMENTS)
1193 action = ACTION_DEFAULT;
1195 element_info[element].sound[action] = sound;
1198 /* now set all '-1' values to element specific default values */
1199 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1201 for (act = 0; act < NUM_ACTIONS; act++)
1203 /* generic default action sound (defined by "[default]" directive) */
1204 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1206 /* look for special default action sound (classic game specific) */
1207 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1208 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1209 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1210 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1211 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1212 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1214 /* !!! there's no such thing as a "default action sound" !!! */
1216 /* look for element specific default sound (independent from action) */
1217 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1218 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1221 /* no sound for this specific action -- use default action sound */
1222 if (element_info[i].sound[act] == -1)
1223 element_info[i].sound[act] = default_action_sound;
1228 static void InitGameModeSoundInfo()
1232 /* set values to -1 to identify later as "uninitialized" values */
1233 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1236 /* initialize gamemode/sound mapping from static configuration */
1237 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1239 int gamemode = gamemode_to_sound[i].gamemode;
1240 int sound = gamemode_to_sound[i].sound;
1243 gamemode = GAME_MODE_DEFAULT;
1245 menu.sound[gamemode] = sound;
1248 /* now set all '-1' values to levelset specific default values */
1249 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1250 if (menu.sound[i] == -1)
1251 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1255 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1256 if (menu.sound[i] != -1)
1257 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1261 static void set_sound_parameters(int sound, char **parameter_raw)
1263 int parameter[NUM_SND_ARGS];
1266 /* get integer values from string parameters */
1267 for (i = 0; i < NUM_SND_ARGS; i++)
1269 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1270 sound_config_suffix[i].type);
1272 /* explicit loop mode setting in configuration overrides default value */
1273 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1274 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1277 static void InitSoundInfo()
1280 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1281 int num_property_mappings = getSoundListPropertyMappingSize();
1283 int *sound_effect_properties;
1284 int num_sounds = getSoundListSize();
1287 checked_free(sound_info);
1289 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1290 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1292 /* initialize sound effect for all elements to "no sound" */
1293 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1294 for (j = 0; j < NUM_ACTIONS; j++)
1295 element_info[i].sound[j] = SND_UNDEFINED;
1297 for (i = 0; i < num_sounds; i++)
1299 struct FileInfo *sound = getSoundListEntry(i);
1300 int len_effect_text = strlen(sound->token);
1302 sound_effect_properties[i] = ACTION_OTHER;
1303 sound_info[i].loop = FALSE; /* default: play sound only once */
1306 printf("::: sound %d: '%s'\n", i, sound->token);
1309 /* determine all loop sounds and identify certain sound classes */
1311 for (j = 0; element_action_info[j].suffix; j++)
1313 int len_action_text = strlen(element_action_info[j].suffix);
1315 if (len_action_text < len_effect_text &&
1316 strcmp(&sound->token[len_effect_text - len_action_text],
1317 element_action_info[j].suffix) == 0)
1319 sound_effect_properties[i] = element_action_info[j].value;
1320 sound_info[i].loop = element_action_info[j].is_loop_sound;
1327 if (strcmp(sound->token, "custom_42") == 0)
1328 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1331 /* associate elements and some selected sound actions */
1333 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1335 if (element_info[j].class_name)
1337 int len_class_text = strlen(element_info[j].class_name);
1339 if (len_class_text + 1 < len_effect_text &&
1340 strncmp(sound->token,
1341 element_info[j].class_name, len_class_text) == 0 &&
1342 sound->token[len_class_text] == '.')
1344 int sound_action_value = sound_effect_properties[i];
1346 element_info[j].sound[sound_action_value] = i;
1351 set_sound_parameters(i, sound->parameter);
1354 free(sound_effect_properties);
1357 /* !!! now handled in InitElementSoundInfo() !!! */
1358 /* initialize element/sound mapping from dynamic configuration */
1359 for (i = 0; i < num_property_mappings; i++)
1361 int element = property_mapping[i].base_index;
1362 int action = property_mapping[i].ext1_index;
1363 int sound = property_mapping[i].artwork_index;
1366 action = ACTION_DEFAULT;
1368 printf("::: %d: %d, %d, %d ['%s']\n",
1369 i, element, action, sound, element_info[element].token_name);
1371 element_info[element].sound[action] = sound;
1378 int element = EL_CUSTOM_11;
1381 while (element_action_info[j].suffix)
1383 printf("element %d, sound action '%s' == %d\n",
1384 element, element_action_info[j].suffix,
1385 element_info[element].sound[j]);
1390 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1396 int element = EL_SAND;
1397 int sound_action = ACTION_DIGGING;
1400 while (element_action_info[j].suffix)
1402 if (element_action_info[j].value == sound_action)
1403 printf("element %d, sound action '%s' == %d\n",
1404 element, element_action_info[j].suffix,
1405 element_info[element].sound[sound_action]);
1412 static void InitGameModeMusicInfo()
1414 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1415 int num_property_mappings = getMusicListPropertyMappingSize();
1416 int default_levelset_music = -1;
1419 /* set values to -1 to identify later as "uninitialized" values */
1420 for (i = 0; i < MAX_LEVELS; i++)
1421 levelset.music[i] = -1;
1422 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1425 /* initialize gamemode/music mapping from static configuration */
1426 for (i = 0; gamemode_to_music[i].music > -1; i++)
1428 int gamemode = gamemode_to_music[i].gamemode;
1429 int music = gamemode_to_music[i].music;
1432 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1436 gamemode = GAME_MODE_DEFAULT;
1438 menu.music[gamemode] = music;
1441 /* initialize gamemode/music mapping from dynamic configuration */
1442 for (i = 0; i < num_property_mappings; i++)
1444 int prefix = property_mapping[i].base_index;
1445 int gamemode = property_mapping[i].ext1_index;
1446 int level = property_mapping[i].ext2_index;
1447 int music = property_mapping[i].artwork_index;
1450 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1451 prefix, gamemode, level, music);
1454 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1458 gamemode = GAME_MODE_DEFAULT;
1460 /* level specific music only allowed for in-game music */
1461 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1462 gamemode = GAME_MODE_PLAYING;
1467 default_levelset_music = music;
1470 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1471 levelset.music[level] = music;
1472 if (gamemode != GAME_MODE_PLAYING)
1473 menu.music[gamemode] = music;
1476 /* now set all '-1' values to menu specific default values */
1477 /* (undefined values of "levelset.music[]" might stay at "-1" to
1478 allow dynamic selection of music files from music directory!) */
1479 for (i = 0; i < MAX_LEVELS; i++)
1480 if (levelset.music[i] == -1)
1481 levelset.music[i] = default_levelset_music;
1482 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1483 if (menu.music[i] == -1)
1484 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1488 for (i = 0; i < MAX_LEVELS; i++)
1489 if (levelset.music[i] != -1)
1490 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1491 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1492 if (menu.music[i] != -1)
1493 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1497 static void set_music_parameters(int music, char **parameter_raw)
1499 int parameter[NUM_MUS_ARGS];
1502 /* get integer values from string parameters */
1503 for (i = 0; i < NUM_MUS_ARGS; i++)
1505 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1506 music_config_suffix[i].type);
1508 /* explicit loop mode setting in configuration overrides default value */
1509 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1510 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1513 static void InitMusicInfo()
1515 int num_music = getMusicListSize();
1518 checked_free(music_info);
1520 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1522 for (i = 0; i < num_music; i++)
1524 struct FileInfo *music = getMusicListEntry(i);
1525 int len_music_text = strlen(music->token);
1527 music_info[i].loop = TRUE; /* default: play music in loop mode */
1529 /* determine all loop music */
1531 for (j = 0; music_prefix_info[j].prefix; j++)
1533 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1535 if (len_prefix_text < len_music_text &&
1536 strncmp(music->token,
1537 music_prefix_info[j].prefix, len_prefix_text) == 0)
1539 music_info[i].loop = music_prefix_info[j].is_loop_music;
1545 set_music_parameters(i, music->parameter);
1549 static void ReinitializeGraphics()
1551 InitGraphicInfo(); /* graphic properties mapping */
1552 InitElementGraphicInfo(); /* element game graphic mapping */
1553 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1555 InitElementSmallImages(); /* create editor and preview images */
1556 InitFontGraphicInfo(); /* initialize text drawing functions */
1558 SetMainBackgroundImage(IMG_BACKGROUND);
1559 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1565 static void ReinitializeSounds()
1567 InitSoundInfo(); /* sound properties mapping */
1568 InitElementSoundInfo(); /* element game sound mapping */
1569 InitGameModeSoundInfo(); /* game mode sound mapping */
1571 InitPlayLevelSound(); /* internal game sound settings */
1574 static void ReinitializeMusic()
1576 InitMusicInfo(); /* music properties mapping */
1577 InitGameModeMusicInfo(); /* game mode music mapping */
1580 static int get_special_property_bit(int element, int property_bit_nr)
1582 struct PropertyBitInfo
1588 static struct PropertyBitInfo pb_can_move_into_acid[] =
1590 /* the player may be able fall into acid when gravity is activated */
1595 { EL_SP_MURPHY, 0 },
1596 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1598 /* all element that can move may be able to also move into acid */
1601 { EL_BUG_RIGHT, 1 },
1604 { EL_SPACESHIP, 2 },
1605 { EL_SPACESHIP_LEFT, 2 },
1606 { EL_SPACESHIP_RIGHT, 2 },
1607 { EL_SPACESHIP_UP, 2 },
1608 { EL_SPACESHIP_DOWN, 2 },
1609 { EL_BD_BUTTERFLY, 3 },
1610 { EL_BD_BUTTERFLY_LEFT, 3 },
1611 { EL_BD_BUTTERFLY_RIGHT, 3 },
1612 { EL_BD_BUTTERFLY_UP, 3 },
1613 { EL_BD_BUTTERFLY_DOWN, 3 },
1614 { EL_BD_FIREFLY, 4 },
1615 { EL_BD_FIREFLY_LEFT, 4 },
1616 { EL_BD_FIREFLY_RIGHT, 4 },
1617 { EL_BD_FIREFLY_UP, 4 },
1618 { EL_BD_FIREFLY_DOWN, 4 },
1620 { EL_DARK_YAMYAM, 6 },
1623 { EL_PACMAN_LEFT, 8 },
1624 { EL_PACMAN_RIGHT, 8 },
1625 { EL_PACMAN_UP, 8 },
1626 { EL_PACMAN_DOWN, 8 },
1628 { EL_MOLE_LEFT, 9 },
1629 { EL_MOLE_RIGHT, 9 },
1631 { EL_MOLE_DOWN, 9 },
1635 { EL_SATELLITE, 13 },
1636 { EL_SP_SNIKSNAK, 14 },
1637 { EL_SP_ELECTRON, 15 },
1644 static struct PropertyBitInfo pb_dont_collide_with[] =
1646 { EL_SP_SNIKSNAK, 0 },
1647 { EL_SP_ELECTRON, 1 },
1655 struct PropertyBitInfo *pb_info;
1658 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1659 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1664 struct PropertyBitInfo *pb_info = NULL;
1667 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1668 if (pb_definition[i].bit_nr == property_bit_nr)
1669 pb_info = pb_definition[i].pb_info;
1671 if (pb_info == NULL)
1674 for (i = 0; pb_info[i].element != -1; i++)
1675 if (pb_info[i].element == element)
1676 return pb_info[i].bit_nr;
1682 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1683 boolean property_value)
1685 int bit_nr = get_special_property_bit(element, property_bit_nr);
1690 *bitfield |= (1 << bit_nr);
1692 *bitfield &= ~(1 << bit_nr);
1696 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1698 int bit_nr = get_special_property_bit(element, property_bit_nr);
1701 return ((*bitfield & (1 << bit_nr)) != 0);
1708 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1710 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1714 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1717 level->can_move_into_acid_bits |= (1 << bit_nr);
1721 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1723 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1726 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1732 void InitElementPropertiesStatic()
1734 static int ep_diggable[] =
1739 EL_SP_BUGGY_BASE_ACTIVATING,
1742 EL_INVISIBLE_SAND_ACTIVE,
1744 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1745 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1749 EL_SP_BUGGY_BASE_ACTIVE,
1754 static int ep_collectible_only[] =
1771 EL_DYNABOMB_INCREASE_NUMBER,
1772 EL_DYNABOMB_INCREASE_SIZE,
1773 EL_DYNABOMB_INCREASE_POWER,
1790 static int ep_dont_run_into[] =
1792 /* same elements as in 'ep_dont_touch' */
1798 /* same elements as in 'ep_dont_collide_with' */
1810 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1814 EL_SP_BUGGY_BASE_ACTIVE,
1819 static int ep_dont_collide_with[] =
1821 /* same elements as in 'ep_dont_touch' */
1837 static int ep_dont_touch[] =
1846 static int ep_indestructible[] =
1850 EL_ACID_POOL_TOPLEFT,
1851 EL_ACID_POOL_TOPRIGHT,
1852 EL_ACID_POOL_BOTTOMLEFT,
1853 EL_ACID_POOL_BOTTOM,
1854 EL_ACID_POOL_BOTTOMRIGHT,
1855 EL_SP_HARDWARE_GRAY,
1856 EL_SP_HARDWARE_GREEN,
1857 EL_SP_HARDWARE_BLUE,
1859 EL_SP_HARDWARE_YELLOW,
1860 EL_SP_HARDWARE_BASE_1,
1861 EL_SP_HARDWARE_BASE_2,
1862 EL_SP_HARDWARE_BASE_3,
1863 EL_SP_HARDWARE_BASE_4,
1864 EL_SP_HARDWARE_BASE_5,
1865 EL_SP_HARDWARE_BASE_6,
1866 EL_INVISIBLE_STEELWALL,
1867 EL_INVISIBLE_STEELWALL_ACTIVE,
1868 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1869 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1870 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1871 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1872 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1873 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1874 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1875 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1876 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1877 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1878 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1879 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1881 EL_LIGHT_SWITCH_ACTIVE,
1882 EL_SIGN_EXCLAMATION,
1883 EL_SIGN_RADIOACTIVITY,
1894 EL_STEELWALL_SLIPPERY,
1917 EL_SWITCHGATE_OPENING,
1918 EL_SWITCHGATE_CLOSED,
1919 EL_SWITCHGATE_CLOSING,
1921 EL_SWITCHGATE_SWITCH_UP,
1922 EL_SWITCHGATE_SWITCH_DOWN,
1925 EL_TIMEGATE_OPENING,
1927 EL_TIMEGATE_CLOSING,
1930 EL_TIMEGATE_SWITCH_ACTIVE,
1935 EL_TUBE_VERTICAL_LEFT,
1936 EL_TUBE_VERTICAL_RIGHT,
1937 EL_TUBE_HORIZONTAL_UP,
1938 EL_TUBE_HORIZONTAL_DOWN,
1946 static int ep_slippery[] =
1960 EL_ROBOT_WHEEL_ACTIVE,
1966 EL_ACID_POOL_TOPLEFT,
1967 EL_ACID_POOL_TOPRIGHT,
1977 EL_STEELWALL_SLIPPERY,
1983 static int ep_can_change[] =
1988 static int ep_can_move[] =
1990 /* same elements as in 'pb_can_move_into_acid' */
2011 static int ep_can_fall[] =
2026 EL_BD_MAGIC_WALL_FULL,
2039 static int ep_can_smash_player[] =
2064 static int ep_can_smash_enemies[] =
2072 static int ep_can_smash_everything[] =
2080 static int ep_explodes_by_fire[] =
2082 /* same elements as in 'ep_explodes_impact' */
2087 /* same elements as in 'ep_explodes_smashed' */
2096 EL_DYNABOMB_PLAYER_1_ACTIVE,
2097 EL_DYNABOMB_PLAYER_2_ACTIVE,
2098 EL_DYNABOMB_PLAYER_3_ACTIVE,
2099 EL_DYNABOMB_PLAYER_4_ACTIVE,
2100 EL_DYNABOMB_INCREASE_NUMBER,
2101 EL_DYNABOMB_INCREASE_SIZE,
2102 EL_DYNABOMB_INCREASE_POWER,
2103 EL_SP_DISK_RED_ACTIVE,
2116 static int ep_explodes_smashed[] =
2118 /* same elements as in 'ep_explodes_impact' */
2131 static int ep_explodes_impact[] =
2139 static int ep_walkable_over[] =
2143 EL_SOKOBAN_FIELD_EMPTY,
2161 static int ep_walkable_inside[] =
2166 EL_TUBE_VERTICAL_LEFT,
2167 EL_TUBE_VERTICAL_RIGHT,
2168 EL_TUBE_HORIZONTAL_UP,
2169 EL_TUBE_HORIZONTAL_DOWN,
2177 static int ep_walkable_under[] =
2182 static int ep_passable_over[] =
2197 static int ep_passable_inside[] =
2203 EL_SP_PORT_HORIZONTAL,
2204 EL_SP_PORT_VERTICAL,
2206 EL_SP_GRAVITY_PORT_LEFT,
2207 EL_SP_GRAVITY_PORT_RIGHT,
2208 EL_SP_GRAVITY_PORT_UP,
2209 EL_SP_GRAVITY_PORT_DOWN,
2210 EL_SP_GRAVITY_ON_PORT_LEFT,
2211 EL_SP_GRAVITY_ON_PORT_RIGHT,
2212 EL_SP_GRAVITY_ON_PORT_UP,
2213 EL_SP_GRAVITY_ON_PORT_DOWN,
2214 EL_SP_GRAVITY_OFF_PORT_LEFT,
2215 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2216 EL_SP_GRAVITY_OFF_PORT_UP,
2217 EL_SP_GRAVITY_OFF_PORT_DOWN,
2221 static int ep_passable_under[] =
2226 static int ep_droppable[] =
2231 static int ep_explodes_1x1_old[] =
2236 static int ep_pushable[] =
2248 EL_SOKOBAN_FIELD_FULL,
2255 static int ep_explodes_cross_old[] =
2260 static int ep_protected[] =
2262 /* same elements as in 'ep_walkable_inside' */
2266 EL_TUBE_VERTICAL_LEFT,
2267 EL_TUBE_VERTICAL_RIGHT,
2268 EL_TUBE_HORIZONTAL_UP,
2269 EL_TUBE_HORIZONTAL_DOWN,
2275 /* same elements as in 'ep_passable_over' */
2287 /* same elements as in 'ep_passable_inside' */
2292 EL_SP_PORT_HORIZONTAL,
2293 EL_SP_PORT_VERTICAL,
2295 EL_SP_GRAVITY_PORT_LEFT,
2296 EL_SP_GRAVITY_PORT_RIGHT,
2297 EL_SP_GRAVITY_PORT_UP,
2298 EL_SP_GRAVITY_PORT_DOWN,
2299 EL_SP_GRAVITY_ON_PORT_LEFT,
2300 EL_SP_GRAVITY_ON_PORT_RIGHT,
2301 EL_SP_GRAVITY_ON_PORT_UP,
2302 EL_SP_GRAVITY_ON_PORT_DOWN,
2303 EL_SP_GRAVITY_OFF_PORT_LEFT,
2304 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2305 EL_SP_GRAVITY_OFF_PORT_UP,
2306 EL_SP_GRAVITY_OFF_PORT_DOWN,
2310 static int ep_throwable[] =
2315 static int ep_can_explode[] =
2317 /* same elements as in 'ep_explodes_impact' */
2322 /* same elements as in 'ep_explodes_smashed' */
2328 /* elements that can explode by explosion or by dragonfire */
2331 EL_DYNABOMB_PLAYER_1_ACTIVE,
2332 EL_DYNABOMB_PLAYER_2_ACTIVE,
2333 EL_DYNABOMB_PLAYER_3_ACTIVE,
2334 EL_DYNABOMB_PLAYER_4_ACTIVE,
2335 EL_DYNABOMB_INCREASE_NUMBER,
2336 EL_DYNABOMB_INCREASE_SIZE,
2337 EL_DYNABOMB_INCREASE_POWER,
2338 EL_SP_DISK_RED_ACTIVE,
2346 /* elements that can explode only by explosion */
2351 static int ep_gravity_reachable[] =
2357 EL_INVISIBLE_SAND_ACTIVE,
2362 EL_SP_PORT_HORIZONTAL,
2363 EL_SP_PORT_VERTICAL,
2365 EL_SP_GRAVITY_PORT_LEFT,
2366 EL_SP_GRAVITY_PORT_RIGHT,
2367 EL_SP_GRAVITY_PORT_UP,
2368 EL_SP_GRAVITY_PORT_DOWN,
2369 EL_SP_GRAVITY_ON_PORT_LEFT,
2370 EL_SP_GRAVITY_ON_PORT_RIGHT,
2371 EL_SP_GRAVITY_ON_PORT_UP,
2372 EL_SP_GRAVITY_ON_PORT_DOWN,
2373 EL_SP_GRAVITY_OFF_PORT_LEFT,
2374 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2375 EL_SP_GRAVITY_OFF_PORT_UP,
2376 EL_SP_GRAVITY_OFF_PORT_DOWN,
2380 static int ep_player[] =
2387 EL_SOKOBAN_FIELD_PLAYER,
2392 static int ep_can_pass_magic_wall[] =
2405 static int ep_switchable[] =
2409 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2410 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2411 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2412 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2413 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2414 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2415 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2416 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2417 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2418 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2419 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2420 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2421 EL_SWITCHGATE_SWITCH_UP,
2422 EL_SWITCHGATE_SWITCH_DOWN,
2424 EL_LIGHT_SWITCH_ACTIVE,
2426 EL_BALLOON_SWITCH_LEFT,
2427 EL_BALLOON_SWITCH_RIGHT,
2428 EL_BALLOON_SWITCH_UP,
2429 EL_BALLOON_SWITCH_DOWN,
2430 EL_BALLOON_SWITCH_ANY,
2436 static int ep_bd_element[] =
2469 static int ep_sp_element[] =
2471 /* should always be valid */
2474 /* standard classic Supaplex elements */
2481 EL_SP_HARDWARE_GRAY,
2489 EL_SP_GRAVITY_PORT_RIGHT,
2490 EL_SP_GRAVITY_PORT_DOWN,
2491 EL_SP_GRAVITY_PORT_LEFT,
2492 EL_SP_GRAVITY_PORT_UP,
2497 EL_SP_PORT_VERTICAL,
2498 EL_SP_PORT_HORIZONTAL,
2504 EL_SP_HARDWARE_BASE_1,
2505 EL_SP_HARDWARE_GREEN,
2506 EL_SP_HARDWARE_BLUE,
2508 EL_SP_HARDWARE_YELLOW,
2509 EL_SP_HARDWARE_BASE_2,
2510 EL_SP_HARDWARE_BASE_3,
2511 EL_SP_HARDWARE_BASE_4,
2512 EL_SP_HARDWARE_BASE_5,
2513 EL_SP_HARDWARE_BASE_6,
2517 /* additional elements that appeared in newer Supaplex levels */
2520 /* additional gravity port elements (not switching, but setting gravity) */
2521 EL_SP_GRAVITY_ON_PORT_LEFT,
2522 EL_SP_GRAVITY_ON_PORT_RIGHT,
2523 EL_SP_GRAVITY_ON_PORT_UP,
2524 EL_SP_GRAVITY_ON_PORT_DOWN,
2525 EL_SP_GRAVITY_OFF_PORT_LEFT,
2526 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2527 EL_SP_GRAVITY_OFF_PORT_UP,
2528 EL_SP_GRAVITY_OFF_PORT_DOWN,
2530 /* more than one Murphy in a level results in an inactive clone */
2533 /* runtime Supaplex elements */
2534 EL_SP_DISK_RED_ACTIVE,
2535 EL_SP_TERMINAL_ACTIVE,
2536 EL_SP_BUGGY_BASE_ACTIVATING,
2537 EL_SP_BUGGY_BASE_ACTIVE,
2543 static int ep_sb_element[] =
2548 EL_SOKOBAN_FIELD_EMPTY,
2549 EL_SOKOBAN_FIELD_FULL,
2550 EL_SOKOBAN_FIELD_PLAYER,
2555 EL_INVISIBLE_STEELWALL,
2559 static int ep_gem[] =
2570 static int ep_food_dark_yamyam[] =
2597 static int ep_food_penguin[] =
2610 static int ep_food_pig[] =
2621 static int ep_historic_wall[] =
2646 EL_EXPANDABLE_WALL_HORIZONTAL,
2647 EL_EXPANDABLE_WALL_VERTICAL,
2648 EL_EXPANDABLE_WALL_ANY,
2649 EL_EXPANDABLE_WALL_GROWING,
2656 EL_SP_HARDWARE_GRAY,
2657 EL_SP_HARDWARE_GREEN,
2658 EL_SP_HARDWARE_BLUE,
2660 EL_SP_HARDWARE_YELLOW,
2661 EL_SP_HARDWARE_BASE_1,
2662 EL_SP_HARDWARE_BASE_2,
2663 EL_SP_HARDWARE_BASE_3,
2664 EL_SP_HARDWARE_BASE_4,
2665 EL_SP_HARDWARE_BASE_5,
2666 EL_SP_HARDWARE_BASE_6,
2668 EL_SP_TERMINAL_ACTIVE,
2671 EL_INVISIBLE_STEELWALL,
2672 EL_INVISIBLE_STEELWALL_ACTIVE,
2674 EL_INVISIBLE_WALL_ACTIVE,
2675 EL_STEELWALL_SLIPPERY,
2691 static int ep_historic_solid[] =
2695 EL_EXPANDABLE_WALL_HORIZONTAL,
2696 EL_EXPANDABLE_WALL_VERTICAL,
2697 EL_EXPANDABLE_WALL_ANY,
2710 EL_QUICKSAND_FILLING,
2711 EL_QUICKSAND_EMPTYING,
2713 EL_MAGIC_WALL_ACTIVE,
2714 EL_MAGIC_WALL_EMPTYING,
2715 EL_MAGIC_WALL_FILLING,
2719 EL_BD_MAGIC_WALL_ACTIVE,
2720 EL_BD_MAGIC_WALL_EMPTYING,
2721 EL_BD_MAGIC_WALL_FULL,
2722 EL_BD_MAGIC_WALL_FILLING,
2723 EL_BD_MAGIC_WALL_DEAD,
2732 EL_SP_TERMINAL_ACTIVE,
2736 EL_INVISIBLE_WALL_ACTIVE,
2737 EL_SWITCHGATE_SWITCH_UP,
2738 EL_SWITCHGATE_SWITCH_DOWN,
2740 EL_TIMEGATE_SWITCH_ACTIVE,
2752 /* the following elements are a direct copy of "indestructible" elements,
2753 except "EL_ACID", which is "indestructible", but not "solid"! */
2758 EL_ACID_POOL_TOPLEFT,
2759 EL_ACID_POOL_TOPRIGHT,
2760 EL_ACID_POOL_BOTTOMLEFT,
2761 EL_ACID_POOL_BOTTOM,
2762 EL_ACID_POOL_BOTTOMRIGHT,
2763 EL_SP_HARDWARE_GRAY,
2764 EL_SP_HARDWARE_GREEN,
2765 EL_SP_HARDWARE_BLUE,
2767 EL_SP_HARDWARE_YELLOW,
2768 EL_SP_HARDWARE_BASE_1,
2769 EL_SP_HARDWARE_BASE_2,
2770 EL_SP_HARDWARE_BASE_3,
2771 EL_SP_HARDWARE_BASE_4,
2772 EL_SP_HARDWARE_BASE_5,
2773 EL_SP_HARDWARE_BASE_6,
2774 EL_INVISIBLE_STEELWALL,
2775 EL_INVISIBLE_STEELWALL_ACTIVE,
2776 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2777 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2778 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2779 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2780 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2781 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2782 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2783 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2784 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2785 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2786 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2787 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2789 EL_LIGHT_SWITCH_ACTIVE,
2790 EL_SIGN_EXCLAMATION,
2791 EL_SIGN_RADIOACTIVITY,
2802 EL_STEELWALL_SLIPPERY,
2825 EL_SWITCHGATE_OPENING,
2826 EL_SWITCHGATE_CLOSED,
2827 EL_SWITCHGATE_CLOSING,
2829 EL_TIMEGATE_OPENING,
2831 EL_TIMEGATE_CLOSING,
2835 EL_TUBE_VERTICAL_LEFT,
2836 EL_TUBE_VERTICAL_RIGHT,
2837 EL_TUBE_HORIZONTAL_UP,
2838 EL_TUBE_HORIZONTAL_DOWN,
2846 static int ep_classic_enemy[] =
2862 static int ep_belt[] =
2864 EL_CONVEYOR_BELT_1_LEFT,
2865 EL_CONVEYOR_BELT_1_MIDDLE,
2866 EL_CONVEYOR_BELT_1_RIGHT,
2867 EL_CONVEYOR_BELT_2_LEFT,
2868 EL_CONVEYOR_BELT_2_MIDDLE,
2869 EL_CONVEYOR_BELT_2_RIGHT,
2870 EL_CONVEYOR_BELT_3_LEFT,
2871 EL_CONVEYOR_BELT_3_MIDDLE,
2872 EL_CONVEYOR_BELT_3_RIGHT,
2873 EL_CONVEYOR_BELT_4_LEFT,
2874 EL_CONVEYOR_BELT_4_MIDDLE,
2875 EL_CONVEYOR_BELT_4_RIGHT,
2879 static int ep_belt_active[] =
2881 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2882 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2883 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2884 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2885 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2886 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2887 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2888 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2889 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2890 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2891 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2892 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2896 static int ep_belt_switch[] =
2898 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2899 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2900 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2901 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2902 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2903 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2904 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2905 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2906 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2907 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2908 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2909 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2913 static int ep_tube[] =
2920 EL_TUBE_HORIZONTAL_UP,
2921 EL_TUBE_HORIZONTAL_DOWN,
2923 EL_TUBE_VERTICAL_LEFT,
2924 EL_TUBE_VERTICAL_RIGHT,
2929 static int ep_keygate[] =
2950 static int ep_amoeboid[] =
2960 static int ep_amoebalive[] =
2969 static int ep_has_content[] =
2979 static int ep_can_turn_each_move[] =
2981 /* !!! do something with this one !!! */
2985 static int ep_can_grow[] =
2997 static int ep_active_bomb[] =
3000 EL_DYNABOMB_PLAYER_1_ACTIVE,
3001 EL_DYNABOMB_PLAYER_2_ACTIVE,
3002 EL_DYNABOMB_PLAYER_3_ACTIVE,
3003 EL_DYNABOMB_PLAYER_4_ACTIVE,
3004 EL_SP_DISK_RED_ACTIVE,
3008 static int ep_inactive[] =
3045 EL_INVISIBLE_STEELWALL,
3053 EL_WALL_EMERALD_YELLOW,
3054 EL_DYNABOMB_INCREASE_NUMBER,
3055 EL_DYNABOMB_INCREASE_SIZE,
3056 EL_DYNABOMB_INCREASE_POWER,
3060 EL_SOKOBAN_FIELD_EMPTY,
3061 EL_SOKOBAN_FIELD_FULL,
3062 EL_WALL_EMERALD_RED,
3063 EL_WALL_EMERALD_PURPLE,
3064 EL_ACID_POOL_TOPLEFT,
3065 EL_ACID_POOL_TOPRIGHT,
3066 EL_ACID_POOL_BOTTOMLEFT,
3067 EL_ACID_POOL_BOTTOM,
3068 EL_ACID_POOL_BOTTOMRIGHT,
3072 EL_BD_MAGIC_WALL_DEAD,
3073 EL_AMOEBA_TO_DIAMOND,
3081 EL_SP_GRAVITY_PORT_RIGHT,
3082 EL_SP_GRAVITY_PORT_DOWN,
3083 EL_SP_GRAVITY_PORT_LEFT,
3084 EL_SP_GRAVITY_PORT_UP,
3085 EL_SP_PORT_HORIZONTAL,
3086 EL_SP_PORT_VERTICAL,
3097 EL_SP_HARDWARE_GRAY,
3098 EL_SP_HARDWARE_GREEN,
3099 EL_SP_HARDWARE_BLUE,
3101 EL_SP_HARDWARE_YELLOW,
3102 EL_SP_HARDWARE_BASE_1,
3103 EL_SP_HARDWARE_BASE_2,
3104 EL_SP_HARDWARE_BASE_3,
3105 EL_SP_HARDWARE_BASE_4,
3106 EL_SP_HARDWARE_BASE_5,
3107 EL_SP_HARDWARE_BASE_6,
3108 EL_SP_GRAVITY_ON_PORT_LEFT,
3109 EL_SP_GRAVITY_ON_PORT_RIGHT,
3110 EL_SP_GRAVITY_ON_PORT_UP,
3111 EL_SP_GRAVITY_ON_PORT_DOWN,
3112 EL_SP_GRAVITY_OFF_PORT_LEFT,
3113 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3114 EL_SP_GRAVITY_OFF_PORT_UP,
3115 EL_SP_GRAVITY_OFF_PORT_DOWN,
3116 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3117 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3118 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3119 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3120 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3121 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3122 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3123 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3124 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3125 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3126 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3127 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3128 EL_SIGN_EXCLAMATION,
3129 EL_SIGN_RADIOACTIVITY,
3140 EL_STEELWALL_SLIPPERY,
3156 static int ep_em_slippery_wall[] =
3161 static int ep_gfx_crumbled[] =
3174 } element_properties[] =
3176 { ep_diggable, EP_DIGGABLE },
3177 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3178 { ep_dont_run_into, EP_DONT_RUN_INTO },
3179 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3180 { ep_dont_touch, EP_DONT_TOUCH },
3181 { ep_indestructible, EP_INDESTRUCTIBLE },
3182 { ep_slippery, EP_SLIPPERY },
3183 { ep_can_change, EP_CAN_CHANGE },
3184 { ep_can_move, EP_CAN_MOVE },
3185 { ep_can_fall, EP_CAN_FALL },
3186 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3187 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3188 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3189 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3190 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3191 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3192 { ep_walkable_over, EP_WALKABLE_OVER },
3193 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3194 { ep_walkable_under, EP_WALKABLE_UNDER },
3195 { ep_passable_over, EP_PASSABLE_OVER },
3196 { ep_passable_inside, EP_PASSABLE_INSIDE },
3197 { ep_passable_under, EP_PASSABLE_UNDER },
3198 { ep_droppable, EP_DROPPABLE },
3199 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3200 { ep_pushable, EP_PUSHABLE },
3201 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3202 { ep_protected, EP_PROTECTED },
3203 { ep_throwable, EP_THROWABLE },
3204 { ep_can_explode, EP_CAN_EXPLODE },
3205 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3207 { ep_player, EP_PLAYER },
3208 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3209 { ep_switchable, EP_SWITCHABLE },
3210 { ep_bd_element, EP_BD_ELEMENT },
3211 { ep_sp_element, EP_SP_ELEMENT },
3212 { ep_sb_element, EP_SB_ELEMENT },
3214 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3215 { ep_food_penguin, EP_FOOD_PENGUIN },
3216 { ep_food_pig, EP_FOOD_PIG },
3217 { ep_historic_wall, EP_HISTORIC_WALL },
3218 { ep_historic_solid, EP_HISTORIC_SOLID },
3219 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3220 { ep_belt, EP_BELT },
3221 { ep_belt_active, EP_BELT_ACTIVE },
3222 { ep_belt_switch, EP_BELT_SWITCH },
3223 { ep_tube, EP_TUBE },
3224 { ep_keygate, EP_KEYGATE },
3225 { ep_amoeboid, EP_AMOEBOID },
3226 { ep_amoebalive, EP_AMOEBALIVE },
3227 { ep_has_content, EP_HAS_CONTENT },
3228 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3229 { ep_can_grow, EP_CAN_GROW },
3230 { ep_active_bomb, EP_ACTIVE_BOMB },
3231 { ep_inactive, EP_INACTIVE },
3233 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3235 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3240 static int copy_properties[][5] =
3244 EL_BUG_LEFT, EL_BUG_RIGHT,
3245 EL_BUG_UP, EL_BUG_DOWN
3249 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3250 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3254 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3255 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3259 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3260 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3264 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3265 EL_PACMAN_UP, EL_PACMAN_DOWN
3269 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3270 EL_MOLE_UP, EL_MOLE_DOWN
3280 /* always start with reliable default values (element has no properties) */
3281 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3282 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3283 SET_PROPERTY(i, j, FALSE);
3285 /* set all base element properties from above array definitions */
3286 for (i = 0; element_properties[i].elements != NULL; i++)
3287 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3288 SET_PROPERTY((element_properties[i].elements)[j],
3289 element_properties[i].property, TRUE);
3291 /* copy properties to some elements that are only stored in level file */
3292 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3293 for (j = 0; copy_properties[j][0] != -1; j++)
3294 if (HAS_PROPERTY(copy_properties[j][0], i))
3295 for (k = 1; k <= 4; k++)
3296 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3299 void InitElementPropertiesEngine(int engine_version)
3302 static int active_properties[] =
3307 EP_DONT_COLLIDE_WITH,
3311 EP_CAN_PASS_MAGIC_WALL,
3316 EP_EXPLODES_BY_FIRE,
3329 EP_EM_SLIPPERY_WALL,
3333 static int no_wall_properties[] =
3336 EP_COLLECTIBLE_ONLY,
3338 EP_DONT_COLLIDE_WITH,
3341 EP_CAN_SMASH_PLAYER,
3342 EP_CAN_SMASH_ENEMIES,
3343 EP_CAN_SMASH_EVERYTHING,
3348 EP_FOOD_DARK_YAMYAM,
3365 InitElementPropertiesStatic();
3368 /* important: after initialization in InitElementPropertiesStatic(), the
3369 elements are not again initialized to a default value; therefore all
3370 changes have to make sure that they leave the element with a defined
3371 property (which means that conditional property changes must be set to
3372 a reliable default value before) */
3374 /* set all special, combined or engine dependent element properties */
3375 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3378 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3379 SET_PROPERTY(i, j, FALSE);
3382 /* ---------- INACTIVE ------------------------------------------------- */
3383 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3385 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3386 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3387 IS_WALKABLE_INSIDE(i) ||
3388 IS_WALKABLE_UNDER(i)));
3390 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3391 IS_PASSABLE_INSIDE(i) ||
3392 IS_PASSABLE_UNDER(i)));
3394 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3395 IS_PASSABLE_OVER(i)));
3397 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3398 IS_PASSABLE_INSIDE(i)));
3400 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3401 IS_PASSABLE_UNDER(i)));
3403 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3406 /* ---------- COLLECTIBLE ---------------------------------------------- */
3407 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3411 /* ---------- SNAPPABLE ------------------------------------------------ */
3412 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3413 IS_COLLECTIBLE(i) ||
3417 /* ---------- WALL ----------------------------------------------------- */
3418 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3420 for (j = 0; no_wall_properties[j] != -1; j++)
3421 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3422 i >= EL_FIRST_RUNTIME_UNREAL)
3423 SET_PROPERTY(i, EP_WALL, FALSE);
3425 if (IS_HISTORIC_WALL(i))
3426 SET_PROPERTY(i, EP_WALL, TRUE);
3428 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3429 if (engine_version < VERSION_IDENT(2,2,0,0))
3430 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3432 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3434 !IS_COLLECTIBLE(i)));
3437 /* ---------- PROTECTED ------------------------------------------------ */
3438 if (IS_ACCESSIBLE_INSIDE(i))
3439 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3442 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3444 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3445 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3447 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3448 IS_INDESTRUCTIBLE(i)));
3450 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3452 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3453 else if (engine_version < VERSION_IDENT(2,2,0,0))
3454 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3457 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3462 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3463 !IS_WALKABLE_OVER(i) &&
3464 !IS_WALKABLE_UNDER(i)));
3466 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3471 if (IS_CUSTOM_ELEMENT(i))
3473 /* these are additional properties which are initially false when set */
3475 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3477 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3478 if (DONT_COLLIDE_WITH(i))
3479 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3481 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3482 if (CAN_SMASH_EVERYTHING(i))
3483 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3484 if (CAN_SMASH_ENEMIES(i))
3485 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3488 /* ---------- CAN_SMASH ------------------------------------------------ */
3489 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3490 CAN_SMASH_ENEMIES(i) ||
3491 CAN_SMASH_EVERYTHING(i)));
3494 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3495 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3496 CAN_EXPLODE_SMASHED(i) ||
3497 CAN_EXPLODE_IMPACT(i)));
3501 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3503 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3504 !CAN_EXPLODE_CROSS(i)));
3506 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3507 !CAN_EXPLODE_1X1(i) &&
3508 !CAN_EXPLODE_CROSS(i)));
3512 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3513 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3514 EXPLODES_BY_FIRE(i)));
3516 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3517 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3518 EXPLODES_SMASHED(i)));
3520 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3521 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3522 EXPLODES_IMPACT(i)));
3524 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3525 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3527 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3528 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3529 i == EL_BLACK_ORB));
3531 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3532 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3534 IS_CUSTOM_ELEMENT(i)));
3536 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3537 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3538 i == EL_SP_ELECTRON));
3540 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3541 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3542 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3543 getMoveIntoAcidProperty(&level, i));
3545 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3546 if (MAYBE_DONT_COLLIDE_WITH(i))
3547 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3548 getDontCollideWithProperty(&level, i));
3550 /* ---------- SP_PORT -------------------------------------------------- */
3551 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3552 IS_PASSABLE_INSIDE(i)));
3554 /* ---------- CAN_CHANGE ----------------------------------------------- */
3555 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3556 for (j = 0; j < element_info[i].num_change_pages; j++)
3557 if (element_info[i].change_page[j].can_change)
3558 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3560 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3561 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3562 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3566 /* determine inactive elements (used for engine main loop optimization) */
3567 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3569 boolean active = FALSE;
3571 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3573 if (HAS_PROPERTY(i, j))
3579 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3584 /* dynamically adjust element properties according to game engine version */
3586 static int ep_em_slippery_wall[] =
3591 EL_EXPANDABLE_WALL_HORIZONTAL,
3592 EL_EXPANDABLE_WALL_VERTICAL,
3593 EL_EXPANDABLE_WALL_ANY,
3597 /* special EM style gems behaviour */
3598 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3599 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3600 level.em_slippery_gems);
3602 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3603 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3604 (level.em_slippery_gems &&
3605 engine_version > VERSION_IDENT(2,0,1,0)));
3609 /* set default push delay values (corrected since version 3.0.7-1) */
3610 if (engine_version < VERSION_IDENT(3,0,7,1))
3612 game.default_push_delay_fixed = 2;
3613 game.default_push_delay_random = 8;
3617 game.default_push_delay_fixed = 8;
3618 game.default_push_delay_random = 8;
3621 /* set uninitialized push delay values of custom elements in older levels */
3622 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3624 int element = EL_CUSTOM_START + i;
3626 if (element_info[element].push_delay_fixed == -1)
3627 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3628 if (element_info[element].push_delay_random == -1)
3629 element_info[element].push_delay_random = game.default_push_delay_random;
3632 /* set some other uninitialized values of custom elements in older levels */
3633 if (engine_version < VERSION_IDENT(3,1,0,0))
3635 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3637 int element = EL_CUSTOM_START + i;
3639 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3641 element_info[element].explosion_delay = 17;
3642 element_info[element].ignition_delay = 8;
3647 /* set element properties that were handled incorrectly in older levels */
3648 if (engine_version < VERSION_IDENT(3,1,0,0))
3650 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3651 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3657 /* this is needed because some graphics depend on element properties */
3658 if (game_status == GAME_MODE_PLAYING)
3659 InitElementGraphicInfo();
3662 static void InitGlobal()
3666 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3668 element_info[i].token_name = element_name_info[i].token_name;
3669 element_info[i].class_name = element_name_info[i].class_name;
3670 element_info[i].editor_description=element_name_info[i].editor_description;
3673 global.autoplay_leveldir = NULL;
3674 global.convert_leveldir = NULL;
3676 global.frames_per_second = 0;
3677 global.fps_slowdown = FALSE;
3678 global.fps_slowdown_factor = 1;
3681 void Execute_Command(char *command)
3685 if (strcmp(command, "print graphicsinfo.conf") == 0)
3687 printf("# You can configure additional/alternative image files here.\n");
3688 printf("# (The entries below are default and therefore commented out.)\n");
3690 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3692 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3695 for (i = 0; image_config[i].token != NULL; i++)
3696 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3697 image_config[i].value));
3701 else if (strcmp(command, "print soundsinfo.conf") == 0)
3703 printf("# You can configure additional/alternative sound files here.\n");
3704 printf("# (The entries below are default and therefore commented out.)\n");
3706 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3708 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3711 for (i = 0; sound_config[i].token != NULL; i++)
3712 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3713 sound_config[i].value));
3717 else if (strcmp(command, "print musicinfo.conf") == 0)
3719 printf("# You can configure additional/alternative music files here.\n");
3720 printf("# (The entries below are default and therefore commented out.)\n");
3722 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3724 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3727 for (i = 0; music_config[i].token != NULL; i++)
3728 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3729 music_config[i].value));
3733 else if (strcmp(command, "print editorsetup.conf") == 0)
3735 printf("# You can configure your personal editor element list here.\n");
3736 printf("# (The entries below are default and therefore commented out.)\n");
3739 PrintEditorElementList();
3743 else if (strcmp(command, "print helpanim.conf") == 0)
3745 printf("# You can configure different element help animations here.\n");
3746 printf("# (The entries below are default and therefore commented out.)\n");
3749 for (i = 0; helpanim_config[i].token != NULL; i++)
3751 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3752 helpanim_config[i].value));
3754 if (strcmp(helpanim_config[i].token, "end") == 0)
3760 else if (strcmp(command, "print helptext.conf") == 0)
3762 printf("# You can configure different element help text here.\n");
3763 printf("# (The entries below are default and therefore commented out.)\n");
3766 for (i = 0; helptext_config[i].token != NULL; i++)
3767 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3768 helptext_config[i].value));
3772 else if (strncmp(command, "dump level ", 11) == 0)
3774 char *filename = &command[11];
3776 if (access(filename, F_OK) != 0)
3777 Error(ERR_EXIT, "cannot open file '%s'", filename);
3779 LoadLevelFromFilename(&level, filename);
3784 else if (strncmp(command, "dump tape ", 10) == 0)
3786 char *filename = &command[10];
3788 if (access(filename, F_OK) != 0)
3789 Error(ERR_EXIT, "cannot open file '%s'", filename);
3791 LoadTapeFromFilename(filename);
3796 else if (strncmp(command, "autoplay ", 9) == 0)
3798 char *str_copy = getStringCopy(&command[9]);
3799 char *str_ptr = strchr(str_copy, ' ');
3801 global.autoplay_leveldir = str_copy;
3802 global.autoplay_level_nr = -1;
3804 if (str_ptr != NULL)
3806 *str_ptr++ = '\0'; /* terminate leveldir string */
3807 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3810 else if (strncmp(command, "convert ", 8) == 0)
3812 char *str_copy = getStringCopy(&command[8]);
3813 char *str_ptr = strchr(str_copy, ' ');
3815 global.convert_leveldir = str_copy;
3816 global.convert_level_nr = -1;
3818 if (str_ptr != NULL)
3820 *str_ptr++ = '\0'; /* terminate leveldir string */
3821 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3826 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3830 static void InitSetup()
3832 LoadSetup(); /* global setup info */
3834 /* set some options from setup file */
3836 if (setup.options.verbose)
3837 options.verbose = TRUE;
3840 static void InitPlayerInfo()
3844 /* choose default local player */
3845 local_player = &stored_player[0];
3847 for (i = 0; i < MAX_PLAYERS; i++)
3848 stored_player[i].connected = FALSE;
3850 local_player->connected = TRUE;
3853 static void InitArtworkInfo()
3858 static char *get_string_in_brackets(char *string)
3860 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3862 sprintf(string_in_brackets, "[%s]", string);
3864 return string_in_brackets;
3867 static char *get_level_id_suffix(int id_nr)
3869 char *id_suffix = checked_malloc(1 + 3 + 1);
3871 if (id_nr < 0 || id_nr > 999)
3874 sprintf(id_suffix, ".%03d", id_nr);
3880 static char *get_element_class_token(int element)
3882 char *element_class_name = element_info[element].class_name;
3883 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3885 sprintf(element_class_token, "[%s]", element_class_name);
3887 return element_class_token;
3890 static char *get_action_class_token(int action)
3892 char *action_class_name = &element_action_info[action].suffix[1];
3893 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3895 sprintf(action_class_token, "[%s]", action_class_name);
3897 return action_class_token;
3901 static void InitArtworkConfig()
3903 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3904 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3905 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3906 static char *action_id_suffix[NUM_ACTIONS + 1];
3907 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3908 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3909 static char *level_id_suffix[MAX_LEVELS + 1];
3910 static char *dummy[1] = { NULL };
3911 static char *ignore_generic_tokens[] =
3917 static char **ignore_image_tokens;
3918 static char **ignore_sound_tokens;
3919 static char **ignore_music_tokens;
3920 int num_ignore_generic_tokens;
3921 int num_ignore_image_tokens;
3922 int num_ignore_sound_tokens;
3923 int num_ignore_music_tokens;
3926 /* dynamically determine list of generic tokens to be ignored */
3927 num_ignore_generic_tokens = 0;
3928 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3929 num_ignore_generic_tokens++;
3931 /* dynamically determine list of image tokens to be ignored */
3932 num_ignore_image_tokens = num_ignore_generic_tokens;
3933 for (i = 0; image_config_vars[i].token != NULL; i++)
3934 num_ignore_image_tokens++;
3935 ignore_image_tokens =
3936 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3937 for (i = 0; i < num_ignore_generic_tokens; i++)
3938 ignore_image_tokens[i] = ignore_generic_tokens[i];
3939 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3940 ignore_image_tokens[num_ignore_generic_tokens + i] =
3941 image_config_vars[i].token;
3942 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3944 /* dynamically determine list of sound tokens to be ignored */
3945 num_ignore_sound_tokens = num_ignore_generic_tokens;
3946 ignore_sound_tokens =
3947 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3948 for (i = 0; i < num_ignore_generic_tokens; i++)
3949 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3950 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3952 /* dynamically determine list of music tokens to be ignored */
3953 num_ignore_music_tokens = num_ignore_generic_tokens;
3954 ignore_music_tokens =
3955 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3956 for (i = 0; i < num_ignore_generic_tokens; i++)
3957 ignore_music_tokens[i] = ignore_generic_tokens[i];
3958 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3960 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3961 image_id_prefix[i] = element_info[i].token_name;
3962 for (i = 0; i < NUM_FONTS; i++)
3963 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3964 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3967 sound_id_prefix[i] = element_info[i].token_name;
3968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3969 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3970 get_string_in_brackets(element_info[i].class_name);
3971 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3973 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3974 music_id_prefix[i] = music_prefix_info[i].prefix;
3975 music_id_prefix[MAX_LEVELS] = NULL;
3977 for (i = 0; i < NUM_ACTIONS; i++)
3978 action_id_suffix[i] = element_action_info[i].suffix;
3979 action_id_suffix[NUM_ACTIONS] = NULL;
3981 for (i = 0; i < NUM_DIRECTIONS; i++)
3982 direction_id_suffix[i] = element_direction_info[i].suffix;
3983 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3985 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3986 special_id_suffix[i] = special_suffix_info[i].suffix;
3987 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3989 for (i = 0; i < MAX_LEVELS; i++)
3990 level_id_suffix[i] = get_level_id_suffix(i);
3991 level_id_suffix[MAX_LEVELS] = NULL;
3993 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3994 image_id_prefix, action_id_suffix, direction_id_suffix,
3995 special_id_suffix, ignore_image_tokens);
3996 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3997 sound_id_prefix, action_id_suffix, dummy,
3998 special_id_suffix, ignore_sound_tokens);
3999 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4000 music_id_prefix, special_id_suffix, level_id_suffix,
4001 dummy, ignore_music_tokens);
4004 static void InitMixer()
4012 char *filename_font_initial = NULL;
4013 Bitmap *bitmap_font_initial = NULL;
4016 /* determine settings for initial font (for displaying startup messages) */
4017 for (i = 0; image_config[i].token != NULL; i++)
4019 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4021 char font_token[128];
4024 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4025 len_font_token = strlen(font_token);
4027 if (strcmp(image_config[i].token, font_token) == 0)
4028 filename_font_initial = image_config[i].value;
4029 else if (strlen(image_config[i].token) > len_font_token &&
4030 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4032 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4033 font_initial[j].src_x = atoi(image_config[i].value);
4034 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4035 font_initial[j].src_y = atoi(image_config[i].value);
4036 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4037 font_initial[j].width = atoi(image_config[i].value);
4038 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4039 font_initial[j].height = atoi(image_config[i].value);
4044 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4046 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4047 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4050 if (filename_font_initial == NULL) /* should not happen */
4051 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4053 /* create additional image buffers for double-buffering */
4054 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4055 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4057 /* initialize screen properties */
4058 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4059 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4061 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4062 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4063 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4065 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4067 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4068 font_initial[j].bitmap = bitmap_font_initial;
4070 InitFontGraphicInfo();
4072 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4073 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4075 DrawInitText("Loading graphics:", 120, FC_GREEN);
4077 InitTileClipmasks();
4080 void InitGfxBackground()
4084 drawto = backbuffer;
4085 fieldbuffer = bitmap_db_field;
4086 SetDrawtoField(DRAW_BACKBUFFER);
4088 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4089 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4090 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4091 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4093 for (x = 0; x < MAX_BUF_XSIZE; x++)
4094 for (y = 0; y < MAX_BUF_YSIZE; y++)
4097 redraw_mask = REDRAW_ALL;
4100 static void InitLevelInfo()
4102 LoadLevelInfo(); /* global level info */
4103 LoadLevelSetup_LastSeries(); /* last played series info */
4104 LoadLevelSetup_SeriesInfo(); /* last played level info */
4107 void InitLevelArtworkInfo()
4109 LoadLevelArtworkInfo();
4112 static void InitImages()
4115 setLevelArtworkDir(artwork.gfx_first);
4119 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4120 leveldir_current->identifier,
4121 artwork.gfx_current_identifier,
4122 artwork.gfx_current->identifier,
4123 leveldir_current->graphics_set,
4124 leveldir_current->graphics_path);
4127 ReloadCustomImages();
4129 LoadCustomElementDescriptions();
4130 LoadSpecialMenuDesignSettings();
4132 ReinitializeGraphics();
4135 static void InitSound(char *identifier)
4137 if (identifier == NULL)
4138 identifier = artwork.snd_current->identifier;
4141 /* set artwork path to send it to the sound server process */
4142 setLevelArtworkDir(artwork.snd_first);
4145 InitReloadCustomSounds(identifier);
4146 ReinitializeSounds();
4149 static void InitMusic(char *identifier)
4151 if (identifier == NULL)
4152 identifier = artwork.mus_current->identifier;
4155 /* set artwork path to send it to the sound server process */
4156 setLevelArtworkDir(artwork.mus_first);
4159 InitReloadCustomMusic(identifier);
4160 ReinitializeMusic();
4163 void InitNetworkServer()
4165 #if defined(NETWORK_AVALIABLE)
4169 if (!options.network)
4172 #if defined(NETWORK_AVALIABLE)
4173 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4175 if (!ConnectToServer(options.server_host, options.server_port))
4176 Error(ERR_EXIT, "cannot connect to network game server");
4178 SendToServer_PlayerName(setup.player_name);
4179 SendToServer_ProtocolVersion();
4182 SendToServer_NrWanted(nr_wanted);
4186 static char *getNewArtworkIdentifier(int type)
4188 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4189 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4190 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4191 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4192 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4193 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4194 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4195 char *leveldir_identifier = leveldir_current->identifier;
4197 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4198 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4200 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4202 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4203 char *artwork_current_identifier;
4204 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4206 /* leveldir_current may be invalid (level group, parent link) */
4207 if (!validLevelSeries(leveldir_current))
4210 /* 1st step: determine artwork set to be activated in descending order:
4211 --------------------------------------------------------------------
4212 1. setup artwork (when configured to override everything else)
4213 2. artwork set configured in "levelinfo.conf" of current level set
4214 (artwork in level directory will have priority when loading later)
4215 3. artwork in level directory (stored in artwork sub-directory)
4216 4. setup artwork (currently configured in setup menu) */
4218 if (setup_override_artwork)
4219 artwork_current_identifier = setup_artwork_set;
4220 else if (leveldir_artwork_set != NULL)
4221 artwork_current_identifier = leveldir_artwork_set;
4222 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4223 artwork_current_identifier = leveldir_identifier;
4225 artwork_current_identifier = setup_artwork_set;
4228 /* 2nd step: check if it is really needed to reload artwork set
4229 ------------------------------------------------------------ */
4232 if (type == ARTWORK_TYPE_GRAPHICS)
4233 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4234 artwork_new_identifier,
4235 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4236 artwork_current_identifier,
4237 leveldir_current->graphics_set,
4238 leveldir_current->identifier);
4241 /* ---------- reload if level set and also artwork set has changed ------- */
4242 if (leveldir_current_identifier[type] != leveldir_identifier &&
4243 (last_has_level_artwork_set[type] || has_level_artwork_set))
4244 artwork_new_identifier = artwork_current_identifier;
4246 leveldir_current_identifier[type] = leveldir_identifier;
4247 last_has_level_artwork_set[type] = has_level_artwork_set;
4250 if (type == ARTWORK_TYPE_GRAPHICS)
4251 printf("::: 1: '%s'\n", artwork_new_identifier);
4254 /* ---------- reload if "override artwork" setting has changed ----------- */
4255 if (last_override_level_artwork[type] != setup_override_artwork)
4256 artwork_new_identifier = artwork_current_identifier;
4258 last_override_level_artwork[type] = setup_override_artwork;
4261 if (type == ARTWORK_TYPE_GRAPHICS)
4262 printf("::: 2: '%s'\n", artwork_new_identifier);
4265 /* ---------- reload if current artwork identifier has changed ----------- */
4266 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4267 artwork_current_identifier) != 0)
4268 artwork_new_identifier = artwork_current_identifier;
4270 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4273 if (type == ARTWORK_TYPE_GRAPHICS)
4274 printf("::: 3: '%s'\n", artwork_new_identifier);
4277 /* ---------- do not reload directly after starting ---------------------- */
4278 if (!initialized[type])
4279 artwork_new_identifier = NULL;
4281 initialized[type] = TRUE;
4284 if (type == ARTWORK_TYPE_GRAPHICS)
4285 printf("::: 4: '%s'\n", artwork_new_identifier);
4289 if (type == ARTWORK_TYPE_GRAPHICS)
4290 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4291 artwork.gfx_current_identifier, artwork_current_identifier,
4292 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4293 artwork_new_identifier);
4296 return artwork_new_identifier;
4299 void ReloadCustomArtwork(int force_reload)
4301 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4302 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4303 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4304 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4305 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4306 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4307 boolean redraw_screen = FALSE;
4309 if (gfx_new_identifier != NULL || force_reload_gfx)
4312 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4313 artwork.gfx_current_identifier,
4315 artwork.gfx_current->identifier,
4316 leveldir_current->graphics_set);
4319 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4324 printf("... '%s'\n",
4325 leveldir_current->graphics_set);
4328 FreeTileClipmasks();
4329 InitTileClipmasks();
4331 redraw_screen = TRUE;
4334 if (snd_new_identifier != NULL || force_reload_snd)
4336 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4338 InitSound(snd_new_identifier);
4340 redraw_screen = TRUE;
4343 if (mus_new_identifier != NULL || force_reload_mus)
4345 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4347 InitMusic(mus_new_identifier);
4349 redraw_screen = TRUE;
4354 InitGfxBackground();
4356 /* force redraw of (open or closed) door graphics */
4357 SetDoorState(DOOR_OPEN_ALL);
4358 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4362 void KeyboardAutoRepeatOffUnlessAutoplay()
4364 if (global.autoplay_leveldir == NULL)
4365 KeyboardAutoRepeatOff();
4369 /* ========================================================================= */
4371 /* ========================================================================= */
4375 InitGlobal(); /* initialize some global variables */
4377 if (options.execute_command)
4378 Execute_Command(options.execute_command);
4380 if (options.serveronly)
4382 #if defined(PLATFORM_UNIX)
4383 NetworkServer(options.server_port, options.serveronly);
4385 Error(ERR_WARN, "networking only supported in Unix version");
4387 exit(0); /* never reached */
4393 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4394 InitArtworkConfig(); /* needed before forking sound child process */
4399 InitRND(NEW_RANDOMIZE);
4400 InitSimpleRND(NEW_RANDOMIZE);
4405 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4408 InitEventFilter(FilterMouseMotionEvents);
4410 InitElementPropertiesStatic();
4411 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4416 InitLevelArtworkInfo();
4418 InitImages(); /* needs to know current level directory */
4419 InitSound(NULL); /* needs to know current level directory */
4420 InitMusic(NULL); /* needs to know current level directory */
4422 InitGfxBackground();
4424 if (global.autoplay_leveldir)
4429 else if (global.convert_leveldir)
4435 game_status = GAME_MODE_MAIN;
4443 InitNetworkServer();
4446 void CloseAllAndExit(int exit_value)
4451 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4458 FreeTileClipmasks();
4460 #if defined(TARGET_SDL)
4461 if (network_server) /* terminate network server */
4462 SDL_KillThread(server_thread);
4465 CloseVideoDisplay();
4466 ClosePlatformDependentStuff();