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"
28 #include "conf_e2g.c" /* include auto-generated data structure definitions */
29 #include "conf_esg.c" /* include auto-generated data structure definitions */
30 #include "conf_e2s.c" /* include auto-generated data structure definitions */
31 #include "conf_fnt.c" /* include auto-generated data structure definitions */
34 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
40 static void InitTileClipmasks()
43 #if defined(TARGET_X11)
44 XGCValues clip_gc_values;
45 unsigned long clip_gc_valuemask;
47 #if defined(TARGET_X11_NATIVE)
57 tile_needs_clipping[] =
59 { GFX_SPIELER1_UP, 4 },
60 { GFX_SPIELER1_DOWN, 4 },
61 { GFX_SPIELER1_LEFT, 4 },
62 { GFX_SPIELER1_RIGHT, 4 },
63 { GFX_SPIELER1_PUSH_LEFT, 4 },
64 { GFX_SPIELER1_PUSH_RIGHT, 4 },
65 { GFX_SPIELER2_UP, 4 },
66 { GFX_SPIELER2_DOWN, 4 },
67 { GFX_SPIELER2_LEFT, 4 },
68 { GFX_SPIELER2_RIGHT, 4 },
69 { GFX_SPIELER2_PUSH_LEFT, 4 },
70 { GFX_SPIELER2_PUSH_RIGHT, 4 },
71 { GFX_SPIELER3_UP, 4 },
72 { GFX_SPIELER3_DOWN, 4 },
73 { GFX_SPIELER3_LEFT, 4 },
74 { GFX_SPIELER3_RIGHT, 4 },
75 { GFX_SPIELER3_PUSH_LEFT, 4 },
76 { GFX_SPIELER3_PUSH_RIGHT, 4 },
77 { GFX_SPIELER4_UP, 4 },
78 { GFX_SPIELER4_DOWN, 4 },
79 { GFX_SPIELER4_LEFT, 4 },
80 { GFX_SPIELER4_RIGHT, 4 },
81 { GFX_SPIELER4_PUSH_LEFT, 4 },
82 { GFX_SPIELER4_PUSH_RIGHT, 4 },
84 { GFX_MURPHY_GO_LEFT, 3 },
85 { GFX_MURPHY_GO_RIGHT, 3 },
86 { GFX_MURPHY_SNAP_UP, 1 },
87 { GFX_MURPHY_SNAP_DOWN, 1 },
88 { GFX_MURPHY_SNAP_RIGHT, 1 },
89 { GFX_MURPHY_SNAP_LEFT, 1 },
90 { GFX_MURPHY_PUSH_RIGHT, 1 },
91 { GFX_MURPHY_PUSH_LEFT, 1 },
96 { GFX_SOKOBAN_OBJEKT, 1 },
97 { GFX_FUNKELN_BLAU, 3 },
98 { GFX_FUNKELN_WEISS, 3 },
99 { GFX2_SHIELD_PASSIVE, 3 },
100 { GFX2_SHIELD_ACTIVE, 3 },
105 #endif /* TARGET_X11_NATIVE */
106 #endif /* TARGET_X11 */
110 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
111 for (i=0; i<NUM_TILES; i++)
112 tile_clipmask[i] = None;
114 #if defined(TARGET_X11)
115 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
116 often very slow when preparing a masked XCopyArea() for big Pixmaps.
117 To prevent this, create small (tile-sized) mask Pixmaps which will then
118 be set much faster with XSetClipOrigin() and speed things up a lot. */
120 clip_gc_values.graphics_exposures = False;
121 clip_gc_valuemask = GCGraphicsExposures;
122 tile_clip_gc = XCreateGC(display, window->drawable,
123 clip_gc_valuemask, &clip_gc_values);
126 for (i=0; i<NUM_BITMAPS; i++)
128 if (pix[i]->clip_mask)
130 clip_gc_values.graphics_exposures = False;
131 clip_gc_values.clip_mask = pix[i]->clip_mask;
132 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
133 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
134 clip_gc_valuemask, &clip_gc_values);
139 #if defined(TARGET_X11_NATIVE)
142 /* create graphic context structures needed for clipping */
143 clip_gc_values.graphics_exposures = False;
144 clip_gc_valuemask = GCGraphicsExposures;
145 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
146 clip_gc_valuemask, &clip_gc_values);
148 /* create only those clipping Pixmaps we really need */
149 for (i=0; tile_needs_clipping[i].start>=0; i++)
153 for (j=0; j<tile_needs_clipping[i].count; j++)
155 int tile = tile_needs_clipping[i].start + j;
161 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
162 src_pixmap = src_bitmap->clip_mask;
164 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
167 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
168 src_x, src_y, TILEX, TILEY, 0, 0);
172 XFreeGC(display, copy_clipmask_gc);
175 #endif /* TARGET_X11_NATIVE */
176 #endif /* TARGET_X11 */
180 void FreeTileClipmasks()
183 #if defined(TARGET_X11)
186 for (i=0; i<NUM_TILES; i++)
188 if (tile_clipmask[i] != None)
190 XFreePixmap(display, tile_clipmask[i]);
191 tile_clipmask[i] = None;
196 XFreeGC(display, tile_clip_gc);
200 for (i=0; i<NUM_BITMAPS; i++)
202 if (pix[i] != NULL && pix[i]->stored_clip_gc)
204 XFreeGC(display, pix[i]->stored_clip_gc);
205 pix[i]->stored_clip_gc = None;
210 #endif /* TARGET_X11 */
216 FreeLevelEditorGadgets();
225 static boolean gadgets_initialized = FALSE;
227 if (gadgets_initialized)
230 CreateLevelEditorGadgets();
234 CreateScreenGadgets();
236 gadgets_initialized = TRUE;
239 void InitElementSmallImages()
241 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
242 int num_property_mappings = getImageListPropertyMappingSize();
245 /* initialize normal images from static configuration */
246 for (i=0; element_to_graphic[i].element > -1; i++)
247 CreateImageWithSmallImages(element_to_graphic[i].graphic);
249 /* initialize special images from static configuration */
250 for (i=0; element_to_special_graphic[i].element > -1; i++)
251 CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
253 /* initialize images from dynamic configuration */
254 for (i=0; i < num_property_mappings; i++)
255 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
256 CreateImageWithSmallImages(property_mapping[i].artwork_index);
259 static int getFontBitmapID(int font_nr)
263 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
264 special = game_status;
265 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
266 special = GFX_SPECIAL_ARG_MAIN;
267 else if (game_status == GAME_MODE_PLAYING)
268 special = GFX_SPECIAL_ARG_DOOR;
271 return font_info[font_nr].special_bitmap_id[special];
276 void InitFontGraphicInfo()
278 static struct FontBitmapInfo *font_bitmap_info = NULL;
279 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
280 int num_property_mappings = getImageListPropertyMappingSize();
281 int num_font_bitmaps = NUM_FONTS;
284 if (graphic_info == NULL) /* still at startup phase */
286 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
291 /* ---------- initialize font graphic definitions ---------- */
293 /* always start with reliable default values (normal font graphics) */
295 for (i=0; i < NUM_FONTS; i++)
296 font_info[i].graphic = IMG_FONT_INITIAL_1;
298 for (i=0; i < NUM_FONTS; i++)
299 font_info[i].graphic = FONT_INITIAL_1;
302 /* initialize normal font/graphic mapping from static configuration */
303 for (i=0; font_to_graphic[i].font_nr > -1; i++)
305 int font_nr = font_to_graphic[i].font_nr;
306 int special = font_to_graphic[i].special;
307 int graphic = font_to_graphic[i].graphic;
312 font_info[font_nr].graphic = graphic;
315 /* always start with reliable default values (special font graphics) */
316 for (i=0; i < NUM_FONTS; i++)
318 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
320 font_info[i].special_graphic[j] = font_info[i].graphic;
321 font_info[i].special_bitmap_id[j] = i;
325 /* initialize special font/graphic mapping from static configuration */
326 for (i=0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
332 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
334 font_info[font_nr].special_graphic[special] = graphic;
335 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
340 /* initialize special element/graphic mapping from dynamic configuration */
341 for (i=0; i < num_property_mappings; i++)
343 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
344 int special = property_mapping[i].ext3_index;
345 int graphic = property_mapping[i].artwork_index;
350 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
352 font_info[font_nr].special_graphic[special] = graphic;
353 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
358 /* ---------- initialize font bitmap array ---------- */
360 if (font_bitmap_info != NULL)
361 FreeFontInfo(font_bitmap_info);
364 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
366 /* ---------- initialize font bitmap definitions ---------- */
368 for (i=0; i < NUM_FONTS; i++)
370 if (i < NUM_INITIAL_FONTS)
372 font_bitmap_info[i] = font_initial[i];
376 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
378 int font_bitmap_id = font_info[i].special_bitmap_id[j];
379 int graphic = font_info[i].special_graphic[j];
381 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
382 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
384 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
385 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
388 /* copy font relevant information from graphics information */
389 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
390 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
391 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
392 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
393 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
394 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
395 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
397 font_bitmap_info[font_bitmap_id].num_chars =
398 graphic_info[graphic].anim_frames;
399 font_bitmap_info[font_bitmap_id].num_chars_per_line =
400 graphic_info[graphic].anim_frames_per_line;
404 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
407 void InitElementGraphicInfo()
409 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
410 int num_property_mappings = getImageListPropertyMappingSize();
413 /* set values to -1 to identify later as "uninitialized" values */
414 for (i=0; i<MAX_NUM_ELEMENTS; i++)
416 for (act=0; act<NUM_ACTIONS; act++)
418 element_info[i].graphic[act] = -1;
419 element_info[i].crumbled[act] = -1;
421 for (dir=0; dir<NUM_DIRECTIONS; dir++)
423 element_info[i].direction_graphic[act][dir] = -1;
424 element_info[i].direction_crumbled[act][dir] = -1;
429 /* initialize normal element/graphic mapping from static configuration */
430 for (i=0; element_to_graphic[i].element > -1; i++)
432 int element = element_to_graphic[i].element;
433 int action = element_to_graphic[i].action;
434 int direction = element_to_graphic[i].direction;
435 boolean crumbled = element_to_graphic[i].crumbled;
436 int graphic = element_to_graphic[i].graphic;
438 if (graphic_info[graphic].bitmap == NULL)
441 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
442 el2img(element) != -1)
444 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
445 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
447 /* if the base graphic ("emerald", for example) has been redefined,
448 but not the action graphic ("emerald.falling", for example), do not
449 use an existing (in this case considered obsolete) action graphic
450 anymore, but use the automatically determined default graphic */
451 if (base_redefined && !act_dir_redefined)
456 action = ACTION_DEFAULT;
461 element_info[element].direction_crumbled[action][direction] = graphic;
463 element_info[element].crumbled[action] = graphic;
468 element_info[element].direction_graphic[action][direction] = graphic;
470 element_info[element].graphic[action] = graphic;
474 /* initialize normal element/graphic mapping from dynamic configuration */
475 for (i=0; i < num_property_mappings; i++)
477 int element = property_mapping[i].base_index;
478 int action = property_mapping[i].ext1_index;
479 int direction = property_mapping[i].ext2_index;
480 int special = property_mapping[i].ext3_index;
481 int graphic = property_mapping[i].artwork_index;
482 boolean crumbled = FALSE;
484 if (special == GFX_SPECIAL_ARG_CRUMBLED)
490 if (graphic_info[graphic].bitmap == NULL)
493 if (element >= MAX_NUM_ELEMENTS || special != -1)
497 action = ACTION_DEFAULT;
502 for (dir=0; dir<NUM_DIRECTIONS; dir++)
503 element_info[element].direction_crumbled[action][dir] = -1;
506 element_info[element].direction_crumbled[action][direction] = graphic;
508 element_info[element].crumbled[action] = graphic;
513 for (dir=0; dir<NUM_DIRECTIONS; dir++)
514 element_info[element].direction_graphic[action][dir] = -1;
517 element_info[element].direction_graphic[action][direction] = graphic;
519 element_info[element].graphic[action] = graphic;
523 /* now copy all graphics that are defined to be cloned from other graphics */
524 for (i=0; i<MAX_NUM_ELEMENTS; i++)
526 int graphic = element_info[i].graphic[ACTION_DEFAULT];
527 int crumbled_like, diggable_like;
532 crumbled_like = graphic_info[graphic].crumbled_like;
533 diggable_like = graphic_info[graphic].diggable_like;
535 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
537 for (act=0; act<NUM_ACTIONS; act++)
538 element_info[i].crumbled[act] =
539 element_info[crumbled_like].crumbled[act];
540 for (act=0; act<NUM_ACTIONS; act++)
541 for (dir=0; dir<NUM_DIRECTIONS; dir++)
542 element_info[i].direction_crumbled[act][dir] =
543 element_info[crumbled_like].direction_crumbled[act][dir];
546 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
548 element_info[i].graphic[ACTION_DIGGING] =
549 element_info[diggable_like].graphic[ACTION_DIGGING];
550 for (dir=0; dir<NUM_DIRECTIONS; dir++)
551 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
552 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
557 /* now set all undefined/invalid graphics to -1 to set to default after it */
558 for (i=0; i<MAX_NUM_ELEMENTS; i++)
560 for (act=0; act<NUM_ACTIONS; act++)
564 graphic = element_info[i].graphic[act];
565 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
566 element_info[i].graphic[act] = -1;
568 graphic = element_info[i].crumbled[act];
569 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
570 element_info[i].crumbled[act] = -1;
572 for (dir=0; dir<NUM_DIRECTIONS; dir++)
574 graphic = element_info[i].direction_graphic[act][dir];
575 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
576 element_info[i].direction_graphic[act][dir] = -1;
578 graphic = element_info[i].direction_crumbled[act][dir];
579 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
580 element_info[i].direction_crumbled[act][dir] = -1;
586 /* now set all '-1' values to element specific default values */
587 for (i=0; i<MAX_NUM_ELEMENTS; i++)
589 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
590 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
591 int default_direction_graphic[NUM_DIRECTIONS];
592 int default_direction_crumbled[NUM_DIRECTIONS];
594 if (default_graphic == -1)
595 default_graphic = IMG_CHAR_QUESTION;
596 if (default_crumbled == -1)
597 default_crumbled = IMG_EMPTY;
599 for (dir=0; dir<NUM_DIRECTIONS; dir++)
601 default_direction_graphic[dir] =
602 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
603 default_direction_crumbled[dir] =
604 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
606 if (default_direction_graphic[dir] == -1)
607 default_direction_graphic[dir] = default_graphic;
608 if (default_direction_crumbled[dir] == -1)
609 default_direction_crumbled[dir] = default_crumbled;
612 for (act=0; act<NUM_ACTIONS; act++)
614 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
615 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
616 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
618 /* generic default action graphic (defined by "[default]" directive) */
619 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
620 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
622 /* look for special default action graphic (classic game specific) */
623 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
624 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
625 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
626 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
627 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
628 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
630 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
631 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
632 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
633 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
634 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
635 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
637 if (default_action_graphic == -1)
638 default_action_graphic = default_graphic;
639 if (default_action_crumbled == -1)
640 default_action_crumbled = default_crumbled;
642 for (dir=0; dir<NUM_DIRECTIONS; dir++)
644 int default_action_direction_graphic = element_info[i].graphic[act];
645 int default_action_direction_crumbled = element_info[i].crumbled[act];
647 /* no graphic for current action -- use default direction graphic */
648 if (default_action_direction_graphic == -1)
649 default_action_direction_graphic =
650 (act_remove ? IMG_EMPTY : default_direction_graphic[dir]);
651 if (default_action_direction_crumbled == -1)
652 default_action_direction_crumbled =
653 (act_remove ? IMG_EMPTY : default_direction_crumbled[dir]);
655 if (element_info[i].direction_graphic[act][dir] == -1)
656 element_info[i].direction_graphic[act][dir] =
657 default_action_direction_graphic;
658 if (element_info[i].direction_crumbled[act][dir] == -1)
659 element_info[i].direction_crumbled[act][dir] =
660 default_action_direction_crumbled;
663 /* no graphic for this specific action -- use default action graphic */
664 if (element_info[i].graphic[act] == -1)
665 element_info[i].graphic[act] =
666 (act_remove ? IMG_EMPTY : default_action_graphic);
667 if (element_info[i].crumbled[act] == -1)
668 element_info[i].crumbled[act] =
669 (act_remove ? IMG_EMPTY : default_action_crumbled);
674 /* set animation mode to "none" for each graphic with only 1 frame */
675 for (i=0; i<MAX_NUM_ELEMENTS; i++)
677 for (act=0; act<NUM_ACTIONS; act++)
679 int graphic = element_info[i].graphic[act];
680 int crumbled = element_info[i].crumbled[act];
682 if (graphic_info[graphic].anim_frames == 1)
683 graphic_info[graphic].anim_mode = ANIM_NONE;
684 if (graphic_info[crumbled].anim_frames == 1)
685 graphic_info[crumbled].anim_mode = ANIM_NONE;
687 for (dir=0; dir<NUM_DIRECTIONS; dir++)
689 graphic = element_info[i].direction_graphic[act][dir];
690 crumbled = element_info[i].direction_crumbled[act][dir];
692 if (graphic_info[graphic].anim_frames == 1)
693 graphic_info[graphic].anim_mode = ANIM_NONE;
694 if (graphic_info[crumbled].anim_frames == 1)
695 graphic_info[crumbled].anim_mode = ANIM_NONE;
705 for (i=0; i<MAX_NUM_ELEMENTS; i++)
706 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
707 i != EL_CHAR_QUESTION)
708 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
709 element_info[i].token_name, i);
715 void InitElementSpecialGraphicInfo()
717 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
718 int num_property_mappings = getImageListPropertyMappingSize();
721 /* always start with reliable default values */
722 for (i=0; i < MAX_NUM_ELEMENTS; i++)
723 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
724 element_info[i].special_graphic[j] =
725 element_info[i].graphic[ACTION_DEFAULT];
727 /* initialize special element/graphic mapping from static configuration */
728 for (i=0; element_to_special_graphic[i].element > -1; i++)
730 int element = element_to_special_graphic[i].element;
731 int special = element_to_special_graphic[i].special;
732 int graphic = element_to_special_graphic[i].graphic;
733 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
734 boolean special_redefined = getImageListEntry(graphic)->redefined;
736 /* if the base graphic ("emerald", for example) has been redefined,
737 but not the special graphic ("emerald.EDITOR", for example), do not
738 use an existing (in this case considered obsolete) special graphic
739 anymore, but use the automatically created (down-scaled) graphic */
740 if (base_redefined && !special_redefined)
743 element_info[element].special_graphic[special] = graphic;
746 /* initialize special element/graphic mapping from dynamic configuration */
747 for (i=0; i < num_property_mappings; i++)
749 int element = property_mapping[i].base_index;
750 int special = property_mapping[i].ext3_index;
751 int graphic = property_mapping[i].artwork_index;
753 if (element >= MAX_NUM_ELEMENTS)
756 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
757 element_info[element].special_graphic[special] = graphic;
761 /* now set all undefined/invalid graphics to default */
762 for (i=0; i < MAX_NUM_ELEMENTS; i++)
763 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
764 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
765 element_info[i].special_graphic[j] =
766 element_info[i].graphic[ACTION_DEFAULT];
770 static int get_element_from_token(char *token)
774 for (i=0; i < MAX_NUM_ELEMENTS; i++)
775 if (strcmp(element_info[i].token_name, token) == 0)
781 static void set_graphic_parameters(int graphic, char **parameter_raw)
783 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
784 int parameter[NUM_GFX_ARGS];
785 int anim_frames_per_row = 1, anim_frames_per_col = 1;
786 int anim_frames_per_line = 1;
789 /* get integer values from string parameters */
790 for (i=0; i < NUM_GFX_ARGS; i++)
793 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
794 image_config_suffix[i].type);
796 if (image_config_suffix[i].type == TYPE_TOKEN)
797 parameter[i] = get_element_from_token(parameter_raw[i]);
800 graphic_info[graphic].bitmap = src_bitmap;
802 /* start with reliable default values */
803 graphic_info[graphic].src_x = 0;
804 graphic_info[graphic].src_y = 0;
805 graphic_info[graphic].width = TILEX;
806 graphic_info[graphic].height = TILEY;
807 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
808 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
809 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
810 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
811 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
813 /* optional x and y tile position of animation frame sequence */
814 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
815 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
816 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
817 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
819 /* optional x and y pixel position of animation frame sequence */
820 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
821 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
822 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
823 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
825 /* optional width and height of each animation frame */
826 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
827 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
828 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
829 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
833 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
834 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
837 /* correct x or y offset dependent of vertical or horizontal frame order */
838 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
840 graphic_info[graphic].offset_y =
841 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
842 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
843 anim_frames_per_line = anim_frames_per_col;
845 else /* frames are ordered horizontally */
847 graphic_info[graphic].offset_x =
848 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
849 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
850 anim_frames_per_line = anim_frames_per_row;
853 /* optionally, the x and y offset of frames can be specified directly */
854 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
855 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
856 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
857 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
859 /* automatically determine correct number of frames, if not defined */
860 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
861 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
862 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
863 graphic_info[graphic].anim_frames = anim_frames_per_row;
864 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
865 graphic_info[graphic].anim_frames = anim_frames_per_col;
867 graphic_info[graphic].anim_frames = 1;
869 graphic_info[graphic].anim_frames_per_line =
870 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
871 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
873 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
874 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
875 graphic_info[graphic].anim_delay = 1;
877 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
879 if (graphic_info[graphic].anim_frames == 1)
880 graphic_info[graphic].anim_mode = ANIM_NONE;
883 /* automatically determine correct start frame, if not defined */
884 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].anim_start_frame = 0;
886 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
887 graphic_info[graphic].anim_start_frame =
888 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
890 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
892 /* animation synchronized with global frame counter, not move position */
893 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
895 /* optional element for cloning crumble graphics */
896 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
897 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
899 /* optional element for cloning digging graphics */
900 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
901 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
903 /* optional border size for "crumbling" diggable graphics */
904 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
905 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
907 /* this is only used for toon animations */
908 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
909 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
911 /* this is only used for drawing font characters */
912 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
913 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
915 /* this is only used for drawing envelope graphics */
916 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
919 static void InitGraphicInfo()
921 int fallback_graphic = IMG_CHAR_EXCLAM;
922 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
923 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
924 int num_images = getImageListSize();
927 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
928 static boolean clipmasks_initialized = FALSE;
930 XGCValues clip_gc_values;
931 unsigned long clip_gc_valuemask;
932 GC copy_clipmask_gc = None;
935 if (graphic_info != NULL)
938 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
941 printf("::: graphic_info: %d entries\n", num_images);
944 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
945 if (clipmasks_initialized)
947 for (i=0; i<num_images; i++)
949 if (graphic_info[i].clip_mask)
950 XFreePixmap(display, graphic_info[i].clip_mask);
951 if (graphic_info[i].clip_gc)
952 XFreeGC(display, graphic_info[i].clip_gc);
954 graphic_info[i].clip_mask = None;
955 graphic_info[i].clip_gc = None;
960 for (i=0; i<num_images; i++)
962 struct FileInfo *image = getImageListEntry(i);
965 int first_frame, last_frame;
968 printf("::: image: '%s' [%d]\n", image->token, i);
972 printf("::: image # %d: '%s' ['%s']\n",
974 getTokenFromImageID(i));
977 set_graphic_parameters(i, image->parameter);
979 /* now check if no animation frames are outside of the loaded image */
981 if (graphic_info[i].bitmap == NULL)
982 continue; /* skip check for optional images that are undefined */
985 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
986 if (src_x < 0 || src_y < 0 ||
987 src_x + TILEX > src_bitmap->width ||
988 src_y + TILEY > src_bitmap->height)
990 Error(ERR_RETURN_LINE, "-");
991 Error(ERR_RETURN, "warning: error found in config file:");
992 Error(ERR_RETURN, "- config file: '%s'",
993 getImageConfigFilename());
994 Error(ERR_RETURN, "- config token: '%s'",
995 getTokenFromImageID(i));
996 Error(ERR_RETURN, "- image file: '%s'",
997 src_bitmap->source_filename);
999 "error: first animation frame out of bounds (%d, %d)",
1001 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1003 if (i == fallback_graphic)
1004 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1006 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1007 Error(ERR_RETURN_LINE, "-");
1009 set_graphic_parameters(i, fallback_image->default_parameter);
1010 graphic_info[i].bitmap = fallback_bitmap;
1013 last_frame = graphic_info[i].anim_frames - 1;
1014 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1015 if (src_x < 0 || src_y < 0 ||
1016 src_x + TILEX > src_bitmap->width ||
1017 src_y + TILEY > src_bitmap->height)
1019 Error(ERR_RETURN_LINE, "-");
1020 Error(ERR_RETURN, "warning: error found in config file:");
1021 Error(ERR_RETURN, "- config file: '%s'",
1022 getImageConfigFilename());
1023 Error(ERR_RETURN, "- config token: '%s'",
1024 getTokenFromImageID(i));
1025 Error(ERR_RETURN, "- image file: '%s'",
1026 src_bitmap->source_filename);
1028 "error: last animation frame (%d) out of bounds (%d, %d)",
1029 last_frame, src_x, src_y);
1030 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1032 if (i == fallback_graphic)
1033 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1035 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1036 Error(ERR_RETURN_LINE, "-");
1038 set_graphic_parameters(i, fallback_image->default_parameter);
1039 graphic_info[i].bitmap = fallback_bitmap;
1042 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1043 /* currently we need only a tile clip mask from the first frame */
1044 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1046 if (copy_clipmask_gc == None)
1048 clip_gc_values.graphics_exposures = False;
1049 clip_gc_valuemask = GCGraphicsExposures;
1050 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1051 clip_gc_valuemask, &clip_gc_values);
1054 graphic_info[i].clip_mask =
1055 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1057 src_pixmap = src_bitmap->clip_mask;
1058 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1059 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1061 clip_gc_values.graphics_exposures = False;
1062 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1063 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1065 graphic_info[i].clip_gc =
1066 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1070 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1071 if (copy_clipmask_gc)
1072 XFreeGC(display, copy_clipmask_gc);
1074 clipmasks_initialized = TRUE;
1078 static void InitElementSoundInfo()
1080 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1081 int num_property_mappings = getSoundListPropertyMappingSize();
1084 /* set values to -1 to identify later as "uninitialized" values */
1085 for (i=0; i < MAX_NUM_ELEMENTS; i++)
1086 for (act=0; act < NUM_ACTIONS; act++)
1087 element_info[i].sound[act] = -1;
1089 /* initialize element/sound mapping from static configuration */
1090 for (i=0; element_to_sound[i].element > -1; i++)
1092 int element = element_to_sound[i].element;
1093 int action = element_to_sound[i].action;
1094 int sound = element_to_sound[i].sound;
1095 boolean is_class = element_to_sound[i].is_class;
1098 action = ACTION_DEFAULT;
1101 element_info[element].sound[action] = sound;
1103 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1104 if (strcmp(element_info[j].class_name,
1105 element_info[element].class_name) == 0)
1106 element_info[j].sound[action] = sound;
1109 /* initialize element class/sound mapping from dynamic configuration */
1110 for (i=0; i < num_property_mappings; i++)
1112 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1113 int action = property_mapping[i].ext1_index;
1114 int sound = property_mapping[i].artwork_index;
1116 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1120 action = ACTION_DEFAULT;
1122 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1123 if (strcmp(element_info[j].class_name,
1124 element_info[element_class].class_name) == 0)
1125 element_info[j].sound[action] = sound;
1128 /* initialize element/sound mapping from dynamic configuration */
1129 for (i=0; i < num_property_mappings; i++)
1131 int element = property_mapping[i].base_index;
1132 int action = property_mapping[i].ext1_index;
1133 int sound = property_mapping[i].artwork_index;
1135 if (element >= MAX_NUM_ELEMENTS)
1139 action = ACTION_DEFAULT;
1141 element_info[element].sound[action] = sound;
1144 /* now set all '-1' values to element specific default values */
1145 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1147 for (act=0; act < NUM_ACTIONS; act++)
1149 /* generic default action sound (defined by "[default]" directive) */
1150 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1152 /* look for special default action sound (classic game specific) */
1153 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1154 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1155 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1156 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1157 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1158 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1160 /* look for element specific default sound (independent from action) */
1161 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1162 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1164 /* no sound for this specific action -- use default action sound */
1165 if (element_info[i].sound[act] == -1)
1166 element_info[i].sound[act] = default_action_sound;
1171 static void set_sound_parameters(int sound, char **parameter_raw)
1173 int parameter[NUM_SND_ARGS];
1176 /* get integer values from string parameters */
1177 for (i=0; i < NUM_SND_ARGS; i++)
1179 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1180 sound_config_suffix[i].type);
1182 /* explicit loop mode setting in configuration overrides default value */
1183 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1184 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1187 static void InitSoundInfo()
1190 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1191 int num_property_mappings = getSoundListPropertyMappingSize();
1193 int *sound_effect_properties;
1194 int num_sounds = getSoundListSize();
1197 if (sound_info != NULL)
1200 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1201 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1203 /* initialize sound effect for all elements to "no sound" */
1204 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1205 for (j=0; j<NUM_ACTIONS; j++)
1206 element_info[i].sound[j] = SND_UNDEFINED;
1208 for (i=0; i<num_sounds; i++)
1210 struct FileInfo *sound = getSoundListEntry(i);
1211 int len_effect_text = strlen(sound->token);
1213 sound_effect_properties[i] = ACTION_OTHER;
1214 sound_info[i].loop = FALSE;
1217 printf("::: sound %d: '%s'\n", i, sound->token);
1220 /* determine all loop sounds and identify certain sound classes */
1222 for (j=0; element_action_info[j].suffix; j++)
1224 int len_action_text = strlen(element_action_info[j].suffix);
1226 if (len_action_text < len_effect_text &&
1227 strcmp(&sound->token[len_effect_text - len_action_text],
1228 element_action_info[j].suffix) == 0)
1230 sound_effect_properties[i] = element_action_info[j].value;
1231 sound_info[i].loop = element_action_info[j].is_loop_sound;
1238 if (strcmp(sound->token, "custom_42") == 0)
1239 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1242 /* associate elements and some selected sound actions */
1244 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1246 if (element_info[j].class_name)
1248 int len_class_text = strlen(element_info[j].class_name);
1250 if (len_class_text + 1 < len_effect_text &&
1251 strncmp(sound->token,
1252 element_info[j].class_name, len_class_text) == 0 &&
1253 sound->token[len_class_text] == '.')
1255 int sound_action_value = sound_effect_properties[i];
1257 element_info[j].sound[sound_action_value] = i;
1262 set_sound_parameters(i, sound->parameter);
1265 free(sound_effect_properties);
1268 /* !!! now handled in InitElementSoundInfo() !!! */
1269 /* initialize element/sound mapping from dynamic configuration */
1270 for (i=0; i < num_property_mappings; i++)
1272 int element = property_mapping[i].base_index;
1273 int action = property_mapping[i].ext1_index;
1274 int sound = property_mapping[i].artwork_index;
1277 action = ACTION_DEFAULT;
1279 printf("::: %d: %d, %d, %d ['%s']\n",
1280 i, element, action, sound, element_info[element].token_name);
1282 element_info[element].sound[action] = sound;
1289 int element = EL_CUSTOM_11;
1292 while (element_action_info[j].suffix)
1294 printf("element %d, sound action '%s' == %d\n",
1295 element, element_action_info[j].suffix,
1296 element_info[element].sound[j]);
1301 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1307 int element = EL_SAND;
1308 int sound_action = ACTION_DIGGING;
1311 while (element_action_info[j].suffix)
1313 if (element_action_info[j].value == sound_action)
1314 printf("element %d, sound action '%s' == %d\n",
1315 element, element_action_info[j].suffix,
1316 element_info[element].sound[sound_action]);
1323 static void ReinitializeGraphics()
1325 InitGraphicInfo(); /* graphic properties mapping */
1326 InitElementGraphicInfo(); /* element game graphic mapping */
1327 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1329 InitElementSmallImages(); /* create editor and preview images */
1330 InitFontGraphicInfo(); /* initialize text drawing functions */
1332 SetMainBackgroundImage(IMG_BACKGROUND);
1333 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1339 static void ReinitializeSounds()
1341 InitSoundInfo(); /* sound properties mapping */
1342 InitElementSoundInfo(); /* element game sound mapping */
1344 InitPlaySoundLevel(); /* internal game sound settings */
1347 static void ReinitializeMusic()
1349 /* currently nothing to do */
1352 void InitElementPropertiesStatic()
1354 static int ep_diggable[] =
1359 EL_SP_BUGGY_BASE_ACTIVATING,
1362 EL_INVISIBLE_SAND_ACTIVE,
1364 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1368 EL_SP_BUGGY_BASE_ACTIVE,
1373 static int ep_collectible_only[] =
1390 EL_DYNABOMB_INCREASE_NUMBER,
1391 EL_DYNABOMB_INCREASE_SIZE,
1392 EL_DYNABOMB_INCREASE_POWER,
1409 static int ep_dont_run_into[] =
1411 /* same elements as in 'ep_dont_touch' */
1417 /* same elements as in 'ep_dont_collide_with' */
1429 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1433 EL_SP_BUGGY_BASE_ACTIVE,
1438 static int ep_dont_collide_with[] =
1440 /* same elements as in 'ep_dont_touch' */
1456 static int ep_dont_touch[] =
1465 static int ep_indestructible[] =
1469 EL_ACID_POOL_TOPLEFT,
1470 EL_ACID_POOL_TOPRIGHT,
1471 EL_ACID_POOL_BOTTOMLEFT,
1472 EL_ACID_POOL_BOTTOM,
1473 EL_ACID_POOL_BOTTOMRIGHT,
1474 EL_SP_HARDWARE_GRAY,
1475 EL_SP_HARDWARE_GREEN,
1476 EL_SP_HARDWARE_BLUE,
1478 EL_SP_HARDWARE_YELLOW,
1479 EL_SP_HARDWARE_BASE_1,
1480 EL_SP_HARDWARE_BASE_2,
1481 EL_SP_HARDWARE_BASE_3,
1482 EL_SP_HARDWARE_BASE_4,
1483 EL_SP_HARDWARE_BASE_5,
1484 EL_SP_HARDWARE_BASE_6,
1485 EL_INVISIBLE_STEELWALL,
1486 EL_INVISIBLE_STEELWALL_ACTIVE,
1487 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1488 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1489 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1490 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1491 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1492 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1493 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1494 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1495 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1496 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1497 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1498 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1500 EL_LIGHT_SWITCH_ACTIVE,
1501 EL_SIGN_EXCLAMATION,
1502 EL_SIGN_RADIOACTIVITY,
1513 EL_STEELWALL_SLIPPERY,
1536 EL_SWITCHGATE_OPENING,
1537 EL_SWITCHGATE_CLOSED,
1538 EL_SWITCHGATE_CLOSING,
1540 EL_SWITCHGATE_SWITCH_UP,
1541 EL_SWITCHGATE_SWITCH_DOWN,
1544 EL_TIMEGATE_OPENING,
1546 EL_TIMEGATE_CLOSING,
1549 EL_TIMEGATE_SWITCH_ACTIVE,
1554 EL_TUBE_VERTICAL_LEFT,
1555 EL_TUBE_VERTICAL_RIGHT,
1556 EL_TUBE_HORIZONTAL_UP,
1557 EL_TUBE_HORIZONTAL_DOWN,
1565 static int ep_slippery[] =
1579 EL_ROBOT_WHEEL_ACTIVE,
1585 EL_ACID_POOL_TOPLEFT,
1586 EL_ACID_POOL_TOPRIGHT,
1596 EL_STEELWALL_SLIPPERY,
1602 static int ep_can_change[] =
1607 static int ep_can_move[] =
1629 static int ep_can_fall[] =
1644 EL_BD_MAGIC_WALL_FULL,
1657 static int ep_can_smash_player[] =
1682 static int ep_can_smash_enemies[] =
1690 static int ep_can_smash_everything[] =
1698 static int ep_can_explode_by_fire[] =
1700 /* same elements as in 'ep_can_explode_impact' */
1705 /* same elements as in 'ep_can_explode_smashed' */
1714 EL_DYNABOMB_PLAYER_1_ACTIVE,
1715 EL_DYNABOMB_PLAYER_2_ACTIVE,
1716 EL_DYNABOMB_PLAYER_3_ACTIVE,
1717 EL_DYNABOMB_PLAYER_4_ACTIVE,
1718 EL_DYNABOMB_INCREASE_NUMBER,
1719 EL_DYNABOMB_INCREASE_SIZE,
1720 EL_DYNABOMB_INCREASE_POWER,
1721 EL_SP_DISK_RED_ACTIVE,
1731 static int ep_can_explode_smashed[] =
1733 /* same elements as in 'ep_can_explode_impact' */
1746 static int ep_can_explode_impact[] =
1754 static int ep_walkable_over[] =
1758 EL_SOKOBAN_FIELD_EMPTY,
1775 static int ep_walkable_inside[] =
1780 EL_TUBE_VERTICAL_LEFT,
1781 EL_TUBE_VERTICAL_RIGHT,
1782 EL_TUBE_HORIZONTAL_UP,
1783 EL_TUBE_HORIZONTAL_DOWN,
1791 static int ep_walkable_under[] =
1796 static int ep_passable_over[] =
1811 static int ep_passable_inside[] =
1817 EL_SP_PORT_HORIZONTAL,
1818 EL_SP_PORT_VERTICAL,
1820 EL_SP_GRAVITY_PORT_LEFT,
1821 EL_SP_GRAVITY_PORT_RIGHT,
1822 EL_SP_GRAVITY_PORT_UP,
1823 EL_SP_GRAVITY_PORT_DOWN,
1827 static int ep_passable_under[] =
1832 static int ep_droppable[] =
1837 static int ep_can_explode_1x1[] =
1842 static int ep_pushable[] =
1854 EL_SOKOBAN_FIELD_FULL,
1861 static int ep_player[] =
1871 static int ep_can_pass_magic_wall[] =
1884 static int ep_switchable[] =
1888 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1889 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1890 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1891 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1892 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1893 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1894 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1895 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1896 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1897 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1898 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1899 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1900 EL_SWITCHGATE_SWITCH_UP,
1901 EL_SWITCHGATE_SWITCH_DOWN,
1903 EL_LIGHT_SWITCH_ACTIVE,
1905 EL_BALLOON_SWITCH_LEFT,
1906 EL_BALLOON_SWITCH_RIGHT,
1907 EL_BALLOON_SWITCH_UP,
1908 EL_BALLOON_SWITCH_DOWN,
1909 EL_BALLOON_SWITCH_ANY,
1915 static int ep_bd_element[] =
1944 static int ep_sp_element[] =
1946 /* should always be valid */
1955 EL_SP_HARDWARE_GRAY,
1963 EL_SP_GRAVITY_PORT_RIGHT,
1964 EL_SP_GRAVITY_PORT_DOWN,
1965 EL_SP_GRAVITY_PORT_LEFT,
1966 EL_SP_GRAVITY_PORT_UP,
1971 EL_SP_PORT_VERTICAL,
1972 EL_SP_PORT_HORIZONTAL,
1978 EL_SP_HARDWARE_BASE_1,
1979 EL_SP_HARDWARE_GREEN,
1980 EL_SP_HARDWARE_BLUE,
1982 EL_SP_HARDWARE_YELLOW,
1983 EL_SP_HARDWARE_BASE_2,
1984 EL_SP_HARDWARE_BASE_3,
1985 EL_SP_HARDWARE_BASE_4,
1986 EL_SP_HARDWARE_BASE_5,
1987 EL_SP_HARDWARE_BASE_6,
1990 /* additional elements that appeared in newer Supaplex levels */
1992 /* more than one murphy in a level results in an inactive clone */
1994 /* runtime elements*/
1995 EL_SP_DISK_RED_ACTIVE,
1996 EL_SP_TERMINAL_ACTIVE,
1997 EL_SP_BUGGY_BASE_ACTIVATING,
1998 EL_SP_BUGGY_BASE_ACTIVE,
2002 static int ep_sb_element[] =
2007 EL_SOKOBAN_FIELD_EMPTY,
2008 EL_SOKOBAN_FIELD_FULL,
2010 EL_INVISIBLE_STEELWALL,
2014 static int ep_gem[] =
2025 static int ep_food_dark_yamyam[] =
2052 static int ep_food_penguin[] =
2065 static int ep_food_pig[] =
2076 static int ep_historic_wall[] =
2101 EL_EXPANDABLE_WALL_HORIZONTAL,
2102 EL_EXPANDABLE_WALL_VERTICAL,
2103 EL_EXPANDABLE_WALL_ANY,
2104 EL_EXPANDABLE_WALL_GROWING,
2111 EL_SP_HARDWARE_GRAY,
2112 EL_SP_HARDWARE_GREEN,
2113 EL_SP_HARDWARE_BLUE,
2115 EL_SP_HARDWARE_YELLOW,
2116 EL_SP_HARDWARE_BASE_1,
2117 EL_SP_HARDWARE_BASE_2,
2118 EL_SP_HARDWARE_BASE_3,
2119 EL_SP_HARDWARE_BASE_4,
2120 EL_SP_HARDWARE_BASE_5,
2121 EL_SP_HARDWARE_BASE_6,
2123 EL_SP_TERMINAL_ACTIVE,
2126 EL_INVISIBLE_STEELWALL,
2127 EL_INVISIBLE_STEELWALL_ACTIVE,
2129 EL_INVISIBLE_WALL_ACTIVE,
2130 EL_STEELWALL_SLIPPERY,
2146 static int ep_historic_solid[] =
2150 EL_EXPANDABLE_WALL_HORIZONTAL,
2151 EL_EXPANDABLE_WALL_VERTICAL,
2152 EL_EXPANDABLE_WALL_ANY,
2165 EL_QUICKSAND_FILLING,
2166 EL_QUICKSAND_EMPTYING,
2168 EL_MAGIC_WALL_ACTIVE,
2169 EL_MAGIC_WALL_EMPTYING,
2170 EL_MAGIC_WALL_FILLING,
2174 EL_BD_MAGIC_WALL_ACTIVE,
2175 EL_BD_MAGIC_WALL_EMPTYING,
2176 EL_BD_MAGIC_WALL_FULL,
2177 EL_BD_MAGIC_WALL_FILLING,
2178 EL_BD_MAGIC_WALL_DEAD,
2187 EL_SP_TERMINAL_ACTIVE,
2191 EL_INVISIBLE_WALL_ACTIVE,
2192 EL_SWITCHGATE_SWITCH_UP,
2193 EL_SWITCHGATE_SWITCH_DOWN,
2195 EL_TIMEGATE_SWITCH_ACTIVE,
2207 /* the following elements are a direct copy of "indestructible" elements,
2208 except "EL_ACID", which is "indestructible", but not "solid"! */
2213 EL_ACID_POOL_TOPLEFT,
2214 EL_ACID_POOL_TOPRIGHT,
2215 EL_ACID_POOL_BOTTOMLEFT,
2216 EL_ACID_POOL_BOTTOM,
2217 EL_ACID_POOL_BOTTOMRIGHT,
2218 EL_SP_HARDWARE_GRAY,
2219 EL_SP_HARDWARE_GREEN,
2220 EL_SP_HARDWARE_BLUE,
2222 EL_SP_HARDWARE_YELLOW,
2223 EL_SP_HARDWARE_BASE_1,
2224 EL_SP_HARDWARE_BASE_2,
2225 EL_SP_HARDWARE_BASE_3,
2226 EL_SP_HARDWARE_BASE_4,
2227 EL_SP_HARDWARE_BASE_5,
2228 EL_SP_HARDWARE_BASE_6,
2229 EL_INVISIBLE_STEELWALL,
2230 EL_INVISIBLE_STEELWALL_ACTIVE,
2231 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2232 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2233 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2234 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2235 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2236 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2237 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2238 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2239 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2240 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2241 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2242 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2244 EL_LIGHT_SWITCH_ACTIVE,
2245 EL_SIGN_EXCLAMATION,
2246 EL_SIGN_RADIOACTIVITY,
2257 EL_STEELWALL_SLIPPERY,
2280 EL_SWITCHGATE_OPENING,
2281 EL_SWITCHGATE_CLOSED,
2282 EL_SWITCHGATE_CLOSING,
2284 EL_TIMEGATE_OPENING,
2286 EL_TIMEGATE_CLOSING,
2290 EL_TUBE_VERTICAL_LEFT,
2291 EL_TUBE_VERTICAL_RIGHT,
2292 EL_TUBE_HORIZONTAL_UP,
2293 EL_TUBE_HORIZONTAL_DOWN,
2301 static int ep_classic_enemy[] =
2317 static int ep_belt[] =
2319 EL_CONVEYOR_BELT_1_LEFT,
2320 EL_CONVEYOR_BELT_1_MIDDLE,
2321 EL_CONVEYOR_BELT_1_RIGHT,
2322 EL_CONVEYOR_BELT_2_LEFT,
2323 EL_CONVEYOR_BELT_2_MIDDLE,
2324 EL_CONVEYOR_BELT_2_RIGHT,
2325 EL_CONVEYOR_BELT_3_LEFT,
2326 EL_CONVEYOR_BELT_3_MIDDLE,
2327 EL_CONVEYOR_BELT_3_RIGHT,
2328 EL_CONVEYOR_BELT_4_LEFT,
2329 EL_CONVEYOR_BELT_4_MIDDLE,
2330 EL_CONVEYOR_BELT_4_RIGHT,
2334 static int ep_belt_active[] =
2336 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2337 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2338 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2339 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2340 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2341 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2342 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2343 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2344 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2345 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2346 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2347 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2351 static int ep_belt_switch[] =
2353 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2354 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2355 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2356 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2357 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2358 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2359 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2360 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2361 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2362 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2363 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2364 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2368 static int ep_tube[] =
2375 EL_TUBE_HORIZONTAL_UP,
2376 EL_TUBE_HORIZONTAL_DOWN,
2378 EL_TUBE_VERTICAL_LEFT,
2379 EL_TUBE_VERTICAL_RIGHT,
2384 static int ep_keygate[] =
2405 static int ep_amoeboid[] =
2415 static int ep_amoebalive[] =
2424 static int ep_has_content[] =
2434 static int ep_active_bomb[] =
2437 EL_DYNABOMB_PLAYER_1_ACTIVE,
2438 EL_DYNABOMB_PLAYER_2_ACTIVE,
2439 EL_DYNABOMB_PLAYER_3_ACTIVE,
2440 EL_DYNABOMB_PLAYER_4_ACTIVE,
2441 EL_SP_DISK_RED_ACTIVE,
2445 static int ep_inactive[] =
2482 EL_INVISIBLE_STEELWALL,
2490 EL_WALL_EMERALD_YELLOW,
2491 EL_DYNABOMB_INCREASE_NUMBER,
2492 EL_DYNABOMB_INCREASE_SIZE,
2493 EL_DYNABOMB_INCREASE_POWER,
2497 EL_SOKOBAN_FIELD_EMPTY,
2498 EL_SOKOBAN_FIELD_FULL,
2499 EL_WALL_EMERALD_RED,
2500 EL_WALL_EMERALD_PURPLE,
2501 EL_ACID_POOL_TOPLEFT,
2502 EL_ACID_POOL_TOPRIGHT,
2503 EL_ACID_POOL_BOTTOMLEFT,
2504 EL_ACID_POOL_BOTTOM,
2505 EL_ACID_POOL_BOTTOMRIGHT,
2509 EL_BD_MAGIC_WALL_DEAD,
2510 EL_AMOEBA_TO_DIAMOND,
2518 EL_SP_GRAVITY_PORT_RIGHT,
2519 EL_SP_GRAVITY_PORT_DOWN,
2520 EL_SP_GRAVITY_PORT_LEFT,
2521 EL_SP_GRAVITY_PORT_UP,
2522 EL_SP_PORT_HORIZONTAL,
2523 EL_SP_PORT_VERTICAL,
2534 EL_SP_HARDWARE_GRAY,
2535 EL_SP_HARDWARE_GREEN,
2536 EL_SP_HARDWARE_BLUE,
2538 EL_SP_HARDWARE_YELLOW,
2539 EL_SP_HARDWARE_BASE_1,
2540 EL_SP_HARDWARE_BASE_2,
2541 EL_SP_HARDWARE_BASE_3,
2542 EL_SP_HARDWARE_BASE_4,
2543 EL_SP_HARDWARE_BASE_5,
2544 EL_SP_HARDWARE_BASE_6,
2545 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2546 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2547 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2548 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2549 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2550 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2551 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2552 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2553 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2554 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2555 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2556 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2557 EL_SIGN_EXCLAMATION,
2558 EL_SIGN_RADIOACTIVITY,
2569 EL_STEELWALL_SLIPPERY,
2585 static int ep_em_slippery_wall[] =
2590 static int ep_gfx_crumbled[] =
2603 } element_properties[] =
2605 { ep_diggable, EP_DIGGABLE },
2606 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2607 { ep_dont_run_into, EP_DONT_RUN_INTO },
2608 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2609 { ep_dont_touch, EP_DONT_TOUCH },
2610 { ep_indestructible, EP_INDESTRUCTIBLE },
2611 { ep_slippery, EP_SLIPPERY },
2612 { ep_can_change, EP_CAN_CHANGE },
2613 { ep_can_move, EP_CAN_MOVE },
2614 { ep_can_fall, EP_CAN_FALL },
2615 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2616 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2617 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2618 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2619 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2620 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2621 { ep_walkable_over, EP_WALKABLE_OVER },
2622 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2623 { ep_walkable_under, EP_WALKABLE_UNDER },
2624 { ep_passable_over, EP_PASSABLE_OVER },
2625 { ep_passable_inside, EP_PASSABLE_INSIDE },
2626 { ep_passable_under, EP_PASSABLE_UNDER },
2627 { ep_droppable, EP_DROPPABLE },
2628 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2629 { ep_pushable, EP_PUSHABLE },
2631 { ep_player, EP_PLAYER },
2632 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2633 { ep_switchable, EP_SWITCHABLE },
2634 { ep_bd_element, EP_BD_ELEMENT },
2635 { ep_sp_element, EP_SP_ELEMENT },
2636 { ep_sb_element, EP_SB_ELEMENT },
2638 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2639 { ep_food_penguin, EP_FOOD_PENGUIN },
2640 { ep_food_pig, EP_FOOD_PIG },
2641 { ep_historic_wall, EP_HISTORIC_WALL },
2642 { ep_historic_solid, EP_HISTORIC_SOLID },
2643 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2644 { ep_belt, EP_BELT },
2645 { ep_belt_active, EP_BELT_ACTIVE },
2646 { ep_belt_switch, EP_BELT_SWITCH },
2647 { ep_tube, EP_TUBE },
2648 { ep_keygate, EP_KEYGATE },
2649 { ep_amoeboid, EP_AMOEBOID },
2650 { ep_amoebalive, EP_AMOEBALIVE },
2651 { ep_has_content, EP_HAS_CONTENT },
2652 { ep_active_bomb, EP_ACTIVE_BOMB },
2653 { ep_inactive, EP_INACTIVE },
2655 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2657 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2662 static int copy_properties[][5] =
2666 EL_BUG_LEFT, EL_BUG_RIGHT,
2667 EL_BUG_UP, EL_BUG_DOWN
2671 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2672 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2676 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2677 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2681 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2682 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2686 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2687 EL_PACMAN_UP, EL_PACMAN_DOWN
2697 /* always start with reliable default values (element has no properties) */
2698 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2699 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2700 SET_PROPERTY(i, j, FALSE);
2702 /* set all base element properties from above array definitions */
2703 for (i=0; element_properties[i].elements != NULL; i++)
2704 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2705 SET_PROPERTY((element_properties[i].elements)[j],
2706 element_properties[i].property, TRUE);
2708 /* copy properties to some elements that are only stored in level file */
2709 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2710 for (j=0; copy_properties[j][0] != -1; j++)
2711 if (HAS_PROPERTY(copy_properties[j][0], i))
2712 for (k=1; k<=4; k++)
2713 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2716 void InitElementPropertiesEngine(int engine_version)
2719 static int active_properties[] =
2724 EP_DONT_COLLIDE_WITH,
2728 EP_CAN_PASS_MAGIC_WALL,
2733 EP_CAN_EXPLODE_BY_FIRE,
2746 EP_EM_SLIPPERY_WALL,
2750 static int no_wall_properties[] =
2753 EP_COLLECTIBLE_ONLY,
2755 EP_DONT_COLLIDE_WITH,
2758 EP_CAN_SMASH_PLAYER,
2759 EP_CAN_SMASH_ENEMIES,
2760 EP_CAN_SMASH_EVERYTHING,
2765 EP_FOOD_DARK_YAMYAM,
2781 InitElementPropertiesStatic();
2784 /* set all special, combined or engine dependent element properties */
2785 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2788 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2789 SET_PROPERTY(i, j, FALSE);
2792 /* ---------- INACTIVE ------------------------------------------------- */
2793 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2794 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2796 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2797 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2798 IS_WALKABLE_INSIDE(i) ||
2799 IS_WALKABLE_UNDER(i)));
2801 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2802 IS_PASSABLE_INSIDE(i) ||
2803 IS_PASSABLE_UNDER(i)));
2805 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2806 IS_PASSABLE_OVER(i)));
2808 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2809 IS_PASSABLE_INSIDE(i)));
2811 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2812 IS_PASSABLE_UNDER(i)));
2814 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2817 /* ---------- COLLECTIBLE ---------------------------------------------- */
2818 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
2821 /* ---------- SNAPPABLE ------------------------------------------------ */
2822 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2823 IS_COLLECTIBLE(i) ||
2827 /* ---------- WALL ----------------------------------------------------- */
2828 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2830 for (j=0; no_wall_properties[j] != -1; j++)
2831 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2832 i >= EL_FIRST_RUNTIME_UNREAL)
2833 SET_PROPERTY(i, EP_WALL, FALSE);
2835 if (IS_HISTORIC_WALL(i))
2836 SET_PROPERTY(i, EP_WALL, TRUE);
2838 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2839 if (engine_version < VERSION_IDENT(2,2,0))
2840 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2842 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2844 !IS_COLLECTIBLE(i)));
2846 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2848 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2849 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2851 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2852 IS_INDESTRUCTIBLE(i)));
2854 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2856 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2857 else if (engine_version < VERSION_IDENT(2,2,0))
2858 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2860 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2861 !IS_WALKABLE_OVER(i) &&
2862 !IS_WALKABLE_UNDER(i)));
2864 if (IS_CUSTOM_ELEMENT(i))
2866 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2868 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2869 if (DONT_COLLIDE_WITH(i))
2870 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2872 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2873 if (CAN_SMASH_EVERYTHING(i))
2874 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2875 if (CAN_SMASH_ENEMIES(i))
2876 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2879 /* ---------- CAN_SMASH ------------------------------------------------ */
2880 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2881 CAN_SMASH_ENEMIES(i) ||
2882 CAN_SMASH_EVERYTHING(i)));
2884 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2885 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2886 CAN_EXPLODE_SMASHED(i) ||
2887 CAN_EXPLODE_IMPACT(i)));
2889 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
2890 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
2891 !CAN_EXPLODE_1X1(i)));
2893 /* ---------- CAN_CHANGE ----------------------------------------------- */
2894 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
2895 for (j=0; j < element_info[i].num_change_pages; j++)
2896 if (element_info[i].change_page[j].can_change)
2897 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
2899 /* ---------- GFX_CRUMBLED --------------------------------------------- */
2900 SET_PROPERTY(i, EP_GFX_CRUMBLED,
2901 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
2905 /* determine inactive elements (used for engine main loop optimization) */
2906 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2908 boolean active = FALSE;
2910 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2912 if (HAS_PROPERTY(i, j))
2918 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2923 /* dynamically adjust element properties according to game engine version */
2925 static int ep_em_slippery_wall[] =
2930 EL_EXPANDABLE_WALL_HORIZONTAL,
2931 EL_EXPANDABLE_WALL_VERTICAL,
2932 EL_EXPANDABLE_WALL_ANY,
2936 /* special EM style gems behaviour */
2937 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2938 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2939 level.em_slippery_gems);
2941 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2942 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2943 (level.em_slippery_gems &&
2944 engine_version > VERSION_IDENT(2,0,1)));
2948 /* dynamically adjust element properties according to game engine version */
2950 if (engine_version < RELEASE_IDENT(2,2,0,7))
2953 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2955 int element = EL_CUSTOM_START + i;
2957 element_info[element].push_delay_fixed = 2;
2958 element_info[element].push_delay_random = 8;
2964 static void InitGlobal()
2966 global.autoplay_leveldir = NULL;
2968 global.frames_per_second = 0;
2969 global.fps_slowdown = FALSE;
2970 global.fps_slowdown_factor = 1;
2973 void Execute_Command(char *command)
2975 if (strcmp(command, "print graphicsinfo.conf") == 0)
2979 printf("# You can configure additional/alternative image files here.\n");
2980 printf("# (The images below are default and therefore commented out.)\n");
2982 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2984 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2987 for (i=0; image_config[i].token != NULL; i++)
2989 getFormattedSetupEntry(image_config[i].token,
2990 image_config[i].value));
2994 else if (strcmp(command, "print soundsinfo.conf") == 0)
2998 printf("# You can configure additional/alternative sound files here.\n");
2999 printf("# (The sounds below are default and therefore commented out.)\n");
3001 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3003 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3006 for (i=0; sound_config[i].token != NULL; i++)
3008 getFormattedSetupEntry(sound_config[i].token,
3009 sound_config[i].value));
3013 else if (strcmp(command, "print musicinfo.conf") == 0)
3015 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
3017 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3019 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3023 else if (strncmp(command, "dump level ", 11) == 0)
3025 char *filename = &command[11];
3027 if (access(filename, F_OK) != 0)
3028 Error(ERR_EXIT, "cannot open file '%s'", filename);
3030 LoadLevelFromFilename(&level, filename);
3035 else if (strncmp(command, "dump tape ", 10) == 0)
3037 char *filename = &command[10];
3039 if (access(filename, F_OK) != 0)
3040 Error(ERR_EXIT, "cannot open file '%s'", filename);
3042 LoadTapeFromFilename(filename);
3047 else if (strncmp(command, "autoplay ", 9) == 0)
3049 char *str_copy = getStringCopy(&command[9]);
3050 char *str_ptr = strchr(str_copy, ' ');
3052 global.autoplay_leveldir = str_copy;
3053 global.autoplay_level_nr = -1;
3055 if (str_ptr != NULL)
3057 *str_ptr++ = '\0'; /* terminate leveldir string */
3058 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3063 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3067 static void InitSetup()
3069 LoadSetup(); /* global setup info */
3071 /* set some options from setup file */
3073 if (setup.options.verbose)
3074 options.verbose = TRUE;
3077 static void InitPlayerInfo()
3081 /* choose default local player */
3082 local_player = &stored_player[0];
3084 for (i=0; i<MAX_PLAYERS; i++)
3085 stored_player[i].connected = FALSE;
3087 local_player->connected = TRUE;
3090 static void InitArtworkInfo()
3095 static char *get_string_in_brackets(char *string)
3097 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3099 sprintf(string_in_brackets, "[%s]", string);
3101 return string_in_brackets;
3105 static char *get_element_class_token(int element)
3107 char *element_class_name = element_info[element].class_name;
3108 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3110 sprintf(element_class_token, "[%s]", element_class_name);
3112 return element_class_token;
3115 static char *get_action_class_token(int action)
3117 char *action_class_name = &element_action_info[action].suffix[1];
3118 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3120 sprintf(action_class_token, "[%s]", action_class_name);
3122 return action_class_token;
3126 static void InitArtworkConfig()
3128 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3129 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3130 static char *action_id_suffix[NUM_ACTIONS + 1];
3131 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3132 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3133 static char *dummy[1] = { NULL };
3134 static char *ignore_generic_tokens[] =
3140 static char **ignore_image_tokens, **ignore_sound_tokens;
3141 int num_ignore_generic_tokens;
3142 int num_ignore_image_tokens, num_ignore_sound_tokens;
3145 /* dynamically determine list of generic tokens to be ignored */
3146 num_ignore_generic_tokens = 0;
3147 for (i=0; ignore_generic_tokens[i] != NULL; i++)
3148 num_ignore_generic_tokens++;
3150 /* dynamically determine list of image tokens to be ignored */
3151 num_ignore_image_tokens = num_ignore_generic_tokens;
3152 for (i=0; image_config_vars[i].token != NULL; i++)
3153 num_ignore_image_tokens++;
3154 ignore_image_tokens =
3155 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3156 for (i=0; i < num_ignore_generic_tokens; i++)
3157 ignore_image_tokens[i] = ignore_generic_tokens[i];
3158 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3159 ignore_image_tokens[num_ignore_generic_tokens + i] =
3160 image_config_vars[i].token;
3161 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3163 /* dynamically determine list of sound tokens to be ignored */
3164 num_ignore_sound_tokens = num_ignore_generic_tokens;
3165 ignore_sound_tokens =
3166 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3167 for (i=0; i < num_ignore_generic_tokens; i++)
3168 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3169 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3171 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3172 image_id_prefix[i] = element_info[i].token_name;
3173 for (i=0; i<NUM_FONTS; i++)
3174 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3175 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3177 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3178 sound_id_prefix[i] = element_info[i].token_name;
3179 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3180 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3181 get_string_in_brackets(element_info[i].class_name);
3182 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3184 for (i=0; i<NUM_ACTIONS; i++)
3185 action_id_suffix[i] = element_action_info[i].suffix;
3186 action_id_suffix[NUM_ACTIONS] = NULL;
3188 for (i=0; i<NUM_DIRECTIONS; i++)
3189 direction_id_suffix[i] = element_direction_info[i].suffix;
3190 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3192 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
3193 special_id_suffix[i] = special_suffix_info[i].suffix;
3194 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3196 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3197 image_id_prefix, action_id_suffix, direction_id_suffix,
3198 special_id_suffix, ignore_image_tokens);
3199 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3200 sound_id_prefix, action_id_suffix, dummy,
3201 special_id_suffix, ignore_sound_tokens);
3204 static void InitMixer()
3212 char *filename_font_initial = NULL;
3213 Bitmap *bitmap_font_initial = NULL;
3216 /* determine settings for initial font (for displaying startup messages) */
3217 for (i=0; image_config[i].token != NULL; i++)
3219 for (j=0; j < NUM_INITIAL_FONTS; j++)
3221 char font_token[128];
3224 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3225 len_font_token = strlen(font_token);
3227 if (strcmp(image_config[i].token, font_token) == 0)
3228 filename_font_initial = image_config[i].value;
3229 else if (strlen(image_config[i].token) > len_font_token &&
3230 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3232 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3233 font_initial[j].src_x = atoi(image_config[i].value);
3234 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3235 font_initial[j].src_y = atoi(image_config[i].value);
3236 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3237 font_initial[j].width = atoi(image_config[i].value);
3238 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3239 font_initial[j].height = atoi(image_config[i].value);
3244 for (j=0; j < NUM_INITIAL_FONTS; j++)
3246 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3247 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3250 if (filename_font_initial == NULL) /* should not happen */
3251 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3253 /* create additional image buffers for double-buffering */
3254 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3255 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3257 /* initialize screen properties */
3258 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3259 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3261 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3262 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3263 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3265 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3267 for (j=0; j < NUM_INITIAL_FONTS; j++)
3268 font_initial[j].bitmap = bitmap_font_initial;
3270 InitFontGraphicInfo();
3272 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
3273 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
3275 DrawInitText("Loading graphics:", 120, FC_GREEN);
3277 InitTileClipmasks();
3280 void InitGfxBackground()
3284 drawto = backbuffer;
3285 fieldbuffer = bitmap_db_field;
3286 SetDrawtoField(DRAW_BACKBUFFER);
3288 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3289 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3290 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3291 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3293 for (x=0; x<MAX_BUF_XSIZE; x++)
3294 for (y=0; y<MAX_BUF_YSIZE; y++)
3297 redraw_mask = REDRAW_ALL;
3300 static void InitLevelInfo()
3302 LoadLevelInfo(); /* global level info */
3303 LoadLevelSetup_LastSeries(); /* last played series info */
3304 LoadLevelSetup_SeriesInfo(); /* last played level info */
3307 void InitLevelArtworkInfo()
3309 LoadLevelArtworkInfo();
3312 static void InitImages()
3315 setLevelArtworkDir(artwork.gfx_first);
3319 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3320 leveldir_current->identifier,
3321 artwork.gfx_current_identifier,
3322 artwork.gfx_current->identifier,
3323 leveldir_current->graphics_set,
3324 leveldir_current->graphics_path);
3327 ReloadCustomImages();
3329 LoadCustomElementDescriptions();
3330 LoadSpecialMenuDesignSettings();
3332 ReinitializeGraphics();
3335 static void InitSound(char *identifier)
3337 if (identifier == NULL)
3338 identifier = artwork.snd_current->identifier;
3341 /* set artwork path to send it to the sound server process */
3342 setLevelArtworkDir(artwork.snd_first);
3345 InitReloadCustomSounds(identifier);
3346 ReinitializeSounds();
3349 static void InitMusic(char *identifier)
3351 if (identifier == NULL)
3352 identifier = artwork.mus_current->identifier;
3355 /* set artwork path to send it to the sound server process */
3356 setLevelArtworkDir(artwork.mus_first);
3359 InitReloadCustomMusic(identifier);
3360 ReinitializeMusic();
3363 void InitNetworkServer()
3365 #if defined(PLATFORM_UNIX)
3369 if (!options.network)
3372 #if defined(PLATFORM_UNIX)
3373 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3375 if (!ConnectToServer(options.server_host, options.server_port))
3376 Error(ERR_EXIT, "cannot connect to network game server");
3378 SendToServer_PlayerName(setup.player_name);
3379 SendToServer_ProtocolVersion();
3382 SendToServer_NrWanted(nr_wanted);
3386 static char *getNewArtworkIdentifier(int type)
3388 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3389 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3390 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3391 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3392 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3393 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3394 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3395 char *leveldir_identifier = leveldir_current->identifier;
3397 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3398 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3400 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3402 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3403 char *artwork_current_identifier;
3404 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3406 /* leveldir_current may be invalid (level group, parent link) */
3407 if (!validLevelSeries(leveldir_current))
3410 /* 1st step: determine artwork set to be activated in descending order:
3411 --------------------------------------------------------------------
3412 1. setup artwork (when configured to override everything else)
3413 2. artwork set configured in "levelinfo.conf" of current level set
3414 (artwork in level directory will have priority when loading later)
3415 3. artwork in level directory (stored in artwork sub-directory)
3416 4. setup artwork (currently configured in setup menu) */
3418 if (setup_override_artwork)
3419 artwork_current_identifier = setup_artwork_set;
3420 else if (leveldir_artwork_set != NULL)
3421 artwork_current_identifier = leveldir_artwork_set;
3422 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3423 artwork_current_identifier = leveldir_identifier;
3425 artwork_current_identifier = setup_artwork_set;
3428 /* 2nd step: check if it is really needed to reload artwork set
3429 ------------------------------------------------------------ */
3432 if (type == ARTWORK_TYPE_GRAPHICS)
3433 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3434 artwork_new_identifier,
3435 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3436 artwork_current_identifier,
3437 leveldir_current->graphics_set,
3438 leveldir_current->identifier);
3441 /* ---------- reload if level set and also artwork set has changed ------- */
3442 if (leveldir_current_identifier[type] != leveldir_identifier &&
3443 (last_has_level_artwork_set[type] || has_level_artwork_set))
3444 artwork_new_identifier = artwork_current_identifier;
3446 leveldir_current_identifier[type] = leveldir_identifier;
3447 last_has_level_artwork_set[type] = has_level_artwork_set;
3450 if (type == ARTWORK_TYPE_GRAPHICS)
3451 printf("::: 1: '%s'\n", artwork_new_identifier);
3454 /* ---------- reload if "override artwork" setting has changed ----------- */
3455 if (last_override_level_artwork[type] != setup_override_artwork)
3456 artwork_new_identifier = artwork_current_identifier;
3458 last_override_level_artwork[type] = setup_override_artwork;
3461 if (type == ARTWORK_TYPE_GRAPHICS)
3462 printf("::: 2: '%s'\n", artwork_new_identifier);
3465 /* ---------- reload if current artwork identifier has changed ----------- */
3466 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3467 artwork_current_identifier) != 0)
3468 artwork_new_identifier = artwork_current_identifier;
3470 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3473 if (type == ARTWORK_TYPE_GRAPHICS)
3474 printf("::: 3: '%s'\n", artwork_new_identifier);
3477 /* ---------- do not reload directly after starting ---------------------- */
3478 if (!initialized[type])
3479 artwork_new_identifier = NULL;
3481 initialized[type] = TRUE;
3484 if (type == ARTWORK_TYPE_GRAPHICS)
3485 printf("::: 4: '%s'\n", artwork_new_identifier);
3489 if (type == ARTWORK_TYPE_GRAPHICS)
3490 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3491 artwork.gfx_current_identifier, artwork_current_identifier,
3492 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3493 artwork_new_identifier);
3496 return artwork_new_identifier;
3499 void ReloadCustomArtwork()
3501 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3502 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3503 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3504 boolean redraw_screen = FALSE;
3506 if (gfx_new_identifier != NULL)
3509 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3510 artwork.gfx_current_identifier,
3512 artwork.gfx_current->identifier,
3513 leveldir_current->graphics_set);
3516 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3521 printf("... '%s'\n",
3522 leveldir_current->graphics_set);
3525 FreeTileClipmasks();
3526 InitTileClipmasks();
3528 redraw_screen = TRUE;
3531 if (snd_new_identifier != NULL)
3533 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3535 InitSound(snd_new_identifier);
3537 redraw_screen = TRUE;
3540 if (mus_new_identifier != NULL)
3542 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3544 InitMusic(mus_new_identifier);
3546 redraw_screen = TRUE;
3551 InitGfxBackground();
3553 /* force redraw of (open or closed) door graphics */
3554 SetDoorState(DOOR_OPEN_ALL);
3555 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3559 void KeyboardAutoRepeatOffUnlessAutoplay()
3561 if (global.autoplay_leveldir == NULL)
3562 KeyboardAutoRepeatOff();
3566 /* ========================================================================= */
3568 /* ========================================================================= */
3572 InitGlobal(); /* initialize some global variables */
3574 if (options.execute_command)
3575 Execute_Command(options.execute_command);
3577 if (options.serveronly)
3579 #if defined(PLATFORM_UNIX)
3580 NetworkServer(options.server_port, options.serveronly);
3582 Error(ERR_WARN, "networking only supported in Unix version");
3584 exit(0); /* never reached */
3590 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3591 InitArtworkConfig(); /* needed before forking sound child process */
3596 InitRND(NEW_RANDOMIZE);
3597 InitSimpleRND(NEW_RANDOMIZE);
3602 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3605 InitEventFilter(FilterMouseMotionEvents);
3607 InitElementPropertiesStatic();
3608 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3613 InitLevelArtworkInfo();
3615 InitImages(); /* needs to know current level directory */
3616 InitSound(NULL); /* needs to know current level directory */
3617 InitMusic(NULL); /* needs to know current level directory */
3619 InitGfxBackground();
3621 if (global.autoplay_leveldir)
3627 game_status = GAME_MODE_MAIN;
3631 InitNetworkServer();
3634 void CloseAllAndExit(int exit_value)
3639 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3642 FreeTileClipmasks();
3644 CloseVideoDisplay();
3645 ClosePlatformDependentStuff();