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].scale_up_factor = 0; /* default: no scaling up */
850 graphic_info[graphic].anim_delay_fixed = 0;
851 graphic_info[graphic].anim_delay_random = 0;
852 graphic_info[graphic].post_delay_fixed = 0;
853 graphic_info[graphic].post_delay_random = 0;
855 /* optional x and y tile position of animation frame sequence */
856 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
857 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
858 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
859 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
861 /* optional x and y pixel position of animation frame sequence */
862 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
863 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
864 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
865 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
867 /* optional width and height of each animation frame */
868 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
869 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
870 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
871 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
875 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
876 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
879 /* correct x or y offset dependent of vertical or horizontal frame order */
880 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
882 graphic_info[graphic].offset_y =
883 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
884 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
885 anim_frames_per_line = anim_frames_per_col;
887 else /* frames are ordered horizontally */
889 graphic_info[graphic].offset_x =
890 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
891 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
892 anim_frames_per_line = anim_frames_per_row;
895 /* optionally, the x and y offset of frames can be specified directly */
896 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
897 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
898 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
899 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
901 /* automatically determine correct number of frames, if not defined */
902 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
903 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
904 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
905 graphic_info[graphic].anim_frames = anim_frames_per_row;
906 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
907 graphic_info[graphic].anim_frames = anim_frames_per_col;
909 graphic_info[graphic].anim_frames = 1;
911 graphic_info[graphic].anim_frames_per_line =
912 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
913 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
915 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
916 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
917 graphic_info[graphic].anim_delay = 1;
919 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
921 if (graphic_info[graphic].anim_frames == 1)
922 graphic_info[graphic].anim_mode = ANIM_NONE;
925 /* automatically determine correct start frame, if not defined */
926 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
927 graphic_info[graphic].anim_start_frame = 0;
928 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
929 graphic_info[graphic].anim_start_frame =
930 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
932 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
934 /* animation synchronized with global frame counter, not move position */
935 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
937 /* optional element for cloning crumble graphics */
938 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
939 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
941 /* optional element for cloning digging graphics */
942 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
943 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
945 /* optional border size for "crumbling" diggable graphics */
946 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
947 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
949 /* optional zoom factor for scaling up the image to a larger size */
950 if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
951 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
953 /* this is only used for player "boring" and "sleeping" actions */
954 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
955 graphic_info[graphic].anim_delay_fixed =
956 parameter[GFX_ARG_ANIM_DELAY_FIXED];
957 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
958 graphic_info[graphic].anim_delay_random =
959 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
960 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
961 graphic_info[graphic].post_delay_fixed =
962 parameter[GFX_ARG_POST_DELAY_FIXED];
963 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
964 graphic_info[graphic].post_delay_random =
965 parameter[GFX_ARG_POST_DELAY_RANDOM];
967 /* this is only used for toon animations */
968 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
969 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
971 /* this is only used for drawing font characters */
972 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
973 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
975 /* this is only used for drawing envelope graphics */
976 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
979 static void InitGraphicInfo()
981 int fallback_graphic = IMG_CHAR_EXCLAM;
982 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
983 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
984 int num_images = getImageListSize();
987 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
988 static boolean clipmasks_initialized = FALSE;
990 XGCValues clip_gc_values;
991 unsigned long clip_gc_valuemask;
992 GC copy_clipmask_gc = None;
995 checked_free(graphic_info);
997 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1000 printf("::: graphic_info: %d entries\n", num_images);
1003 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1004 if (clipmasks_initialized)
1006 for (i = 0; i < num_images; i++)
1008 if (graphic_info[i].clip_mask)
1009 XFreePixmap(display, graphic_info[i].clip_mask);
1010 if (graphic_info[i].clip_gc)
1011 XFreeGC(display, graphic_info[i].clip_gc);
1013 graphic_info[i].clip_mask = None;
1014 graphic_info[i].clip_gc = None;
1019 for (i = 0; i < num_images; i++)
1021 struct FileInfo *image = getImageListEntry(i);
1024 int first_frame, last_frame;
1027 printf("::: image: '%s' [%d]\n", image->token, i);
1031 printf("::: image # %d: '%s' ['%s']\n",
1033 getTokenFromImageID(i));
1036 set_graphic_parameters(i, image->parameter);
1038 /* now check if no animation frames are outside of the loaded image */
1040 if (graphic_info[i].bitmap == NULL)
1041 continue; /* skip check for optional images that are undefined */
1044 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1045 if (src_x < 0 || src_y < 0 ||
1046 src_x + TILEX > src_bitmap->width ||
1047 src_y + TILEY > src_bitmap->height)
1049 Error(ERR_RETURN_LINE, "-");
1050 Error(ERR_RETURN, "warning: error found in config file:");
1051 Error(ERR_RETURN, "- config file: '%s'",
1052 getImageConfigFilename());
1053 Error(ERR_RETURN, "- config token: '%s'",
1054 getTokenFromImageID(i));
1055 Error(ERR_RETURN, "- image file: '%s'",
1056 src_bitmap->source_filename);
1058 "error: first animation frame out of bounds (%d, %d)",
1060 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1062 if (i == fallback_graphic)
1063 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1065 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1066 Error(ERR_RETURN_LINE, "-");
1068 set_graphic_parameters(i, fallback_image->default_parameter);
1069 graphic_info[i].bitmap = fallback_bitmap;
1072 last_frame = graphic_info[i].anim_frames - 1;
1073 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1074 if (src_x < 0 || src_y < 0 ||
1075 src_x + TILEX > src_bitmap->width ||
1076 src_y + TILEY > src_bitmap->height)
1078 Error(ERR_RETURN_LINE, "-");
1079 Error(ERR_RETURN, "warning: error found in config file:");
1080 Error(ERR_RETURN, "- config file: '%s'",
1081 getImageConfigFilename());
1082 Error(ERR_RETURN, "- config token: '%s'",
1083 getTokenFromImageID(i));
1084 Error(ERR_RETURN, "- image file: '%s'",
1085 src_bitmap->source_filename);
1087 "error: last animation frame (%d) out of bounds (%d, %d)",
1088 last_frame, src_x, src_y);
1089 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1091 if (i == fallback_graphic)
1092 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1094 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1095 Error(ERR_RETURN_LINE, "-");
1097 set_graphic_parameters(i, fallback_image->default_parameter);
1098 graphic_info[i].bitmap = fallback_bitmap;
1101 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1102 /* currently we need only a tile clip mask from the first frame */
1103 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1105 if (copy_clipmask_gc == None)
1107 clip_gc_values.graphics_exposures = False;
1108 clip_gc_valuemask = GCGraphicsExposures;
1109 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1110 clip_gc_valuemask, &clip_gc_values);
1113 graphic_info[i].clip_mask =
1114 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1116 src_pixmap = src_bitmap->clip_mask;
1117 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1118 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1120 clip_gc_values.graphics_exposures = False;
1121 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1122 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1124 graphic_info[i].clip_gc =
1125 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1129 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1130 if (copy_clipmask_gc)
1131 XFreeGC(display, copy_clipmask_gc);
1133 clipmasks_initialized = TRUE;
1137 static void InitElementSoundInfo()
1139 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1140 int num_property_mappings = getSoundListPropertyMappingSize();
1143 /* set values to -1 to identify later as "uninitialized" values */
1144 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1145 for (act = 0; act < NUM_ACTIONS; act++)
1146 element_info[i].sound[act] = -1;
1148 /* initialize element/sound mapping from static configuration */
1149 for (i = 0; element_to_sound[i].element > -1; i++)
1151 int element = element_to_sound[i].element;
1152 int action = element_to_sound[i].action;
1153 int sound = element_to_sound[i].sound;
1154 boolean is_class = element_to_sound[i].is_class;
1157 action = ACTION_DEFAULT;
1160 element_info[element].sound[action] = sound;
1162 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1163 if (strcmp(element_info[j].class_name,
1164 element_info[element].class_name) == 0)
1165 element_info[j].sound[action] = sound;
1168 /* initialize element class/sound mapping from dynamic configuration */
1169 for (i = 0; i < num_property_mappings; i++)
1171 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1172 int action = property_mapping[i].ext1_index;
1173 int sound = property_mapping[i].artwork_index;
1175 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1179 action = ACTION_DEFAULT;
1181 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1182 if (strcmp(element_info[j].class_name,
1183 element_info[element_class].class_name) == 0)
1184 element_info[j].sound[action] = sound;
1187 /* initialize element/sound mapping from dynamic configuration */
1188 for (i = 0; i < num_property_mappings; i++)
1190 int element = property_mapping[i].base_index;
1191 int action = property_mapping[i].ext1_index;
1192 int sound = property_mapping[i].artwork_index;
1194 if (element >= MAX_NUM_ELEMENTS)
1198 action = ACTION_DEFAULT;
1200 element_info[element].sound[action] = sound;
1203 /* now set all '-1' values to element specific default values */
1204 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1206 for (act = 0; act < NUM_ACTIONS; act++)
1208 /* generic default action sound (defined by "[default]" directive) */
1209 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1211 /* look for special default action sound (classic game specific) */
1212 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1213 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1214 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1215 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1216 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1217 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1219 /* !!! there's no such thing as a "default action sound" !!! */
1221 /* look for element specific default sound (independent from action) */
1222 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1223 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1226 /* no sound for this specific action -- use default action sound */
1227 if (element_info[i].sound[act] == -1)
1228 element_info[i].sound[act] = default_action_sound;
1233 static void InitGameModeSoundInfo()
1237 /* set values to -1 to identify later as "uninitialized" values */
1238 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1241 /* initialize gamemode/sound mapping from static configuration */
1242 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1244 int gamemode = gamemode_to_sound[i].gamemode;
1245 int sound = gamemode_to_sound[i].sound;
1248 gamemode = GAME_MODE_DEFAULT;
1250 menu.sound[gamemode] = sound;
1253 /* now set all '-1' values to levelset specific default values */
1254 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1255 if (menu.sound[i] == -1)
1256 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1260 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1261 if (menu.sound[i] != -1)
1262 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1266 static void set_sound_parameters(int sound, char **parameter_raw)
1268 int parameter[NUM_SND_ARGS];
1271 /* get integer values from string parameters */
1272 for (i = 0; i < NUM_SND_ARGS; i++)
1274 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1275 sound_config_suffix[i].type);
1277 /* explicit loop mode setting in configuration overrides default value */
1278 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1279 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1282 static void InitSoundInfo()
1285 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1286 int num_property_mappings = getSoundListPropertyMappingSize();
1288 int *sound_effect_properties;
1289 int num_sounds = getSoundListSize();
1292 checked_free(sound_info);
1294 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1295 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1297 /* initialize sound effect for all elements to "no sound" */
1298 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1299 for (j = 0; j < NUM_ACTIONS; j++)
1300 element_info[i].sound[j] = SND_UNDEFINED;
1302 for (i = 0; i < num_sounds; i++)
1304 struct FileInfo *sound = getSoundListEntry(i);
1305 int len_effect_text = strlen(sound->token);
1307 sound_effect_properties[i] = ACTION_OTHER;
1308 sound_info[i].loop = FALSE; /* default: play sound only once */
1311 printf("::: sound %d: '%s'\n", i, sound->token);
1314 /* determine all loop sounds and identify certain sound classes */
1316 for (j = 0; element_action_info[j].suffix; j++)
1318 int len_action_text = strlen(element_action_info[j].suffix);
1320 if (len_action_text < len_effect_text &&
1321 strcmp(&sound->token[len_effect_text - len_action_text],
1322 element_action_info[j].suffix) == 0)
1324 sound_effect_properties[i] = element_action_info[j].value;
1325 sound_info[i].loop = element_action_info[j].is_loop_sound;
1332 if (strcmp(sound->token, "custom_42") == 0)
1333 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1336 /* associate elements and some selected sound actions */
1338 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1340 if (element_info[j].class_name)
1342 int len_class_text = strlen(element_info[j].class_name);
1344 if (len_class_text + 1 < len_effect_text &&
1345 strncmp(sound->token,
1346 element_info[j].class_name, len_class_text) == 0 &&
1347 sound->token[len_class_text] == '.')
1349 int sound_action_value = sound_effect_properties[i];
1351 element_info[j].sound[sound_action_value] = i;
1356 set_sound_parameters(i, sound->parameter);
1359 free(sound_effect_properties);
1362 /* !!! now handled in InitElementSoundInfo() !!! */
1363 /* initialize element/sound mapping from dynamic configuration */
1364 for (i = 0; i < num_property_mappings; i++)
1366 int element = property_mapping[i].base_index;
1367 int action = property_mapping[i].ext1_index;
1368 int sound = property_mapping[i].artwork_index;
1371 action = ACTION_DEFAULT;
1373 printf("::: %d: %d, %d, %d ['%s']\n",
1374 i, element, action, sound, element_info[element].token_name);
1376 element_info[element].sound[action] = sound;
1383 int element = EL_CUSTOM_11;
1386 while (element_action_info[j].suffix)
1388 printf("element %d, sound action '%s' == %d\n",
1389 element, element_action_info[j].suffix,
1390 element_info[element].sound[j]);
1395 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1401 int element = EL_SAND;
1402 int sound_action = ACTION_DIGGING;
1405 while (element_action_info[j].suffix)
1407 if (element_action_info[j].value == sound_action)
1408 printf("element %d, sound action '%s' == %d\n",
1409 element, element_action_info[j].suffix,
1410 element_info[element].sound[sound_action]);
1417 static void InitGameModeMusicInfo()
1419 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1420 int num_property_mappings = getMusicListPropertyMappingSize();
1421 int default_levelset_music = -1;
1424 /* set values to -1 to identify later as "uninitialized" values */
1425 for (i = 0; i < MAX_LEVELS; i++)
1426 levelset.music[i] = -1;
1427 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1430 /* initialize gamemode/music mapping from static configuration */
1431 for (i = 0; gamemode_to_music[i].music > -1; i++)
1433 int gamemode = gamemode_to_music[i].gamemode;
1434 int music = gamemode_to_music[i].music;
1437 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1441 gamemode = GAME_MODE_DEFAULT;
1443 menu.music[gamemode] = music;
1446 /* initialize gamemode/music mapping from dynamic configuration */
1447 for (i = 0; i < num_property_mappings; i++)
1449 int prefix = property_mapping[i].base_index;
1450 int gamemode = property_mapping[i].ext1_index;
1451 int level = property_mapping[i].ext2_index;
1452 int music = property_mapping[i].artwork_index;
1455 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1456 prefix, gamemode, level, music);
1459 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1463 gamemode = GAME_MODE_DEFAULT;
1465 /* level specific music only allowed for in-game music */
1466 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1467 gamemode = GAME_MODE_PLAYING;
1472 default_levelset_music = music;
1475 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1476 levelset.music[level] = music;
1477 if (gamemode != GAME_MODE_PLAYING)
1478 menu.music[gamemode] = music;
1481 /* now set all '-1' values to menu specific default values */
1482 /* (undefined values of "levelset.music[]" might stay at "-1" to
1483 allow dynamic selection of music files from music directory!) */
1484 for (i = 0; i < MAX_LEVELS; i++)
1485 if (levelset.music[i] == -1)
1486 levelset.music[i] = default_levelset_music;
1487 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1488 if (menu.music[i] == -1)
1489 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1493 for (i = 0; i < MAX_LEVELS; i++)
1494 if (levelset.music[i] != -1)
1495 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1496 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1497 if (menu.music[i] != -1)
1498 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1502 static void set_music_parameters(int music, char **parameter_raw)
1504 int parameter[NUM_MUS_ARGS];
1507 /* get integer values from string parameters */
1508 for (i = 0; i < NUM_MUS_ARGS; i++)
1510 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1511 music_config_suffix[i].type);
1513 /* explicit loop mode setting in configuration overrides default value */
1514 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1515 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1518 static void InitMusicInfo()
1520 int num_music = getMusicListSize();
1523 checked_free(music_info);
1525 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1527 for (i = 0; i < num_music; i++)
1529 struct FileInfo *music = getMusicListEntry(i);
1530 int len_music_text = strlen(music->token);
1532 music_info[i].loop = TRUE; /* default: play music in loop mode */
1534 /* determine all loop music */
1536 for (j = 0; music_prefix_info[j].prefix; j++)
1538 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1540 if (len_prefix_text < len_music_text &&
1541 strncmp(music->token,
1542 music_prefix_info[j].prefix, len_prefix_text) == 0)
1544 music_info[i].loop = music_prefix_info[j].is_loop_music;
1550 set_music_parameters(i, music->parameter);
1554 static void ReinitializeGraphics()
1556 InitGraphicInfo(); /* graphic properties mapping */
1557 InitElementGraphicInfo(); /* element game graphic mapping */
1558 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1560 InitElementSmallImages(); /* create editor and preview images */
1561 InitFontGraphicInfo(); /* initialize text drawing functions */
1563 SetMainBackgroundImage(IMG_BACKGROUND);
1564 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1570 static void ReinitializeSounds()
1572 InitSoundInfo(); /* sound properties mapping */
1573 InitElementSoundInfo(); /* element game sound mapping */
1574 InitGameModeSoundInfo(); /* game mode sound mapping */
1576 InitPlayLevelSound(); /* internal game sound settings */
1579 static void ReinitializeMusic()
1581 InitMusicInfo(); /* music properties mapping */
1582 InitGameModeMusicInfo(); /* game mode music mapping */
1585 static int get_special_property_bit(int element, int property_bit_nr)
1587 struct PropertyBitInfo
1593 static struct PropertyBitInfo pb_can_move_into_acid[] =
1595 /* the player may be able fall into acid when gravity is activated */
1600 { EL_SP_MURPHY, 0 },
1601 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1603 /* all element that can move may be able to also move into acid */
1606 { EL_BUG_RIGHT, 1 },
1609 { EL_SPACESHIP, 2 },
1610 { EL_SPACESHIP_LEFT, 2 },
1611 { EL_SPACESHIP_RIGHT, 2 },
1612 { EL_SPACESHIP_UP, 2 },
1613 { EL_SPACESHIP_DOWN, 2 },
1614 { EL_BD_BUTTERFLY, 3 },
1615 { EL_BD_BUTTERFLY_LEFT, 3 },
1616 { EL_BD_BUTTERFLY_RIGHT, 3 },
1617 { EL_BD_BUTTERFLY_UP, 3 },
1618 { EL_BD_BUTTERFLY_DOWN, 3 },
1619 { EL_BD_FIREFLY, 4 },
1620 { EL_BD_FIREFLY_LEFT, 4 },
1621 { EL_BD_FIREFLY_RIGHT, 4 },
1622 { EL_BD_FIREFLY_UP, 4 },
1623 { EL_BD_FIREFLY_DOWN, 4 },
1625 { EL_DARK_YAMYAM, 6 },
1628 { EL_PACMAN_LEFT, 8 },
1629 { EL_PACMAN_RIGHT, 8 },
1630 { EL_PACMAN_UP, 8 },
1631 { EL_PACMAN_DOWN, 8 },
1633 { EL_MOLE_LEFT, 9 },
1634 { EL_MOLE_RIGHT, 9 },
1636 { EL_MOLE_DOWN, 9 },
1640 { EL_SATELLITE, 13 },
1641 { EL_SP_SNIKSNAK, 14 },
1642 { EL_SP_ELECTRON, 15 },
1649 static struct PropertyBitInfo pb_dont_collide_with[] =
1651 { EL_SP_SNIKSNAK, 0 },
1652 { EL_SP_ELECTRON, 1 },
1660 struct PropertyBitInfo *pb_info;
1663 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1664 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1669 struct PropertyBitInfo *pb_info = NULL;
1672 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1673 if (pb_definition[i].bit_nr == property_bit_nr)
1674 pb_info = pb_definition[i].pb_info;
1676 if (pb_info == NULL)
1679 for (i = 0; pb_info[i].element != -1; i++)
1680 if (pb_info[i].element == element)
1681 return pb_info[i].bit_nr;
1687 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1688 boolean property_value)
1690 int bit_nr = get_special_property_bit(element, property_bit_nr);
1695 *bitfield |= (1 << bit_nr);
1697 *bitfield &= ~(1 << bit_nr);
1701 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1703 int bit_nr = get_special_property_bit(element, property_bit_nr);
1706 return ((*bitfield & (1 << bit_nr)) != 0);
1713 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1715 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1719 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1722 level->can_move_into_acid_bits |= (1 << bit_nr);
1726 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1728 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1731 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1737 void InitElementPropertiesStatic()
1739 static int ep_diggable[] =
1744 EL_SP_BUGGY_BASE_ACTIVATING,
1747 EL_INVISIBLE_SAND_ACTIVE,
1749 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1750 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1754 EL_SP_BUGGY_BASE_ACTIVE,
1759 static int ep_collectible_only[] =
1776 EL_DYNABOMB_INCREASE_NUMBER,
1777 EL_DYNABOMB_INCREASE_SIZE,
1778 EL_DYNABOMB_INCREASE_POWER,
1795 static int ep_dont_run_into[] =
1797 /* same elements as in 'ep_dont_touch' */
1803 /* same elements as in 'ep_dont_collide_with' */
1815 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1819 EL_SP_BUGGY_BASE_ACTIVE,
1824 static int ep_dont_collide_with[] =
1826 /* same elements as in 'ep_dont_touch' */
1842 static int ep_dont_touch[] =
1851 static int ep_indestructible[] =
1855 EL_ACID_POOL_TOPLEFT,
1856 EL_ACID_POOL_TOPRIGHT,
1857 EL_ACID_POOL_BOTTOMLEFT,
1858 EL_ACID_POOL_BOTTOM,
1859 EL_ACID_POOL_BOTTOMRIGHT,
1860 EL_SP_HARDWARE_GRAY,
1861 EL_SP_HARDWARE_GREEN,
1862 EL_SP_HARDWARE_BLUE,
1864 EL_SP_HARDWARE_YELLOW,
1865 EL_SP_HARDWARE_BASE_1,
1866 EL_SP_HARDWARE_BASE_2,
1867 EL_SP_HARDWARE_BASE_3,
1868 EL_SP_HARDWARE_BASE_4,
1869 EL_SP_HARDWARE_BASE_5,
1870 EL_SP_HARDWARE_BASE_6,
1871 EL_INVISIBLE_STEELWALL,
1872 EL_INVISIBLE_STEELWALL_ACTIVE,
1873 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1874 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1875 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1876 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1877 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1878 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1879 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1880 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1881 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1882 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1883 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1884 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1886 EL_LIGHT_SWITCH_ACTIVE,
1887 EL_SIGN_EXCLAMATION,
1888 EL_SIGN_RADIOACTIVITY,
1899 EL_STEELWALL_SLIPPERY,
1922 EL_SWITCHGATE_OPENING,
1923 EL_SWITCHGATE_CLOSED,
1924 EL_SWITCHGATE_CLOSING,
1926 EL_SWITCHGATE_SWITCH_UP,
1927 EL_SWITCHGATE_SWITCH_DOWN,
1930 EL_TIMEGATE_OPENING,
1932 EL_TIMEGATE_CLOSING,
1935 EL_TIMEGATE_SWITCH_ACTIVE,
1940 EL_TUBE_VERTICAL_LEFT,
1941 EL_TUBE_VERTICAL_RIGHT,
1942 EL_TUBE_HORIZONTAL_UP,
1943 EL_TUBE_HORIZONTAL_DOWN,
1951 static int ep_slippery[] =
1965 EL_ROBOT_WHEEL_ACTIVE,
1971 EL_ACID_POOL_TOPLEFT,
1972 EL_ACID_POOL_TOPRIGHT,
1982 EL_STEELWALL_SLIPPERY,
1988 static int ep_can_change[] =
1993 static int ep_can_move[] =
1995 /* same elements as in 'pb_can_move_into_acid' */
2016 static int ep_can_fall[] =
2031 EL_BD_MAGIC_WALL_FULL,
2044 static int ep_can_smash_player[] =
2069 static int ep_can_smash_enemies[] =
2077 static int ep_can_smash_everything[] =
2085 static int ep_explodes_by_fire[] =
2087 /* same elements as in 'ep_explodes_impact' */
2092 /* same elements as in 'ep_explodes_smashed' */
2101 EL_DYNABOMB_PLAYER_1_ACTIVE,
2102 EL_DYNABOMB_PLAYER_2_ACTIVE,
2103 EL_DYNABOMB_PLAYER_3_ACTIVE,
2104 EL_DYNABOMB_PLAYER_4_ACTIVE,
2105 EL_DYNABOMB_INCREASE_NUMBER,
2106 EL_DYNABOMB_INCREASE_SIZE,
2107 EL_DYNABOMB_INCREASE_POWER,
2108 EL_SP_DISK_RED_ACTIVE,
2121 static int ep_explodes_smashed[] =
2123 /* same elements as in 'ep_explodes_impact' */
2136 static int ep_explodes_impact[] =
2144 static int ep_walkable_over[] =
2148 EL_SOKOBAN_FIELD_EMPTY,
2166 static int ep_walkable_inside[] =
2171 EL_TUBE_VERTICAL_LEFT,
2172 EL_TUBE_VERTICAL_RIGHT,
2173 EL_TUBE_HORIZONTAL_UP,
2174 EL_TUBE_HORIZONTAL_DOWN,
2182 static int ep_walkable_under[] =
2187 static int ep_passable_over[] =
2202 static int ep_passable_inside[] =
2208 EL_SP_PORT_HORIZONTAL,
2209 EL_SP_PORT_VERTICAL,
2211 EL_SP_GRAVITY_PORT_LEFT,
2212 EL_SP_GRAVITY_PORT_RIGHT,
2213 EL_SP_GRAVITY_PORT_UP,
2214 EL_SP_GRAVITY_PORT_DOWN,
2215 EL_SP_GRAVITY_ON_PORT_LEFT,
2216 EL_SP_GRAVITY_ON_PORT_RIGHT,
2217 EL_SP_GRAVITY_ON_PORT_UP,
2218 EL_SP_GRAVITY_ON_PORT_DOWN,
2219 EL_SP_GRAVITY_OFF_PORT_LEFT,
2220 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2221 EL_SP_GRAVITY_OFF_PORT_UP,
2222 EL_SP_GRAVITY_OFF_PORT_DOWN,
2226 static int ep_passable_under[] =
2231 static int ep_droppable[] =
2236 static int ep_explodes_1x1_old[] =
2241 static int ep_pushable[] =
2253 EL_SOKOBAN_FIELD_FULL,
2260 static int ep_explodes_cross_old[] =
2265 static int ep_protected[] =
2267 /* same elements as in 'ep_walkable_inside' */
2271 EL_TUBE_VERTICAL_LEFT,
2272 EL_TUBE_VERTICAL_RIGHT,
2273 EL_TUBE_HORIZONTAL_UP,
2274 EL_TUBE_HORIZONTAL_DOWN,
2280 /* same elements as in 'ep_passable_over' */
2292 /* same elements as in 'ep_passable_inside' */
2297 EL_SP_PORT_HORIZONTAL,
2298 EL_SP_PORT_VERTICAL,
2300 EL_SP_GRAVITY_PORT_LEFT,
2301 EL_SP_GRAVITY_PORT_RIGHT,
2302 EL_SP_GRAVITY_PORT_UP,
2303 EL_SP_GRAVITY_PORT_DOWN,
2304 EL_SP_GRAVITY_ON_PORT_LEFT,
2305 EL_SP_GRAVITY_ON_PORT_RIGHT,
2306 EL_SP_GRAVITY_ON_PORT_UP,
2307 EL_SP_GRAVITY_ON_PORT_DOWN,
2308 EL_SP_GRAVITY_OFF_PORT_LEFT,
2309 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2310 EL_SP_GRAVITY_OFF_PORT_UP,
2311 EL_SP_GRAVITY_OFF_PORT_DOWN,
2315 static int ep_throwable[] =
2320 static int ep_can_explode[] =
2322 /* same elements as in 'ep_explodes_impact' */
2327 /* same elements as in 'ep_explodes_smashed' */
2333 /* elements that can explode by explosion or by dragonfire */
2336 EL_DYNABOMB_PLAYER_1_ACTIVE,
2337 EL_DYNABOMB_PLAYER_2_ACTIVE,
2338 EL_DYNABOMB_PLAYER_3_ACTIVE,
2339 EL_DYNABOMB_PLAYER_4_ACTIVE,
2340 EL_DYNABOMB_INCREASE_NUMBER,
2341 EL_DYNABOMB_INCREASE_SIZE,
2342 EL_DYNABOMB_INCREASE_POWER,
2343 EL_SP_DISK_RED_ACTIVE,
2351 /* elements that can explode only by explosion */
2356 static int ep_gravity_reachable[] =
2362 EL_INVISIBLE_SAND_ACTIVE,
2367 EL_SP_PORT_HORIZONTAL,
2368 EL_SP_PORT_VERTICAL,
2370 EL_SP_GRAVITY_PORT_LEFT,
2371 EL_SP_GRAVITY_PORT_RIGHT,
2372 EL_SP_GRAVITY_PORT_UP,
2373 EL_SP_GRAVITY_PORT_DOWN,
2374 EL_SP_GRAVITY_ON_PORT_LEFT,
2375 EL_SP_GRAVITY_ON_PORT_RIGHT,
2376 EL_SP_GRAVITY_ON_PORT_UP,
2377 EL_SP_GRAVITY_ON_PORT_DOWN,
2378 EL_SP_GRAVITY_OFF_PORT_LEFT,
2379 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2380 EL_SP_GRAVITY_OFF_PORT_UP,
2381 EL_SP_GRAVITY_OFF_PORT_DOWN,
2385 static int ep_player[] =
2392 EL_SOKOBAN_FIELD_PLAYER,
2397 static int ep_can_pass_magic_wall[] =
2410 static int ep_switchable[] =
2414 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2415 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2416 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2417 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2418 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2419 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2420 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2421 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2422 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2423 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2424 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2425 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2426 EL_SWITCHGATE_SWITCH_UP,
2427 EL_SWITCHGATE_SWITCH_DOWN,
2429 EL_LIGHT_SWITCH_ACTIVE,
2431 EL_BALLOON_SWITCH_LEFT,
2432 EL_BALLOON_SWITCH_RIGHT,
2433 EL_BALLOON_SWITCH_UP,
2434 EL_BALLOON_SWITCH_DOWN,
2435 EL_BALLOON_SWITCH_ANY,
2441 static int ep_bd_element[] =
2474 static int ep_sp_element[] =
2476 /* should always be valid */
2479 /* standard classic Supaplex elements */
2486 EL_SP_HARDWARE_GRAY,
2494 EL_SP_GRAVITY_PORT_RIGHT,
2495 EL_SP_GRAVITY_PORT_DOWN,
2496 EL_SP_GRAVITY_PORT_LEFT,
2497 EL_SP_GRAVITY_PORT_UP,
2502 EL_SP_PORT_VERTICAL,
2503 EL_SP_PORT_HORIZONTAL,
2509 EL_SP_HARDWARE_BASE_1,
2510 EL_SP_HARDWARE_GREEN,
2511 EL_SP_HARDWARE_BLUE,
2513 EL_SP_HARDWARE_YELLOW,
2514 EL_SP_HARDWARE_BASE_2,
2515 EL_SP_HARDWARE_BASE_3,
2516 EL_SP_HARDWARE_BASE_4,
2517 EL_SP_HARDWARE_BASE_5,
2518 EL_SP_HARDWARE_BASE_6,
2522 /* additional elements that appeared in newer Supaplex levels */
2525 /* additional gravity port elements (not switching, but setting gravity) */
2526 EL_SP_GRAVITY_ON_PORT_LEFT,
2527 EL_SP_GRAVITY_ON_PORT_RIGHT,
2528 EL_SP_GRAVITY_ON_PORT_UP,
2529 EL_SP_GRAVITY_ON_PORT_DOWN,
2530 EL_SP_GRAVITY_OFF_PORT_LEFT,
2531 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2532 EL_SP_GRAVITY_OFF_PORT_UP,
2533 EL_SP_GRAVITY_OFF_PORT_DOWN,
2535 /* more than one Murphy in a level results in an inactive clone */
2538 /* runtime Supaplex elements */
2539 EL_SP_DISK_RED_ACTIVE,
2540 EL_SP_TERMINAL_ACTIVE,
2541 EL_SP_BUGGY_BASE_ACTIVATING,
2542 EL_SP_BUGGY_BASE_ACTIVE,
2548 static int ep_sb_element[] =
2553 EL_SOKOBAN_FIELD_EMPTY,
2554 EL_SOKOBAN_FIELD_FULL,
2555 EL_SOKOBAN_FIELD_PLAYER,
2560 EL_INVISIBLE_STEELWALL,
2564 static int ep_gem[] =
2575 static int ep_food_dark_yamyam[] =
2602 static int ep_food_penguin[] =
2615 static int ep_food_pig[] =
2626 static int ep_historic_wall[] =
2651 EL_EXPANDABLE_WALL_HORIZONTAL,
2652 EL_EXPANDABLE_WALL_VERTICAL,
2653 EL_EXPANDABLE_WALL_ANY,
2654 EL_EXPANDABLE_WALL_GROWING,
2661 EL_SP_HARDWARE_GRAY,
2662 EL_SP_HARDWARE_GREEN,
2663 EL_SP_HARDWARE_BLUE,
2665 EL_SP_HARDWARE_YELLOW,
2666 EL_SP_HARDWARE_BASE_1,
2667 EL_SP_HARDWARE_BASE_2,
2668 EL_SP_HARDWARE_BASE_3,
2669 EL_SP_HARDWARE_BASE_4,
2670 EL_SP_HARDWARE_BASE_5,
2671 EL_SP_HARDWARE_BASE_6,
2673 EL_SP_TERMINAL_ACTIVE,
2676 EL_INVISIBLE_STEELWALL,
2677 EL_INVISIBLE_STEELWALL_ACTIVE,
2679 EL_INVISIBLE_WALL_ACTIVE,
2680 EL_STEELWALL_SLIPPERY,
2696 static int ep_historic_solid[] =
2700 EL_EXPANDABLE_WALL_HORIZONTAL,
2701 EL_EXPANDABLE_WALL_VERTICAL,
2702 EL_EXPANDABLE_WALL_ANY,
2715 EL_QUICKSAND_FILLING,
2716 EL_QUICKSAND_EMPTYING,
2718 EL_MAGIC_WALL_ACTIVE,
2719 EL_MAGIC_WALL_EMPTYING,
2720 EL_MAGIC_WALL_FILLING,
2724 EL_BD_MAGIC_WALL_ACTIVE,
2725 EL_BD_MAGIC_WALL_EMPTYING,
2726 EL_BD_MAGIC_WALL_FULL,
2727 EL_BD_MAGIC_WALL_FILLING,
2728 EL_BD_MAGIC_WALL_DEAD,
2737 EL_SP_TERMINAL_ACTIVE,
2741 EL_INVISIBLE_WALL_ACTIVE,
2742 EL_SWITCHGATE_SWITCH_UP,
2743 EL_SWITCHGATE_SWITCH_DOWN,
2745 EL_TIMEGATE_SWITCH_ACTIVE,
2757 /* the following elements are a direct copy of "indestructible" elements,
2758 except "EL_ACID", which is "indestructible", but not "solid"! */
2763 EL_ACID_POOL_TOPLEFT,
2764 EL_ACID_POOL_TOPRIGHT,
2765 EL_ACID_POOL_BOTTOMLEFT,
2766 EL_ACID_POOL_BOTTOM,
2767 EL_ACID_POOL_BOTTOMRIGHT,
2768 EL_SP_HARDWARE_GRAY,
2769 EL_SP_HARDWARE_GREEN,
2770 EL_SP_HARDWARE_BLUE,
2772 EL_SP_HARDWARE_YELLOW,
2773 EL_SP_HARDWARE_BASE_1,
2774 EL_SP_HARDWARE_BASE_2,
2775 EL_SP_HARDWARE_BASE_3,
2776 EL_SP_HARDWARE_BASE_4,
2777 EL_SP_HARDWARE_BASE_5,
2778 EL_SP_HARDWARE_BASE_6,
2779 EL_INVISIBLE_STEELWALL,
2780 EL_INVISIBLE_STEELWALL_ACTIVE,
2781 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2782 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2783 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2784 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2785 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2786 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2787 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2788 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2789 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2790 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2791 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2792 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2794 EL_LIGHT_SWITCH_ACTIVE,
2795 EL_SIGN_EXCLAMATION,
2796 EL_SIGN_RADIOACTIVITY,
2807 EL_STEELWALL_SLIPPERY,
2830 EL_SWITCHGATE_OPENING,
2831 EL_SWITCHGATE_CLOSED,
2832 EL_SWITCHGATE_CLOSING,
2834 EL_TIMEGATE_OPENING,
2836 EL_TIMEGATE_CLOSING,
2840 EL_TUBE_VERTICAL_LEFT,
2841 EL_TUBE_VERTICAL_RIGHT,
2842 EL_TUBE_HORIZONTAL_UP,
2843 EL_TUBE_HORIZONTAL_DOWN,
2851 static int ep_classic_enemy[] =
2867 static int ep_belt[] =
2869 EL_CONVEYOR_BELT_1_LEFT,
2870 EL_CONVEYOR_BELT_1_MIDDLE,
2871 EL_CONVEYOR_BELT_1_RIGHT,
2872 EL_CONVEYOR_BELT_2_LEFT,
2873 EL_CONVEYOR_BELT_2_MIDDLE,
2874 EL_CONVEYOR_BELT_2_RIGHT,
2875 EL_CONVEYOR_BELT_3_LEFT,
2876 EL_CONVEYOR_BELT_3_MIDDLE,
2877 EL_CONVEYOR_BELT_3_RIGHT,
2878 EL_CONVEYOR_BELT_4_LEFT,
2879 EL_CONVEYOR_BELT_4_MIDDLE,
2880 EL_CONVEYOR_BELT_4_RIGHT,
2884 static int ep_belt_active[] =
2886 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2887 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2888 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2889 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2890 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2891 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2892 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2893 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2894 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2895 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2896 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2897 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2901 static int ep_belt_switch[] =
2903 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2904 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2905 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2906 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2907 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2908 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2909 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2910 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2911 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2912 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2913 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2914 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2918 static int ep_tube[] =
2925 EL_TUBE_HORIZONTAL_UP,
2926 EL_TUBE_HORIZONTAL_DOWN,
2928 EL_TUBE_VERTICAL_LEFT,
2929 EL_TUBE_VERTICAL_RIGHT,
2934 static int ep_keygate[] =
2955 static int ep_amoeboid[] =
2965 static int ep_amoebalive[] =
2974 static int ep_has_content[] =
2984 static int ep_can_turn_each_move[] =
2986 /* !!! do something with this one !!! */
2990 static int ep_can_grow[] =
3002 static int ep_active_bomb[] =
3005 EL_DYNABOMB_PLAYER_1_ACTIVE,
3006 EL_DYNABOMB_PLAYER_2_ACTIVE,
3007 EL_DYNABOMB_PLAYER_3_ACTIVE,
3008 EL_DYNABOMB_PLAYER_4_ACTIVE,
3009 EL_SP_DISK_RED_ACTIVE,
3013 static int ep_inactive[] =
3050 EL_INVISIBLE_STEELWALL,
3058 EL_WALL_EMERALD_YELLOW,
3059 EL_DYNABOMB_INCREASE_NUMBER,
3060 EL_DYNABOMB_INCREASE_SIZE,
3061 EL_DYNABOMB_INCREASE_POWER,
3065 EL_SOKOBAN_FIELD_EMPTY,
3066 EL_SOKOBAN_FIELD_FULL,
3067 EL_WALL_EMERALD_RED,
3068 EL_WALL_EMERALD_PURPLE,
3069 EL_ACID_POOL_TOPLEFT,
3070 EL_ACID_POOL_TOPRIGHT,
3071 EL_ACID_POOL_BOTTOMLEFT,
3072 EL_ACID_POOL_BOTTOM,
3073 EL_ACID_POOL_BOTTOMRIGHT,
3077 EL_BD_MAGIC_WALL_DEAD,
3078 EL_AMOEBA_TO_DIAMOND,
3086 EL_SP_GRAVITY_PORT_RIGHT,
3087 EL_SP_GRAVITY_PORT_DOWN,
3088 EL_SP_GRAVITY_PORT_LEFT,
3089 EL_SP_GRAVITY_PORT_UP,
3090 EL_SP_PORT_HORIZONTAL,
3091 EL_SP_PORT_VERTICAL,
3102 EL_SP_HARDWARE_GRAY,
3103 EL_SP_HARDWARE_GREEN,
3104 EL_SP_HARDWARE_BLUE,
3106 EL_SP_HARDWARE_YELLOW,
3107 EL_SP_HARDWARE_BASE_1,
3108 EL_SP_HARDWARE_BASE_2,
3109 EL_SP_HARDWARE_BASE_3,
3110 EL_SP_HARDWARE_BASE_4,
3111 EL_SP_HARDWARE_BASE_5,
3112 EL_SP_HARDWARE_BASE_6,
3113 EL_SP_GRAVITY_ON_PORT_LEFT,
3114 EL_SP_GRAVITY_ON_PORT_RIGHT,
3115 EL_SP_GRAVITY_ON_PORT_UP,
3116 EL_SP_GRAVITY_ON_PORT_DOWN,
3117 EL_SP_GRAVITY_OFF_PORT_LEFT,
3118 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3119 EL_SP_GRAVITY_OFF_PORT_UP,
3120 EL_SP_GRAVITY_OFF_PORT_DOWN,
3121 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3122 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3123 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3124 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3125 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3126 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3127 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3128 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3129 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3130 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3131 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3132 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3133 EL_SIGN_EXCLAMATION,
3134 EL_SIGN_RADIOACTIVITY,
3145 EL_STEELWALL_SLIPPERY,
3161 static int ep_em_slippery_wall[] =
3166 static int ep_gfx_crumbled[] =
3179 } element_properties[] =
3181 { ep_diggable, EP_DIGGABLE },
3182 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3183 { ep_dont_run_into, EP_DONT_RUN_INTO },
3184 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3185 { ep_dont_touch, EP_DONT_TOUCH },
3186 { ep_indestructible, EP_INDESTRUCTIBLE },
3187 { ep_slippery, EP_SLIPPERY },
3188 { ep_can_change, EP_CAN_CHANGE },
3189 { ep_can_move, EP_CAN_MOVE },
3190 { ep_can_fall, EP_CAN_FALL },
3191 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3192 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3193 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3194 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3195 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3196 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3197 { ep_walkable_over, EP_WALKABLE_OVER },
3198 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3199 { ep_walkable_under, EP_WALKABLE_UNDER },
3200 { ep_passable_over, EP_PASSABLE_OVER },
3201 { ep_passable_inside, EP_PASSABLE_INSIDE },
3202 { ep_passable_under, EP_PASSABLE_UNDER },
3203 { ep_droppable, EP_DROPPABLE },
3204 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3205 { ep_pushable, EP_PUSHABLE },
3206 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3207 { ep_protected, EP_PROTECTED },
3208 { ep_throwable, EP_THROWABLE },
3209 { ep_can_explode, EP_CAN_EXPLODE },
3210 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3212 { ep_player, EP_PLAYER },
3213 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3214 { ep_switchable, EP_SWITCHABLE },
3215 { ep_bd_element, EP_BD_ELEMENT },
3216 { ep_sp_element, EP_SP_ELEMENT },
3217 { ep_sb_element, EP_SB_ELEMENT },
3219 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3220 { ep_food_penguin, EP_FOOD_PENGUIN },
3221 { ep_food_pig, EP_FOOD_PIG },
3222 { ep_historic_wall, EP_HISTORIC_WALL },
3223 { ep_historic_solid, EP_HISTORIC_SOLID },
3224 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3225 { ep_belt, EP_BELT },
3226 { ep_belt_active, EP_BELT_ACTIVE },
3227 { ep_belt_switch, EP_BELT_SWITCH },
3228 { ep_tube, EP_TUBE },
3229 { ep_keygate, EP_KEYGATE },
3230 { ep_amoeboid, EP_AMOEBOID },
3231 { ep_amoebalive, EP_AMOEBALIVE },
3232 { ep_has_content, EP_HAS_CONTENT },
3233 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3234 { ep_can_grow, EP_CAN_GROW },
3235 { ep_active_bomb, EP_ACTIVE_BOMB },
3236 { ep_inactive, EP_INACTIVE },
3238 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3240 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3245 static int copy_properties[][5] =
3249 EL_BUG_LEFT, EL_BUG_RIGHT,
3250 EL_BUG_UP, EL_BUG_DOWN
3254 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3255 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3259 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3260 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3264 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3265 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3269 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3270 EL_PACMAN_UP, EL_PACMAN_DOWN
3274 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3275 EL_MOLE_UP, EL_MOLE_DOWN
3285 /* always start with reliable default values (element has no properties) */
3286 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3287 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3288 SET_PROPERTY(i, j, FALSE);
3290 /* set all base element properties from above array definitions */
3291 for (i = 0; element_properties[i].elements != NULL; i++)
3292 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3293 SET_PROPERTY((element_properties[i].elements)[j],
3294 element_properties[i].property, TRUE);
3296 /* copy properties to some elements that are only stored in level file */
3297 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3298 for (j = 0; copy_properties[j][0] != -1; j++)
3299 if (HAS_PROPERTY(copy_properties[j][0], i))
3300 for (k = 1; k <= 4; k++)
3301 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3304 void InitElementPropertiesEngine(int engine_version)
3307 static int active_properties[] =
3312 EP_DONT_COLLIDE_WITH,
3316 EP_CAN_PASS_MAGIC_WALL,
3321 EP_EXPLODES_BY_FIRE,
3334 EP_EM_SLIPPERY_WALL,
3338 static int no_wall_properties[] =
3341 EP_COLLECTIBLE_ONLY,
3343 EP_DONT_COLLIDE_WITH,
3346 EP_CAN_SMASH_PLAYER,
3347 EP_CAN_SMASH_ENEMIES,
3348 EP_CAN_SMASH_EVERYTHING,
3353 EP_FOOD_DARK_YAMYAM,
3370 InitElementPropertiesStatic();
3373 /* important: after initialization in InitElementPropertiesStatic(), the
3374 elements are not again initialized to a default value; therefore all
3375 changes have to make sure that they leave the element with a defined
3376 property (which means that conditional property changes must be set to
3377 a reliable default value before) */
3379 /* set all special, combined or engine dependent element properties */
3380 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3383 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3384 SET_PROPERTY(i, j, FALSE);
3387 /* ---------- INACTIVE ------------------------------------------------- */
3388 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3390 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3391 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3392 IS_WALKABLE_INSIDE(i) ||
3393 IS_WALKABLE_UNDER(i)));
3395 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3396 IS_PASSABLE_INSIDE(i) ||
3397 IS_PASSABLE_UNDER(i)));
3399 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3400 IS_PASSABLE_OVER(i)));
3402 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3403 IS_PASSABLE_INSIDE(i)));
3405 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3406 IS_PASSABLE_UNDER(i)));
3408 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3411 /* ---------- COLLECTIBLE ---------------------------------------------- */
3412 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3416 /* ---------- SNAPPABLE ------------------------------------------------ */
3417 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3418 IS_COLLECTIBLE(i) ||
3422 /* ---------- WALL ----------------------------------------------------- */
3423 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3425 for (j = 0; no_wall_properties[j] != -1; j++)
3426 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3427 i >= EL_FIRST_RUNTIME_UNREAL)
3428 SET_PROPERTY(i, EP_WALL, FALSE);
3430 if (IS_HISTORIC_WALL(i))
3431 SET_PROPERTY(i, EP_WALL, TRUE);
3433 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3434 if (engine_version < VERSION_IDENT(2,2,0,0))
3435 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3437 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3439 !IS_COLLECTIBLE(i)));
3442 /* ---------- PROTECTED ------------------------------------------------ */
3443 if (IS_ACCESSIBLE_INSIDE(i))
3444 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3447 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3449 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3450 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3452 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3453 IS_INDESTRUCTIBLE(i)));
3455 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3457 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3458 else if (engine_version < VERSION_IDENT(2,2,0,0))
3459 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3462 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3467 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3468 !IS_WALKABLE_OVER(i) &&
3469 !IS_WALKABLE_UNDER(i)));
3471 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3476 if (IS_CUSTOM_ELEMENT(i))
3478 /* these are additional properties which are initially false when set */
3480 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3482 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3483 if (DONT_COLLIDE_WITH(i))
3484 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3486 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3487 if (CAN_SMASH_EVERYTHING(i))
3488 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3489 if (CAN_SMASH_ENEMIES(i))
3490 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3493 /* ---------- CAN_SMASH ------------------------------------------------ */
3494 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3495 CAN_SMASH_ENEMIES(i) ||
3496 CAN_SMASH_EVERYTHING(i)));
3499 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3500 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3501 CAN_EXPLODE_SMASHED(i) ||
3502 CAN_EXPLODE_IMPACT(i)));
3506 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3508 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3509 !CAN_EXPLODE_CROSS(i)));
3511 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3512 !CAN_EXPLODE_1X1(i) &&
3513 !CAN_EXPLODE_CROSS(i)));
3517 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3518 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3519 EXPLODES_BY_FIRE(i)));
3521 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3522 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3523 EXPLODES_SMASHED(i)));
3525 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3526 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3527 EXPLODES_IMPACT(i)));
3529 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3530 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3532 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3533 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3534 i == EL_BLACK_ORB));
3536 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3537 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3539 IS_CUSTOM_ELEMENT(i)));
3541 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3542 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3543 i == EL_SP_ELECTRON));
3545 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3546 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3547 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3548 getMoveIntoAcidProperty(&level, i));
3550 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3551 if (MAYBE_DONT_COLLIDE_WITH(i))
3552 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3553 getDontCollideWithProperty(&level, i));
3555 /* ---------- SP_PORT -------------------------------------------------- */
3556 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3557 IS_PASSABLE_INSIDE(i)));
3559 /* ---------- CAN_CHANGE ----------------------------------------------- */
3560 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3561 for (j = 0; j < element_info[i].num_change_pages; j++)
3562 if (element_info[i].change_page[j].can_change)
3563 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3565 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3566 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3567 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3571 /* determine inactive elements (used for engine main loop optimization) */
3572 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3574 boolean active = FALSE;
3576 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3578 if (HAS_PROPERTY(i, j))
3584 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3589 /* dynamically adjust element properties according to game engine version */
3591 static int ep_em_slippery_wall[] =
3596 EL_EXPANDABLE_WALL_HORIZONTAL,
3597 EL_EXPANDABLE_WALL_VERTICAL,
3598 EL_EXPANDABLE_WALL_ANY,
3602 /* special EM style gems behaviour */
3603 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3604 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3605 level.em_slippery_gems);
3607 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3608 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3609 (level.em_slippery_gems &&
3610 engine_version > VERSION_IDENT(2,0,1,0)));
3614 /* set default push delay values (corrected since version 3.0.7-1) */
3615 if (engine_version < VERSION_IDENT(3,0,7,1))
3617 game.default_push_delay_fixed = 2;
3618 game.default_push_delay_random = 8;
3622 game.default_push_delay_fixed = 8;
3623 game.default_push_delay_random = 8;
3626 /* set uninitialized push delay values of custom elements in older levels */
3627 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3629 int element = EL_CUSTOM_START + i;
3631 if (element_info[element].push_delay_fixed == -1)
3632 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3633 if (element_info[element].push_delay_random == -1)
3634 element_info[element].push_delay_random = game.default_push_delay_random;
3637 /* set some other uninitialized values of custom elements in older levels */
3638 if (engine_version < VERSION_IDENT(3,1,0,0))
3640 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3642 int element = EL_CUSTOM_START + i;
3644 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3646 element_info[element].explosion_delay = 17;
3647 element_info[element].ignition_delay = 8;
3652 /* set element properties that were handled incorrectly in older levels */
3653 if (engine_version < VERSION_IDENT(3,1,0,0))
3655 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3656 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3662 /* this is needed because some graphics depend on element properties */
3663 if (game_status == GAME_MODE_PLAYING)
3664 InitElementGraphicInfo();
3667 static void InitGlobal()
3671 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3673 element_info[i].token_name = element_name_info[i].token_name;
3674 element_info[i].class_name = element_name_info[i].class_name;
3675 element_info[i].editor_description=element_name_info[i].editor_description;
3678 global.autoplay_leveldir = NULL;
3679 global.convert_leveldir = NULL;
3681 global.frames_per_second = 0;
3682 global.fps_slowdown = FALSE;
3683 global.fps_slowdown_factor = 1;
3686 void Execute_Command(char *command)
3690 if (strcmp(command, "print graphicsinfo.conf") == 0)
3692 printf("# You can configure additional/alternative image files here.\n");
3693 printf("# (The entries below are default and therefore commented out.)\n");
3695 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3697 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3700 for (i = 0; image_config[i].token != NULL; i++)
3701 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3702 image_config[i].value));
3706 else if (strcmp(command, "print soundsinfo.conf") == 0)
3708 printf("# You can configure additional/alternative sound files here.\n");
3709 printf("# (The entries below are default and therefore commented out.)\n");
3711 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3713 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3716 for (i = 0; sound_config[i].token != NULL; i++)
3717 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3718 sound_config[i].value));
3722 else if (strcmp(command, "print musicinfo.conf") == 0)
3724 printf("# You can configure additional/alternative music files here.\n");
3725 printf("# (The entries below are default and therefore commented out.)\n");
3727 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3729 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3732 for (i = 0; music_config[i].token != NULL; i++)
3733 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3734 music_config[i].value));
3738 else if (strcmp(command, "print editorsetup.conf") == 0)
3740 printf("# You can configure your personal editor element list here.\n");
3741 printf("# (The entries below are default and therefore commented out.)\n");
3744 PrintEditorElementList();
3748 else if (strcmp(command, "print helpanim.conf") == 0)
3750 printf("# You can configure different element help animations here.\n");
3751 printf("# (The entries below are default and therefore commented out.)\n");
3754 for (i = 0; helpanim_config[i].token != NULL; i++)
3756 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3757 helpanim_config[i].value));
3759 if (strcmp(helpanim_config[i].token, "end") == 0)
3765 else if (strcmp(command, "print helptext.conf") == 0)
3767 printf("# You can configure different element help text here.\n");
3768 printf("# (The entries below are default and therefore commented out.)\n");
3771 for (i = 0; helptext_config[i].token != NULL; i++)
3772 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3773 helptext_config[i].value));
3777 else if (strncmp(command, "dump level ", 11) == 0)
3779 char *filename = &command[11];
3781 if (access(filename, F_OK) != 0)
3782 Error(ERR_EXIT, "cannot open file '%s'", filename);
3784 LoadLevelFromFilename(&level, filename);
3789 else if (strncmp(command, "dump tape ", 10) == 0)
3791 char *filename = &command[10];
3793 if (access(filename, F_OK) != 0)
3794 Error(ERR_EXIT, "cannot open file '%s'", filename);
3796 LoadTapeFromFilename(filename);
3801 else if (strncmp(command, "autoplay ", 9) == 0)
3803 char *str_copy = getStringCopy(&command[9]);
3804 char *str_ptr = strchr(str_copy, ' ');
3806 global.autoplay_leveldir = str_copy;
3807 global.autoplay_level_nr = -1;
3809 if (str_ptr != NULL)
3811 *str_ptr++ = '\0'; /* terminate leveldir string */
3812 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3815 else if (strncmp(command, "convert ", 8) == 0)
3817 char *str_copy = getStringCopy(&command[8]);
3818 char *str_ptr = strchr(str_copy, ' ');
3820 global.convert_leveldir = str_copy;
3821 global.convert_level_nr = -1;
3823 if (str_ptr != NULL)
3825 *str_ptr++ = '\0'; /* terminate leveldir string */
3826 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3831 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3835 static void InitSetup()
3837 LoadSetup(); /* global setup info */
3839 /* set some options from setup file */
3841 if (setup.options.verbose)
3842 options.verbose = TRUE;
3845 static void InitPlayerInfo()
3849 /* choose default local player */
3850 local_player = &stored_player[0];
3852 for (i = 0; i < MAX_PLAYERS; i++)
3853 stored_player[i].connected = FALSE;
3855 local_player->connected = TRUE;
3858 static void InitArtworkInfo()
3863 static char *get_string_in_brackets(char *string)
3865 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3867 sprintf(string_in_brackets, "[%s]", string);
3869 return string_in_brackets;
3872 static char *get_level_id_suffix(int id_nr)
3874 char *id_suffix = checked_malloc(1 + 3 + 1);
3876 if (id_nr < 0 || id_nr > 999)
3879 sprintf(id_suffix, ".%03d", id_nr);
3885 static char *get_element_class_token(int element)
3887 char *element_class_name = element_info[element].class_name;
3888 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3890 sprintf(element_class_token, "[%s]", element_class_name);
3892 return element_class_token;
3895 static char *get_action_class_token(int action)
3897 char *action_class_name = &element_action_info[action].suffix[1];
3898 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3900 sprintf(action_class_token, "[%s]", action_class_name);
3902 return action_class_token;
3906 static void InitArtworkConfig()
3908 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3909 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3910 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3911 static char *action_id_suffix[NUM_ACTIONS + 1];
3912 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3913 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3914 static char *level_id_suffix[MAX_LEVELS + 1];
3915 static char *dummy[1] = { NULL };
3916 static char *ignore_generic_tokens[] =
3922 static char **ignore_image_tokens;
3923 static char **ignore_sound_tokens;
3924 static char **ignore_music_tokens;
3925 int num_ignore_generic_tokens;
3926 int num_ignore_image_tokens;
3927 int num_ignore_sound_tokens;
3928 int num_ignore_music_tokens;
3931 /* dynamically determine list of generic tokens to be ignored */
3932 num_ignore_generic_tokens = 0;
3933 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3934 num_ignore_generic_tokens++;
3936 /* dynamically determine list of image tokens to be ignored */
3937 num_ignore_image_tokens = num_ignore_generic_tokens;
3938 for (i = 0; image_config_vars[i].token != NULL; i++)
3939 num_ignore_image_tokens++;
3940 ignore_image_tokens =
3941 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3942 for (i = 0; i < num_ignore_generic_tokens; i++)
3943 ignore_image_tokens[i] = ignore_generic_tokens[i];
3944 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3945 ignore_image_tokens[num_ignore_generic_tokens + i] =
3946 image_config_vars[i].token;
3947 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3949 /* dynamically determine list of sound tokens to be ignored */
3950 num_ignore_sound_tokens = num_ignore_generic_tokens;
3951 ignore_sound_tokens =
3952 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3953 for (i = 0; i < num_ignore_generic_tokens; i++)
3954 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3955 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3957 /* dynamically determine list of music tokens to be ignored */
3958 num_ignore_music_tokens = num_ignore_generic_tokens;
3959 ignore_music_tokens =
3960 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3961 for (i = 0; i < num_ignore_generic_tokens; i++)
3962 ignore_music_tokens[i] = ignore_generic_tokens[i];
3963 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3965 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3966 image_id_prefix[i] = element_info[i].token_name;
3967 for (i = 0; i < NUM_FONTS; i++)
3968 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3969 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3972 sound_id_prefix[i] = element_info[i].token_name;
3973 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3974 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3975 get_string_in_brackets(element_info[i].class_name);
3976 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3978 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3979 music_id_prefix[i] = music_prefix_info[i].prefix;
3980 music_id_prefix[MAX_LEVELS] = NULL;
3982 for (i = 0; i < NUM_ACTIONS; i++)
3983 action_id_suffix[i] = element_action_info[i].suffix;
3984 action_id_suffix[NUM_ACTIONS] = NULL;
3986 for (i = 0; i < NUM_DIRECTIONS; i++)
3987 direction_id_suffix[i] = element_direction_info[i].suffix;
3988 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3990 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3991 special_id_suffix[i] = special_suffix_info[i].suffix;
3992 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3994 for (i = 0; i < MAX_LEVELS; i++)
3995 level_id_suffix[i] = get_level_id_suffix(i);
3996 level_id_suffix[MAX_LEVELS] = NULL;
3998 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3999 image_id_prefix, action_id_suffix, direction_id_suffix,
4000 special_id_suffix, ignore_image_tokens);
4001 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4002 sound_id_prefix, action_id_suffix, dummy,
4003 special_id_suffix, ignore_sound_tokens);
4004 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4005 music_id_prefix, special_id_suffix, level_id_suffix,
4006 dummy, ignore_music_tokens);
4009 static void InitMixer()
4017 char *filename_font_initial = NULL;
4018 Bitmap *bitmap_font_initial = NULL;
4021 /* determine settings for initial font (for displaying startup messages) */
4022 for (i = 0; image_config[i].token != NULL; i++)
4024 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4026 char font_token[128];
4029 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4030 len_font_token = strlen(font_token);
4032 if (strcmp(image_config[i].token, font_token) == 0)
4033 filename_font_initial = image_config[i].value;
4034 else if (strlen(image_config[i].token) > len_font_token &&
4035 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4037 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4038 font_initial[j].src_x = atoi(image_config[i].value);
4039 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4040 font_initial[j].src_y = atoi(image_config[i].value);
4041 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4042 font_initial[j].width = atoi(image_config[i].value);
4043 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4044 font_initial[j].height = atoi(image_config[i].value);
4049 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4051 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4052 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4055 if (filename_font_initial == NULL) /* should not happen */
4056 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4058 /* create additional image buffers for double-buffering */
4059 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4060 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4062 /* initialize screen properties */
4063 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4064 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4066 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4067 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4068 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4070 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4072 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4073 font_initial[j].bitmap = bitmap_font_initial;
4075 InitFontGraphicInfo();
4077 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4078 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4080 DrawInitText("Loading graphics:", 120, FC_GREEN);
4082 InitTileClipmasks();
4085 void InitGfxBackground()
4089 drawto = backbuffer;
4090 fieldbuffer = bitmap_db_field;
4091 SetDrawtoField(DRAW_BACKBUFFER);
4093 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4094 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4095 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4096 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4098 for (x = 0; x < MAX_BUF_XSIZE; x++)
4099 for (y = 0; y < MAX_BUF_YSIZE; y++)
4102 redraw_mask = REDRAW_ALL;
4105 static void InitLevelInfo()
4107 LoadLevelInfo(); /* global level info */
4108 LoadLevelSetup_LastSeries(); /* last played series info */
4109 LoadLevelSetup_SeriesInfo(); /* last played level info */
4112 void InitLevelArtworkInfo()
4114 LoadLevelArtworkInfo();
4117 static void InitImages()
4120 setLevelArtworkDir(artwork.gfx_first);
4124 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4125 leveldir_current->identifier,
4126 artwork.gfx_current_identifier,
4127 artwork.gfx_current->identifier,
4128 leveldir_current->graphics_set,
4129 leveldir_current->graphics_path);
4132 ReloadCustomImages();
4134 LoadCustomElementDescriptions();
4135 LoadSpecialMenuDesignSettings();
4137 ReinitializeGraphics();
4140 static void InitSound(char *identifier)
4142 if (identifier == NULL)
4143 identifier = artwork.snd_current->identifier;
4146 /* set artwork path to send it to the sound server process */
4147 setLevelArtworkDir(artwork.snd_first);
4150 InitReloadCustomSounds(identifier);
4151 ReinitializeSounds();
4154 static void InitMusic(char *identifier)
4156 if (identifier == NULL)
4157 identifier = artwork.mus_current->identifier;
4160 /* set artwork path to send it to the sound server process */
4161 setLevelArtworkDir(artwork.mus_first);
4164 InitReloadCustomMusic(identifier);
4165 ReinitializeMusic();
4168 void InitNetworkServer()
4170 #if defined(NETWORK_AVALIABLE)
4174 if (!options.network)
4177 #if defined(NETWORK_AVALIABLE)
4178 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4180 if (!ConnectToServer(options.server_host, options.server_port))
4181 Error(ERR_EXIT, "cannot connect to network game server");
4183 SendToServer_PlayerName(setup.player_name);
4184 SendToServer_ProtocolVersion();
4187 SendToServer_NrWanted(nr_wanted);
4191 static char *getNewArtworkIdentifier(int type)
4193 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4194 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4195 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4196 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4197 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4198 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4199 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4200 char *leveldir_identifier = leveldir_current->identifier;
4202 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4203 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4205 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4207 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4208 char *artwork_current_identifier;
4209 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4211 /* leveldir_current may be invalid (level group, parent link) */
4212 if (!validLevelSeries(leveldir_current))
4215 /* 1st step: determine artwork set to be activated in descending order:
4216 --------------------------------------------------------------------
4217 1. setup artwork (when configured to override everything else)
4218 2. artwork set configured in "levelinfo.conf" of current level set
4219 (artwork in level directory will have priority when loading later)
4220 3. artwork in level directory (stored in artwork sub-directory)
4221 4. setup artwork (currently configured in setup menu) */
4223 if (setup_override_artwork)
4224 artwork_current_identifier = setup_artwork_set;
4225 else if (leveldir_artwork_set != NULL)
4226 artwork_current_identifier = leveldir_artwork_set;
4227 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4228 artwork_current_identifier = leveldir_identifier;
4230 artwork_current_identifier = setup_artwork_set;
4233 /* 2nd step: check if it is really needed to reload artwork set
4234 ------------------------------------------------------------ */
4237 if (type == ARTWORK_TYPE_GRAPHICS)
4238 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4239 artwork_new_identifier,
4240 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4241 artwork_current_identifier,
4242 leveldir_current->graphics_set,
4243 leveldir_current->identifier);
4246 /* ---------- reload if level set and also artwork set has changed ------- */
4247 if (leveldir_current_identifier[type] != leveldir_identifier &&
4248 (last_has_level_artwork_set[type] || has_level_artwork_set))
4249 artwork_new_identifier = artwork_current_identifier;
4251 leveldir_current_identifier[type] = leveldir_identifier;
4252 last_has_level_artwork_set[type] = has_level_artwork_set;
4255 if (type == ARTWORK_TYPE_GRAPHICS)
4256 printf("::: 1: '%s'\n", artwork_new_identifier);
4259 /* ---------- reload if "override artwork" setting has changed ----------- */
4260 if (last_override_level_artwork[type] != setup_override_artwork)
4261 artwork_new_identifier = artwork_current_identifier;
4263 last_override_level_artwork[type] = setup_override_artwork;
4266 if (type == ARTWORK_TYPE_GRAPHICS)
4267 printf("::: 2: '%s'\n", artwork_new_identifier);
4270 /* ---------- reload if current artwork identifier has changed ----------- */
4271 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4272 artwork_current_identifier) != 0)
4273 artwork_new_identifier = artwork_current_identifier;
4275 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4278 if (type == ARTWORK_TYPE_GRAPHICS)
4279 printf("::: 3: '%s'\n", artwork_new_identifier);
4282 /* ---------- do not reload directly after starting ---------------------- */
4283 if (!initialized[type])
4284 artwork_new_identifier = NULL;
4286 initialized[type] = TRUE;
4289 if (type == ARTWORK_TYPE_GRAPHICS)
4290 printf("::: 4: '%s'\n", artwork_new_identifier);
4294 if (type == ARTWORK_TYPE_GRAPHICS)
4295 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4296 artwork.gfx_current_identifier, artwork_current_identifier,
4297 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4298 artwork_new_identifier);
4301 return artwork_new_identifier;
4304 void ReloadCustomArtwork(int force_reload)
4306 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4307 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4308 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4309 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4310 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4311 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4312 boolean redraw_screen = FALSE;
4314 if (gfx_new_identifier != NULL || force_reload_gfx)
4317 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4318 artwork.gfx_current_identifier,
4320 artwork.gfx_current->identifier,
4321 leveldir_current->graphics_set);
4324 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4329 printf("... '%s'\n",
4330 leveldir_current->graphics_set);
4333 FreeTileClipmasks();
4334 InitTileClipmasks();
4336 redraw_screen = TRUE;
4339 if (snd_new_identifier != NULL || force_reload_snd)
4341 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4343 InitSound(snd_new_identifier);
4345 redraw_screen = TRUE;
4348 if (mus_new_identifier != NULL || force_reload_mus)
4350 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4352 InitMusic(mus_new_identifier);
4354 redraw_screen = TRUE;
4359 InitGfxBackground();
4361 /* force redraw of (open or closed) door graphics */
4362 SetDoorState(DOOR_OPEN_ALL);
4363 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4367 void KeyboardAutoRepeatOffUnlessAutoplay()
4369 if (global.autoplay_leveldir == NULL)
4370 KeyboardAutoRepeatOff();
4374 /* ========================================================================= */
4376 /* ========================================================================= */
4380 InitGlobal(); /* initialize some global variables */
4382 if (options.execute_command)
4383 Execute_Command(options.execute_command);
4385 if (options.serveronly)
4387 #if defined(PLATFORM_UNIX)
4388 NetworkServer(options.server_port, options.serveronly);
4390 Error(ERR_WARN, "networking only supported in Unix version");
4392 exit(0); /* never reached */
4398 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4399 InitArtworkConfig(); /* needed before forking sound child process */
4404 InitRND(NEW_RANDOMIZE);
4405 InitSimpleRND(NEW_RANDOMIZE);
4410 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4413 InitEventFilter(FilterMouseMotionEvents);
4415 InitElementPropertiesStatic();
4416 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4421 InitLevelArtworkInfo();
4423 InitImages(); /* needs to know current level directory */
4424 InitSound(NULL); /* needs to know current level directory */
4425 InitMusic(NULL); /* needs to know current level directory */
4427 InitGfxBackground();
4429 if (global.autoplay_leveldir)
4434 else if (global.convert_leveldir)
4440 game_status = GAME_MODE_MAIN;
4448 InitNetworkServer();
4451 void CloseAllAndExit(int exit_value)
4456 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4463 FreeTileClipmasks();
4465 #if defined(TARGET_SDL)
4466 if (network_server) /* terminate network server */
4467 SDL_KillThread(server_thread);
4470 CloseVideoDisplay();
4471 ClosePlatformDependentStuff();