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 /* now set all undefined/invalid graphics to -1 to set to default after it */
565 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
567 for (act = 0; act < NUM_ACTIONS; act++)
571 graphic = element_info[i].graphic[act];
572 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
573 element_info[i].graphic[act] = -1;
575 graphic = element_info[i].crumbled[act];
576 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
577 element_info[i].crumbled[act] = -1;
579 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
581 graphic = element_info[i].direction_graphic[act][dir];
582 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
583 element_info[i].direction_graphic[act][dir] = -1;
585 graphic = element_info[i].direction_crumbled[act][dir];
586 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
587 element_info[i].direction_crumbled[act][dir] = -1;
593 /* now set all '-1' values to element specific default values */
594 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
596 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
597 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
598 int default_direction_graphic[NUM_DIRECTIONS];
599 int default_direction_crumbled[NUM_DIRECTIONS];
601 if (default_graphic == -1)
602 default_graphic = IMG_UNKNOWN;
603 if (default_crumbled == -1)
604 default_crumbled = IMG_EMPTY;
606 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
608 default_direction_graphic[dir] =
609 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
610 default_direction_crumbled[dir] =
611 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
613 if (default_direction_graphic[dir] == -1)
614 default_direction_graphic[dir] = default_graphic;
615 if (default_direction_crumbled[dir] == -1)
616 default_direction_crumbled[dir] = default_crumbled;
619 for (act = 0; act < NUM_ACTIONS; act++)
621 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
622 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
623 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
624 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
625 act == ACTION_TURNING_FROM_RIGHT ||
626 act == ACTION_TURNING_FROM_UP ||
627 act == ACTION_TURNING_FROM_DOWN);
629 /* generic default action graphic (defined by "[default]" directive) */
630 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
631 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
633 /* look for special default action graphic (classic game specific) */
634 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
635 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
636 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
637 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
638 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
639 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
641 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
642 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
643 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
644 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
645 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
646 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
649 /* !!! make this better !!! */
650 if (i == EL_EMPTY_SPACE)
652 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
653 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
657 if (default_action_graphic == -1)
658 default_action_graphic = default_graphic;
659 if (default_action_crumbled == -1)
660 default_action_crumbled = default_crumbled;
662 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
664 int default_action_direction_graphic = element_info[i].graphic[act];
665 int default_action_direction_crumbled = element_info[i].crumbled[act];
667 /* no graphic for current action -- use default direction graphic */
668 if (default_action_direction_graphic == -1)
669 default_action_direction_graphic =
670 (act_remove ? IMG_EMPTY :
672 element_info[i].direction_graphic[ACTION_TURNING][dir] :
673 default_direction_graphic[dir]);
674 if (default_action_direction_crumbled == -1)
675 default_action_direction_crumbled =
676 (act_remove ? IMG_EMPTY :
678 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
679 default_direction_crumbled[dir]);
681 if (element_info[i].direction_graphic[act][dir] == -1)
682 element_info[i].direction_graphic[act][dir] =
683 default_action_direction_graphic;
684 if (element_info[i].direction_crumbled[act][dir] == -1)
685 element_info[i].direction_crumbled[act][dir] =
686 default_action_direction_crumbled;
689 /* no graphic for this specific action -- use default action graphic */
690 if (element_info[i].graphic[act] == -1)
691 element_info[i].graphic[act] =
692 (act_remove ? IMG_EMPTY :
693 act_turning ? element_info[i].graphic[ACTION_TURNING] :
694 default_action_graphic);
695 if (element_info[i].crumbled[act] == -1)
696 element_info[i].crumbled[act] =
697 (act_remove ? IMG_EMPTY :
698 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
699 default_action_crumbled);
704 /* set animation mode to "none" for each graphic with only 1 frame */
705 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
707 for (act = 0; act < NUM_ACTIONS; act++)
709 int graphic = element_info[i].graphic[act];
710 int crumbled = element_info[i].crumbled[act];
712 if (graphic_info[graphic].anim_frames == 1)
713 graphic_info[graphic].anim_mode = ANIM_NONE;
714 if (graphic_info[crumbled].anim_frames == 1)
715 graphic_info[crumbled].anim_mode = ANIM_NONE;
717 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
719 graphic = element_info[i].direction_graphic[act][dir];
720 crumbled = element_info[i].direction_crumbled[act][dir];
722 if (graphic_info[graphic].anim_frames == 1)
723 graphic_info[graphic].anim_mode = ANIM_NONE;
724 if (graphic_info[crumbled].anim_frames == 1)
725 graphic_info[crumbled].anim_mode = ANIM_NONE;
735 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
736 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
738 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
739 element_info[i].token_name, i);
745 void InitElementSpecialGraphicInfo()
747 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
748 int num_property_mappings = getImageListPropertyMappingSize();
751 /* always start with reliable default values */
752 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
753 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
754 element_info[i].special_graphic[j] =
755 element_info[i].graphic[ACTION_DEFAULT];
757 /* initialize special element/graphic mapping from static configuration */
758 for (i = 0; element_to_special_graphic[i].element > -1; i++)
760 int element = element_to_special_graphic[i].element;
761 int special = element_to_special_graphic[i].special;
762 int graphic = element_to_special_graphic[i].graphic;
763 int base_graphic = el2baseimg(element);
764 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
765 boolean special_redefined = getImageListEntry(graphic)->redefined;
767 /* if the base graphic ("emerald", for example) has been redefined,
768 but not the special graphic ("emerald.EDITOR", for example), do not
769 use an existing (in this case considered obsolete) special graphic
770 anymore, but use the automatically created (down-scaled) graphic */
771 if (base_redefined && !special_redefined)
774 element_info[element].special_graphic[special] = graphic;
777 /* initialize special element/graphic mapping from dynamic configuration */
778 for (i = 0; i < num_property_mappings; i++)
780 int element = property_mapping[i].base_index;
781 int special = property_mapping[i].ext3_index;
782 int graphic = property_mapping[i].artwork_index;
784 if (element >= MAX_NUM_ELEMENTS)
787 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
788 element_info[element].special_graphic[special] = graphic;
792 /* now set all undefined/invalid graphics to default */
793 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
794 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
795 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
796 element_info[i].special_graphic[j] =
797 element_info[i].graphic[ACTION_DEFAULT];
801 static int get_element_from_token(char *token)
805 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
806 if (strcmp(element_info[i].token_name, token) == 0)
812 static void set_graphic_parameters(int graphic, char **parameter_raw)
814 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
815 int parameter[NUM_GFX_ARGS];
816 int anim_frames_per_row = 1, anim_frames_per_col = 1;
817 int anim_frames_per_line = 1;
820 /* get integer values from string parameters */
821 for (i = 0; i < NUM_GFX_ARGS; i++)
824 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
825 image_config_suffix[i].type);
827 if (image_config_suffix[i].type == TYPE_TOKEN)
828 parameter[i] = get_element_from_token(parameter_raw[i]);
831 graphic_info[graphic].bitmap = src_bitmap;
833 /* start with reliable default values */
834 graphic_info[graphic].src_x = 0;
835 graphic_info[graphic].src_y = 0;
836 graphic_info[graphic].width = TILEX;
837 graphic_info[graphic].height = TILEY;
838 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
839 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
840 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
841 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
842 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
843 graphic_info[graphic].anim_delay_fixed = 0;
844 graphic_info[graphic].anim_delay_random = 0;
845 graphic_info[graphic].post_delay_fixed = 0;
846 graphic_info[graphic].post_delay_random = 0;
848 /* optional x and y tile position of animation frame sequence */
849 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
850 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
851 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
852 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
854 /* optional x and y pixel position of animation frame sequence */
855 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
856 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
857 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
858 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
860 /* optional width and height of each animation frame */
861 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
862 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
863 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
864 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
868 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
869 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
872 /* correct x or y offset dependent of vertical or horizontal frame order */
873 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
875 graphic_info[graphic].offset_y =
876 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
877 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
878 anim_frames_per_line = anim_frames_per_col;
880 else /* frames are ordered horizontally */
882 graphic_info[graphic].offset_x =
883 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
884 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
885 anim_frames_per_line = anim_frames_per_row;
888 /* optionally, the x and y offset of frames can be specified directly */
889 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
890 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
891 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
892 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
894 /* automatically determine correct number of frames, if not defined */
895 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
896 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
897 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
898 graphic_info[graphic].anim_frames = anim_frames_per_row;
899 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
900 graphic_info[graphic].anim_frames = anim_frames_per_col;
902 graphic_info[graphic].anim_frames = 1;
904 graphic_info[graphic].anim_frames_per_line =
905 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
906 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
908 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
909 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
910 graphic_info[graphic].anim_delay = 1;
912 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
914 if (graphic_info[graphic].anim_frames == 1)
915 graphic_info[graphic].anim_mode = ANIM_NONE;
918 /* automatically determine correct start frame, if not defined */
919 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
920 graphic_info[graphic].anim_start_frame = 0;
921 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
922 graphic_info[graphic].anim_start_frame =
923 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
925 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
927 /* animation synchronized with global frame counter, not move position */
928 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
930 /* optional element for cloning crumble graphics */
931 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
932 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
934 /* optional element for cloning digging graphics */
935 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
936 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
938 /* optional border size for "crumbling" diggable graphics */
939 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
940 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
942 /* this is only used for player "boring" and "sleeping" actions */
943 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
944 graphic_info[graphic].anim_delay_fixed =
945 parameter[GFX_ARG_ANIM_DELAY_FIXED];
946 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
947 graphic_info[graphic].anim_delay_random =
948 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
949 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
950 graphic_info[graphic].post_delay_fixed =
951 parameter[GFX_ARG_POST_DELAY_FIXED];
952 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
953 graphic_info[graphic].post_delay_random =
954 parameter[GFX_ARG_POST_DELAY_RANDOM];
956 /* this is only used for toon animations */
957 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
958 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
960 /* this is only used for drawing font characters */
961 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
962 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
964 /* this is only used for drawing envelope graphics */
965 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
968 static void InitGraphicInfo()
970 int fallback_graphic = IMG_CHAR_EXCLAM;
971 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
972 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
973 int num_images = getImageListSize();
976 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
977 static boolean clipmasks_initialized = FALSE;
979 XGCValues clip_gc_values;
980 unsigned long clip_gc_valuemask;
981 GC copy_clipmask_gc = None;
984 checked_free(graphic_info);
986 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
989 printf("::: graphic_info: %d entries\n", num_images);
992 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
993 if (clipmasks_initialized)
995 for (i = 0; i < num_images; i++)
997 if (graphic_info[i].clip_mask)
998 XFreePixmap(display, graphic_info[i].clip_mask);
999 if (graphic_info[i].clip_gc)
1000 XFreeGC(display, graphic_info[i].clip_gc);
1002 graphic_info[i].clip_mask = None;
1003 graphic_info[i].clip_gc = None;
1008 for (i = 0; i < num_images; i++)
1010 struct FileInfo *image = getImageListEntry(i);
1013 int first_frame, last_frame;
1016 printf("::: image: '%s' [%d]\n", image->token, i);
1020 printf("::: image # %d: '%s' ['%s']\n",
1022 getTokenFromImageID(i));
1025 set_graphic_parameters(i, image->parameter);
1027 /* now check if no animation frames are outside of the loaded image */
1029 if (graphic_info[i].bitmap == NULL)
1030 continue; /* skip check for optional images that are undefined */
1033 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1034 if (src_x < 0 || src_y < 0 ||
1035 src_x + TILEX > src_bitmap->width ||
1036 src_y + TILEY > src_bitmap->height)
1038 Error(ERR_RETURN_LINE, "-");
1039 Error(ERR_RETURN, "warning: error found in config file:");
1040 Error(ERR_RETURN, "- config file: '%s'",
1041 getImageConfigFilename());
1042 Error(ERR_RETURN, "- config token: '%s'",
1043 getTokenFromImageID(i));
1044 Error(ERR_RETURN, "- image file: '%s'",
1045 src_bitmap->source_filename);
1047 "error: first animation frame out of bounds (%d, %d)",
1049 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1051 if (i == fallback_graphic)
1052 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1054 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1055 Error(ERR_RETURN_LINE, "-");
1057 set_graphic_parameters(i, fallback_image->default_parameter);
1058 graphic_info[i].bitmap = fallback_bitmap;
1061 last_frame = graphic_info[i].anim_frames - 1;
1062 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1063 if (src_x < 0 || src_y < 0 ||
1064 src_x + TILEX > src_bitmap->width ||
1065 src_y + TILEY > src_bitmap->height)
1067 Error(ERR_RETURN_LINE, "-");
1068 Error(ERR_RETURN, "warning: error found in config file:");
1069 Error(ERR_RETURN, "- config file: '%s'",
1070 getImageConfigFilename());
1071 Error(ERR_RETURN, "- config token: '%s'",
1072 getTokenFromImageID(i));
1073 Error(ERR_RETURN, "- image file: '%s'",
1074 src_bitmap->source_filename);
1076 "error: last animation frame (%d) out of bounds (%d, %d)",
1077 last_frame, src_x, src_y);
1078 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1080 if (i == fallback_graphic)
1081 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1083 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1084 Error(ERR_RETURN_LINE, "-");
1086 set_graphic_parameters(i, fallback_image->default_parameter);
1087 graphic_info[i].bitmap = fallback_bitmap;
1090 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1091 /* currently we need only a tile clip mask from the first frame */
1092 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1094 if (copy_clipmask_gc == None)
1096 clip_gc_values.graphics_exposures = False;
1097 clip_gc_valuemask = GCGraphicsExposures;
1098 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1099 clip_gc_valuemask, &clip_gc_values);
1102 graphic_info[i].clip_mask =
1103 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1105 src_pixmap = src_bitmap->clip_mask;
1106 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1107 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1109 clip_gc_values.graphics_exposures = False;
1110 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1111 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1113 graphic_info[i].clip_gc =
1114 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1118 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1119 if (copy_clipmask_gc)
1120 XFreeGC(display, copy_clipmask_gc);
1122 clipmasks_initialized = TRUE;
1126 static void InitElementSoundInfo()
1128 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1129 int num_property_mappings = getSoundListPropertyMappingSize();
1132 /* set values to -1 to identify later as "uninitialized" values */
1133 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1134 for (act = 0; act < NUM_ACTIONS; act++)
1135 element_info[i].sound[act] = -1;
1137 /* initialize element/sound mapping from static configuration */
1138 for (i = 0; element_to_sound[i].element > -1; i++)
1140 int element = element_to_sound[i].element;
1141 int action = element_to_sound[i].action;
1142 int sound = element_to_sound[i].sound;
1143 boolean is_class = element_to_sound[i].is_class;
1146 action = ACTION_DEFAULT;
1149 element_info[element].sound[action] = sound;
1151 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1152 if (strcmp(element_info[j].class_name,
1153 element_info[element].class_name) == 0)
1154 element_info[j].sound[action] = sound;
1157 /* initialize element class/sound mapping from dynamic configuration */
1158 for (i = 0; i < num_property_mappings; i++)
1160 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1161 int action = property_mapping[i].ext1_index;
1162 int sound = property_mapping[i].artwork_index;
1164 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1168 action = ACTION_DEFAULT;
1170 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1171 if (strcmp(element_info[j].class_name,
1172 element_info[element_class].class_name) == 0)
1173 element_info[j].sound[action] = sound;
1176 /* initialize element/sound mapping from dynamic configuration */
1177 for (i = 0; i < num_property_mappings; i++)
1179 int element = property_mapping[i].base_index;
1180 int action = property_mapping[i].ext1_index;
1181 int sound = property_mapping[i].artwork_index;
1183 if (element >= MAX_NUM_ELEMENTS)
1187 action = ACTION_DEFAULT;
1189 element_info[element].sound[action] = sound;
1192 /* now set all '-1' values to element specific default values */
1193 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1195 for (act = 0; act < NUM_ACTIONS; act++)
1197 /* generic default action sound (defined by "[default]" directive) */
1198 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1200 /* look for special default action sound (classic game specific) */
1201 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1202 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1203 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1204 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1205 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1206 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1208 /* !!! there's no such thing as a "default action sound" !!! */
1210 /* look for element specific default sound (independent from action) */
1211 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1212 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1215 /* no sound for this specific action -- use default action sound */
1216 if (element_info[i].sound[act] == -1)
1217 element_info[i].sound[act] = default_action_sound;
1222 static void InitGameModeSoundInfo()
1226 /* set values to -1 to identify later as "uninitialized" values */
1227 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1230 /* initialize gamemode/sound mapping from static configuration */
1231 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1233 int gamemode = gamemode_to_sound[i].gamemode;
1234 int sound = gamemode_to_sound[i].sound;
1237 gamemode = GAME_MODE_DEFAULT;
1239 menu.sound[gamemode] = sound;
1242 /* now set all '-1' values to levelset specific default values */
1243 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1244 if (menu.sound[i] == -1)
1245 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1249 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1250 if (menu.sound[i] != -1)
1251 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1255 static void set_sound_parameters(int sound, char **parameter_raw)
1257 int parameter[NUM_SND_ARGS];
1260 /* get integer values from string parameters */
1261 for (i = 0; i < NUM_SND_ARGS; i++)
1263 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1264 sound_config_suffix[i].type);
1266 /* explicit loop mode setting in configuration overrides default value */
1267 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1268 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1271 static void InitSoundInfo()
1274 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1275 int num_property_mappings = getSoundListPropertyMappingSize();
1277 int *sound_effect_properties;
1278 int num_sounds = getSoundListSize();
1281 checked_free(sound_info);
1283 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1284 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1286 /* initialize sound effect for all elements to "no sound" */
1287 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1288 for (j = 0; j < NUM_ACTIONS; j++)
1289 element_info[i].sound[j] = SND_UNDEFINED;
1291 for (i = 0; i < num_sounds; i++)
1293 struct FileInfo *sound = getSoundListEntry(i);
1294 int len_effect_text = strlen(sound->token);
1296 sound_effect_properties[i] = ACTION_OTHER;
1297 sound_info[i].loop = FALSE; /* default: play sound only once */
1300 printf("::: sound %d: '%s'\n", i, sound->token);
1303 /* determine all loop sounds and identify certain sound classes */
1305 for (j = 0; element_action_info[j].suffix; j++)
1307 int len_action_text = strlen(element_action_info[j].suffix);
1309 if (len_action_text < len_effect_text &&
1310 strcmp(&sound->token[len_effect_text - len_action_text],
1311 element_action_info[j].suffix) == 0)
1313 sound_effect_properties[i] = element_action_info[j].value;
1314 sound_info[i].loop = element_action_info[j].is_loop_sound;
1321 if (strcmp(sound->token, "custom_42") == 0)
1322 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1325 /* associate elements and some selected sound actions */
1327 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1329 if (element_info[j].class_name)
1331 int len_class_text = strlen(element_info[j].class_name);
1333 if (len_class_text + 1 < len_effect_text &&
1334 strncmp(sound->token,
1335 element_info[j].class_name, len_class_text) == 0 &&
1336 sound->token[len_class_text] == '.')
1338 int sound_action_value = sound_effect_properties[i];
1340 element_info[j].sound[sound_action_value] = i;
1345 set_sound_parameters(i, sound->parameter);
1348 free(sound_effect_properties);
1351 /* !!! now handled in InitElementSoundInfo() !!! */
1352 /* initialize element/sound mapping from dynamic configuration */
1353 for (i = 0; i < num_property_mappings; i++)
1355 int element = property_mapping[i].base_index;
1356 int action = property_mapping[i].ext1_index;
1357 int sound = property_mapping[i].artwork_index;
1360 action = ACTION_DEFAULT;
1362 printf("::: %d: %d, %d, %d ['%s']\n",
1363 i, element, action, sound, element_info[element].token_name);
1365 element_info[element].sound[action] = sound;
1372 int element = EL_CUSTOM_11;
1375 while (element_action_info[j].suffix)
1377 printf("element %d, sound action '%s' == %d\n",
1378 element, element_action_info[j].suffix,
1379 element_info[element].sound[j]);
1384 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1390 int element = EL_SAND;
1391 int sound_action = ACTION_DIGGING;
1394 while (element_action_info[j].suffix)
1396 if (element_action_info[j].value == sound_action)
1397 printf("element %d, sound action '%s' == %d\n",
1398 element, element_action_info[j].suffix,
1399 element_info[element].sound[sound_action]);
1406 static void InitGameModeMusicInfo()
1408 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1409 int num_property_mappings = getMusicListPropertyMappingSize();
1410 int default_levelset_music = -1;
1413 /* set values to -1 to identify later as "uninitialized" values */
1414 for (i = 0; i < MAX_LEVELS; i++)
1415 levelset.music[i] = -1;
1416 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1419 /* initialize gamemode/music mapping from static configuration */
1420 for (i = 0; gamemode_to_music[i].music > -1; i++)
1422 int gamemode = gamemode_to_music[i].gamemode;
1423 int music = gamemode_to_music[i].music;
1426 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1430 gamemode = GAME_MODE_DEFAULT;
1432 menu.music[gamemode] = music;
1435 /* initialize gamemode/music mapping from dynamic configuration */
1436 for (i = 0; i < num_property_mappings; i++)
1438 int prefix = property_mapping[i].base_index;
1439 int gamemode = property_mapping[i].ext1_index;
1440 int level = property_mapping[i].ext2_index;
1441 int music = property_mapping[i].artwork_index;
1444 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1445 prefix, gamemode, level, music);
1448 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1452 gamemode = GAME_MODE_DEFAULT;
1454 /* level specific music only allowed for in-game music */
1455 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1456 gamemode = GAME_MODE_PLAYING;
1461 default_levelset_music = music;
1464 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1465 levelset.music[level] = music;
1466 if (gamemode != GAME_MODE_PLAYING)
1467 menu.music[gamemode] = music;
1470 /* now set all '-1' values to menu specific default values */
1471 /* (undefined values of "levelset.music[]" might stay at "-1" to
1472 allow dynamic selection of music files from music directory!) */
1473 for (i = 0; i < MAX_LEVELS; i++)
1474 if (levelset.music[i] == -1)
1475 levelset.music[i] = default_levelset_music;
1476 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1477 if (menu.music[i] == -1)
1478 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1482 for (i = 0; i < MAX_LEVELS; i++)
1483 if (levelset.music[i] != -1)
1484 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1485 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1486 if (menu.music[i] != -1)
1487 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1491 static void set_music_parameters(int music, char **parameter_raw)
1493 int parameter[NUM_MUS_ARGS];
1496 /* get integer values from string parameters */
1497 for (i = 0; i < NUM_MUS_ARGS; i++)
1499 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1500 music_config_suffix[i].type);
1502 /* explicit loop mode setting in configuration overrides default value */
1503 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1504 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1507 static void InitMusicInfo()
1509 int num_music = getMusicListSize();
1512 checked_free(music_info);
1514 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1516 for (i = 0; i < num_music; i++)
1518 struct FileInfo *music = getMusicListEntry(i);
1519 int len_music_text = strlen(music->token);
1521 music_info[i].loop = TRUE; /* default: play music in loop mode */
1523 /* determine all loop music */
1525 for (j = 0; music_prefix_info[j].prefix; j++)
1527 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1529 if (len_prefix_text < len_music_text &&
1530 strncmp(music->token,
1531 music_prefix_info[j].prefix, len_prefix_text) == 0)
1533 music_info[i].loop = music_prefix_info[j].is_loop_music;
1539 set_music_parameters(i, music->parameter);
1543 static void ReinitializeGraphics()
1545 InitGraphicInfo(); /* graphic properties mapping */
1546 InitElementGraphicInfo(); /* element game graphic mapping */
1547 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1549 InitElementSmallImages(); /* create editor and preview images */
1550 InitFontGraphicInfo(); /* initialize text drawing functions */
1552 SetMainBackgroundImage(IMG_BACKGROUND);
1553 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1559 static void ReinitializeSounds()
1561 InitSoundInfo(); /* sound properties mapping */
1562 InitElementSoundInfo(); /* element game sound mapping */
1563 InitGameModeSoundInfo(); /* game mode sound mapping */
1565 InitPlayLevelSound(); /* internal game sound settings */
1568 static void ReinitializeMusic()
1570 InitMusicInfo(); /* music properties mapping */
1571 InitGameModeMusicInfo(); /* game mode music mapping */
1574 static int get_special_property_bit(int element, int property_bit_nr)
1576 struct PropertyBitInfo
1582 static struct PropertyBitInfo pb_can_move_into_acid[] =
1584 /* the player may be able fall into acid when gravity is activated */
1589 { EL_SP_MURPHY, 0 },
1590 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1592 /* all element that can move may be able to also move into acid */
1595 { EL_BUG_RIGHT, 1 },
1598 { EL_SPACESHIP, 2 },
1599 { EL_SPACESHIP_LEFT, 2 },
1600 { EL_SPACESHIP_RIGHT, 2 },
1601 { EL_SPACESHIP_UP, 2 },
1602 { EL_SPACESHIP_DOWN, 2 },
1603 { EL_BD_BUTTERFLY, 3 },
1604 { EL_BD_BUTTERFLY_LEFT, 3 },
1605 { EL_BD_BUTTERFLY_RIGHT, 3 },
1606 { EL_BD_BUTTERFLY_UP, 3 },
1607 { EL_BD_BUTTERFLY_DOWN, 3 },
1608 { EL_BD_FIREFLY, 4 },
1609 { EL_BD_FIREFLY_LEFT, 4 },
1610 { EL_BD_FIREFLY_RIGHT, 4 },
1611 { EL_BD_FIREFLY_UP, 4 },
1612 { EL_BD_FIREFLY_DOWN, 4 },
1614 { EL_DARK_YAMYAM, 6 },
1617 { EL_PACMAN_LEFT, 8 },
1618 { EL_PACMAN_RIGHT, 8 },
1619 { EL_PACMAN_UP, 8 },
1620 { EL_PACMAN_DOWN, 8 },
1622 { EL_MOLE_LEFT, 9 },
1623 { EL_MOLE_RIGHT, 9 },
1625 { EL_MOLE_DOWN, 9 },
1629 { EL_SATELLITE, 13 },
1630 { EL_SP_SNIKSNAK, 14 },
1631 { EL_SP_ELECTRON, 15 },
1638 static struct PropertyBitInfo pb_dont_collide_with[] =
1640 { EL_SP_SNIKSNAK, 0 },
1641 { EL_SP_ELECTRON, 1 },
1649 struct PropertyBitInfo *pb_info;
1652 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1653 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1658 struct PropertyBitInfo *pb_info = NULL;
1661 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1662 if (pb_definition[i].bit_nr == property_bit_nr)
1663 pb_info = pb_definition[i].pb_info;
1665 if (pb_info == NULL)
1668 for (i = 0; pb_info[i].element != -1; i++)
1669 if (pb_info[i].element == element)
1670 return pb_info[i].bit_nr;
1676 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1677 boolean property_value)
1679 int bit_nr = get_special_property_bit(element, property_bit_nr);
1684 *bitfield |= (1 << bit_nr);
1686 *bitfield &= ~(1 << bit_nr);
1690 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1692 int bit_nr = get_special_property_bit(element, property_bit_nr);
1695 return ((*bitfield & (1 << bit_nr)) != 0);
1702 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1704 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1708 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1711 level->can_move_into_acid_bits |= (1 << bit_nr);
1715 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1717 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1720 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1726 void InitElementPropertiesStatic()
1728 static int ep_diggable[] =
1733 EL_SP_BUGGY_BASE_ACTIVATING,
1736 EL_INVISIBLE_SAND_ACTIVE,
1738 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1739 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1743 EL_SP_BUGGY_BASE_ACTIVE,
1748 static int ep_collectible_only[] =
1765 EL_DYNABOMB_INCREASE_NUMBER,
1766 EL_DYNABOMB_INCREASE_SIZE,
1767 EL_DYNABOMB_INCREASE_POWER,
1784 static int ep_dont_run_into[] =
1786 /* same elements as in 'ep_dont_touch' */
1792 /* same elements as in 'ep_dont_collide_with' */
1804 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1808 EL_SP_BUGGY_BASE_ACTIVE,
1813 static int ep_dont_collide_with[] =
1815 /* same elements as in 'ep_dont_touch' */
1831 static int ep_dont_touch[] =
1840 static int ep_indestructible[] =
1844 EL_ACID_POOL_TOPLEFT,
1845 EL_ACID_POOL_TOPRIGHT,
1846 EL_ACID_POOL_BOTTOMLEFT,
1847 EL_ACID_POOL_BOTTOM,
1848 EL_ACID_POOL_BOTTOMRIGHT,
1849 EL_SP_HARDWARE_GRAY,
1850 EL_SP_HARDWARE_GREEN,
1851 EL_SP_HARDWARE_BLUE,
1853 EL_SP_HARDWARE_YELLOW,
1854 EL_SP_HARDWARE_BASE_1,
1855 EL_SP_HARDWARE_BASE_2,
1856 EL_SP_HARDWARE_BASE_3,
1857 EL_SP_HARDWARE_BASE_4,
1858 EL_SP_HARDWARE_BASE_5,
1859 EL_SP_HARDWARE_BASE_6,
1860 EL_INVISIBLE_STEELWALL,
1861 EL_INVISIBLE_STEELWALL_ACTIVE,
1862 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1863 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1864 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1865 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1866 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1867 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1868 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1869 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1870 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1871 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1872 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1873 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1875 EL_LIGHT_SWITCH_ACTIVE,
1876 EL_SIGN_EXCLAMATION,
1877 EL_SIGN_RADIOACTIVITY,
1888 EL_STEELWALL_SLIPPERY,
1911 EL_SWITCHGATE_OPENING,
1912 EL_SWITCHGATE_CLOSED,
1913 EL_SWITCHGATE_CLOSING,
1915 EL_SWITCHGATE_SWITCH_UP,
1916 EL_SWITCHGATE_SWITCH_DOWN,
1919 EL_TIMEGATE_OPENING,
1921 EL_TIMEGATE_CLOSING,
1924 EL_TIMEGATE_SWITCH_ACTIVE,
1929 EL_TUBE_VERTICAL_LEFT,
1930 EL_TUBE_VERTICAL_RIGHT,
1931 EL_TUBE_HORIZONTAL_UP,
1932 EL_TUBE_HORIZONTAL_DOWN,
1940 static int ep_slippery[] =
1954 EL_ROBOT_WHEEL_ACTIVE,
1960 EL_ACID_POOL_TOPLEFT,
1961 EL_ACID_POOL_TOPRIGHT,
1971 EL_STEELWALL_SLIPPERY,
1977 static int ep_can_change[] =
1982 static int ep_can_move[] =
1984 /* same elements as in 'pb_can_move_into_acid' */
2005 static int ep_can_fall[] =
2020 EL_BD_MAGIC_WALL_FULL,
2033 static int ep_can_smash_player[] =
2058 static int ep_can_smash_enemies[] =
2066 static int ep_can_smash_everything[] =
2074 static int ep_explodes_by_fire[] =
2076 /* same elements as in 'ep_explodes_impact' */
2081 /* same elements as in 'ep_explodes_smashed' */
2090 EL_DYNABOMB_PLAYER_1_ACTIVE,
2091 EL_DYNABOMB_PLAYER_2_ACTIVE,
2092 EL_DYNABOMB_PLAYER_3_ACTIVE,
2093 EL_DYNABOMB_PLAYER_4_ACTIVE,
2094 EL_DYNABOMB_INCREASE_NUMBER,
2095 EL_DYNABOMB_INCREASE_SIZE,
2096 EL_DYNABOMB_INCREASE_POWER,
2097 EL_SP_DISK_RED_ACTIVE,
2110 static int ep_explodes_smashed[] =
2112 /* same elements as in 'ep_explodes_impact' */
2125 static int ep_explodes_impact[] =
2133 static int ep_walkable_over[] =
2137 EL_SOKOBAN_FIELD_EMPTY,
2155 static int ep_walkable_inside[] =
2160 EL_TUBE_VERTICAL_LEFT,
2161 EL_TUBE_VERTICAL_RIGHT,
2162 EL_TUBE_HORIZONTAL_UP,
2163 EL_TUBE_HORIZONTAL_DOWN,
2171 static int ep_walkable_under[] =
2176 static int ep_passable_over[] =
2191 static int ep_passable_inside[] =
2197 EL_SP_PORT_HORIZONTAL,
2198 EL_SP_PORT_VERTICAL,
2200 EL_SP_GRAVITY_PORT_LEFT,
2201 EL_SP_GRAVITY_PORT_RIGHT,
2202 EL_SP_GRAVITY_PORT_UP,
2203 EL_SP_GRAVITY_PORT_DOWN,
2204 EL_SP_GRAVITY_ON_PORT_LEFT,
2205 EL_SP_GRAVITY_ON_PORT_RIGHT,
2206 EL_SP_GRAVITY_ON_PORT_UP,
2207 EL_SP_GRAVITY_ON_PORT_DOWN,
2208 EL_SP_GRAVITY_OFF_PORT_LEFT,
2209 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2210 EL_SP_GRAVITY_OFF_PORT_UP,
2211 EL_SP_GRAVITY_OFF_PORT_DOWN,
2215 static int ep_passable_under[] =
2220 static int ep_droppable[] =
2225 static int ep_explodes_1x1_old[] =
2230 static int ep_pushable[] =
2242 EL_SOKOBAN_FIELD_FULL,
2249 static int ep_explodes_cross_old[] =
2254 static int ep_protected[] =
2256 /* same elements as in 'ep_walkable_inside' */
2260 EL_TUBE_VERTICAL_LEFT,
2261 EL_TUBE_VERTICAL_RIGHT,
2262 EL_TUBE_HORIZONTAL_UP,
2263 EL_TUBE_HORIZONTAL_DOWN,
2269 /* same elements as in 'ep_passable_over' */
2281 /* same elements as in 'ep_passable_inside' */
2286 EL_SP_PORT_HORIZONTAL,
2287 EL_SP_PORT_VERTICAL,
2289 EL_SP_GRAVITY_PORT_LEFT,
2290 EL_SP_GRAVITY_PORT_RIGHT,
2291 EL_SP_GRAVITY_PORT_UP,
2292 EL_SP_GRAVITY_PORT_DOWN,
2293 EL_SP_GRAVITY_ON_PORT_LEFT,
2294 EL_SP_GRAVITY_ON_PORT_RIGHT,
2295 EL_SP_GRAVITY_ON_PORT_UP,
2296 EL_SP_GRAVITY_ON_PORT_DOWN,
2297 EL_SP_GRAVITY_OFF_PORT_LEFT,
2298 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2299 EL_SP_GRAVITY_OFF_PORT_UP,
2300 EL_SP_GRAVITY_OFF_PORT_DOWN,
2304 static int ep_throwable[] =
2309 static int ep_can_explode[] =
2311 /* same elements as in 'ep_explodes_impact' */
2316 /* same elements as in 'ep_explodes_smashed' */
2322 /* elements that can explode by explosion or by dragonfire */
2325 EL_DYNABOMB_PLAYER_1_ACTIVE,
2326 EL_DYNABOMB_PLAYER_2_ACTIVE,
2327 EL_DYNABOMB_PLAYER_3_ACTIVE,
2328 EL_DYNABOMB_PLAYER_4_ACTIVE,
2329 EL_DYNABOMB_INCREASE_NUMBER,
2330 EL_DYNABOMB_INCREASE_SIZE,
2331 EL_DYNABOMB_INCREASE_POWER,
2332 EL_SP_DISK_RED_ACTIVE,
2340 /* elements that can explode only by explosion */
2345 static int ep_gravity_reachable[] =
2351 EL_INVISIBLE_SAND_ACTIVE,
2356 EL_SP_PORT_HORIZONTAL,
2357 EL_SP_PORT_VERTICAL,
2359 EL_SP_GRAVITY_PORT_LEFT,
2360 EL_SP_GRAVITY_PORT_RIGHT,
2361 EL_SP_GRAVITY_PORT_UP,
2362 EL_SP_GRAVITY_PORT_DOWN,
2363 EL_SP_GRAVITY_ON_PORT_LEFT,
2364 EL_SP_GRAVITY_ON_PORT_RIGHT,
2365 EL_SP_GRAVITY_ON_PORT_UP,
2366 EL_SP_GRAVITY_ON_PORT_DOWN,
2367 EL_SP_GRAVITY_OFF_PORT_LEFT,
2368 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2369 EL_SP_GRAVITY_OFF_PORT_UP,
2370 EL_SP_GRAVITY_OFF_PORT_DOWN,
2374 static int ep_player[] =
2381 EL_SOKOBAN_FIELD_PLAYER,
2386 static int ep_can_pass_magic_wall[] =
2399 static int ep_switchable[] =
2403 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2404 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2405 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2406 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2407 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2408 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2409 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2410 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2411 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2412 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2413 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2414 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2415 EL_SWITCHGATE_SWITCH_UP,
2416 EL_SWITCHGATE_SWITCH_DOWN,
2418 EL_LIGHT_SWITCH_ACTIVE,
2420 EL_BALLOON_SWITCH_LEFT,
2421 EL_BALLOON_SWITCH_RIGHT,
2422 EL_BALLOON_SWITCH_UP,
2423 EL_BALLOON_SWITCH_DOWN,
2424 EL_BALLOON_SWITCH_ANY,
2430 static int ep_bd_element[] =
2463 static int ep_sp_element[] =
2465 /* should always be valid */
2468 /* standard classic Supaplex elements */
2475 EL_SP_HARDWARE_GRAY,
2483 EL_SP_GRAVITY_PORT_RIGHT,
2484 EL_SP_GRAVITY_PORT_DOWN,
2485 EL_SP_GRAVITY_PORT_LEFT,
2486 EL_SP_GRAVITY_PORT_UP,
2491 EL_SP_PORT_VERTICAL,
2492 EL_SP_PORT_HORIZONTAL,
2498 EL_SP_HARDWARE_BASE_1,
2499 EL_SP_HARDWARE_GREEN,
2500 EL_SP_HARDWARE_BLUE,
2502 EL_SP_HARDWARE_YELLOW,
2503 EL_SP_HARDWARE_BASE_2,
2504 EL_SP_HARDWARE_BASE_3,
2505 EL_SP_HARDWARE_BASE_4,
2506 EL_SP_HARDWARE_BASE_5,
2507 EL_SP_HARDWARE_BASE_6,
2511 /* additional elements that appeared in newer Supaplex levels */
2514 /* additional gravity port elements (not switching, but setting gravity) */
2515 EL_SP_GRAVITY_ON_PORT_LEFT,
2516 EL_SP_GRAVITY_ON_PORT_RIGHT,
2517 EL_SP_GRAVITY_ON_PORT_UP,
2518 EL_SP_GRAVITY_ON_PORT_DOWN,
2519 EL_SP_GRAVITY_OFF_PORT_LEFT,
2520 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2521 EL_SP_GRAVITY_OFF_PORT_UP,
2522 EL_SP_GRAVITY_OFF_PORT_DOWN,
2524 /* more than one Murphy in a level results in an inactive clone */
2527 /* runtime Supaplex elements */
2528 EL_SP_DISK_RED_ACTIVE,
2529 EL_SP_TERMINAL_ACTIVE,
2530 EL_SP_BUGGY_BASE_ACTIVATING,
2531 EL_SP_BUGGY_BASE_ACTIVE,
2537 static int ep_sb_element[] =
2542 EL_SOKOBAN_FIELD_EMPTY,
2543 EL_SOKOBAN_FIELD_FULL,
2544 EL_SOKOBAN_FIELD_PLAYER,
2549 EL_INVISIBLE_STEELWALL,
2553 static int ep_gem[] =
2564 static int ep_food_dark_yamyam[] =
2591 static int ep_food_penguin[] =
2604 static int ep_food_pig[] =
2615 static int ep_historic_wall[] =
2640 EL_EXPANDABLE_WALL_HORIZONTAL,
2641 EL_EXPANDABLE_WALL_VERTICAL,
2642 EL_EXPANDABLE_WALL_ANY,
2643 EL_EXPANDABLE_WALL_GROWING,
2650 EL_SP_HARDWARE_GRAY,
2651 EL_SP_HARDWARE_GREEN,
2652 EL_SP_HARDWARE_BLUE,
2654 EL_SP_HARDWARE_YELLOW,
2655 EL_SP_HARDWARE_BASE_1,
2656 EL_SP_HARDWARE_BASE_2,
2657 EL_SP_HARDWARE_BASE_3,
2658 EL_SP_HARDWARE_BASE_4,
2659 EL_SP_HARDWARE_BASE_5,
2660 EL_SP_HARDWARE_BASE_6,
2662 EL_SP_TERMINAL_ACTIVE,
2665 EL_INVISIBLE_STEELWALL,
2666 EL_INVISIBLE_STEELWALL_ACTIVE,
2668 EL_INVISIBLE_WALL_ACTIVE,
2669 EL_STEELWALL_SLIPPERY,
2685 static int ep_historic_solid[] =
2689 EL_EXPANDABLE_WALL_HORIZONTAL,
2690 EL_EXPANDABLE_WALL_VERTICAL,
2691 EL_EXPANDABLE_WALL_ANY,
2704 EL_QUICKSAND_FILLING,
2705 EL_QUICKSAND_EMPTYING,
2707 EL_MAGIC_WALL_ACTIVE,
2708 EL_MAGIC_WALL_EMPTYING,
2709 EL_MAGIC_WALL_FILLING,
2713 EL_BD_MAGIC_WALL_ACTIVE,
2714 EL_BD_MAGIC_WALL_EMPTYING,
2715 EL_BD_MAGIC_WALL_FULL,
2716 EL_BD_MAGIC_WALL_FILLING,
2717 EL_BD_MAGIC_WALL_DEAD,
2726 EL_SP_TERMINAL_ACTIVE,
2730 EL_INVISIBLE_WALL_ACTIVE,
2731 EL_SWITCHGATE_SWITCH_UP,
2732 EL_SWITCHGATE_SWITCH_DOWN,
2734 EL_TIMEGATE_SWITCH_ACTIVE,
2746 /* the following elements are a direct copy of "indestructible" elements,
2747 except "EL_ACID", which is "indestructible", but not "solid"! */
2752 EL_ACID_POOL_TOPLEFT,
2753 EL_ACID_POOL_TOPRIGHT,
2754 EL_ACID_POOL_BOTTOMLEFT,
2755 EL_ACID_POOL_BOTTOM,
2756 EL_ACID_POOL_BOTTOMRIGHT,
2757 EL_SP_HARDWARE_GRAY,
2758 EL_SP_HARDWARE_GREEN,
2759 EL_SP_HARDWARE_BLUE,
2761 EL_SP_HARDWARE_YELLOW,
2762 EL_SP_HARDWARE_BASE_1,
2763 EL_SP_HARDWARE_BASE_2,
2764 EL_SP_HARDWARE_BASE_3,
2765 EL_SP_HARDWARE_BASE_4,
2766 EL_SP_HARDWARE_BASE_5,
2767 EL_SP_HARDWARE_BASE_6,
2768 EL_INVISIBLE_STEELWALL,
2769 EL_INVISIBLE_STEELWALL_ACTIVE,
2770 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2771 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2772 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2773 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2774 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2775 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2776 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2777 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2778 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2779 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2780 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2781 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2783 EL_LIGHT_SWITCH_ACTIVE,
2784 EL_SIGN_EXCLAMATION,
2785 EL_SIGN_RADIOACTIVITY,
2796 EL_STEELWALL_SLIPPERY,
2819 EL_SWITCHGATE_OPENING,
2820 EL_SWITCHGATE_CLOSED,
2821 EL_SWITCHGATE_CLOSING,
2823 EL_TIMEGATE_OPENING,
2825 EL_TIMEGATE_CLOSING,
2829 EL_TUBE_VERTICAL_LEFT,
2830 EL_TUBE_VERTICAL_RIGHT,
2831 EL_TUBE_HORIZONTAL_UP,
2832 EL_TUBE_HORIZONTAL_DOWN,
2840 static int ep_classic_enemy[] =
2856 static int ep_belt[] =
2858 EL_CONVEYOR_BELT_1_LEFT,
2859 EL_CONVEYOR_BELT_1_MIDDLE,
2860 EL_CONVEYOR_BELT_1_RIGHT,
2861 EL_CONVEYOR_BELT_2_LEFT,
2862 EL_CONVEYOR_BELT_2_MIDDLE,
2863 EL_CONVEYOR_BELT_2_RIGHT,
2864 EL_CONVEYOR_BELT_3_LEFT,
2865 EL_CONVEYOR_BELT_3_MIDDLE,
2866 EL_CONVEYOR_BELT_3_RIGHT,
2867 EL_CONVEYOR_BELT_4_LEFT,
2868 EL_CONVEYOR_BELT_4_MIDDLE,
2869 EL_CONVEYOR_BELT_4_RIGHT,
2873 static int ep_belt_active[] =
2875 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2876 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2877 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2878 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2879 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2880 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2881 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2882 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2883 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2884 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2885 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2886 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2890 static int ep_belt_switch[] =
2892 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2893 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2894 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2895 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2896 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2897 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2898 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2899 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2900 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2901 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2902 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2903 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2907 static int ep_tube[] =
2914 EL_TUBE_HORIZONTAL_UP,
2915 EL_TUBE_HORIZONTAL_DOWN,
2917 EL_TUBE_VERTICAL_LEFT,
2918 EL_TUBE_VERTICAL_RIGHT,
2923 static int ep_keygate[] =
2944 static int ep_amoeboid[] =
2954 static int ep_amoebalive[] =
2963 static int ep_has_content[] =
2973 static int ep_can_turn_each_move[] =
2975 /* !!! do something with this one !!! */
2979 static int ep_can_grow[] =
2991 static int ep_active_bomb[] =
2994 EL_DYNABOMB_PLAYER_1_ACTIVE,
2995 EL_DYNABOMB_PLAYER_2_ACTIVE,
2996 EL_DYNABOMB_PLAYER_3_ACTIVE,
2997 EL_DYNABOMB_PLAYER_4_ACTIVE,
2998 EL_SP_DISK_RED_ACTIVE,
3002 static int ep_inactive[] =
3039 EL_INVISIBLE_STEELWALL,
3047 EL_WALL_EMERALD_YELLOW,
3048 EL_DYNABOMB_INCREASE_NUMBER,
3049 EL_DYNABOMB_INCREASE_SIZE,
3050 EL_DYNABOMB_INCREASE_POWER,
3054 EL_SOKOBAN_FIELD_EMPTY,
3055 EL_SOKOBAN_FIELD_FULL,
3056 EL_WALL_EMERALD_RED,
3057 EL_WALL_EMERALD_PURPLE,
3058 EL_ACID_POOL_TOPLEFT,
3059 EL_ACID_POOL_TOPRIGHT,
3060 EL_ACID_POOL_BOTTOMLEFT,
3061 EL_ACID_POOL_BOTTOM,
3062 EL_ACID_POOL_BOTTOMRIGHT,
3066 EL_BD_MAGIC_WALL_DEAD,
3067 EL_AMOEBA_TO_DIAMOND,
3075 EL_SP_GRAVITY_PORT_RIGHT,
3076 EL_SP_GRAVITY_PORT_DOWN,
3077 EL_SP_GRAVITY_PORT_LEFT,
3078 EL_SP_GRAVITY_PORT_UP,
3079 EL_SP_PORT_HORIZONTAL,
3080 EL_SP_PORT_VERTICAL,
3091 EL_SP_HARDWARE_GRAY,
3092 EL_SP_HARDWARE_GREEN,
3093 EL_SP_HARDWARE_BLUE,
3095 EL_SP_HARDWARE_YELLOW,
3096 EL_SP_HARDWARE_BASE_1,
3097 EL_SP_HARDWARE_BASE_2,
3098 EL_SP_HARDWARE_BASE_3,
3099 EL_SP_HARDWARE_BASE_4,
3100 EL_SP_HARDWARE_BASE_5,
3101 EL_SP_HARDWARE_BASE_6,
3102 EL_SP_GRAVITY_ON_PORT_LEFT,
3103 EL_SP_GRAVITY_ON_PORT_RIGHT,
3104 EL_SP_GRAVITY_ON_PORT_UP,
3105 EL_SP_GRAVITY_ON_PORT_DOWN,
3106 EL_SP_GRAVITY_OFF_PORT_LEFT,
3107 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3108 EL_SP_GRAVITY_OFF_PORT_UP,
3109 EL_SP_GRAVITY_OFF_PORT_DOWN,
3110 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3111 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3112 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3113 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3114 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3115 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3116 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3117 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3118 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3119 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3120 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3121 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3122 EL_SIGN_EXCLAMATION,
3123 EL_SIGN_RADIOACTIVITY,
3134 EL_STEELWALL_SLIPPERY,
3150 static int ep_em_slippery_wall[] =
3155 static int ep_gfx_crumbled[] =
3168 } element_properties[] =
3170 { ep_diggable, EP_DIGGABLE },
3171 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3172 { ep_dont_run_into, EP_DONT_RUN_INTO },
3173 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3174 { ep_dont_touch, EP_DONT_TOUCH },
3175 { ep_indestructible, EP_INDESTRUCTIBLE },
3176 { ep_slippery, EP_SLIPPERY },
3177 { ep_can_change, EP_CAN_CHANGE },
3178 { ep_can_move, EP_CAN_MOVE },
3179 { ep_can_fall, EP_CAN_FALL },
3180 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3181 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3182 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3183 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3184 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3185 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3186 { ep_walkable_over, EP_WALKABLE_OVER },
3187 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3188 { ep_walkable_under, EP_WALKABLE_UNDER },
3189 { ep_passable_over, EP_PASSABLE_OVER },
3190 { ep_passable_inside, EP_PASSABLE_INSIDE },
3191 { ep_passable_under, EP_PASSABLE_UNDER },
3192 { ep_droppable, EP_DROPPABLE },
3193 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3194 { ep_pushable, EP_PUSHABLE },
3195 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3196 { ep_protected, EP_PROTECTED },
3197 { ep_throwable, EP_THROWABLE },
3198 { ep_can_explode, EP_CAN_EXPLODE },
3199 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3201 { ep_player, EP_PLAYER },
3202 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3203 { ep_switchable, EP_SWITCHABLE },
3204 { ep_bd_element, EP_BD_ELEMENT },
3205 { ep_sp_element, EP_SP_ELEMENT },
3206 { ep_sb_element, EP_SB_ELEMENT },
3208 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3209 { ep_food_penguin, EP_FOOD_PENGUIN },
3210 { ep_food_pig, EP_FOOD_PIG },
3211 { ep_historic_wall, EP_HISTORIC_WALL },
3212 { ep_historic_solid, EP_HISTORIC_SOLID },
3213 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3214 { ep_belt, EP_BELT },
3215 { ep_belt_active, EP_BELT_ACTIVE },
3216 { ep_belt_switch, EP_BELT_SWITCH },
3217 { ep_tube, EP_TUBE },
3218 { ep_keygate, EP_KEYGATE },
3219 { ep_amoeboid, EP_AMOEBOID },
3220 { ep_amoebalive, EP_AMOEBALIVE },
3221 { ep_has_content, EP_HAS_CONTENT },
3222 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3223 { ep_can_grow, EP_CAN_GROW },
3224 { ep_active_bomb, EP_ACTIVE_BOMB },
3225 { ep_inactive, EP_INACTIVE },
3227 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3229 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3234 static int copy_properties[][5] =
3238 EL_BUG_LEFT, EL_BUG_RIGHT,
3239 EL_BUG_UP, EL_BUG_DOWN
3243 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3244 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3248 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3249 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3253 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3254 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3258 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3259 EL_PACMAN_UP, EL_PACMAN_DOWN
3263 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3264 EL_MOLE_UP, EL_MOLE_DOWN
3274 /* always start with reliable default values (element has no properties) */
3275 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3276 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3277 SET_PROPERTY(i, j, FALSE);
3279 /* set all base element properties from above array definitions */
3280 for (i = 0; element_properties[i].elements != NULL; i++)
3281 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3282 SET_PROPERTY((element_properties[i].elements)[j],
3283 element_properties[i].property, TRUE);
3285 /* copy properties to some elements that are only stored in level file */
3286 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3287 for (j = 0; copy_properties[j][0] != -1; j++)
3288 if (HAS_PROPERTY(copy_properties[j][0], i))
3289 for (k = 1; k <= 4; k++)
3290 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3293 void InitElementPropertiesEngine(int engine_version)
3296 static int active_properties[] =
3301 EP_DONT_COLLIDE_WITH,
3305 EP_CAN_PASS_MAGIC_WALL,
3310 EP_EXPLODES_BY_FIRE,
3323 EP_EM_SLIPPERY_WALL,
3327 static int no_wall_properties[] =
3330 EP_COLLECTIBLE_ONLY,
3332 EP_DONT_COLLIDE_WITH,
3335 EP_CAN_SMASH_PLAYER,
3336 EP_CAN_SMASH_ENEMIES,
3337 EP_CAN_SMASH_EVERYTHING,
3342 EP_FOOD_DARK_YAMYAM,
3359 InitElementPropertiesStatic();
3362 /* important: after initialization in InitElementPropertiesStatic(), the
3363 elements are not again initialized to a default value; therefore all
3364 changes have to make sure that they leave the element with a defined
3365 property (which means that conditional property changes must be set to
3366 a reliable default value before) */
3368 /* set all special, combined or engine dependent element properties */
3369 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3372 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3373 SET_PROPERTY(i, j, FALSE);
3376 /* ---------- INACTIVE ------------------------------------------------- */
3377 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3379 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3380 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3381 IS_WALKABLE_INSIDE(i) ||
3382 IS_WALKABLE_UNDER(i)));
3384 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3385 IS_PASSABLE_INSIDE(i) ||
3386 IS_PASSABLE_UNDER(i)));
3388 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3389 IS_PASSABLE_OVER(i)));
3391 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3392 IS_PASSABLE_INSIDE(i)));
3394 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3395 IS_PASSABLE_UNDER(i)));
3397 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3400 /* ---------- COLLECTIBLE ---------------------------------------------- */
3401 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3405 /* ---------- SNAPPABLE ------------------------------------------------ */
3406 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3407 IS_COLLECTIBLE(i) ||
3411 /* ---------- WALL ----------------------------------------------------- */
3412 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3414 for (j = 0; no_wall_properties[j] != -1; j++)
3415 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3416 i >= EL_FIRST_RUNTIME_UNREAL)
3417 SET_PROPERTY(i, EP_WALL, FALSE);
3419 if (IS_HISTORIC_WALL(i))
3420 SET_PROPERTY(i, EP_WALL, TRUE);
3422 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3423 if (engine_version < VERSION_IDENT(2,2,0,0))
3424 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3426 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3428 !IS_COLLECTIBLE(i)));
3431 /* ---------- PROTECTED ------------------------------------------------ */
3432 if (IS_ACCESSIBLE_INSIDE(i))
3433 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3436 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3438 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3439 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3441 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3442 IS_INDESTRUCTIBLE(i)));
3444 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3446 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3447 else if (engine_version < VERSION_IDENT(2,2,0,0))
3448 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3451 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3456 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3457 !IS_WALKABLE_OVER(i) &&
3458 !IS_WALKABLE_UNDER(i)));
3460 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3465 if (IS_CUSTOM_ELEMENT(i))
3467 /* these are additional properties which are initially false when set */
3469 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3471 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3472 if (DONT_COLLIDE_WITH(i))
3473 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3475 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3476 if (CAN_SMASH_EVERYTHING(i))
3477 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3478 if (CAN_SMASH_ENEMIES(i))
3479 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3482 /* ---------- CAN_SMASH ------------------------------------------------ */
3483 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3484 CAN_SMASH_ENEMIES(i) ||
3485 CAN_SMASH_EVERYTHING(i)));
3488 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3489 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3490 CAN_EXPLODE_SMASHED(i) ||
3491 CAN_EXPLODE_IMPACT(i)));
3495 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3497 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3498 !CAN_EXPLODE_CROSS(i)));
3500 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3501 !CAN_EXPLODE_1X1(i) &&
3502 !CAN_EXPLODE_CROSS(i)));
3506 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3507 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3508 EXPLODES_BY_FIRE(i)));
3510 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3511 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3512 EXPLODES_SMASHED(i)));
3514 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3515 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3516 EXPLODES_IMPACT(i)));
3518 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3519 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3521 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3522 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3523 i == EL_BLACK_ORB));
3525 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3526 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3528 IS_CUSTOM_ELEMENT(i)));
3530 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3531 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3532 i == EL_SP_ELECTRON));
3534 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3535 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3536 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3537 getMoveIntoAcidProperty(&level, i));
3539 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3540 if (MAYBE_DONT_COLLIDE_WITH(i))
3541 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3542 getDontCollideWithProperty(&level, i));
3544 /* ---------- SP_PORT -------------------------------------------------- */
3545 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3546 IS_PASSABLE_INSIDE(i)));
3548 /* ---------- CAN_CHANGE ----------------------------------------------- */
3549 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3550 for (j = 0; j < element_info[i].num_change_pages; j++)
3551 if (element_info[i].change_page[j].can_change)
3552 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3554 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3555 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3556 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3560 /* determine inactive elements (used for engine main loop optimization) */
3561 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3563 boolean active = FALSE;
3565 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3567 if (HAS_PROPERTY(i, j))
3573 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3578 /* dynamically adjust element properties according to game engine version */
3580 static int ep_em_slippery_wall[] =
3585 EL_EXPANDABLE_WALL_HORIZONTAL,
3586 EL_EXPANDABLE_WALL_VERTICAL,
3587 EL_EXPANDABLE_WALL_ANY,
3591 /* special EM style gems behaviour */
3592 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3593 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3594 level.em_slippery_gems);
3596 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3597 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3598 (level.em_slippery_gems &&
3599 engine_version > VERSION_IDENT(2,0,1,0)));
3603 /* set default push delay values (corrected since version 3.0.7-1) */
3604 if (engine_version < VERSION_IDENT(3,0,7,1))
3606 game.default_push_delay_fixed = 2;
3607 game.default_push_delay_random = 8;
3611 game.default_push_delay_fixed = 8;
3612 game.default_push_delay_random = 8;
3615 /* set uninitialized push delay values of custom elements in older levels */
3616 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3618 int element = EL_CUSTOM_START + i;
3620 if (element_info[element].push_delay_fixed == -1)
3621 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3622 if (element_info[element].push_delay_random == -1)
3623 element_info[element].push_delay_random = game.default_push_delay_random;
3626 /* set some other uninitialized values of custom elements in older levels */
3627 if (engine_version < VERSION_IDENT(3,1,0,0))
3629 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3631 int element = EL_CUSTOM_START + i;
3633 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3635 element_info[element].explosion_delay = 17;
3636 element_info[element].ignition_delay = 8;
3641 /* set element properties that were handled incorrectly in older levels */
3642 if (engine_version < VERSION_IDENT(3,1,0,0))
3644 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3645 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3651 /* this is needed because some graphics depend on element properties */
3652 if (game_status == GAME_MODE_PLAYING)
3653 InitElementGraphicInfo();
3656 static void InitGlobal()
3658 global.autoplay_leveldir = NULL;
3659 global.convert_leveldir = NULL;
3661 global.frames_per_second = 0;
3662 global.fps_slowdown = FALSE;
3663 global.fps_slowdown_factor = 1;
3666 void Execute_Command(char *command)
3670 if (strcmp(command, "print graphicsinfo.conf") == 0)
3672 printf("# You can configure additional/alternative image files here.\n");
3673 printf("# (The entries below are default and therefore commented out.)\n");
3675 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3677 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3680 for (i = 0; image_config[i].token != NULL; i++)
3681 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3682 image_config[i].value));
3686 else if (strcmp(command, "print soundsinfo.conf") == 0)
3688 printf("# You can configure additional/alternative sound files here.\n");
3689 printf("# (The entries below are default and therefore commented out.)\n");
3691 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3693 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3696 for (i = 0; sound_config[i].token != NULL; i++)
3697 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3698 sound_config[i].value));
3702 else if (strcmp(command, "print musicinfo.conf") == 0)
3704 printf("# You can configure additional/alternative music files here.\n");
3705 printf("# (The entries below are default and therefore commented out.)\n");
3707 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3709 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3712 for (i = 0; music_config[i].token != NULL; i++)
3713 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3714 music_config[i].value));
3718 else if (strcmp(command, "print editorsetup.conf") == 0)
3720 printf("# You can configure your personal editor element list here.\n");
3721 printf("# (The entries below are default and therefore commented out.)\n");
3724 PrintEditorElementList();
3728 else if (strcmp(command, "print helpanim.conf") == 0)
3730 printf("# You can configure different element help animations here.\n");
3731 printf("# (The entries below are default and therefore commented out.)\n");
3734 for (i = 0; helpanim_config[i].token != NULL; i++)
3736 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3737 helpanim_config[i].value));
3739 if (strcmp(helpanim_config[i].token, "end") == 0)
3745 else if (strcmp(command, "print helptext.conf") == 0)
3747 printf("# You can configure different element help text here.\n");
3748 printf("# (The entries below are default and therefore commented out.)\n");
3751 for (i = 0; helptext_config[i].token != NULL; i++)
3752 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3753 helptext_config[i].value));
3757 else if (strncmp(command, "dump level ", 11) == 0)
3759 char *filename = &command[11];
3761 if (access(filename, F_OK) != 0)
3762 Error(ERR_EXIT, "cannot open file '%s'", filename);
3764 LoadLevelFromFilename(&level, filename);
3769 else if (strncmp(command, "dump tape ", 10) == 0)
3771 char *filename = &command[10];
3773 if (access(filename, F_OK) != 0)
3774 Error(ERR_EXIT, "cannot open file '%s'", filename);
3776 LoadTapeFromFilename(filename);
3781 else if (strncmp(command, "autoplay ", 9) == 0)
3783 char *str_copy = getStringCopy(&command[9]);
3784 char *str_ptr = strchr(str_copy, ' ');
3786 global.autoplay_leveldir = str_copy;
3787 global.autoplay_level_nr = -1;
3789 if (str_ptr != NULL)
3791 *str_ptr++ = '\0'; /* terminate leveldir string */
3792 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3795 else if (strncmp(command, "convert ", 8) == 0)
3797 char *str_copy = getStringCopy(&command[8]);
3798 char *str_ptr = strchr(str_copy, ' ');
3800 global.convert_leveldir = str_copy;
3801 global.convert_level_nr = -1;
3803 if (str_ptr != NULL)
3805 *str_ptr++ = '\0'; /* terminate leveldir string */
3806 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3811 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3815 static void InitSetup()
3817 LoadSetup(); /* global setup info */
3819 /* set some options from setup file */
3821 if (setup.options.verbose)
3822 options.verbose = TRUE;
3825 static void InitPlayerInfo()
3829 /* choose default local player */
3830 local_player = &stored_player[0];
3832 for (i = 0; i < MAX_PLAYERS; i++)
3833 stored_player[i].connected = FALSE;
3835 local_player->connected = TRUE;
3838 static void InitArtworkInfo()
3843 static char *get_string_in_brackets(char *string)
3845 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3847 sprintf(string_in_brackets, "[%s]", string);
3849 return string_in_brackets;
3852 static char *get_level_id_suffix(int id_nr)
3854 char *id_suffix = checked_malloc(1 + 3 + 1);
3856 if (id_nr < 0 || id_nr > 999)
3859 sprintf(id_suffix, ".%03d", id_nr);
3865 static char *get_element_class_token(int element)
3867 char *element_class_name = element_info[element].class_name;
3868 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3870 sprintf(element_class_token, "[%s]", element_class_name);
3872 return element_class_token;
3875 static char *get_action_class_token(int action)
3877 char *action_class_name = &element_action_info[action].suffix[1];
3878 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3880 sprintf(action_class_token, "[%s]", action_class_name);
3882 return action_class_token;
3886 static void InitArtworkConfig()
3888 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3889 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3890 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3891 static char *action_id_suffix[NUM_ACTIONS + 1];
3892 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3893 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3894 static char *level_id_suffix[MAX_LEVELS + 1];
3895 static char *dummy[1] = { NULL };
3896 static char *ignore_generic_tokens[] =
3902 static char **ignore_image_tokens;
3903 static char **ignore_sound_tokens;
3904 static char **ignore_music_tokens;
3905 int num_ignore_generic_tokens;
3906 int num_ignore_image_tokens;
3907 int num_ignore_sound_tokens;
3908 int num_ignore_music_tokens;
3911 /* dynamically determine list of generic tokens to be ignored */
3912 num_ignore_generic_tokens = 0;
3913 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3914 num_ignore_generic_tokens++;
3916 /* dynamically determine list of image tokens to be ignored */
3917 num_ignore_image_tokens = num_ignore_generic_tokens;
3918 for (i = 0; image_config_vars[i].token != NULL; i++)
3919 num_ignore_image_tokens++;
3920 ignore_image_tokens =
3921 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3922 for (i = 0; i < num_ignore_generic_tokens; i++)
3923 ignore_image_tokens[i] = ignore_generic_tokens[i];
3924 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3925 ignore_image_tokens[num_ignore_generic_tokens + i] =
3926 image_config_vars[i].token;
3927 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3929 /* dynamically determine list of sound tokens to be ignored */
3930 num_ignore_sound_tokens = num_ignore_generic_tokens;
3931 ignore_sound_tokens =
3932 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3933 for (i = 0; i < num_ignore_generic_tokens; i++)
3934 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3935 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3937 /* dynamically determine list of music tokens to be ignored */
3938 num_ignore_music_tokens = num_ignore_generic_tokens;
3939 ignore_music_tokens =
3940 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3941 for (i = 0; i < num_ignore_generic_tokens; i++)
3942 ignore_music_tokens[i] = ignore_generic_tokens[i];
3943 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3945 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3946 image_id_prefix[i] = element_info[i].token_name;
3947 for (i = 0; i < NUM_FONTS; i++)
3948 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3949 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3951 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3952 sound_id_prefix[i] = element_info[i].token_name;
3953 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3954 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3955 get_string_in_brackets(element_info[i].class_name);
3956 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3958 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3959 music_id_prefix[i] = music_prefix_info[i].prefix;
3960 music_id_prefix[MAX_LEVELS] = NULL;
3962 for (i = 0; i < NUM_ACTIONS; i++)
3963 action_id_suffix[i] = element_action_info[i].suffix;
3964 action_id_suffix[NUM_ACTIONS] = NULL;
3966 for (i = 0; i < NUM_DIRECTIONS; i++)
3967 direction_id_suffix[i] = element_direction_info[i].suffix;
3968 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3970 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3971 special_id_suffix[i] = special_suffix_info[i].suffix;
3972 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3974 for (i = 0; i < MAX_LEVELS; i++)
3975 level_id_suffix[i] = get_level_id_suffix(i);
3976 level_id_suffix[MAX_LEVELS] = NULL;
3978 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3979 image_id_prefix, action_id_suffix, direction_id_suffix,
3980 special_id_suffix, ignore_image_tokens);
3981 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3982 sound_id_prefix, action_id_suffix, dummy,
3983 special_id_suffix, ignore_sound_tokens);
3984 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3985 music_id_prefix, special_id_suffix, level_id_suffix,
3986 dummy, ignore_music_tokens);
3989 static void InitMixer()
3997 char *filename_font_initial = NULL;
3998 Bitmap *bitmap_font_initial = NULL;
4001 /* determine settings for initial font (for displaying startup messages) */
4002 for (i = 0; image_config[i].token != NULL; i++)
4004 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4006 char font_token[128];
4009 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4010 len_font_token = strlen(font_token);
4012 if (strcmp(image_config[i].token, font_token) == 0)
4013 filename_font_initial = image_config[i].value;
4014 else if (strlen(image_config[i].token) > len_font_token &&
4015 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4017 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4018 font_initial[j].src_x = atoi(image_config[i].value);
4019 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4020 font_initial[j].src_y = atoi(image_config[i].value);
4021 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4022 font_initial[j].width = atoi(image_config[i].value);
4023 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4024 font_initial[j].height = atoi(image_config[i].value);
4029 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4031 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4032 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4035 if (filename_font_initial == NULL) /* should not happen */
4036 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4038 /* create additional image buffers for double-buffering */
4039 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4040 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4042 /* initialize screen properties */
4043 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4044 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4046 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4047 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4048 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4050 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4052 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4053 font_initial[j].bitmap = bitmap_font_initial;
4055 InitFontGraphicInfo();
4057 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4058 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4060 DrawInitText("Loading graphics:", 120, FC_GREEN);
4062 InitTileClipmasks();
4065 void InitGfxBackground()
4069 drawto = backbuffer;
4070 fieldbuffer = bitmap_db_field;
4071 SetDrawtoField(DRAW_BACKBUFFER);
4073 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4074 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4075 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4076 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4078 for (x = 0; x < MAX_BUF_XSIZE; x++)
4079 for (y = 0; y < MAX_BUF_YSIZE; y++)
4082 redraw_mask = REDRAW_ALL;
4085 static void InitLevelInfo()
4087 LoadLevelInfo(); /* global level info */
4088 LoadLevelSetup_LastSeries(); /* last played series info */
4089 LoadLevelSetup_SeriesInfo(); /* last played level info */
4092 void InitLevelArtworkInfo()
4094 LoadLevelArtworkInfo();
4097 static void InitImages()
4100 setLevelArtworkDir(artwork.gfx_first);
4104 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4105 leveldir_current->identifier,
4106 artwork.gfx_current_identifier,
4107 artwork.gfx_current->identifier,
4108 leveldir_current->graphics_set,
4109 leveldir_current->graphics_path);
4112 ReloadCustomImages();
4114 LoadCustomElementDescriptions();
4115 LoadSpecialMenuDesignSettings();
4117 ReinitializeGraphics();
4120 static void InitSound(char *identifier)
4122 if (identifier == NULL)
4123 identifier = artwork.snd_current->identifier;
4126 /* set artwork path to send it to the sound server process */
4127 setLevelArtworkDir(artwork.snd_first);
4130 InitReloadCustomSounds(identifier);
4131 ReinitializeSounds();
4134 static void InitMusic(char *identifier)
4136 if (identifier == NULL)
4137 identifier = artwork.mus_current->identifier;
4140 /* set artwork path to send it to the sound server process */
4141 setLevelArtworkDir(artwork.mus_first);
4144 InitReloadCustomMusic(identifier);
4145 ReinitializeMusic();
4148 void InitNetworkServer()
4150 #if defined(NETWORK_AVALIABLE)
4154 if (!options.network)
4157 #if defined(NETWORK_AVALIABLE)
4158 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4160 if (!ConnectToServer(options.server_host, options.server_port))
4161 Error(ERR_EXIT, "cannot connect to network game server");
4163 SendToServer_PlayerName(setup.player_name);
4164 SendToServer_ProtocolVersion();
4167 SendToServer_NrWanted(nr_wanted);
4171 static char *getNewArtworkIdentifier(int type)
4173 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4174 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4175 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4176 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4177 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4178 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4179 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4180 char *leveldir_identifier = leveldir_current->identifier;
4182 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4183 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4185 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4187 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4188 char *artwork_current_identifier;
4189 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4191 /* leveldir_current may be invalid (level group, parent link) */
4192 if (!validLevelSeries(leveldir_current))
4195 /* 1st step: determine artwork set to be activated in descending order:
4196 --------------------------------------------------------------------
4197 1. setup artwork (when configured to override everything else)
4198 2. artwork set configured in "levelinfo.conf" of current level set
4199 (artwork in level directory will have priority when loading later)
4200 3. artwork in level directory (stored in artwork sub-directory)
4201 4. setup artwork (currently configured in setup menu) */
4203 if (setup_override_artwork)
4204 artwork_current_identifier = setup_artwork_set;
4205 else if (leveldir_artwork_set != NULL)
4206 artwork_current_identifier = leveldir_artwork_set;
4207 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4208 artwork_current_identifier = leveldir_identifier;
4210 artwork_current_identifier = setup_artwork_set;
4213 /* 2nd step: check if it is really needed to reload artwork set
4214 ------------------------------------------------------------ */
4217 if (type == ARTWORK_TYPE_GRAPHICS)
4218 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4219 artwork_new_identifier,
4220 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4221 artwork_current_identifier,
4222 leveldir_current->graphics_set,
4223 leveldir_current->identifier);
4226 /* ---------- reload if level set and also artwork set has changed ------- */
4227 if (leveldir_current_identifier[type] != leveldir_identifier &&
4228 (last_has_level_artwork_set[type] || has_level_artwork_set))
4229 artwork_new_identifier = artwork_current_identifier;
4231 leveldir_current_identifier[type] = leveldir_identifier;
4232 last_has_level_artwork_set[type] = has_level_artwork_set;
4235 if (type == ARTWORK_TYPE_GRAPHICS)
4236 printf("::: 1: '%s'\n", artwork_new_identifier);
4239 /* ---------- reload if "override artwork" setting has changed ----------- */
4240 if (last_override_level_artwork[type] != setup_override_artwork)
4241 artwork_new_identifier = artwork_current_identifier;
4243 last_override_level_artwork[type] = setup_override_artwork;
4246 if (type == ARTWORK_TYPE_GRAPHICS)
4247 printf("::: 2: '%s'\n", artwork_new_identifier);
4250 /* ---------- reload if current artwork identifier has changed ----------- */
4251 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4252 artwork_current_identifier) != 0)
4253 artwork_new_identifier = artwork_current_identifier;
4255 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4258 if (type == ARTWORK_TYPE_GRAPHICS)
4259 printf("::: 3: '%s'\n", artwork_new_identifier);
4262 /* ---------- do not reload directly after starting ---------------------- */
4263 if (!initialized[type])
4264 artwork_new_identifier = NULL;
4266 initialized[type] = TRUE;
4269 if (type == ARTWORK_TYPE_GRAPHICS)
4270 printf("::: 4: '%s'\n", artwork_new_identifier);
4274 if (type == ARTWORK_TYPE_GRAPHICS)
4275 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4276 artwork.gfx_current_identifier, artwork_current_identifier,
4277 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4278 artwork_new_identifier);
4281 return artwork_new_identifier;
4284 void ReloadCustomArtwork(int force_reload)
4286 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4287 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4288 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4289 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4290 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4291 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4292 boolean redraw_screen = FALSE;
4294 if (gfx_new_identifier != NULL || force_reload_gfx)
4297 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4298 artwork.gfx_current_identifier,
4300 artwork.gfx_current->identifier,
4301 leveldir_current->graphics_set);
4304 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4309 printf("... '%s'\n",
4310 leveldir_current->graphics_set);
4313 FreeTileClipmasks();
4314 InitTileClipmasks();
4316 redraw_screen = TRUE;
4319 if (snd_new_identifier != NULL || force_reload_snd)
4321 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4323 InitSound(snd_new_identifier);
4325 redraw_screen = TRUE;
4328 if (mus_new_identifier != NULL || force_reload_mus)
4330 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4332 InitMusic(mus_new_identifier);
4334 redraw_screen = TRUE;
4339 InitGfxBackground();
4341 /* force redraw of (open or closed) door graphics */
4342 SetDoorState(DOOR_OPEN_ALL);
4343 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4347 void KeyboardAutoRepeatOffUnlessAutoplay()
4349 if (global.autoplay_leveldir == NULL)
4350 KeyboardAutoRepeatOff();
4354 /* ========================================================================= */
4356 /* ========================================================================= */
4360 InitGlobal(); /* initialize some global variables */
4362 if (options.execute_command)
4363 Execute_Command(options.execute_command);
4365 if (options.serveronly)
4367 #if defined(PLATFORM_UNIX)
4368 NetworkServer(options.server_port, options.serveronly);
4370 Error(ERR_WARN, "networking only supported in Unix version");
4372 exit(0); /* never reached */
4378 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4379 InitArtworkConfig(); /* needed before forking sound child process */
4384 InitRND(NEW_RANDOMIZE);
4385 InitSimpleRND(NEW_RANDOMIZE);
4390 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4393 InitEventFilter(FilterMouseMotionEvents);
4395 InitElementPropertiesStatic();
4396 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4401 InitLevelArtworkInfo();
4403 InitImages(); /* needs to know current level directory */
4404 InitSound(NULL); /* needs to know current level directory */
4405 InitMusic(NULL); /* needs to know current level directory */
4407 InitGfxBackground();
4409 if (global.autoplay_leveldir)
4414 else if (global.convert_leveldir)
4420 game_status = GAME_MODE_MAIN;
4424 InitNetworkServer();
4427 void CloseAllAndExit(int exit_value)
4432 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4435 FreeTileClipmasks();
4437 #if defined(TARGET_SDL)
4438 if (network_server) /* terminate network server */
4439 SDL_KillThread(server_thread);
4442 CloseVideoDisplay();
4443 ClosePlatformDependentStuff();