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 */
35 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
38 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static void InitTileClipmasks()
44 #if defined(TARGET_X11)
45 XGCValues clip_gc_values;
46 unsigned long clip_gc_valuemask;
48 #if defined(TARGET_X11_NATIVE)
58 tile_needs_clipping[] =
60 { GFX_SPIELER1_UP, 4 },
61 { GFX_SPIELER1_DOWN, 4 },
62 { GFX_SPIELER1_LEFT, 4 },
63 { GFX_SPIELER1_RIGHT, 4 },
64 { GFX_SPIELER1_PUSH_LEFT, 4 },
65 { GFX_SPIELER1_PUSH_RIGHT, 4 },
66 { GFX_SPIELER2_UP, 4 },
67 { GFX_SPIELER2_DOWN, 4 },
68 { GFX_SPIELER2_LEFT, 4 },
69 { GFX_SPIELER2_RIGHT, 4 },
70 { GFX_SPIELER2_PUSH_LEFT, 4 },
71 { GFX_SPIELER2_PUSH_RIGHT, 4 },
72 { GFX_SPIELER3_UP, 4 },
73 { GFX_SPIELER3_DOWN, 4 },
74 { GFX_SPIELER3_LEFT, 4 },
75 { GFX_SPIELER3_RIGHT, 4 },
76 { GFX_SPIELER3_PUSH_LEFT, 4 },
77 { GFX_SPIELER3_PUSH_RIGHT, 4 },
78 { GFX_SPIELER4_UP, 4 },
79 { GFX_SPIELER4_DOWN, 4 },
80 { GFX_SPIELER4_LEFT, 4 },
81 { GFX_SPIELER4_RIGHT, 4 },
82 { GFX_SPIELER4_PUSH_LEFT, 4 },
83 { GFX_SPIELER4_PUSH_RIGHT, 4 },
85 { GFX_MURPHY_GO_LEFT, 3 },
86 { GFX_MURPHY_GO_RIGHT, 3 },
87 { GFX_MURPHY_SNAP_UP, 1 },
88 { GFX_MURPHY_SNAP_DOWN, 1 },
89 { GFX_MURPHY_SNAP_RIGHT, 1 },
90 { GFX_MURPHY_SNAP_LEFT, 1 },
91 { GFX_MURPHY_PUSH_RIGHT, 1 },
92 { GFX_MURPHY_PUSH_LEFT, 1 },
97 { GFX_SOKOBAN_OBJEKT, 1 },
98 { GFX_FUNKELN_BLAU, 3 },
99 { GFX_FUNKELN_WEISS, 3 },
100 { GFX2_SHIELD_PASSIVE, 3 },
101 { GFX2_SHIELD_ACTIVE, 3 },
106 #endif /* TARGET_X11_NATIVE */
107 #endif /* TARGET_X11 */
111 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
112 for (i=0; i<NUM_TILES; i++)
113 tile_clipmask[i] = None;
115 #if defined(TARGET_X11)
116 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
117 often very slow when preparing a masked XCopyArea() for big Pixmaps.
118 To prevent this, create small (tile-sized) mask Pixmaps which will then
119 be set much faster with XSetClipOrigin() and speed things up a lot. */
121 clip_gc_values.graphics_exposures = False;
122 clip_gc_valuemask = GCGraphicsExposures;
123 tile_clip_gc = XCreateGC(display, window->drawable,
124 clip_gc_valuemask, &clip_gc_values);
127 for (i=0; i<NUM_BITMAPS; i++)
129 if (pix[i]->clip_mask)
131 clip_gc_values.graphics_exposures = False;
132 clip_gc_values.clip_mask = pix[i]->clip_mask;
133 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
134 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
135 clip_gc_valuemask, &clip_gc_values);
140 #if defined(TARGET_X11_NATIVE)
143 /* create graphic context structures needed for clipping */
144 clip_gc_values.graphics_exposures = False;
145 clip_gc_valuemask = GCGraphicsExposures;
146 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
147 clip_gc_valuemask, &clip_gc_values);
149 /* create only those clipping Pixmaps we really need */
150 for (i=0; tile_needs_clipping[i].start>=0; i++)
154 for (j=0; j<tile_needs_clipping[i].count; j++)
156 int tile = tile_needs_clipping[i].start + j;
162 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
163 src_pixmap = src_bitmap->clip_mask;
165 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
168 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
169 src_x, src_y, TILEX, TILEY, 0, 0);
173 XFreeGC(display, copy_clipmask_gc);
176 #endif /* TARGET_X11_NATIVE */
177 #endif /* TARGET_X11 */
181 void FreeTileClipmasks()
184 #if defined(TARGET_X11)
187 for (i=0; i<NUM_TILES; i++)
189 if (tile_clipmask[i] != None)
191 XFreePixmap(display, tile_clipmask[i]);
192 tile_clipmask[i] = None;
197 XFreeGC(display, tile_clip_gc);
201 for (i=0; i<NUM_BITMAPS; i++)
203 if (pix[i] != NULL && pix[i]->stored_clip_gc)
205 XFreeGC(display, pix[i]->stored_clip_gc);
206 pix[i]->stored_clip_gc = None;
211 #endif /* TARGET_X11 */
217 FreeLevelEditorGadgets();
226 static boolean gadgets_initialized = FALSE;
228 if (gadgets_initialized)
231 CreateLevelEditorGadgets();
235 CreateScreenGadgets();
237 gadgets_initialized = TRUE;
240 void InitElementSmallImages()
242 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
243 int num_property_mappings = getImageListPropertyMappingSize();
246 /* initialize normal images from static configuration */
247 for (i=0; element_to_graphic[i].element > -1; i++)
248 CreateImageWithSmallImages(element_to_graphic[i].graphic);
250 /* initialize special images from static configuration */
251 for (i=0; element_to_special_graphic[i].element > -1; i++)
252 CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
254 /* initialize images from dynamic configuration */
255 for (i=0; i < num_property_mappings; i++)
256 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
257 CreateImageWithSmallImages(property_mapping[i].artwork_index);
260 static int getFontBitmapID(int font_nr)
264 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
265 special = game_status;
266 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
267 special = GFX_SPECIAL_ARG_MAIN;
268 else if (game_status == GAME_MODE_PLAYING)
269 special = GFX_SPECIAL_ARG_DOOR;
272 return font_info[font_nr].special_bitmap_id[special];
277 void InitFontGraphicInfo()
279 static struct FontBitmapInfo *font_bitmap_info = NULL;
280 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
281 int num_property_mappings = getImageListPropertyMappingSize();
282 int num_font_bitmaps = NUM_FONTS;
285 if (graphic_info == NULL) /* still at startup phase */
287 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
292 /* ---------- initialize font graphic definitions ---------- */
294 /* always start with reliable default values (normal font graphics) */
296 for (i=0; i < NUM_FONTS; i++)
297 font_info[i].graphic = IMG_FONT_INITIAL_1;
299 for (i=0; i < NUM_FONTS; i++)
300 font_info[i].graphic = FONT_INITIAL_1;
303 /* initialize normal font/graphic mapping from static configuration */
304 for (i=0; font_to_graphic[i].font_nr > -1; i++)
306 int font_nr = font_to_graphic[i].font_nr;
307 int special = font_to_graphic[i].special;
308 int graphic = font_to_graphic[i].graphic;
313 font_info[font_nr].graphic = graphic;
316 /* always start with reliable default values (special font graphics) */
317 for (i=0; i < NUM_FONTS; i++)
319 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
321 font_info[i].special_graphic[j] = font_info[i].graphic;
322 font_info[i].special_bitmap_id[j] = i;
326 /* initialize special font/graphic mapping from static configuration */
327 for (i=0; font_to_graphic[i].font_nr > -1; i++)
329 int font_nr = font_to_graphic[i].font_nr;
330 int special = font_to_graphic[i].special;
331 int graphic = font_to_graphic[i].graphic;
333 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
335 font_info[font_nr].special_graphic[special] = graphic;
336 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
341 /* initialize special element/graphic mapping from dynamic configuration */
342 for (i=0; i < num_property_mappings; i++)
344 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
345 int special = property_mapping[i].ext3_index;
346 int graphic = property_mapping[i].artwork_index;
351 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
353 font_info[font_nr].special_graphic[special] = graphic;
354 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
359 /* ---------- initialize font bitmap array ---------- */
361 if (font_bitmap_info != NULL)
362 FreeFontInfo(font_bitmap_info);
365 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
367 /* ---------- initialize font bitmap definitions ---------- */
369 for (i=0; i < NUM_FONTS; i++)
371 if (i < NUM_INITIAL_FONTS)
373 font_bitmap_info[i] = font_initial[i];
377 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
379 int font_bitmap_id = font_info[i].special_bitmap_id[j];
380 int graphic = font_info[i].special_graphic[j];
382 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
383 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
385 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
386 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
389 /* copy font relevant information from graphics information */
390 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
391 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
392 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
393 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
394 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
395 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
396 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
398 font_bitmap_info[font_bitmap_id].num_chars =
399 graphic_info[graphic].anim_frames;
400 font_bitmap_info[font_bitmap_id].num_chars_per_line =
401 graphic_info[graphic].anim_frames_per_line;
405 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
408 void InitElementGraphicInfo()
410 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
411 int num_property_mappings = getImageListPropertyMappingSize();
414 /* set values to -1 to identify later as "uninitialized" values */
415 for (i=0; i<MAX_NUM_ELEMENTS; i++)
417 for (act=0; act<NUM_ACTIONS; act++)
419 element_info[i].graphic[act] = -1;
420 element_info[i].crumbled[act] = -1;
422 for (dir=0; dir<NUM_DIRECTIONS; dir++)
424 element_info[i].direction_graphic[act][dir] = -1;
425 element_info[i].direction_crumbled[act][dir] = -1;
430 /* initialize normal element/graphic mapping from static configuration */
431 for (i=0; element_to_graphic[i].element > -1; i++)
433 int element = element_to_graphic[i].element;
434 int action = element_to_graphic[i].action;
435 int direction = element_to_graphic[i].direction;
436 boolean crumbled = element_to_graphic[i].crumbled;
437 int graphic = element_to_graphic[i].graphic;
439 if (graphic_info[graphic].bitmap == NULL)
442 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
443 el2img(element) != -1)
445 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
446 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
448 /* if the base graphic ("emerald", for example) has been redefined,
449 but not the action graphic ("emerald.falling", for example), do not
450 use an existing (in this case considered obsolete) action graphic
451 anymore, but use the automatically determined default graphic */
452 if (base_redefined && !act_dir_redefined)
457 action = ACTION_DEFAULT;
462 element_info[element].direction_crumbled[action][direction] = graphic;
464 element_info[element].crumbled[action] = graphic;
469 element_info[element].direction_graphic[action][direction] = graphic;
471 element_info[element].graphic[action] = graphic;
475 /* initialize normal element/graphic mapping from dynamic configuration */
476 for (i=0; i < num_property_mappings; i++)
478 int element = property_mapping[i].base_index;
479 int action = property_mapping[i].ext1_index;
480 int direction = property_mapping[i].ext2_index;
481 int special = property_mapping[i].ext3_index;
482 int graphic = property_mapping[i].artwork_index;
483 boolean crumbled = FALSE;
485 if (special == GFX_SPECIAL_ARG_CRUMBLED)
491 if (graphic_info[graphic].bitmap == NULL)
494 if (element >= MAX_NUM_ELEMENTS || special != -1)
498 action = ACTION_DEFAULT;
503 for (dir=0; dir<NUM_DIRECTIONS; dir++)
504 element_info[element].direction_crumbled[action][dir] = -1;
507 element_info[element].direction_crumbled[action][direction] = graphic;
509 element_info[element].crumbled[action] = graphic;
514 for (dir=0; dir<NUM_DIRECTIONS; dir++)
515 element_info[element].direction_graphic[action][dir] = -1;
518 element_info[element].direction_graphic[action][direction] = graphic;
520 element_info[element].graphic[action] = graphic;
524 /* now copy all graphics that are defined to be cloned from other graphics */
525 for (i=0; i<MAX_NUM_ELEMENTS; i++)
527 int graphic = element_info[i].graphic[ACTION_DEFAULT];
528 int crumbled_like, diggable_like;
533 crumbled_like = graphic_info[graphic].crumbled_like;
534 diggable_like = graphic_info[graphic].diggable_like;
536 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
538 for (act=0; act<NUM_ACTIONS; act++)
539 element_info[i].crumbled[act] =
540 element_info[crumbled_like].crumbled[act];
541 for (act=0; act<NUM_ACTIONS; act++)
542 for (dir=0; dir<NUM_DIRECTIONS; dir++)
543 element_info[i].direction_crumbled[act][dir] =
544 element_info[crumbled_like].direction_crumbled[act][dir];
547 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
549 element_info[i].graphic[ACTION_DIGGING] =
550 element_info[diggable_like].graphic[ACTION_DIGGING];
551 for (dir=0; dir<NUM_DIRECTIONS; dir++)
552 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
553 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
558 /* now set all undefined/invalid graphics to -1 to set to default after it */
559 for (i=0; i<MAX_NUM_ELEMENTS; i++)
561 for (act=0; act<NUM_ACTIONS; act++)
565 graphic = element_info[i].graphic[act];
566 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
567 element_info[i].graphic[act] = -1;
569 graphic = element_info[i].crumbled[act];
570 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
571 element_info[i].crumbled[act] = -1;
573 for (dir=0; dir<NUM_DIRECTIONS; dir++)
575 graphic = element_info[i].direction_graphic[act][dir];
576 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
577 element_info[i].direction_graphic[act][dir] = -1;
579 graphic = element_info[i].direction_crumbled[act][dir];
580 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
581 element_info[i].direction_crumbled[act][dir] = -1;
587 /* now set all '-1' values to element specific default values */
588 for (i=0; i<MAX_NUM_ELEMENTS; i++)
590 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
591 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
592 int default_direction_graphic[NUM_DIRECTIONS];
593 int default_direction_crumbled[NUM_DIRECTIONS];
595 if (default_graphic == -1)
596 default_graphic = IMG_CHAR_QUESTION;
597 if (default_crumbled == -1)
598 default_crumbled = IMG_EMPTY;
600 for (dir=0; dir<NUM_DIRECTIONS; dir++)
602 default_direction_graphic[dir] =
603 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
604 default_direction_crumbled[dir] =
605 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
607 if (default_direction_graphic[dir] == -1)
608 default_direction_graphic[dir] = default_graphic;
609 if (default_direction_crumbled[dir] == -1)
610 default_direction_crumbled[dir] = default_crumbled;
613 for (act=0; act<NUM_ACTIONS; act++)
615 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
616 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
617 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
619 /* generic default action graphic (defined by "[default]" directive) */
620 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
621 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
623 /* look for special default action graphic (classic game specific) */
624 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
625 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
626 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
627 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
628 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
629 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
631 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
632 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
633 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
634 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
635 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
636 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
638 if (default_action_graphic == -1)
639 default_action_graphic = default_graphic;
640 if (default_action_crumbled == -1)
641 default_action_crumbled = default_crumbled;
643 for (dir=0; dir<NUM_DIRECTIONS; dir++)
645 int default_action_direction_graphic = element_info[i].graphic[act];
646 int default_action_direction_crumbled = element_info[i].crumbled[act];
648 /* no graphic for current action -- use default direction graphic */
649 if (default_action_direction_graphic == -1)
650 default_action_direction_graphic =
651 (act_remove ? IMG_EMPTY : default_direction_graphic[dir]);
652 if (default_action_direction_crumbled == -1)
653 default_action_direction_crumbled =
654 (act_remove ? IMG_EMPTY : default_direction_crumbled[dir]);
656 if (element_info[i].direction_graphic[act][dir] == -1)
657 element_info[i].direction_graphic[act][dir] =
658 default_action_direction_graphic;
659 if (element_info[i].direction_crumbled[act][dir] == -1)
660 element_info[i].direction_crumbled[act][dir] =
661 default_action_direction_crumbled;
664 /* no graphic for this specific action -- use default action graphic */
665 if (element_info[i].graphic[act] == -1)
666 element_info[i].graphic[act] =
667 (act_remove ? IMG_EMPTY : default_action_graphic);
668 if (element_info[i].crumbled[act] == -1)
669 element_info[i].crumbled[act] =
670 (act_remove ? IMG_EMPTY : default_action_crumbled);
675 /* set animation mode to "none" for each graphic with only 1 frame */
676 for (i=0; i<MAX_NUM_ELEMENTS; i++)
678 for (act=0; act<NUM_ACTIONS; act++)
680 int graphic = element_info[i].graphic[act];
681 int crumbled = element_info[i].crumbled[act];
683 if (graphic_info[graphic].anim_frames == 1)
684 graphic_info[graphic].anim_mode = ANIM_NONE;
685 if (graphic_info[crumbled].anim_frames == 1)
686 graphic_info[crumbled].anim_mode = ANIM_NONE;
688 for (dir=0; dir<NUM_DIRECTIONS; dir++)
690 graphic = element_info[i].direction_graphic[act][dir];
691 crumbled = element_info[i].direction_crumbled[act][dir];
693 if (graphic_info[graphic].anim_frames == 1)
694 graphic_info[graphic].anim_mode = ANIM_NONE;
695 if (graphic_info[crumbled].anim_frames == 1)
696 graphic_info[crumbled].anim_mode = ANIM_NONE;
706 for (i=0; i<MAX_NUM_ELEMENTS; i++)
707 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
708 i != EL_CHAR_QUESTION)
709 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
710 element_info[i].token_name, i);
716 void InitElementSpecialGraphicInfo()
718 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
719 int num_property_mappings = getImageListPropertyMappingSize();
722 /* always start with reliable default values */
723 for (i=0; i < MAX_NUM_ELEMENTS; i++)
724 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
725 element_info[i].special_graphic[j] =
726 element_info[i].graphic[ACTION_DEFAULT];
728 /* initialize special element/graphic mapping from static configuration */
729 for (i=0; element_to_special_graphic[i].element > -1; i++)
731 int element = element_to_special_graphic[i].element;
732 int special = element_to_special_graphic[i].special;
733 int graphic = element_to_special_graphic[i].graphic;
734 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
735 boolean special_redefined = getImageListEntry(graphic)->redefined;
737 /* if the base graphic ("emerald", for example) has been redefined,
738 but not the special graphic ("emerald.EDITOR", for example), do not
739 use an existing (in this case considered obsolete) special graphic
740 anymore, but use the automatically created (down-scaled) graphic */
741 if (base_redefined && !special_redefined)
744 element_info[element].special_graphic[special] = graphic;
747 /* initialize special element/graphic mapping from dynamic configuration */
748 for (i=0; i < num_property_mappings; i++)
750 int element = property_mapping[i].base_index;
751 int special = property_mapping[i].ext3_index;
752 int graphic = property_mapping[i].artwork_index;
754 if (element >= MAX_NUM_ELEMENTS)
757 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
758 element_info[element].special_graphic[special] = graphic;
762 /* now set all undefined/invalid graphics to default */
763 for (i=0; i < MAX_NUM_ELEMENTS; i++)
764 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
765 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
766 element_info[i].special_graphic[j] =
767 element_info[i].graphic[ACTION_DEFAULT];
771 static int get_element_from_token(char *token)
775 for (i=0; i < MAX_NUM_ELEMENTS; i++)
776 if (strcmp(element_info[i].token_name, token) == 0)
782 static void set_graphic_parameters(int graphic, char **parameter_raw)
784 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
785 int parameter[NUM_GFX_ARGS];
786 int anim_frames_per_row = 1, anim_frames_per_col = 1;
787 int anim_frames_per_line = 1;
790 /* get integer values from string parameters */
791 for (i=0; i < NUM_GFX_ARGS; i++)
794 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
795 image_config_suffix[i].type);
797 if (image_config_suffix[i].type == TYPE_TOKEN)
798 parameter[i] = get_element_from_token(parameter_raw[i]);
801 graphic_info[graphic].bitmap = src_bitmap;
803 /* start with reliable default values */
804 graphic_info[graphic].src_x = 0;
805 graphic_info[graphic].src_y = 0;
806 graphic_info[graphic].width = TILEX;
807 graphic_info[graphic].height = TILEY;
808 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
809 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
810 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
811 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
812 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
814 /* optional x and y tile position of animation frame sequence */
815 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
816 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
817 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
818 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
820 /* optional x and y pixel position of animation frame sequence */
821 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
822 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
823 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
824 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
826 /* optional width and height of each animation frame */
827 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
828 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
829 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
830 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
834 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
835 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
838 /* correct x or y offset dependent of vertical or horizontal frame order */
839 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
841 graphic_info[graphic].offset_y =
842 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
843 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
844 anim_frames_per_line = anim_frames_per_col;
846 else /* frames are ordered horizontally */
848 graphic_info[graphic].offset_x =
849 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
850 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
851 anim_frames_per_line = anim_frames_per_row;
854 /* optionally, the x and y offset of frames can be specified directly */
855 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
856 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
857 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
858 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
860 /* automatically determine correct number of frames, if not defined */
861 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
862 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
863 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
864 graphic_info[graphic].anim_frames = anim_frames_per_row;
865 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
866 graphic_info[graphic].anim_frames = anim_frames_per_col;
868 graphic_info[graphic].anim_frames = 1;
870 graphic_info[graphic].anim_frames_per_line =
871 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
872 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
874 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
875 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
876 graphic_info[graphic].anim_delay = 1;
878 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
880 if (graphic_info[graphic].anim_frames == 1)
881 graphic_info[graphic].anim_mode = ANIM_NONE;
884 /* automatically determine correct start frame, if not defined */
885 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
886 graphic_info[graphic].anim_start_frame = 0;
887 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
888 graphic_info[graphic].anim_start_frame =
889 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
891 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
893 /* animation synchronized with global frame counter, not move position */
894 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
896 /* optional element for cloning crumble graphics */
897 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
898 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
900 /* optional element for cloning digging graphics */
901 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
902 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
904 /* optional border size for "crumbling" diggable graphics */
905 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
906 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
908 /* this is only used for toon animations */
909 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
910 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
912 /* this is only used for drawing font characters */
913 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
914 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
916 /* this is only used for drawing envelope graphics */
917 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
920 static void InitGraphicInfo()
922 int fallback_graphic = IMG_CHAR_EXCLAM;
923 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
924 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
925 int num_images = getImageListSize();
928 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
929 static boolean clipmasks_initialized = FALSE;
931 XGCValues clip_gc_values;
932 unsigned long clip_gc_valuemask;
933 GC copy_clipmask_gc = None;
936 if (graphic_info != NULL)
939 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
942 printf("::: graphic_info: %d entries\n", num_images);
945 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
946 if (clipmasks_initialized)
948 for (i=0; i<num_images; i++)
950 if (graphic_info[i].clip_mask)
951 XFreePixmap(display, graphic_info[i].clip_mask);
952 if (graphic_info[i].clip_gc)
953 XFreeGC(display, graphic_info[i].clip_gc);
955 graphic_info[i].clip_mask = None;
956 graphic_info[i].clip_gc = None;
961 for (i=0; i<num_images; i++)
963 struct FileInfo *image = getImageListEntry(i);
966 int first_frame, last_frame;
969 printf("::: image: '%s' [%d]\n", image->token, i);
973 printf("::: image # %d: '%s' ['%s']\n",
975 getTokenFromImageID(i));
978 set_graphic_parameters(i, image->parameter);
980 /* now check if no animation frames are outside of the loaded image */
982 if (graphic_info[i].bitmap == NULL)
983 continue; /* skip check for optional images that are undefined */
986 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
987 if (src_x < 0 || src_y < 0 ||
988 src_x + TILEX > src_bitmap->width ||
989 src_y + TILEY > src_bitmap->height)
991 Error(ERR_RETURN_LINE, "-");
992 Error(ERR_RETURN, "warning: error found in config file:");
993 Error(ERR_RETURN, "- config file: '%s'",
994 getImageConfigFilename());
995 Error(ERR_RETURN, "- config token: '%s'",
996 getTokenFromImageID(i));
997 Error(ERR_RETURN, "- image file: '%s'",
998 src_bitmap->source_filename);
1000 "error: first animation frame out of bounds (%d, %d)",
1002 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1004 if (i == fallback_graphic)
1005 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1007 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1008 Error(ERR_RETURN_LINE, "-");
1010 set_graphic_parameters(i, fallback_image->default_parameter);
1011 graphic_info[i].bitmap = fallback_bitmap;
1014 last_frame = graphic_info[i].anim_frames - 1;
1015 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1016 if (src_x < 0 || src_y < 0 ||
1017 src_x + TILEX > src_bitmap->width ||
1018 src_y + TILEY > src_bitmap->height)
1020 Error(ERR_RETURN_LINE, "-");
1021 Error(ERR_RETURN, "warning: error found in config file:");
1022 Error(ERR_RETURN, "- config file: '%s'",
1023 getImageConfigFilename());
1024 Error(ERR_RETURN, "- config token: '%s'",
1025 getTokenFromImageID(i));
1026 Error(ERR_RETURN, "- image file: '%s'",
1027 src_bitmap->source_filename);
1029 "error: last animation frame (%d) out of bounds (%d, %d)",
1030 last_frame, src_x, src_y);
1031 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1033 if (i == fallback_graphic)
1034 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1036 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1037 Error(ERR_RETURN_LINE, "-");
1039 set_graphic_parameters(i, fallback_image->default_parameter);
1040 graphic_info[i].bitmap = fallback_bitmap;
1043 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1044 /* currently we need only a tile clip mask from the first frame */
1045 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1047 if (copy_clipmask_gc == None)
1049 clip_gc_values.graphics_exposures = False;
1050 clip_gc_valuemask = GCGraphicsExposures;
1051 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1052 clip_gc_valuemask, &clip_gc_values);
1055 graphic_info[i].clip_mask =
1056 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1058 src_pixmap = src_bitmap->clip_mask;
1059 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1060 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1062 clip_gc_values.graphics_exposures = False;
1063 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1064 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1066 graphic_info[i].clip_gc =
1067 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1071 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1072 if (copy_clipmask_gc)
1073 XFreeGC(display, copy_clipmask_gc);
1075 clipmasks_initialized = TRUE;
1079 static void InitElementSoundInfo()
1081 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1082 int num_property_mappings = getSoundListPropertyMappingSize();
1085 /* set values to -1 to identify later as "uninitialized" values */
1086 for (i=0; i < MAX_NUM_ELEMENTS; i++)
1087 for (act=0; act < NUM_ACTIONS; act++)
1088 element_info[i].sound[act] = -1;
1090 /* initialize element/sound mapping from static configuration */
1091 for (i=0; element_to_sound[i].element > -1; i++)
1093 int element = element_to_sound[i].element;
1094 int action = element_to_sound[i].action;
1095 int sound = element_to_sound[i].sound;
1096 boolean is_class = element_to_sound[i].is_class;
1099 action = ACTION_DEFAULT;
1102 element_info[element].sound[action] = sound;
1104 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1105 if (strcmp(element_info[j].class_name,
1106 element_info[element].class_name) == 0)
1107 element_info[j].sound[action] = sound;
1110 /* initialize element class/sound mapping from dynamic configuration */
1111 for (i=0; i < num_property_mappings; i++)
1113 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1114 int action = property_mapping[i].ext1_index;
1115 int sound = property_mapping[i].artwork_index;
1117 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1121 action = ACTION_DEFAULT;
1123 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1124 if (strcmp(element_info[j].class_name,
1125 element_info[element_class].class_name) == 0)
1126 element_info[j].sound[action] = sound;
1129 /* initialize element/sound mapping from dynamic configuration */
1130 for (i=0; i < num_property_mappings; i++)
1132 int element = property_mapping[i].base_index;
1133 int action = property_mapping[i].ext1_index;
1134 int sound = property_mapping[i].artwork_index;
1136 if (element >= MAX_NUM_ELEMENTS)
1140 action = ACTION_DEFAULT;
1142 element_info[element].sound[action] = sound;
1145 /* now set all '-1' values to element specific default values */
1146 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1148 for (act=0; act < NUM_ACTIONS; act++)
1150 /* generic default action sound (defined by "[default]" directive) */
1151 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1153 /* look for special default action sound (classic game specific) */
1154 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1155 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1156 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1157 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1158 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1159 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1161 /* look for element specific default sound (independent from action) */
1162 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1163 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1165 /* no sound for this specific action -- use default action sound */
1166 if (element_info[i].sound[act] == -1)
1167 element_info[i].sound[act] = default_action_sound;
1172 static void set_sound_parameters(int sound, char **parameter_raw)
1174 int parameter[NUM_SND_ARGS];
1177 /* get integer values from string parameters */
1178 for (i=0; i < NUM_SND_ARGS; i++)
1180 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1181 sound_config_suffix[i].type);
1183 /* explicit loop mode setting in configuration overrides default value */
1184 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1185 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1188 static void InitSoundInfo()
1191 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1192 int num_property_mappings = getSoundListPropertyMappingSize();
1194 int *sound_effect_properties;
1195 int num_sounds = getSoundListSize();
1198 if (sound_info != NULL)
1201 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1202 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1204 /* initialize sound effect for all elements to "no sound" */
1205 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1206 for (j=0; j<NUM_ACTIONS; j++)
1207 element_info[i].sound[j] = SND_UNDEFINED;
1209 for (i=0; i<num_sounds; i++)
1211 struct FileInfo *sound = getSoundListEntry(i);
1212 int len_effect_text = strlen(sound->token);
1214 sound_effect_properties[i] = ACTION_OTHER;
1215 sound_info[i].loop = FALSE;
1218 printf("::: sound %d: '%s'\n", i, sound->token);
1221 /* determine all loop sounds and identify certain sound classes */
1223 for (j=0; element_action_info[j].suffix; j++)
1225 int len_action_text = strlen(element_action_info[j].suffix);
1227 if (len_action_text < len_effect_text &&
1228 strcmp(&sound->token[len_effect_text - len_action_text],
1229 element_action_info[j].suffix) == 0)
1231 sound_effect_properties[i] = element_action_info[j].value;
1232 sound_info[i].loop = element_action_info[j].is_loop_sound;
1239 if (strcmp(sound->token, "custom_42") == 0)
1240 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1243 /* associate elements and some selected sound actions */
1245 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1247 if (element_info[j].class_name)
1249 int len_class_text = strlen(element_info[j].class_name);
1251 if (len_class_text + 1 < len_effect_text &&
1252 strncmp(sound->token,
1253 element_info[j].class_name, len_class_text) == 0 &&
1254 sound->token[len_class_text] == '.')
1256 int sound_action_value = sound_effect_properties[i];
1258 element_info[j].sound[sound_action_value] = i;
1263 set_sound_parameters(i, sound->parameter);
1266 free(sound_effect_properties);
1269 /* !!! now handled in InitElementSoundInfo() !!! */
1270 /* initialize element/sound mapping from dynamic configuration */
1271 for (i=0; i < num_property_mappings; i++)
1273 int element = property_mapping[i].base_index;
1274 int action = property_mapping[i].ext1_index;
1275 int sound = property_mapping[i].artwork_index;
1278 action = ACTION_DEFAULT;
1280 printf("::: %d: %d, %d, %d ['%s']\n",
1281 i, element, action, sound, element_info[element].token_name);
1283 element_info[element].sound[action] = sound;
1290 int element = EL_CUSTOM_11;
1293 while (element_action_info[j].suffix)
1295 printf("element %d, sound action '%s' == %d\n",
1296 element, element_action_info[j].suffix,
1297 element_info[element].sound[j]);
1302 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1308 int element = EL_SAND;
1309 int sound_action = ACTION_DIGGING;
1312 while (element_action_info[j].suffix)
1314 if (element_action_info[j].value == sound_action)
1315 printf("element %d, sound action '%s' == %d\n",
1316 element, element_action_info[j].suffix,
1317 element_info[element].sound[sound_action]);
1324 static void ReinitializeGraphics()
1326 InitGraphicInfo(); /* graphic properties mapping */
1327 InitElementGraphicInfo(); /* element game graphic mapping */
1328 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1330 InitElementSmallImages(); /* create editor and preview images */
1331 InitFontGraphicInfo(); /* initialize text drawing functions */
1333 SetMainBackgroundImage(IMG_BACKGROUND);
1334 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1340 static void ReinitializeSounds()
1342 InitSoundInfo(); /* sound properties mapping */
1343 InitElementSoundInfo(); /* element game sound mapping */
1345 InitPlaySoundLevel(); /* internal game sound settings */
1348 static void ReinitializeMusic()
1350 /* currently nothing to do */
1353 void InitElementPropertiesStatic()
1355 static int ep_diggable[] =
1360 EL_SP_BUGGY_BASE_ACTIVATING,
1363 EL_INVISIBLE_SAND_ACTIVE,
1365 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1369 EL_SP_BUGGY_BASE_ACTIVE,
1374 static int ep_collectible_only[] =
1391 EL_DYNABOMB_INCREASE_NUMBER,
1392 EL_DYNABOMB_INCREASE_SIZE,
1393 EL_DYNABOMB_INCREASE_POWER,
1410 static int ep_dont_run_into[] =
1412 /* same elements as in 'ep_dont_touch' */
1418 /* same elements as in 'ep_dont_collide_with' */
1430 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1434 EL_SP_BUGGY_BASE_ACTIVE,
1439 static int ep_dont_collide_with[] =
1441 /* same elements as in 'ep_dont_touch' */
1457 static int ep_dont_touch[] =
1466 static int ep_indestructible[] =
1470 EL_ACID_POOL_TOPLEFT,
1471 EL_ACID_POOL_TOPRIGHT,
1472 EL_ACID_POOL_BOTTOMLEFT,
1473 EL_ACID_POOL_BOTTOM,
1474 EL_ACID_POOL_BOTTOMRIGHT,
1475 EL_SP_HARDWARE_GRAY,
1476 EL_SP_HARDWARE_GREEN,
1477 EL_SP_HARDWARE_BLUE,
1479 EL_SP_HARDWARE_YELLOW,
1480 EL_SP_HARDWARE_BASE_1,
1481 EL_SP_HARDWARE_BASE_2,
1482 EL_SP_HARDWARE_BASE_3,
1483 EL_SP_HARDWARE_BASE_4,
1484 EL_SP_HARDWARE_BASE_5,
1485 EL_SP_HARDWARE_BASE_6,
1486 EL_INVISIBLE_STEELWALL,
1487 EL_INVISIBLE_STEELWALL_ACTIVE,
1488 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1489 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1490 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1491 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1492 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1493 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1494 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1495 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1496 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1497 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1498 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1499 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1501 EL_LIGHT_SWITCH_ACTIVE,
1502 EL_SIGN_EXCLAMATION,
1503 EL_SIGN_RADIOACTIVITY,
1514 EL_STEELWALL_SLIPPERY,
1537 EL_SWITCHGATE_OPENING,
1538 EL_SWITCHGATE_CLOSED,
1539 EL_SWITCHGATE_CLOSING,
1541 EL_SWITCHGATE_SWITCH_UP,
1542 EL_SWITCHGATE_SWITCH_DOWN,
1545 EL_TIMEGATE_OPENING,
1547 EL_TIMEGATE_CLOSING,
1550 EL_TIMEGATE_SWITCH_ACTIVE,
1555 EL_TUBE_VERTICAL_LEFT,
1556 EL_TUBE_VERTICAL_RIGHT,
1557 EL_TUBE_HORIZONTAL_UP,
1558 EL_TUBE_HORIZONTAL_DOWN,
1566 static int ep_slippery[] =
1580 EL_ROBOT_WHEEL_ACTIVE,
1586 EL_ACID_POOL_TOPLEFT,
1587 EL_ACID_POOL_TOPRIGHT,
1597 EL_STEELWALL_SLIPPERY,
1603 static int ep_can_change[] =
1608 static int ep_can_move[] =
1630 static int ep_can_fall[] =
1645 EL_BD_MAGIC_WALL_FULL,
1658 static int ep_can_smash_player[] =
1683 static int ep_can_smash_enemies[] =
1691 static int ep_can_smash_everything[] =
1699 static int ep_can_explode_by_fire[] =
1701 /* same elements as in 'ep_can_explode_impact' */
1706 /* same elements as in 'ep_can_explode_smashed' */
1715 EL_DYNABOMB_PLAYER_1_ACTIVE,
1716 EL_DYNABOMB_PLAYER_2_ACTIVE,
1717 EL_DYNABOMB_PLAYER_3_ACTIVE,
1718 EL_DYNABOMB_PLAYER_4_ACTIVE,
1719 EL_DYNABOMB_INCREASE_NUMBER,
1720 EL_DYNABOMB_INCREASE_SIZE,
1721 EL_DYNABOMB_INCREASE_POWER,
1722 EL_SP_DISK_RED_ACTIVE,
1732 static int ep_can_explode_smashed[] =
1734 /* same elements as in 'ep_can_explode_impact' */
1747 static int ep_can_explode_impact[] =
1755 static int ep_walkable_over[] =
1759 EL_SOKOBAN_FIELD_EMPTY,
1777 static int ep_walkable_inside[] =
1782 EL_TUBE_VERTICAL_LEFT,
1783 EL_TUBE_VERTICAL_RIGHT,
1784 EL_TUBE_HORIZONTAL_UP,
1785 EL_TUBE_HORIZONTAL_DOWN,
1793 static int ep_walkable_under[] =
1798 static int ep_passable_over[] =
1813 static int ep_passable_inside[] =
1819 EL_SP_PORT_HORIZONTAL,
1820 EL_SP_PORT_VERTICAL,
1822 EL_SP_GRAVITY_PORT_LEFT,
1823 EL_SP_GRAVITY_PORT_RIGHT,
1824 EL_SP_GRAVITY_PORT_UP,
1825 EL_SP_GRAVITY_PORT_DOWN,
1829 static int ep_passable_under[] =
1834 static int ep_droppable[] =
1839 static int ep_can_explode_1x1[] =
1844 static int ep_pushable[] =
1856 EL_SOKOBAN_FIELD_FULL,
1863 static int ep_player[] =
1873 static int ep_can_pass_magic_wall[] =
1886 static int ep_switchable[] =
1890 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1891 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1892 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1893 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1894 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1895 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1896 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1897 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1898 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1899 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1900 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1901 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1902 EL_SWITCHGATE_SWITCH_UP,
1903 EL_SWITCHGATE_SWITCH_DOWN,
1905 EL_LIGHT_SWITCH_ACTIVE,
1907 EL_BALLOON_SWITCH_LEFT,
1908 EL_BALLOON_SWITCH_RIGHT,
1909 EL_BALLOON_SWITCH_UP,
1910 EL_BALLOON_SWITCH_DOWN,
1911 EL_BALLOON_SWITCH_ANY,
1917 static int ep_bd_element[] =
1946 static int ep_sp_element[] =
1948 /* should always be valid */
1957 EL_SP_HARDWARE_GRAY,
1965 EL_SP_GRAVITY_PORT_RIGHT,
1966 EL_SP_GRAVITY_PORT_DOWN,
1967 EL_SP_GRAVITY_PORT_LEFT,
1968 EL_SP_GRAVITY_PORT_UP,
1973 EL_SP_PORT_VERTICAL,
1974 EL_SP_PORT_HORIZONTAL,
1980 EL_SP_HARDWARE_BASE_1,
1981 EL_SP_HARDWARE_GREEN,
1982 EL_SP_HARDWARE_BLUE,
1984 EL_SP_HARDWARE_YELLOW,
1985 EL_SP_HARDWARE_BASE_2,
1986 EL_SP_HARDWARE_BASE_3,
1987 EL_SP_HARDWARE_BASE_4,
1988 EL_SP_HARDWARE_BASE_5,
1989 EL_SP_HARDWARE_BASE_6,
1992 /* additional elements that appeared in newer Supaplex levels */
1994 /* more than one murphy in a level results in an inactive clone */
1996 /* runtime elements*/
1997 EL_SP_DISK_RED_ACTIVE,
1998 EL_SP_TERMINAL_ACTIVE,
1999 EL_SP_BUGGY_BASE_ACTIVATING,
2000 EL_SP_BUGGY_BASE_ACTIVE,
2006 static int ep_sb_element[] =
2011 EL_SOKOBAN_FIELD_EMPTY,
2012 EL_SOKOBAN_FIELD_FULL,
2014 EL_INVISIBLE_STEELWALL,
2018 static int ep_gem[] =
2029 static int ep_food_dark_yamyam[] =
2056 static int ep_food_penguin[] =
2069 static int ep_food_pig[] =
2080 static int ep_historic_wall[] =
2105 EL_EXPANDABLE_WALL_HORIZONTAL,
2106 EL_EXPANDABLE_WALL_VERTICAL,
2107 EL_EXPANDABLE_WALL_ANY,
2108 EL_EXPANDABLE_WALL_GROWING,
2115 EL_SP_HARDWARE_GRAY,
2116 EL_SP_HARDWARE_GREEN,
2117 EL_SP_HARDWARE_BLUE,
2119 EL_SP_HARDWARE_YELLOW,
2120 EL_SP_HARDWARE_BASE_1,
2121 EL_SP_HARDWARE_BASE_2,
2122 EL_SP_HARDWARE_BASE_3,
2123 EL_SP_HARDWARE_BASE_4,
2124 EL_SP_HARDWARE_BASE_5,
2125 EL_SP_HARDWARE_BASE_6,
2127 EL_SP_TERMINAL_ACTIVE,
2130 EL_INVISIBLE_STEELWALL,
2131 EL_INVISIBLE_STEELWALL_ACTIVE,
2133 EL_INVISIBLE_WALL_ACTIVE,
2134 EL_STEELWALL_SLIPPERY,
2150 static int ep_historic_solid[] =
2154 EL_EXPANDABLE_WALL_HORIZONTAL,
2155 EL_EXPANDABLE_WALL_VERTICAL,
2156 EL_EXPANDABLE_WALL_ANY,
2169 EL_QUICKSAND_FILLING,
2170 EL_QUICKSAND_EMPTYING,
2172 EL_MAGIC_WALL_ACTIVE,
2173 EL_MAGIC_WALL_EMPTYING,
2174 EL_MAGIC_WALL_FILLING,
2178 EL_BD_MAGIC_WALL_ACTIVE,
2179 EL_BD_MAGIC_WALL_EMPTYING,
2180 EL_BD_MAGIC_WALL_FULL,
2181 EL_BD_MAGIC_WALL_FILLING,
2182 EL_BD_MAGIC_WALL_DEAD,
2191 EL_SP_TERMINAL_ACTIVE,
2195 EL_INVISIBLE_WALL_ACTIVE,
2196 EL_SWITCHGATE_SWITCH_UP,
2197 EL_SWITCHGATE_SWITCH_DOWN,
2199 EL_TIMEGATE_SWITCH_ACTIVE,
2211 /* the following elements are a direct copy of "indestructible" elements,
2212 except "EL_ACID", which is "indestructible", but not "solid"! */
2217 EL_ACID_POOL_TOPLEFT,
2218 EL_ACID_POOL_TOPRIGHT,
2219 EL_ACID_POOL_BOTTOMLEFT,
2220 EL_ACID_POOL_BOTTOM,
2221 EL_ACID_POOL_BOTTOMRIGHT,
2222 EL_SP_HARDWARE_GRAY,
2223 EL_SP_HARDWARE_GREEN,
2224 EL_SP_HARDWARE_BLUE,
2226 EL_SP_HARDWARE_YELLOW,
2227 EL_SP_HARDWARE_BASE_1,
2228 EL_SP_HARDWARE_BASE_2,
2229 EL_SP_HARDWARE_BASE_3,
2230 EL_SP_HARDWARE_BASE_4,
2231 EL_SP_HARDWARE_BASE_5,
2232 EL_SP_HARDWARE_BASE_6,
2233 EL_INVISIBLE_STEELWALL,
2234 EL_INVISIBLE_STEELWALL_ACTIVE,
2235 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2236 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2237 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2238 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2239 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2240 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2241 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2242 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2243 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2244 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2245 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2246 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2248 EL_LIGHT_SWITCH_ACTIVE,
2249 EL_SIGN_EXCLAMATION,
2250 EL_SIGN_RADIOACTIVITY,
2261 EL_STEELWALL_SLIPPERY,
2284 EL_SWITCHGATE_OPENING,
2285 EL_SWITCHGATE_CLOSED,
2286 EL_SWITCHGATE_CLOSING,
2288 EL_TIMEGATE_OPENING,
2290 EL_TIMEGATE_CLOSING,
2294 EL_TUBE_VERTICAL_LEFT,
2295 EL_TUBE_VERTICAL_RIGHT,
2296 EL_TUBE_HORIZONTAL_UP,
2297 EL_TUBE_HORIZONTAL_DOWN,
2305 static int ep_classic_enemy[] =
2321 static int ep_belt[] =
2323 EL_CONVEYOR_BELT_1_LEFT,
2324 EL_CONVEYOR_BELT_1_MIDDLE,
2325 EL_CONVEYOR_BELT_1_RIGHT,
2326 EL_CONVEYOR_BELT_2_LEFT,
2327 EL_CONVEYOR_BELT_2_MIDDLE,
2328 EL_CONVEYOR_BELT_2_RIGHT,
2329 EL_CONVEYOR_BELT_3_LEFT,
2330 EL_CONVEYOR_BELT_3_MIDDLE,
2331 EL_CONVEYOR_BELT_3_RIGHT,
2332 EL_CONVEYOR_BELT_4_LEFT,
2333 EL_CONVEYOR_BELT_4_MIDDLE,
2334 EL_CONVEYOR_BELT_4_RIGHT,
2338 static int ep_belt_active[] =
2340 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2341 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2342 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2343 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2344 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2345 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2346 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2347 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2348 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2349 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2350 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2351 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2355 static int ep_belt_switch[] =
2357 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2358 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2359 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2360 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2361 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2362 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2363 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2364 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2365 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2366 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2367 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2368 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2372 static int ep_tube[] =
2379 EL_TUBE_HORIZONTAL_UP,
2380 EL_TUBE_HORIZONTAL_DOWN,
2382 EL_TUBE_VERTICAL_LEFT,
2383 EL_TUBE_VERTICAL_RIGHT,
2388 static int ep_keygate[] =
2409 static int ep_amoeboid[] =
2419 static int ep_amoebalive[] =
2428 static int ep_has_content[] =
2438 static int ep_active_bomb[] =
2441 EL_DYNABOMB_PLAYER_1_ACTIVE,
2442 EL_DYNABOMB_PLAYER_2_ACTIVE,
2443 EL_DYNABOMB_PLAYER_3_ACTIVE,
2444 EL_DYNABOMB_PLAYER_4_ACTIVE,
2445 EL_SP_DISK_RED_ACTIVE,
2449 static int ep_inactive[] =
2486 EL_INVISIBLE_STEELWALL,
2494 EL_WALL_EMERALD_YELLOW,
2495 EL_DYNABOMB_INCREASE_NUMBER,
2496 EL_DYNABOMB_INCREASE_SIZE,
2497 EL_DYNABOMB_INCREASE_POWER,
2501 EL_SOKOBAN_FIELD_EMPTY,
2502 EL_SOKOBAN_FIELD_FULL,
2503 EL_WALL_EMERALD_RED,
2504 EL_WALL_EMERALD_PURPLE,
2505 EL_ACID_POOL_TOPLEFT,
2506 EL_ACID_POOL_TOPRIGHT,
2507 EL_ACID_POOL_BOTTOMLEFT,
2508 EL_ACID_POOL_BOTTOM,
2509 EL_ACID_POOL_BOTTOMRIGHT,
2513 EL_BD_MAGIC_WALL_DEAD,
2514 EL_AMOEBA_TO_DIAMOND,
2522 EL_SP_GRAVITY_PORT_RIGHT,
2523 EL_SP_GRAVITY_PORT_DOWN,
2524 EL_SP_GRAVITY_PORT_LEFT,
2525 EL_SP_GRAVITY_PORT_UP,
2526 EL_SP_PORT_HORIZONTAL,
2527 EL_SP_PORT_VERTICAL,
2538 EL_SP_HARDWARE_GRAY,
2539 EL_SP_HARDWARE_GREEN,
2540 EL_SP_HARDWARE_BLUE,
2542 EL_SP_HARDWARE_YELLOW,
2543 EL_SP_HARDWARE_BASE_1,
2544 EL_SP_HARDWARE_BASE_2,
2545 EL_SP_HARDWARE_BASE_3,
2546 EL_SP_HARDWARE_BASE_4,
2547 EL_SP_HARDWARE_BASE_5,
2548 EL_SP_HARDWARE_BASE_6,
2549 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2550 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2551 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2552 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2553 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2554 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2555 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2556 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2557 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2558 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2559 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2560 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2561 EL_SIGN_EXCLAMATION,
2562 EL_SIGN_RADIOACTIVITY,
2573 EL_STEELWALL_SLIPPERY,
2589 static int ep_em_slippery_wall[] =
2594 static int ep_gfx_crumbled[] =
2607 } element_properties[] =
2609 { ep_diggable, EP_DIGGABLE },
2610 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2611 { ep_dont_run_into, EP_DONT_RUN_INTO },
2612 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2613 { ep_dont_touch, EP_DONT_TOUCH },
2614 { ep_indestructible, EP_INDESTRUCTIBLE },
2615 { ep_slippery, EP_SLIPPERY },
2616 { ep_can_change, EP_CAN_CHANGE },
2617 { ep_can_move, EP_CAN_MOVE },
2618 { ep_can_fall, EP_CAN_FALL },
2619 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2620 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2621 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2622 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2623 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2624 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2625 { ep_walkable_over, EP_WALKABLE_OVER },
2626 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2627 { ep_walkable_under, EP_WALKABLE_UNDER },
2628 { ep_passable_over, EP_PASSABLE_OVER },
2629 { ep_passable_inside, EP_PASSABLE_INSIDE },
2630 { ep_passable_under, EP_PASSABLE_UNDER },
2631 { ep_droppable, EP_DROPPABLE },
2632 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2633 { ep_pushable, EP_PUSHABLE },
2635 { ep_player, EP_PLAYER },
2636 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2637 { ep_switchable, EP_SWITCHABLE },
2638 { ep_bd_element, EP_BD_ELEMENT },
2639 { ep_sp_element, EP_SP_ELEMENT },
2640 { ep_sb_element, EP_SB_ELEMENT },
2642 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2643 { ep_food_penguin, EP_FOOD_PENGUIN },
2644 { ep_food_pig, EP_FOOD_PIG },
2645 { ep_historic_wall, EP_HISTORIC_WALL },
2646 { ep_historic_solid, EP_HISTORIC_SOLID },
2647 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2648 { ep_belt, EP_BELT },
2649 { ep_belt_active, EP_BELT_ACTIVE },
2650 { ep_belt_switch, EP_BELT_SWITCH },
2651 { ep_tube, EP_TUBE },
2652 { ep_keygate, EP_KEYGATE },
2653 { ep_amoeboid, EP_AMOEBOID },
2654 { ep_amoebalive, EP_AMOEBALIVE },
2655 { ep_has_content, EP_HAS_CONTENT },
2656 { ep_active_bomb, EP_ACTIVE_BOMB },
2657 { ep_inactive, EP_INACTIVE },
2659 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2661 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2666 static int copy_properties[][5] =
2670 EL_BUG_LEFT, EL_BUG_RIGHT,
2671 EL_BUG_UP, EL_BUG_DOWN
2675 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2676 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2680 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2681 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2685 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2686 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2690 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2691 EL_PACMAN_UP, EL_PACMAN_DOWN
2701 /* always start with reliable default values (element has no properties) */
2702 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2703 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2704 SET_PROPERTY(i, j, FALSE);
2706 /* set all base element properties from above array definitions */
2707 for (i=0; element_properties[i].elements != NULL; i++)
2708 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2709 SET_PROPERTY((element_properties[i].elements)[j],
2710 element_properties[i].property, TRUE);
2712 /* copy properties to some elements that are only stored in level file */
2713 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2714 for (j=0; copy_properties[j][0] != -1; j++)
2715 if (HAS_PROPERTY(copy_properties[j][0], i))
2716 for (k=1; k<=4; k++)
2717 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2720 void InitElementPropertiesEngine(int engine_version)
2723 static int active_properties[] =
2728 EP_DONT_COLLIDE_WITH,
2732 EP_CAN_PASS_MAGIC_WALL,
2737 EP_CAN_EXPLODE_BY_FIRE,
2750 EP_EM_SLIPPERY_WALL,
2754 static int no_wall_properties[] =
2757 EP_COLLECTIBLE_ONLY,
2759 EP_DONT_COLLIDE_WITH,
2762 EP_CAN_SMASH_PLAYER,
2763 EP_CAN_SMASH_ENEMIES,
2764 EP_CAN_SMASH_EVERYTHING,
2769 EP_FOOD_DARK_YAMYAM,
2785 InitElementPropertiesStatic();
2788 /* set all special, combined or engine dependent element properties */
2789 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2792 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2793 SET_PROPERTY(i, j, FALSE);
2796 /* ---------- INACTIVE ------------------------------------------------- */
2797 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2798 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2800 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2801 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2802 IS_WALKABLE_INSIDE(i) ||
2803 IS_WALKABLE_UNDER(i)));
2805 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2806 IS_PASSABLE_INSIDE(i) ||
2807 IS_PASSABLE_UNDER(i)));
2809 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2810 IS_PASSABLE_OVER(i)));
2812 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2813 IS_PASSABLE_INSIDE(i)));
2815 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2816 IS_PASSABLE_UNDER(i)));
2818 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2821 /* ---------- COLLECTIBLE ---------------------------------------------- */
2822 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
2825 /* ---------- SNAPPABLE ------------------------------------------------ */
2826 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2827 IS_COLLECTIBLE(i) ||
2831 /* ---------- WALL ----------------------------------------------------- */
2832 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2834 for (j=0; no_wall_properties[j] != -1; j++)
2835 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2836 i >= EL_FIRST_RUNTIME_UNREAL)
2837 SET_PROPERTY(i, EP_WALL, FALSE);
2839 if (IS_HISTORIC_WALL(i))
2840 SET_PROPERTY(i, EP_WALL, TRUE);
2842 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2843 if (engine_version < VERSION_IDENT(2,2,0,0))
2844 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2846 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2848 !IS_COLLECTIBLE(i)));
2850 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2852 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2853 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2855 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2856 IS_INDESTRUCTIBLE(i)));
2858 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2860 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2861 else if (engine_version < VERSION_IDENT(2,2,0,0))
2862 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2864 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2865 !IS_WALKABLE_OVER(i) &&
2866 !IS_WALKABLE_UNDER(i)));
2868 if (IS_CUSTOM_ELEMENT(i))
2870 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2872 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2873 if (DONT_COLLIDE_WITH(i))
2874 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2876 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2877 if (CAN_SMASH_EVERYTHING(i))
2878 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2879 if (CAN_SMASH_ENEMIES(i))
2880 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2883 /* ---------- CAN_SMASH ------------------------------------------------ */
2884 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2885 CAN_SMASH_ENEMIES(i) ||
2886 CAN_SMASH_EVERYTHING(i)));
2888 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2889 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2890 CAN_EXPLODE_SMASHED(i) ||
2891 CAN_EXPLODE_IMPACT(i)));
2893 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
2894 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
2895 !CAN_EXPLODE_1X1(i)));
2897 /* ---------- CAN_CHANGE ----------------------------------------------- */
2898 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
2899 for (j=0; j < element_info[i].num_change_pages; j++)
2900 if (element_info[i].change_page[j].can_change)
2901 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
2903 /* ---------- GFX_CRUMBLED --------------------------------------------- */
2904 SET_PROPERTY(i, EP_GFX_CRUMBLED,
2905 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
2909 /* determine inactive elements (used for engine main loop optimization) */
2910 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2912 boolean active = FALSE;
2914 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2916 if (HAS_PROPERTY(i, j))
2922 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2927 /* dynamically adjust element properties according to game engine version */
2929 static int ep_em_slippery_wall[] =
2934 EL_EXPANDABLE_WALL_HORIZONTAL,
2935 EL_EXPANDABLE_WALL_VERTICAL,
2936 EL_EXPANDABLE_WALL_ANY,
2940 /* special EM style gems behaviour */
2941 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2942 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2943 level.em_slippery_gems);
2945 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2946 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2947 (level.em_slippery_gems &&
2948 engine_version > VERSION_IDENT(2,0,1,0)));
2952 /* set default push delay values (corrected since version 3.0.7-1) */
2953 if (engine_version < VERSION_IDENT(3,0,7,1))
2955 game.default_push_delay_fixed = 2;
2956 game.default_push_delay_random = 8;
2960 game.default_push_delay_fixed = 8;
2961 game.default_push_delay_random = 8;
2964 /* set uninitialized push delay values of custom elements in older levels */
2965 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2967 int element = EL_CUSTOM_START + i;
2969 if (element_info[element].push_delay_fixed == -1)
2970 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
2971 if (element_info[element].push_delay_random == -1)
2972 element_info[element].push_delay_random = game.default_push_delay_random;
2977 static void InitGlobal()
2979 global.autoplay_leveldir = NULL;
2981 global.frames_per_second = 0;
2982 global.fps_slowdown = FALSE;
2983 global.fps_slowdown_factor = 1;
2986 void Execute_Command(char *command)
2988 if (strcmp(command, "print graphicsinfo.conf") == 0)
2992 printf("# You can configure additional/alternative image files here.\n");
2993 printf("# (The images below are default and therefore commented out.)\n");
2995 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2997 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3000 for (i=0; image_config[i].token != NULL; i++)
3002 getFormattedSetupEntry(image_config[i].token,
3003 image_config[i].value));
3007 else if (strcmp(command, "print soundsinfo.conf") == 0)
3011 printf("# You can configure additional/alternative sound files here.\n");
3012 printf("# (The sounds below are default and therefore commented out.)\n");
3014 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3016 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3019 for (i=0; sound_config[i].token != NULL; i++)
3021 getFormattedSetupEntry(sound_config[i].token,
3022 sound_config[i].value));
3026 else if (strcmp(command, "print musicinfo.conf") == 0)
3028 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
3030 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3032 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3036 else if (strncmp(command, "dump level ", 11) == 0)
3038 char *filename = &command[11];
3040 if (access(filename, F_OK) != 0)
3041 Error(ERR_EXIT, "cannot open file '%s'", filename);
3043 LoadLevelFromFilename(&level, filename);
3048 else if (strncmp(command, "dump tape ", 10) == 0)
3050 char *filename = &command[10];
3052 if (access(filename, F_OK) != 0)
3053 Error(ERR_EXIT, "cannot open file '%s'", filename);
3055 LoadTapeFromFilename(filename);
3060 else if (strncmp(command, "autoplay ", 9) == 0)
3062 char *str_copy = getStringCopy(&command[9]);
3063 char *str_ptr = strchr(str_copy, ' ');
3065 global.autoplay_leveldir = str_copy;
3066 global.autoplay_level_nr = -1;
3068 if (str_ptr != NULL)
3070 *str_ptr++ = '\0'; /* terminate leveldir string */
3071 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3076 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3080 static void InitSetup()
3082 LoadSetup(); /* global setup info */
3084 /* set some options from setup file */
3086 if (setup.options.verbose)
3087 options.verbose = TRUE;
3090 static void InitPlayerInfo()
3094 /* choose default local player */
3095 local_player = &stored_player[0];
3097 for (i=0; i<MAX_PLAYERS; i++)
3098 stored_player[i].connected = FALSE;
3100 local_player->connected = TRUE;
3103 static void InitArtworkInfo()
3108 static char *get_string_in_brackets(char *string)
3110 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3112 sprintf(string_in_brackets, "[%s]", string);
3114 return string_in_brackets;
3118 static char *get_element_class_token(int element)
3120 char *element_class_name = element_info[element].class_name;
3121 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3123 sprintf(element_class_token, "[%s]", element_class_name);
3125 return element_class_token;
3128 static char *get_action_class_token(int action)
3130 char *action_class_name = &element_action_info[action].suffix[1];
3131 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3133 sprintf(action_class_token, "[%s]", action_class_name);
3135 return action_class_token;
3139 static void InitArtworkConfig()
3141 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3142 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3143 static char *action_id_suffix[NUM_ACTIONS + 1];
3144 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3145 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3146 static char *dummy[1] = { NULL };
3147 static char *ignore_generic_tokens[] =
3153 static char **ignore_image_tokens, **ignore_sound_tokens;
3154 int num_ignore_generic_tokens;
3155 int num_ignore_image_tokens, num_ignore_sound_tokens;
3158 /* dynamically determine list of generic tokens to be ignored */
3159 num_ignore_generic_tokens = 0;
3160 for (i=0; ignore_generic_tokens[i] != NULL; i++)
3161 num_ignore_generic_tokens++;
3163 /* dynamically determine list of image tokens to be ignored */
3164 num_ignore_image_tokens = num_ignore_generic_tokens;
3165 for (i=0; image_config_vars[i].token != NULL; i++)
3166 num_ignore_image_tokens++;
3167 ignore_image_tokens =
3168 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3169 for (i=0; i < num_ignore_generic_tokens; i++)
3170 ignore_image_tokens[i] = ignore_generic_tokens[i];
3171 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3172 ignore_image_tokens[num_ignore_generic_tokens + i] =
3173 image_config_vars[i].token;
3174 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3176 /* dynamically determine list of sound tokens to be ignored */
3177 num_ignore_sound_tokens = num_ignore_generic_tokens;
3178 ignore_sound_tokens =
3179 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3180 for (i=0; i < num_ignore_generic_tokens; i++)
3181 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3182 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3184 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3185 image_id_prefix[i] = element_info[i].token_name;
3186 for (i=0; i<NUM_FONTS; i++)
3187 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3188 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3190 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3191 sound_id_prefix[i] = element_info[i].token_name;
3192 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3193 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3194 get_string_in_brackets(element_info[i].class_name);
3195 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3197 for (i=0; i<NUM_ACTIONS; i++)
3198 action_id_suffix[i] = element_action_info[i].suffix;
3199 action_id_suffix[NUM_ACTIONS] = NULL;
3201 for (i=0; i<NUM_DIRECTIONS; i++)
3202 direction_id_suffix[i] = element_direction_info[i].suffix;
3203 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3205 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
3206 special_id_suffix[i] = special_suffix_info[i].suffix;
3207 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3209 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3210 image_id_prefix, action_id_suffix, direction_id_suffix,
3211 special_id_suffix, ignore_image_tokens);
3212 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3213 sound_id_prefix, action_id_suffix, dummy,
3214 special_id_suffix, ignore_sound_tokens);
3217 static void InitMixer()
3225 char *filename_font_initial = NULL;
3226 Bitmap *bitmap_font_initial = NULL;
3229 /* determine settings for initial font (for displaying startup messages) */
3230 for (i=0; image_config[i].token != NULL; i++)
3232 for (j=0; j < NUM_INITIAL_FONTS; j++)
3234 char font_token[128];
3237 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3238 len_font_token = strlen(font_token);
3240 if (strcmp(image_config[i].token, font_token) == 0)
3241 filename_font_initial = image_config[i].value;
3242 else if (strlen(image_config[i].token) > len_font_token &&
3243 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3245 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3246 font_initial[j].src_x = atoi(image_config[i].value);
3247 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3248 font_initial[j].src_y = atoi(image_config[i].value);
3249 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3250 font_initial[j].width = atoi(image_config[i].value);
3251 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3252 font_initial[j].height = atoi(image_config[i].value);
3257 for (j=0; j < NUM_INITIAL_FONTS; j++)
3259 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3260 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3263 if (filename_font_initial == NULL) /* should not happen */
3264 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3266 /* create additional image buffers for double-buffering */
3267 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3268 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3270 /* initialize screen properties */
3271 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3272 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3274 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3275 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3276 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3278 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3280 for (j=0; j < NUM_INITIAL_FONTS; j++)
3281 font_initial[j].bitmap = bitmap_font_initial;
3283 InitFontGraphicInfo();
3285 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3286 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3288 DrawInitText("Loading graphics:", 120, FC_GREEN);
3290 InitTileClipmasks();
3293 void InitGfxBackground()
3297 drawto = backbuffer;
3298 fieldbuffer = bitmap_db_field;
3299 SetDrawtoField(DRAW_BACKBUFFER);
3301 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3302 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3303 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3304 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3306 for (x=0; x<MAX_BUF_XSIZE; x++)
3307 for (y=0; y<MAX_BUF_YSIZE; y++)
3310 redraw_mask = REDRAW_ALL;
3313 static void InitLevelInfo()
3315 LoadLevelInfo(); /* global level info */
3316 LoadLevelSetup_LastSeries(); /* last played series info */
3317 LoadLevelSetup_SeriesInfo(); /* last played level info */
3320 void InitLevelArtworkInfo()
3322 LoadLevelArtworkInfo();
3325 static void InitImages()
3328 setLevelArtworkDir(artwork.gfx_first);
3332 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3333 leveldir_current->identifier,
3334 artwork.gfx_current_identifier,
3335 artwork.gfx_current->identifier,
3336 leveldir_current->graphics_set,
3337 leveldir_current->graphics_path);
3340 ReloadCustomImages();
3342 LoadCustomElementDescriptions();
3343 LoadSpecialMenuDesignSettings();
3345 ReinitializeGraphics();
3348 static void InitSound(char *identifier)
3350 if (identifier == NULL)
3351 identifier = artwork.snd_current->identifier;
3354 /* set artwork path to send it to the sound server process */
3355 setLevelArtworkDir(artwork.snd_first);
3358 InitReloadCustomSounds(identifier);
3359 ReinitializeSounds();
3362 static void InitMusic(char *identifier)
3364 if (identifier == NULL)
3365 identifier = artwork.mus_current->identifier;
3368 /* set artwork path to send it to the sound server process */
3369 setLevelArtworkDir(artwork.mus_first);
3372 InitReloadCustomMusic(identifier);
3373 ReinitializeMusic();
3376 void InitNetworkServer()
3378 #if defined(PLATFORM_UNIX)
3382 if (!options.network)
3385 #if defined(PLATFORM_UNIX)
3386 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3388 if (!ConnectToServer(options.server_host, options.server_port))
3389 Error(ERR_EXIT, "cannot connect to network game server");
3391 SendToServer_PlayerName(setup.player_name);
3392 SendToServer_ProtocolVersion();
3395 SendToServer_NrWanted(nr_wanted);
3399 static char *getNewArtworkIdentifier(int type)
3401 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3402 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3403 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3404 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3405 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3406 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3407 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3408 char *leveldir_identifier = leveldir_current->identifier;
3410 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3411 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3413 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3415 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3416 char *artwork_current_identifier;
3417 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3419 /* leveldir_current may be invalid (level group, parent link) */
3420 if (!validLevelSeries(leveldir_current))
3423 /* 1st step: determine artwork set to be activated in descending order:
3424 --------------------------------------------------------------------
3425 1. setup artwork (when configured to override everything else)
3426 2. artwork set configured in "levelinfo.conf" of current level set
3427 (artwork in level directory will have priority when loading later)
3428 3. artwork in level directory (stored in artwork sub-directory)
3429 4. setup artwork (currently configured in setup menu) */
3431 if (setup_override_artwork)
3432 artwork_current_identifier = setup_artwork_set;
3433 else if (leveldir_artwork_set != NULL)
3434 artwork_current_identifier = leveldir_artwork_set;
3435 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3436 artwork_current_identifier = leveldir_identifier;
3438 artwork_current_identifier = setup_artwork_set;
3441 /* 2nd step: check if it is really needed to reload artwork set
3442 ------------------------------------------------------------ */
3445 if (type == ARTWORK_TYPE_GRAPHICS)
3446 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3447 artwork_new_identifier,
3448 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3449 artwork_current_identifier,
3450 leveldir_current->graphics_set,
3451 leveldir_current->identifier);
3454 /* ---------- reload if level set and also artwork set has changed ------- */
3455 if (leveldir_current_identifier[type] != leveldir_identifier &&
3456 (last_has_level_artwork_set[type] || has_level_artwork_set))
3457 artwork_new_identifier = artwork_current_identifier;
3459 leveldir_current_identifier[type] = leveldir_identifier;
3460 last_has_level_artwork_set[type] = has_level_artwork_set;
3463 if (type == ARTWORK_TYPE_GRAPHICS)
3464 printf("::: 1: '%s'\n", artwork_new_identifier);
3467 /* ---------- reload if "override artwork" setting has changed ----------- */
3468 if (last_override_level_artwork[type] != setup_override_artwork)
3469 artwork_new_identifier = artwork_current_identifier;
3471 last_override_level_artwork[type] = setup_override_artwork;
3474 if (type == ARTWORK_TYPE_GRAPHICS)
3475 printf("::: 2: '%s'\n", artwork_new_identifier);
3478 /* ---------- reload if current artwork identifier has changed ----------- */
3479 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3480 artwork_current_identifier) != 0)
3481 artwork_new_identifier = artwork_current_identifier;
3483 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3486 if (type == ARTWORK_TYPE_GRAPHICS)
3487 printf("::: 3: '%s'\n", artwork_new_identifier);
3490 /* ---------- do not reload directly after starting ---------------------- */
3491 if (!initialized[type])
3492 artwork_new_identifier = NULL;
3494 initialized[type] = TRUE;
3497 if (type == ARTWORK_TYPE_GRAPHICS)
3498 printf("::: 4: '%s'\n", artwork_new_identifier);
3502 if (type == ARTWORK_TYPE_GRAPHICS)
3503 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3504 artwork.gfx_current_identifier, artwork_current_identifier,
3505 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3506 artwork_new_identifier);
3509 return artwork_new_identifier;
3512 void ReloadCustomArtwork()
3514 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3515 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3516 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3517 boolean redraw_screen = FALSE;
3519 if (gfx_new_identifier != NULL)
3522 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3523 artwork.gfx_current_identifier,
3525 artwork.gfx_current->identifier,
3526 leveldir_current->graphics_set);
3529 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3534 printf("... '%s'\n",
3535 leveldir_current->graphics_set);
3538 FreeTileClipmasks();
3539 InitTileClipmasks();
3541 redraw_screen = TRUE;
3544 if (snd_new_identifier != NULL)
3546 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3548 InitSound(snd_new_identifier);
3550 redraw_screen = TRUE;
3553 if (mus_new_identifier != NULL)
3555 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3557 InitMusic(mus_new_identifier);
3559 redraw_screen = TRUE;
3564 InitGfxBackground();
3566 /* force redraw of (open or closed) door graphics */
3567 SetDoorState(DOOR_OPEN_ALL);
3568 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3572 void KeyboardAutoRepeatOffUnlessAutoplay()
3574 if (global.autoplay_leveldir == NULL)
3575 KeyboardAutoRepeatOff();
3579 /* ========================================================================= */
3581 /* ========================================================================= */
3585 InitGlobal(); /* initialize some global variables */
3587 if (options.execute_command)
3588 Execute_Command(options.execute_command);
3590 if (options.serveronly)
3592 #if defined(PLATFORM_UNIX)
3593 NetworkServer(options.server_port, options.serveronly);
3595 Error(ERR_WARN, "networking only supported in Unix version");
3597 exit(0); /* never reached */
3603 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3604 InitArtworkConfig(); /* needed before forking sound child process */
3609 InitRND(NEW_RANDOMIZE);
3610 InitSimpleRND(NEW_RANDOMIZE);
3615 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3618 InitEventFilter(FilterMouseMotionEvents);
3620 InitElementPropertiesStatic();
3621 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3626 InitLevelArtworkInfo();
3628 InitImages(); /* needs to know current level directory */
3629 InitSound(NULL); /* needs to know current level directory */
3630 InitMusic(NULL); /* needs to know current level directory */
3632 InitGfxBackground();
3634 if (global.autoplay_leveldir)
3640 game_status = GAME_MODE_MAIN;
3644 InitNetworkServer();
3647 void CloseAllAndExit(int exit_value)
3652 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3655 FreeTileClipmasks();
3657 CloseVideoDisplay();
3658 ClosePlatformDependentStuff();