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));
618 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
619 act == ACTION_TURNING_FROM_RIGHT ||
620 act == ACTION_TURNING_FROM_UP ||
621 act == ACTION_TURNING_FROM_DOWN);
623 /* generic default action graphic (defined by "[default]" directive) */
624 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
625 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
627 /* look for special default action graphic (classic game specific) */
628 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
629 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
630 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
631 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
632 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
633 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
635 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
636 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
637 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
638 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
639 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
640 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
642 if (default_action_graphic == -1)
643 default_action_graphic = default_graphic;
644 if (default_action_crumbled == -1)
645 default_action_crumbled = default_crumbled;
647 for (dir=0; dir<NUM_DIRECTIONS; dir++)
649 int default_action_direction_graphic = element_info[i].graphic[act];
650 int default_action_direction_crumbled = element_info[i].crumbled[act];
652 /* no graphic for current action -- use default direction graphic */
653 if (default_action_direction_graphic == -1)
654 default_action_direction_graphic =
655 (act_remove ? IMG_EMPTY :
657 element_info[i].direction_graphic[ACTION_TURNING][dir] :
658 default_direction_graphic[dir]);
659 if (default_action_direction_crumbled == -1)
660 default_action_direction_crumbled =
661 (act_remove ? IMG_EMPTY :
663 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
664 default_direction_crumbled[dir]);
666 if (element_info[i].direction_graphic[act][dir] == -1)
667 element_info[i].direction_graphic[act][dir] =
668 default_action_direction_graphic;
669 if (element_info[i].direction_crumbled[act][dir] == -1)
670 element_info[i].direction_crumbled[act][dir] =
671 default_action_direction_crumbled;
674 /* no graphic for this specific action -- use default action graphic */
675 if (element_info[i].graphic[act] == -1)
676 element_info[i].graphic[act] =
677 (act_remove ? IMG_EMPTY :
678 act_turning ? element_info[i].graphic[ACTION_TURNING] :
679 default_action_graphic);
680 if (element_info[i].crumbled[act] == -1)
681 element_info[i].crumbled[act] =
682 (act_remove ? IMG_EMPTY :
683 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
684 default_action_crumbled);
689 /* set animation mode to "none" for each graphic with only 1 frame */
690 for (i=0; i<MAX_NUM_ELEMENTS; i++)
692 for (act=0; act<NUM_ACTIONS; act++)
694 int graphic = element_info[i].graphic[act];
695 int crumbled = element_info[i].crumbled[act];
697 if (graphic_info[graphic].anim_frames == 1)
698 graphic_info[graphic].anim_mode = ANIM_NONE;
699 if (graphic_info[crumbled].anim_frames == 1)
700 graphic_info[crumbled].anim_mode = ANIM_NONE;
702 for (dir=0; dir<NUM_DIRECTIONS; dir++)
704 graphic = element_info[i].direction_graphic[act][dir];
705 crumbled = element_info[i].direction_crumbled[act][dir];
707 if (graphic_info[graphic].anim_frames == 1)
708 graphic_info[graphic].anim_mode = ANIM_NONE;
709 if (graphic_info[crumbled].anim_frames == 1)
710 graphic_info[crumbled].anim_mode = ANIM_NONE;
720 for (i=0; i<MAX_NUM_ELEMENTS; i++)
721 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
722 i != EL_CHAR_QUESTION)
723 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
724 element_info[i].token_name, i);
730 void InitElementSpecialGraphicInfo()
732 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
733 int num_property_mappings = getImageListPropertyMappingSize();
736 /* always start with reliable default values */
737 for (i=0; i < MAX_NUM_ELEMENTS; i++)
738 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
739 element_info[i].special_graphic[j] =
740 element_info[i].graphic[ACTION_DEFAULT];
742 /* initialize special element/graphic mapping from static configuration */
743 for (i=0; element_to_special_graphic[i].element > -1; i++)
745 int element = element_to_special_graphic[i].element;
746 int special = element_to_special_graphic[i].special;
747 int graphic = element_to_special_graphic[i].graphic;
748 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
749 boolean special_redefined = getImageListEntry(graphic)->redefined;
751 /* if the base graphic ("emerald", for example) has been redefined,
752 but not the special graphic ("emerald.EDITOR", for example), do not
753 use an existing (in this case considered obsolete) special graphic
754 anymore, but use the automatically created (down-scaled) graphic */
755 if (base_redefined && !special_redefined)
758 element_info[element].special_graphic[special] = graphic;
761 /* initialize special element/graphic mapping from dynamic configuration */
762 for (i=0; i < num_property_mappings; i++)
764 int element = property_mapping[i].base_index;
765 int special = property_mapping[i].ext3_index;
766 int graphic = property_mapping[i].artwork_index;
768 if (element >= MAX_NUM_ELEMENTS)
771 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
772 element_info[element].special_graphic[special] = graphic;
776 /* now set all undefined/invalid graphics to default */
777 for (i=0; i < MAX_NUM_ELEMENTS; i++)
778 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
779 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
780 element_info[i].special_graphic[j] =
781 element_info[i].graphic[ACTION_DEFAULT];
785 static int get_element_from_token(char *token)
789 for (i=0; i < MAX_NUM_ELEMENTS; i++)
790 if (strcmp(element_info[i].token_name, token) == 0)
796 static void set_graphic_parameters(int graphic, char **parameter_raw)
798 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
799 int parameter[NUM_GFX_ARGS];
800 int anim_frames_per_row = 1, anim_frames_per_col = 1;
801 int anim_frames_per_line = 1;
804 /* get integer values from string parameters */
805 for (i=0; i < NUM_GFX_ARGS; i++)
808 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
809 image_config_suffix[i].type);
811 if (image_config_suffix[i].type == TYPE_TOKEN)
812 parameter[i] = get_element_from_token(parameter_raw[i]);
815 graphic_info[graphic].bitmap = src_bitmap;
817 /* start with reliable default values */
818 graphic_info[graphic].src_x = 0;
819 graphic_info[graphic].src_y = 0;
820 graphic_info[graphic].width = TILEX;
821 graphic_info[graphic].height = TILEY;
822 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
823 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
824 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
825 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
826 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
828 /* optional x and y tile position of animation frame sequence */
829 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
830 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
831 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
832 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
834 /* optional x and y pixel position of animation frame sequence */
835 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
836 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
837 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
838 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
840 /* optional width and height of each animation frame */
841 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
842 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
843 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
844 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
848 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
849 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
852 /* correct x or y offset dependent of vertical or horizontal frame order */
853 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
855 graphic_info[graphic].offset_y =
856 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
857 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
858 anim_frames_per_line = anim_frames_per_col;
860 else /* frames are ordered horizontally */
862 graphic_info[graphic].offset_x =
863 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
864 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
865 anim_frames_per_line = anim_frames_per_row;
868 /* optionally, the x and y offset of frames can be specified directly */
869 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
870 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
871 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
872 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
874 /* automatically determine correct number of frames, if not defined */
875 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
876 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
877 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
878 graphic_info[graphic].anim_frames = anim_frames_per_row;
879 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
880 graphic_info[graphic].anim_frames = anim_frames_per_col;
882 graphic_info[graphic].anim_frames = 1;
884 graphic_info[graphic].anim_frames_per_line =
885 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
886 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
888 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
889 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
890 graphic_info[graphic].anim_delay = 1;
892 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
894 if (graphic_info[graphic].anim_frames == 1)
895 graphic_info[graphic].anim_mode = ANIM_NONE;
898 /* automatically determine correct start frame, if not defined */
899 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
900 graphic_info[graphic].anim_start_frame = 0;
901 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
902 graphic_info[graphic].anim_start_frame =
903 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
905 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
907 /* animation synchronized with global frame counter, not move position */
908 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
910 /* optional element for cloning crumble graphics */
911 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
912 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
914 /* optional element for cloning digging graphics */
915 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
916 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
918 /* optional border size for "crumbling" diggable graphics */
919 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
920 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
922 /* this is only used for toon animations */
923 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
924 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
926 /* this is only used for drawing font characters */
927 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
928 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
930 /* this is only used for drawing envelope graphics */
931 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
934 static void InitGraphicInfo()
936 int fallback_graphic = IMG_CHAR_EXCLAM;
937 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
938 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
939 int num_images = getImageListSize();
942 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
943 static boolean clipmasks_initialized = FALSE;
945 XGCValues clip_gc_values;
946 unsigned long clip_gc_valuemask;
947 GC copy_clipmask_gc = None;
950 if (graphic_info != NULL)
953 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
956 printf("::: graphic_info: %d entries\n", num_images);
959 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
960 if (clipmasks_initialized)
962 for (i=0; i<num_images; i++)
964 if (graphic_info[i].clip_mask)
965 XFreePixmap(display, graphic_info[i].clip_mask);
966 if (graphic_info[i].clip_gc)
967 XFreeGC(display, graphic_info[i].clip_gc);
969 graphic_info[i].clip_mask = None;
970 graphic_info[i].clip_gc = None;
975 for (i=0; i<num_images; i++)
977 struct FileInfo *image = getImageListEntry(i);
980 int first_frame, last_frame;
983 printf("::: image: '%s' [%d]\n", image->token, i);
987 printf("::: image # %d: '%s' ['%s']\n",
989 getTokenFromImageID(i));
992 set_graphic_parameters(i, image->parameter);
994 /* now check if no animation frames are outside of the loaded image */
996 if (graphic_info[i].bitmap == NULL)
997 continue; /* skip check for optional images that are undefined */
1000 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1001 if (src_x < 0 || src_y < 0 ||
1002 src_x + TILEX > src_bitmap->width ||
1003 src_y + TILEY > src_bitmap->height)
1005 Error(ERR_RETURN_LINE, "-");
1006 Error(ERR_RETURN, "warning: error found in config file:");
1007 Error(ERR_RETURN, "- config file: '%s'",
1008 getImageConfigFilename());
1009 Error(ERR_RETURN, "- config token: '%s'",
1010 getTokenFromImageID(i));
1011 Error(ERR_RETURN, "- image file: '%s'",
1012 src_bitmap->source_filename);
1014 "error: first animation frame out of bounds (%d, %d)",
1016 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1018 if (i == fallback_graphic)
1019 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1021 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1022 Error(ERR_RETURN_LINE, "-");
1024 set_graphic_parameters(i, fallback_image->default_parameter);
1025 graphic_info[i].bitmap = fallback_bitmap;
1028 last_frame = graphic_info[i].anim_frames - 1;
1029 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1030 if (src_x < 0 || src_y < 0 ||
1031 src_x + TILEX > src_bitmap->width ||
1032 src_y + TILEY > src_bitmap->height)
1034 Error(ERR_RETURN_LINE, "-");
1035 Error(ERR_RETURN, "warning: error found in config file:");
1036 Error(ERR_RETURN, "- config file: '%s'",
1037 getImageConfigFilename());
1038 Error(ERR_RETURN, "- config token: '%s'",
1039 getTokenFromImageID(i));
1040 Error(ERR_RETURN, "- image file: '%s'",
1041 src_bitmap->source_filename);
1043 "error: last animation frame (%d) out of bounds (%d, %d)",
1044 last_frame, src_x, src_y);
1045 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1047 if (i == fallback_graphic)
1048 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1050 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1051 Error(ERR_RETURN_LINE, "-");
1053 set_graphic_parameters(i, fallback_image->default_parameter);
1054 graphic_info[i].bitmap = fallback_bitmap;
1057 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1058 /* currently we need only a tile clip mask from the first frame */
1059 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1061 if (copy_clipmask_gc == None)
1063 clip_gc_values.graphics_exposures = False;
1064 clip_gc_valuemask = GCGraphicsExposures;
1065 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1066 clip_gc_valuemask, &clip_gc_values);
1069 graphic_info[i].clip_mask =
1070 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1072 src_pixmap = src_bitmap->clip_mask;
1073 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1074 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1076 clip_gc_values.graphics_exposures = False;
1077 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1078 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1080 graphic_info[i].clip_gc =
1081 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1085 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1086 if (copy_clipmask_gc)
1087 XFreeGC(display, copy_clipmask_gc);
1089 clipmasks_initialized = TRUE;
1093 static void InitElementSoundInfo()
1095 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1096 int num_property_mappings = getSoundListPropertyMappingSize();
1099 /* set values to -1 to identify later as "uninitialized" values */
1100 for (i=0; i < MAX_NUM_ELEMENTS; i++)
1101 for (act=0; act < NUM_ACTIONS; act++)
1102 element_info[i].sound[act] = -1;
1104 /* initialize element/sound mapping from static configuration */
1105 for (i=0; element_to_sound[i].element > -1; i++)
1107 int element = element_to_sound[i].element;
1108 int action = element_to_sound[i].action;
1109 int sound = element_to_sound[i].sound;
1110 boolean is_class = element_to_sound[i].is_class;
1113 action = ACTION_DEFAULT;
1116 element_info[element].sound[action] = sound;
1118 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1119 if (strcmp(element_info[j].class_name,
1120 element_info[element].class_name) == 0)
1121 element_info[j].sound[action] = sound;
1124 /* initialize element class/sound mapping from dynamic configuration */
1125 for (i=0; i < num_property_mappings; i++)
1127 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1128 int action = property_mapping[i].ext1_index;
1129 int sound = property_mapping[i].artwork_index;
1131 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1135 action = ACTION_DEFAULT;
1137 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1138 if (strcmp(element_info[j].class_name,
1139 element_info[element_class].class_name) == 0)
1140 element_info[j].sound[action] = sound;
1143 /* initialize element/sound mapping from dynamic configuration */
1144 for (i=0; i < num_property_mappings; i++)
1146 int element = property_mapping[i].base_index;
1147 int action = property_mapping[i].ext1_index;
1148 int sound = property_mapping[i].artwork_index;
1150 if (element >= MAX_NUM_ELEMENTS)
1154 action = ACTION_DEFAULT;
1156 element_info[element].sound[action] = sound;
1159 /* now set all '-1' values to element specific default values */
1160 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1162 for (act=0; act < NUM_ACTIONS; act++)
1164 /* generic default action sound (defined by "[default]" directive) */
1165 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1167 /* look for special default action sound (classic game specific) */
1168 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1169 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1170 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1171 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1172 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1173 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1175 /* look for element specific default sound (independent from action) */
1176 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1177 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1179 /* no sound for this specific action -- use default action sound */
1180 if (element_info[i].sound[act] == -1)
1181 element_info[i].sound[act] = default_action_sound;
1186 static void set_sound_parameters(int sound, char **parameter_raw)
1188 int parameter[NUM_SND_ARGS];
1191 /* get integer values from string parameters */
1192 for (i=0; i < NUM_SND_ARGS; i++)
1194 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1195 sound_config_suffix[i].type);
1197 /* explicit loop mode setting in configuration overrides default value */
1198 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1199 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1202 static void InitSoundInfo()
1205 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1206 int num_property_mappings = getSoundListPropertyMappingSize();
1208 int *sound_effect_properties;
1209 int num_sounds = getSoundListSize();
1212 if (sound_info != NULL)
1215 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1216 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1218 /* initialize sound effect for all elements to "no sound" */
1219 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1220 for (j=0; j<NUM_ACTIONS; j++)
1221 element_info[i].sound[j] = SND_UNDEFINED;
1223 for (i=0; i<num_sounds; i++)
1225 struct FileInfo *sound = getSoundListEntry(i);
1226 int len_effect_text = strlen(sound->token);
1228 sound_effect_properties[i] = ACTION_OTHER;
1229 sound_info[i].loop = FALSE;
1232 printf("::: sound %d: '%s'\n", i, sound->token);
1235 /* determine all loop sounds and identify certain sound classes */
1237 for (j=0; element_action_info[j].suffix; j++)
1239 int len_action_text = strlen(element_action_info[j].suffix);
1241 if (len_action_text < len_effect_text &&
1242 strcmp(&sound->token[len_effect_text - len_action_text],
1243 element_action_info[j].suffix) == 0)
1245 sound_effect_properties[i] = element_action_info[j].value;
1246 sound_info[i].loop = element_action_info[j].is_loop_sound;
1253 if (strcmp(sound->token, "custom_42") == 0)
1254 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1257 /* associate elements and some selected sound actions */
1259 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1261 if (element_info[j].class_name)
1263 int len_class_text = strlen(element_info[j].class_name);
1265 if (len_class_text + 1 < len_effect_text &&
1266 strncmp(sound->token,
1267 element_info[j].class_name, len_class_text) == 0 &&
1268 sound->token[len_class_text] == '.')
1270 int sound_action_value = sound_effect_properties[i];
1272 element_info[j].sound[sound_action_value] = i;
1277 set_sound_parameters(i, sound->parameter);
1280 free(sound_effect_properties);
1283 /* !!! now handled in InitElementSoundInfo() !!! */
1284 /* initialize element/sound mapping from dynamic configuration */
1285 for (i=0; i < num_property_mappings; i++)
1287 int element = property_mapping[i].base_index;
1288 int action = property_mapping[i].ext1_index;
1289 int sound = property_mapping[i].artwork_index;
1292 action = ACTION_DEFAULT;
1294 printf("::: %d: %d, %d, %d ['%s']\n",
1295 i, element, action, sound, element_info[element].token_name);
1297 element_info[element].sound[action] = sound;
1304 int element = EL_CUSTOM_11;
1307 while (element_action_info[j].suffix)
1309 printf("element %d, sound action '%s' == %d\n",
1310 element, element_action_info[j].suffix,
1311 element_info[element].sound[j]);
1316 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1322 int element = EL_SAND;
1323 int sound_action = ACTION_DIGGING;
1326 while (element_action_info[j].suffix)
1328 if (element_action_info[j].value == sound_action)
1329 printf("element %d, sound action '%s' == %d\n",
1330 element, element_action_info[j].suffix,
1331 element_info[element].sound[sound_action]);
1338 static void ReinitializeGraphics()
1340 InitGraphicInfo(); /* graphic properties mapping */
1341 InitElementGraphicInfo(); /* element game graphic mapping */
1342 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1344 InitElementSmallImages(); /* create editor and preview images */
1345 InitFontGraphicInfo(); /* initialize text drawing functions */
1347 SetMainBackgroundImage(IMG_BACKGROUND);
1348 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1354 static void ReinitializeSounds()
1356 InitSoundInfo(); /* sound properties mapping */
1357 InitElementSoundInfo(); /* element game sound mapping */
1359 InitPlaySoundLevel(); /* internal game sound settings */
1362 static void ReinitializeMusic()
1364 /* currently nothing to do */
1367 void InitElementPropertiesStatic()
1369 static int ep_diggable[] =
1374 EL_SP_BUGGY_BASE_ACTIVATING,
1377 EL_INVISIBLE_SAND_ACTIVE,
1379 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1383 EL_SP_BUGGY_BASE_ACTIVE,
1388 static int ep_collectible_only[] =
1405 EL_DYNABOMB_INCREASE_NUMBER,
1406 EL_DYNABOMB_INCREASE_SIZE,
1407 EL_DYNABOMB_INCREASE_POWER,
1424 static int ep_dont_run_into[] =
1426 /* same elements as in 'ep_dont_touch' */
1432 /* same elements as in 'ep_dont_collide_with' */
1444 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1448 EL_SP_BUGGY_BASE_ACTIVE,
1453 static int ep_dont_collide_with[] =
1455 /* same elements as in 'ep_dont_touch' */
1471 static int ep_dont_touch[] =
1480 static int ep_indestructible[] =
1484 EL_ACID_POOL_TOPLEFT,
1485 EL_ACID_POOL_TOPRIGHT,
1486 EL_ACID_POOL_BOTTOMLEFT,
1487 EL_ACID_POOL_BOTTOM,
1488 EL_ACID_POOL_BOTTOMRIGHT,
1489 EL_SP_HARDWARE_GRAY,
1490 EL_SP_HARDWARE_GREEN,
1491 EL_SP_HARDWARE_BLUE,
1493 EL_SP_HARDWARE_YELLOW,
1494 EL_SP_HARDWARE_BASE_1,
1495 EL_SP_HARDWARE_BASE_2,
1496 EL_SP_HARDWARE_BASE_3,
1497 EL_SP_HARDWARE_BASE_4,
1498 EL_SP_HARDWARE_BASE_5,
1499 EL_SP_HARDWARE_BASE_6,
1500 EL_INVISIBLE_STEELWALL,
1501 EL_INVISIBLE_STEELWALL_ACTIVE,
1502 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1503 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1504 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1505 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1506 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1507 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1508 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1509 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1510 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1511 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1512 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1513 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1515 EL_LIGHT_SWITCH_ACTIVE,
1516 EL_SIGN_EXCLAMATION,
1517 EL_SIGN_RADIOACTIVITY,
1528 EL_STEELWALL_SLIPPERY,
1551 EL_SWITCHGATE_OPENING,
1552 EL_SWITCHGATE_CLOSED,
1553 EL_SWITCHGATE_CLOSING,
1555 EL_SWITCHGATE_SWITCH_UP,
1556 EL_SWITCHGATE_SWITCH_DOWN,
1559 EL_TIMEGATE_OPENING,
1561 EL_TIMEGATE_CLOSING,
1564 EL_TIMEGATE_SWITCH_ACTIVE,
1569 EL_TUBE_VERTICAL_LEFT,
1570 EL_TUBE_VERTICAL_RIGHT,
1571 EL_TUBE_HORIZONTAL_UP,
1572 EL_TUBE_HORIZONTAL_DOWN,
1580 static int ep_slippery[] =
1594 EL_ROBOT_WHEEL_ACTIVE,
1600 EL_ACID_POOL_TOPLEFT,
1601 EL_ACID_POOL_TOPRIGHT,
1611 EL_STEELWALL_SLIPPERY,
1617 static int ep_can_change[] =
1622 static int ep_can_move[] =
1644 static int ep_can_fall[] =
1659 EL_BD_MAGIC_WALL_FULL,
1672 static int ep_can_smash_player[] =
1697 static int ep_can_smash_enemies[] =
1705 static int ep_can_smash_everything[] =
1713 static int ep_can_explode_by_fire[] =
1715 /* same elements as in 'ep_can_explode_impact' */
1720 /* same elements as in 'ep_can_explode_smashed' */
1729 EL_DYNABOMB_PLAYER_1_ACTIVE,
1730 EL_DYNABOMB_PLAYER_2_ACTIVE,
1731 EL_DYNABOMB_PLAYER_3_ACTIVE,
1732 EL_DYNABOMB_PLAYER_4_ACTIVE,
1733 EL_DYNABOMB_INCREASE_NUMBER,
1734 EL_DYNABOMB_INCREASE_SIZE,
1735 EL_DYNABOMB_INCREASE_POWER,
1736 EL_SP_DISK_RED_ACTIVE,
1746 static int ep_can_explode_smashed[] =
1748 /* same elements as in 'ep_can_explode_impact' */
1761 static int ep_can_explode_impact[] =
1769 static int ep_walkable_over[] =
1773 EL_SOKOBAN_FIELD_EMPTY,
1791 static int ep_walkable_inside[] =
1796 EL_TUBE_VERTICAL_LEFT,
1797 EL_TUBE_VERTICAL_RIGHT,
1798 EL_TUBE_HORIZONTAL_UP,
1799 EL_TUBE_HORIZONTAL_DOWN,
1807 static int ep_walkable_under[] =
1812 static int ep_passable_over[] =
1827 static int ep_passable_inside[] =
1833 EL_SP_PORT_HORIZONTAL,
1834 EL_SP_PORT_VERTICAL,
1836 EL_SP_GRAVITY_PORT_LEFT,
1837 EL_SP_GRAVITY_PORT_RIGHT,
1838 EL_SP_GRAVITY_PORT_UP,
1839 EL_SP_GRAVITY_PORT_DOWN,
1843 static int ep_passable_under[] =
1848 static int ep_droppable[] =
1853 static int ep_can_explode_1x1[] =
1858 static int ep_pushable[] =
1870 EL_SOKOBAN_FIELD_FULL,
1877 static int ep_player[] =
1887 static int ep_can_pass_magic_wall[] =
1900 static int ep_switchable[] =
1904 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1905 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1906 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1907 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1908 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1909 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1910 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1911 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1912 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1913 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1914 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1915 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1916 EL_SWITCHGATE_SWITCH_UP,
1917 EL_SWITCHGATE_SWITCH_DOWN,
1919 EL_LIGHT_SWITCH_ACTIVE,
1921 EL_BALLOON_SWITCH_LEFT,
1922 EL_BALLOON_SWITCH_RIGHT,
1923 EL_BALLOON_SWITCH_UP,
1924 EL_BALLOON_SWITCH_DOWN,
1925 EL_BALLOON_SWITCH_ANY,
1931 static int ep_bd_element[] =
1960 static int ep_sp_element[] =
1962 /* should always be valid */
1971 EL_SP_HARDWARE_GRAY,
1979 EL_SP_GRAVITY_PORT_RIGHT,
1980 EL_SP_GRAVITY_PORT_DOWN,
1981 EL_SP_GRAVITY_PORT_LEFT,
1982 EL_SP_GRAVITY_PORT_UP,
1987 EL_SP_PORT_VERTICAL,
1988 EL_SP_PORT_HORIZONTAL,
1994 EL_SP_HARDWARE_BASE_1,
1995 EL_SP_HARDWARE_GREEN,
1996 EL_SP_HARDWARE_BLUE,
1998 EL_SP_HARDWARE_YELLOW,
1999 EL_SP_HARDWARE_BASE_2,
2000 EL_SP_HARDWARE_BASE_3,
2001 EL_SP_HARDWARE_BASE_4,
2002 EL_SP_HARDWARE_BASE_5,
2003 EL_SP_HARDWARE_BASE_6,
2006 /* additional elements that appeared in newer Supaplex levels */
2008 /* more than one murphy in a level results in an inactive clone */
2010 /* runtime elements*/
2011 EL_SP_DISK_RED_ACTIVE,
2012 EL_SP_TERMINAL_ACTIVE,
2013 EL_SP_BUGGY_BASE_ACTIVATING,
2014 EL_SP_BUGGY_BASE_ACTIVE,
2020 static int ep_sb_element[] =
2025 EL_SOKOBAN_FIELD_EMPTY,
2026 EL_SOKOBAN_FIELD_FULL,
2028 EL_INVISIBLE_STEELWALL,
2032 static int ep_gem[] =
2043 static int ep_food_dark_yamyam[] =
2070 static int ep_food_penguin[] =
2083 static int ep_food_pig[] =
2094 static int ep_historic_wall[] =
2119 EL_EXPANDABLE_WALL_HORIZONTAL,
2120 EL_EXPANDABLE_WALL_VERTICAL,
2121 EL_EXPANDABLE_WALL_ANY,
2122 EL_EXPANDABLE_WALL_GROWING,
2129 EL_SP_HARDWARE_GRAY,
2130 EL_SP_HARDWARE_GREEN,
2131 EL_SP_HARDWARE_BLUE,
2133 EL_SP_HARDWARE_YELLOW,
2134 EL_SP_HARDWARE_BASE_1,
2135 EL_SP_HARDWARE_BASE_2,
2136 EL_SP_HARDWARE_BASE_3,
2137 EL_SP_HARDWARE_BASE_4,
2138 EL_SP_HARDWARE_BASE_5,
2139 EL_SP_HARDWARE_BASE_6,
2141 EL_SP_TERMINAL_ACTIVE,
2144 EL_INVISIBLE_STEELWALL,
2145 EL_INVISIBLE_STEELWALL_ACTIVE,
2147 EL_INVISIBLE_WALL_ACTIVE,
2148 EL_STEELWALL_SLIPPERY,
2164 static int ep_historic_solid[] =
2168 EL_EXPANDABLE_WALL_HORIZONTAL,
2169 EL_EXPANDABLE_WALL_VERTICAL,
2170 EL_EXPANDABLE_WALL_ANY,
2183 EL_QUICKSAND_FILLING,
2184 EL_QUICKSAND_EMPTYING,
2186 EL_MAGIC_WALL_ACTIVE,
2187 EL_MAGIC_WALL_EMPTYING,
2188 EL_MAGIC_WALL_FILLING,
2192 EL_BD_MAGIC_WALL_ACTIVE,
2193 EL_BD_MAGIC_WALL_EMPTYING,
2194 EL_BD_MAGIC_WALL_FULL,
2195 EL_BD_MAGIC_WALL_FILLING,
2196 EL_BD_MAGIC_WALL_DEAD,
2205 EL_SP_TERMINAL_ACTIVE,
2209 EL_INVISIBLE_WALL_ACTIVE,
2210 EL_SWITCHGATE_SWITCH_UP,
2211 EL_SWITCHGATE_SWITCH_DOWN,
2213 EL_TIMEGATE_SWITCH_ACTIVE,
2225 /* the following elements are a direct copy of "indestructible" elements,
2226 except "EL_ACID", which is "indestructible", but not "solid"! */
2231 EL_ACID_POOL_TOPLEFT,
2232 EL_ACID_POOL_TOPRIGHT,
2233 EL_ACID_POOL_BOTTOMLEFT,
2234 EL_ACID_POOL_BOTTOM,
2235 EL_ACID_POOL_BOTTOMRIGHT,
2236 EL_SP_HARDWARE_GRAY,
2237 EL_SP_HARDWARE_GREEN,
2238 EL_SP_HARDWARE_BLUE,
2240 EL_SP_HARDWARE_YELLOW,
2241 EL_SP_HARDWARE_BASE_1,
2242 EL_SP_HARDWARE_BASE_2,
2243 EL_SP_HARDWARE_BASE_3,
2244 EL_SP_HARDWARE_BASE_4,
2245 EL_SP_HARDWARE_BASE_5,
2246 EL_SP_HARDWARE_BASE_6,
2247 EL_INVISIBLE_STEELWALL,
2248 EL_INVISIBLE_STEELWALL_ACTIVE,
2249 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2250 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2251 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2252 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2253 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2254 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2255 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2256 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2257 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2258 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2259 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2260 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2262 EL_LIGHT_SWITCH_ACTIVE,
2263 EL_SIGN_EXCLAMATION,
2264 EL_SIGN_RADIOACTIVITY,
2275 EL_STEELWALL_SLIPPERY,
2298 EL_SWITCHGATE_OPENING,
2299 EL_SWITCHGATE_CLOSED,
2300 EL_SWITCHGATE_CLOSING,
2302 EL_TIMEGATE_OPENING,
2304 EL_TIMEGATE_CLOSING,
2308 EL_TUBE_VERTICAL_LEFT,
2309 EL_TUBE_VERTICAL_RIGHT,
2310 EL_TUBE_HORIZONTAL_UP,
2311 EL_TUBE_HORIZONTAL_DOWN,
2319 static int ep_classic_enemy[] =
2335 static int ep_belt[] =
2337 EL_CONVEYOR_BELT_1_LEFT,
2338 EL_CONVEYOR_BELT_1_MIDDLE,
2339 EL_CONVEYOR_BELT_1_RIGHT,
2340 EL_CONVEYOR_BELT_2_LEFT,
2341 EL_CONVEYOR_BELT_2_MIDDLE,
2342 EL_CONVEYOR_BELT_2_RIGHT,
2343 EL_CONVEYOR_BELT_3_LEFT,
2344 EL_CONVEYOR_BELT_3_MIDDLE,
2345 EL_CONVEYOR_BELT_3_RIGHT,
2346 EL_CONVEYOR_BELT_4_LEFT,
2347 EL_CONVEYOR_BELT_4_MIDDLE,
2348 EL_CONVEYOR_BELT_4_RIGHT,
2352 static int ep_belt_active[] =
2354 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2355 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2356 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2357 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2358 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2359 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2360 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2361 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2362 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2363 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2364 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2365 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2369 static int ep_belt_switch[] =
2371 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2372 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2373 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2374 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2375 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2376 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2377 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2378 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2379 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2380 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2381 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2382 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2386 static int ep_tube[] =
2393 EL_TUBE_HORIZONTAL_UP,
2394 EL_TUBE_HORIZONTAL_DOWN,
2396 EL_TUBE_VERTICAL_LEFT,
2397 EL_TUBE_VERTICAL_RIGHT,
2402 static int ep_keygate[] =
2423 static int ep_amoeboid[] =
2433 static int ep_amoebalive[] =
2442 static int ep_has_content[] =
2452 static int ep_active_bomb[] =
2455 EL_DYNABOMB_PLAYER_1_ACTIVE,
2456 EL_DYNABOMB_PLAYER_2_ACTIVE,
2457 EL_DYNABOMB_PLAYER_3_ACTIVE,
2458 EL_DYNABOMB_PLAYER_4_ACTIVE,
2459 EL_SP_DISK_RED_ACTIVE,
2463 static int ep_inactive[] =
2500 EL_INVISIBLE_STEELWALL,
2508 EL_WALL_EMERALD_YELLOW,
2509 EL_DYNABOMB_INCREASE_NUMBER,
2510 EL_DYNABOMB_INCREASE_SIZE,
2511 EL_DYNABOMB_INCREASE_POWER,
2515 EL_SOKOBAN_FIELD_EMPTY,
2516 EL_SOKOBAN_FIELD_FULL,
2517 EL_WALL_EMERALD_RED,
2518 EL_WALL_EMERALD_PURPLE,
2519 EL_ACID_POOL_TOPLEFT,
2520 EL_ACID_POOL_TOPRIGHT,
2521 EL_ACID_POOL_BOTTOMLEFT,
2522 EL_ACID_POOL_BOTTOM,
2523 EL_ACID_POOL_BOTTOMRIGHT,
2527 EL_BD_MAGIC_WALL_DEAD,
2528 EL_AMOEBA_TO_DIAMOND,
2536 EL_SP_GRAVITY_PORT_RIGHT,
2537 EL_SP_GRAVITY_PORT_DOWN,
2538 EL_SP_GRAVITY_PORT_LEFT,
2539 EL_SP_GRAVITY_PORT_UP,
2540 EL_SP_PORT_HORIZONTAL,
2541 EL_SP_PORT_VERTICAL,
2552 EL_SP_HARDWARE_GRAY,
2553 EL_SP_HARDWARE_GREEN,
2554 EL_SP_HARDWARE_BLUE,
2556 EL_SP_HARDWARE_YELLOW,
2557 EL_SP_HARDWARE_BASE_1,
2558 EL_SP_HARDWARE_BASE_2,
2559 EL_SP_HARDWARE_BASE_3,
2560 EL_SP_HARDWARE_BASE_4,
2561 EL_SP_HARDWARE_BASE_5,
2562 EL_SP_HARDWARE_BASE_6,
2563 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2564 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2565 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2566 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2567 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2568 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2569 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2570 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2571 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2572 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2573 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2574 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2575 EL_SIGN_EXCLAMATION,
2576 EL_SIGN_RADIOACTIVITY,
2587 EL_STEELWALL_SLIPPERY,
2603 static int ep_em_slippery_wall[] =
2608 static int ep_gfx_crumbled[] =
2621 } element_properties[] =
2623 { ep_diggable, EP_DIGGABLE },
2624 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2625 { ep_dont_run_into, EP_DONT_RUN_INTO },
2626 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2627 { ep_dont_touch, EP_DONT_TOUCH },
2628 { ep_indestructible, EP_INDESTRUCTIBLE },
2629 { ep_slippery, EP_SLIPPERY },
2630 { ep_can_change, EP_CAN_CHANGE },
2631 { ep_can_move, EP_CAN_MOVE },
2632 { ep_can_fall, EP_CAN_FALL },
2633 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2634 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2635 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2636 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2637 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2638 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2639 { ep_walkable_over, EP_WALKABLE_OVER },
2640 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2641 { ep_walkable_under, EP_WALKABLE_UNDER },
2642 { ep_passable_over, EP_PASSABLE_OVER },
2643 { ep_passable_inside, EP_PASSABLE_INSIDE },
2644 { ep_passable_under, EP_PASSABLE_UNDER },
2645 { ep_droppable, EP_DROPPABLE },
2646 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2647 { ep_pushable, EP_PUSHABLE },
2649 { ep_player, EP_PLAYER },
2650 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2651 { ep_switchable, EP_SWITCHABLE },
2652 { ep_bd_element, EP_BD_ELEMENT },
2653 { ep_sp_element, EP_SP_ELEMENT },
2654 { ep_sb_element, EP_SB_ELEMENT },
2656 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2657 { ep_food_penguin, EP_FOOD_PENGUIN },
2658 { ep_food_pig, EP_FOOD_PIG },
2659 { ep_historic_wall, EP_HISTORIC_WALL },
2660 { ep_historic_solid, EP_HISTORIC_SOLID },
2661 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2662 { ep_belt, EP_BELT },
2663 { ep_belt_active, EP_BELT_ACTIVE },
2664 { ep_belt_switch, EP_BELT_SWITCH },
2665 { ep_tube, EP_TUBE },
2666 { ep_keygate, EP_KEYGATE },
2667 { ep_amoeboid, EP_AMOEBOID },
2668 { ep_amoebalive, EP_AMOEBALIVE },
2669 { ep_has_content, EP_HAS_CONTENT },
2670 { ep_active_bomb, EP_ACTIVE_BOMB },
2671 { ep_inactive, EP_INACTIVE },
2673 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2675 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2680 static int copy_properties[][5] =
2684 EL_BUG_LEFT, EL_BUG_RIGHT,
2685 EL_BUG_UP, EL_BUG_DOWN
2689 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2690 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2694 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2695 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2699 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2700 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2704 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2705 EL_PACMAN_UP, EL_PACMAN_DOWN
2715 /* always start with reliable default values (element has no properties) */
2716 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2717 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2718 SET_PROPERTY(i, j, FALSE);
2720 /* set all base element properties from above array definitions */
2721 for (i=0; element_properties[i].elements != NULL; i++)
2722 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2723 SET_PROPERTY((element_properties[i].elements)[j],
2724 element_properties[i].property, TRUE);
2726 /* copy properties to some elements that are only stored in level file */
2727 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2728 for (j=0; copy_properties[j][0] != -1; j++)
2729 if (HAS_PROPERTY(copy_properties[j][0], i))
2730 for (k=1; k<=4; k++)
2731 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2734 void InitElementPropertiesEngine(int engine_version)
2737 static int active_properties[] =
2742 EP_DONT_COLLIDE_WITH,
2746 EP_CAN_PASS_MAGIC_WALL,
2751 EP_CAN_EXPLODE_BY_FIRE,
2764 EP_EM_SLIPPERY_WALL,
2768 static int no_wall_properties[] =
2771 EP_COLLECTIBLE_ONLY,
2773 EP_DONT_COLLIDE_WITH,
2776 EP_CAN_SMASH_PLAYER,
2777 EP_CAN_SMASH_ENEMIES,
2778 EP_CAN_SMASH_EVERYTHING,
2783 EP_FOOD_DARK_YAMYAM,
2799 InitElementPropertiesStatic();
2802 /* set all special, combined or engine dependent element properties */
2803 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2806 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2807 SET_PROPERTY(i, j, FALSE);
2810 /* ---------- INACTIVE ------------------------------------------------- */
2811 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2812 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2814 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2815 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2816 IS_WALKABLE_INSIDE(i) ||
2817 IS_WALKABLE_UNDER(i)));
2819 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2820 IS_PASSABLE_INSIDE(i) ||
2821 IS_PASSABLE_UNDER(i)));
2823 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2824 IS_PASSABLE_OVER(i)));
2826 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2827 IS_PASSABLE_INSIDE(i)));
2829 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2830 IS_PASSABLE_UNDER(i)));
2832 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2835 /* ---------- COLLECTIBLE ---------------------------------------------- */
2836 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
2839 /* ---------- SNAPPABLE ------------------------------------------------ */
2840 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2841 IS_COLLECTIBLE(i) ||
2845 /* ---------- WALL ----------------------------------------------------- */
2846 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2848 for (j=0; no_wall_properties[j] != -1; j++)
2849 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2850 i >= EL_FIRST_RUNTIME_UNREAL)
2851 SET_PROPERTY(i, EP_WALL, FALSE);
2853 if (IS_HISTORIC_WALL(i))
2854 SET_PROPERTY(i, EP_WALL, TRUE);
2856 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2857 if (engine_version < VERSION_IDENT(2,2,0,0))
2858 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2860 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2862 !IS_COLLECTIBLE(i)));
2864 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2866 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2867 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2869 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2870 IS_INDESTRUCTIBLE(i)));
2872 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2874 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2875 else if (engine_version < VERSION_IDENT(2,2,0,0))
2876 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2878 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2879 !IS_WALKABLE_OVER(i) &&
2880 !IS_WALKABLE_UNDER(i)));
2882 if (IS_CUSTOM_ELEMENT(i))
2884 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2886 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2887 if (DONT_COLLIDE_WITH(i))
2888 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2890 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2891 if (CAN_SMASH_EVERYTHING(i))
2892 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2893 if (CAN_SMASH_ENEMIES(i))
2894 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2897 /* ---------- CAN_SMASH ------------------------------------------------ */
2898 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2899 CAN_SMASH_ENEMIES(i) ||
2900 CAN_SMASH_EVERYTHING(i)));
2902 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2903 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2904 CAN_EXPLODE_SMASHED(i) ||
2905 CAN_EXPLODE_IMPACT(i)));
2907 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
2908 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
2909 !CAN_EXPLODE_1X1(i)));
2911 /* ---------- CAN_CHANGE ----------------------------------------------- */
2912 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
2913 for (j=0; j < element_info[i].num_change_pages; j++)
2914 if (element_info[i].change_page[j].can_change)
2915 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
2917 /* ---------- GFX_CRUMBLED --------------------------------------------- */
2918 SET_PROPERTY(i, EP_GFX_CRUMBLED,
2919 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
2923 /* determine inactive elements (used for engine main loop optimization) */
2924 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2926 boolean active = FALSE;
2928 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2930 if (HAS_PROPERTY(i, j))
2936 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2941 /* dynamically adjust element properties according to game engine version */
2943 static int ep_em_slippery_wall[] =
2948 EL_EXPANDABLE_WALL_HORIZONTAL,
2949 EL_EXPANDABLE_WALL_VERTICAL,
2950 EL_EXPANDABLE_WALL_ANY,
2954 /* special EM style gems behaviour */
2955 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2956 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2957 level.em_slippery_gems);
2959 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2960 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2961 (level.em_slippery_gems &&
2962 engine_version > VERSION_IDENT(2,0,1,0)));
2966 /* set default push delay values (corrected since version 3.0.7-1) */
2967 if (engine_version < VERSION_IDENT(3,0,7,1))
2969 game.default_push_delay_fixed = 2;
2970 game.default_push_delay_random = 8;
2974 game.default_push_delay_fixed = 8;
2975 game.default_push_delay_random = 8;
2978 /* set uninitialized push delay values of custom elements in older levels */
2979 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2981 int element = EL_CUSTOM_START + i;
2983 if (element_info[element].push_delay_fixed == -1)
2984 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
2985 if (element_info[element].push_delay_random == -1)
2986 element_info[element].push_delay_random = game.default_push_delay_random;
2991 static void InitGlobal()
2993 global.autoplay_leveldir = NULL;
2995 global.frames_per_second = 0;
2996 global.fps_slowdown = FALSE;
2997 global.fps_slowdown_factor = 1;
3000 void Execute_Command(char *command)
3002 if (strcmp(command, "print graphicsinfo.conf") == 0)
3006 printf("# You can configure additional/alternative image files here.\n");
3007 printf("# (The images below are default and therefore commented out.)\n");
3009 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3011 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3014 for (i=0; image_config[i].token != NULL; i++)
3016 getFormattedSetupEntry(image_config[i].token,
3017 image_config[i].value));
3021 else if (strcmp(command, "print soundsinfo.conf") == 0)
3025 printf("# You can configure additional/alternative sound files here.\n");
3026 printf("# (The sounds below are default and therefore commented out.)\n");
3028 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3030 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3033 for (i=0; sound_config[i].token != NULL; i++)
3035 getFormattedSetupEntry(sound_config[i].token,
3036 sound_config[i].value));
3040 else if (strcmp(command, "print musicinfo.conf") == 0)
3042 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
3044 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3046 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3050 else if (strncmp(command, "dump level ", 11) == 0)
3052 char *filename = &command[11];
3054 if (access(filename, F_OK) != 0)
3055 Error(ERR_EXIT, "cannot open file '%s'", filename);
3057 LoadLevelFromFilename(&level, filename);
3062 else if (strncmp(command, "dump tape ", 10) == 0)
3064 char *filename = &command[10];
3066 if (access(filename, F_OK) != 0)
3067 Error(ERR_EXIT, "cannot open file '%s'", filename);
3069 LoadTapeFromFilename(filename);
3074 else if (strncmp(command, "autoplay ", 9) == 0)
3076 char *str_copy = getStringCopy(&command[9]);
3077 char *str_ptr = strchr(str_copy, ' ');
3079 global.autoplay_leveldir = str_copy;
3080 global.autoplay_level_nr = -1;
3082 if (str_ptr != NULL)
3084 *str_ptr++ = '\0'; /* terminate leveldir string */
3085 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3090 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3094 static void InitSetup()
3096 LoadSetup(); /* global setup info */
3098 /* set some options from setup file */
3100 if (setup.options.verbose)
3101 options.verbose = TRUE;
3104 static void InitPlayerInfo()
3108 /* choose default local player */
3109 local_player = &stored_player[0];
3111 for (i=0; i<MAX_PLAYERS; i++)
3112 stored_player[i].connected = FALSE;
3114 local_player->connected = TRUE;
3117 static void InitArtworkInfo()
3122 static char *get_string_in_brackets(char *string)
3124 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3126 sprintf(string_in_brackets, "[%s]", string);
3128 return string_in_brackets;
3132 static char *get_element_class_token(int element)
3134 char *element_class_name = element_info[element].class_name;
3135 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3137 sprintf(element_class_token, "[%s]", element_class_name);
3139 return element_class_token;
3142 static char *get_action_class_token(int action)
3144 char *action_class_name = &element_action_info[action].suffix[1];
3145 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3147 sprintf(action_class_token, "[%s]", action_class_name);
3149 return action_class_token;
3153 static void InitArtworkConfig()
3155 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3156 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3157 static char *action_id_suffix[NUM_ACTIONS + 1];
3158 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3159 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3160 static char *dummy[1] = { NULL };
3161 static char *ignore_generic_tokens[] =
3167 static char **ignore_image_tokens, **ignore_sound_tokens;
3168 int num_ignore_generic_tokens;
3169 int num_ignore_image_tokens, num_ignore_sound_tokens;
3172 /* dynamically determine list of generic tokens to be ignored */
3173 num_ignore_generic_tokens = 0;
3174 for (i=0; ignore_generic_tokens[i] != NULL; i++)
3175 num_ignore_generic_tokens++;
3177 /* dynamically determine list of image tokens to be ignored */
3178 num_ignore_image_tokens = num_ignore_generic_tokens;
3179 for (i=0; image_config_vars[i].token != NULL; i++)
3180 num_ignore_image_tokens++;
3181 ignore_image_tokens =
3182 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3183 for (i=0; i < num_ignore_generic_tokens; i++)
3184 ignore_image_tokens[i] = ignore_generic_tokens[i];
3185 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3186 ignore_image_tokens[num_ignore_generic_tokens + i] =
3187 image_config_vars[i].token;
3188 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3190 /* dynamically determine list of sound tokens to be ignored */
3191 num_ignore_sound_tokens = num_ignore_generic_tokens;
3192 ignore_sound_tokens =
3193 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3194 for (i=0; i < num_ignore_generic_tokens; i++)
3195 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3196 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3198 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3199 image_id_prefix[i] = element_info[i].token_name;
3200 for (i=0; i<NUM_FONTS; i++)
3201 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3202 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3204 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3205 sound_id_prefix[i] = element_info[i].token_name;
3206 for (i=0; i<MAX_NUM_ELEMENTS; i++)
3207 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3208 get_string_in_brackets(element_info[i].class_name);
3209 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3211 for (i=0; i<NUM_ACTIONS; i++)
3212 action_id_suffix[i] = element_action_info[i].suffix;
3213 action_id_suffix[NUM_ACTIONS] = NULL;
3215 for (i=0; i<NUM_DIRECTIONS; i++)
3216 direction_id_suffix[i] = element_direction_info[i].suffix;
3217 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3219 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
3220 special_id_suffix[i] = special_suffix_info[i].suffix;
3221 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3223 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3224 image_id_prefix, action_id_suffix, direction_id_suffix,
3225 special_id_suffix, ignore_image_tokens);
3226 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3227 sound_id_prefix, action_id_suffix, dummy,
3228 special_id_suffix, ignore_sound_tokens);
3231 static void InitMixer()
3239 char *filename_font_initial = NULL;
3240 Bitmap *bitmap_font_initial = NULL;
3243 /* determine settings for initial font (for displaying startup messages) */
3244 for (i=0; image_config[i].token != NULL; i++)
3246 for (j=0; j < NUM_INITIAL_FONTS; j++)
3248 char font_token[128];
3251 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3252 len_font_token = strlen(font_token);
3254 if (strcmp(image_config[i].token, font_token) == 0)
3255 filename_font_initial = image_config[i].value;
3256 else if (strlen(image_config[i].token) > len_font_token &&
3257 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3259 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3260 font_initial[j].src_x = atoi(image_config[i].value);
3261 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3262 font_initial[j].src_y = atoi(image_config[i].value);
3263 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3264 font_initial[j].width = atoi(image_config[i].value);
3265 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3266 font_initial[j].height = atoi(image_config[i].value);
3271 for (j=0; j < NUM_INITIAL_FONTS; j++)
3273 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3274 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3277 if (filename_font_initial == NULL) /* should not happen */
3278 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3280 /* create additional image buffers for double-buffering */
3281 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3282 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3284 /* initialize screen properties */
3285 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3286 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3288 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3289 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3290 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3292 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3294 for (j=0; j < NUM_INITIAL_FONTS; j++)
3295 font_initial[j].bitmap = bitmap_font_initial;
3297 InitFontGraphicInfo();
3299 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3300 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3302 DrawInitText("Loading graphics:", 120, FC_GREEN);
3304 InitTileClipmasks();
3307 void InitGfxBackground()
3311 drawto = backbuffer;
3312 fieldbuffer = bitmap_db_field;
3313 SetDrawtoField(DRAW_BACKBUFFER);
3315 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3316 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3317 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3318 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3320 for (x=0; x<MAX_BUF_XSIZE; x++)
3321 for (y=0; y<MAX_BUF_YSIZE; y++)
3324 redraw_mask = REDRAW_ALL;
3327 static void InitLevelInfo()
3329 LoadLevelInfo(); /* global level info */
3330 LoadLevelSetup_LastSeries(); /* last played series info */
3331 LoadLevelSetup_SeriesInfo(); /* last played level info */
3334 void InitLevelArtworkInfo()
3336 LoadLevelArtworkInfo();
3339 static void InitImages()
3342 setLevelArtworkDir(artwork.gfx_first);
3346 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3347 leveldir_current->identifier,
3348 artwork.gfx_current_identifier,
3349 artwork.gfx_current->identifier,
3350 leveldir_current->graphics_set,
3351 leveldir_current->graphics_path);
3354 ReloadCustomImages();
3356 LoadCustomElementDescriptions();
3357 LoadSpecialMenuDesignSettings();
3359 ReinitializeGraphics();
3362 static void InitSound(char *identifier)
3364 if (identifier == NULL)
3365 identifier = artwork.snd_current->identifier;
3368 /* set artwork path to send it to the sound server process */
3369 setLevelArtworkDir(artwork.snd_first);
3372 InitReloadCustomSounds(identifier);
3373 ReinitializeSounds();
3376 static void InitMusic(char *identifier)
3378 if (identifier == NULL)
3379 identifier = artwork.mus_current->identifier;
3382 /* set artwork path to send it to the sound server process */
3383 setLevelArtworkDir(artwork.mus_first);
3386 InitReloadCustomMusic(identifier);
3387 ReinitializeMusic();
3390 void InitNetworkServer()
3392 #if defined(PLATFORM_UNIX)
3396 if (!options.network)
3399 #if defined(PLATFORM_UNIX)
3400 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3402 if (!ConnectToServer(options.server_host, options.server_port))
3403 Error(ERR_EXIT, "cannot connect to network game server");
3405 SendToServer_PlayerName(setup.player_name);
3406 SendToServer_ProtocolVersion();
3409 SendToServer_NrWanted(nr_wanted);
3413 static char *getNewArtworkIdentifier(int type)
3415 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3416 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3417 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3418 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3419 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3420 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3421 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3422 char *leveldir_identifier = leveldir_current->identifier;
3424 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3425 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3427 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3429 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3430 char *artwork_current_identifier;
3431 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3433 /* leveldir_current may be invalid (level group, parent link) */
3434 if (!validLevelSeries(leveldir_current))
3437 /* 1st step: determine artwork set to be activated in descending order:
3438 --------------------------------------------------------------------
3439 1. setup artwork (when configured to override everything else)
3440 2. artwork set configured in "levelinfo.conf" of current level set
3441 (artwork in level directory will have priority when loading later)
3442 3. artwork in level directory (stored in artwork sub-directory)
3443 4. setup artwork (currently configured in setup menu) */
3445 if (setup_override_artwork)
3446 artwork_current_identifier = setup_artwork_set;
3447 else if (leveldir_artwork_set != NULL)
3448 artwork_current_identifier = leveldir_artwork_set;
3449 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3450 artwork_current_identifier = leveldir_identifier;
3452 artwork_current_identifier = setup_artwork_set;
3455 /* 2nd step: check if it is really needed to reload artwork set
3456 ------------------------------------------------------------ */
3459 if (type == ARTWORK_TYPE_GRAPHICS)
3460 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3461 artwork_new_identifier,
3462 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3463 artwork_current_identifier,
3464 leveldir_current->graphics_set,
3465 leveldir_current->identifier);
3468 /* ---------- reload if level set and also artwork set has changed ------- */
3469 if (leveldir_current_identifier[type] != leveldir_identifier &&
3470 (last_has_level_artwork_set[type] || has_level_artwork_set))
3471 artwork_new_identifier = artwork_current_identifier;
3473 leveldir_current_identifier[type] = leveldir_identifier;
3474 last_has_level_artwork_set[type] = has_level_artwork_set;
3477 if (type == ARTWORK_TYPE_GRAPHICS)
3478 printf("::: 1: '%s'\n", artwork_new_identifier);
3481 /* ---------- reload if "override artwork" setting has changed ----------- */
3482 if (last_override_level_artwork[type] != setup_override_artwork)
3483 artwork_new_identifier = artwork_current_identifier;
3485 last_override_level_artwork[type] = setup_override_artwork;
3488 if (type == ARTWORK_TYPE_GRAPHICS)
3489 printf("::: 2: '%s'\n", artwork_new_identifier);
3492 /* ---------- reload if current artwork identifier has changed ----------- */
3493 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3494 artwork_current_identifier) != 0)
3495 artwork_new_identifier = artwork_current_identifier;
3497 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3500 if (type == ARTWORK_TYPE_GRAPHICS)
3501 printf("::: 3: '%s'\n", artwork_new_identifier);
3504 /* ---------- do not reload directly after starting ---------------------- */
3505 if (!initialized[type])
3506 artwork_new_identifier = NULL;
3508 initialized[type] = TRUE;
3511 if (type == ARTWORK_TYPE_GRAPHICS)
3512 printf("::: 4: '%s'\n", artwork_new_identifier);
3516 if (type == ARTWORK_TYPE_GRAPHICS)
3517 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3518 artwork.gfx_current_identifier, artwork_current_identifier,
3519 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3520 artwork_new_identifier);
3523 return artwork_new_identifier;
3526 void ReloadCustomArtwork()
3528 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3529 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3530 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3531 boolean redraw_screen = FALSE;
3533 if (gfx_new_identifier != NULL)
3536 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3537 artwork.gfx_current_identifier,
3539 artwork.gfx_current->identifier,
3540 leveldir_current->graphics_set);
3543 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3548 printf("... '%s'\n",
3549 leveldir_current->graphics_set);
3552 FreeTileClipmasks();
3553 InitTileClipmasks();
3555 redraw_screen = TRUE;
3558 if (snd_new_identifier != NULL)
3560 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3562 InitSound(snd_new_identifier);
3564 redraw_screen = TRUE;
3567 if (mus_new_identifier != NULL)
3569 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3571 InitMusic(mus_new_identifier);
3573 redraw_screen = TRUE;
3578 InitGfxBackground();
3580 /* force redraw of (open or closed) door graphics */
3581 SetDoorState(DOOR_OPEN_ALL);
3582 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3586 void KeyboardAutoRepeatOffUnlessAutoplay()
3588 if (global.autoplay_leveldir == NULL)
3589 KeyboardAutoRepeatOff();
3593 /* ========================================================================= */
3595 /* ========================================================================= */
3599 InitGlobal(); /* initialize some global variables */
3601 if (options.execute_command)
3602 Execute_Command(options.execute_command);
3604 if (options.serveronly)
3606 #if defined(PLATFORM_UNIX)
3607 NetworkServer(options.server_port, options.serveronly);
3609 Error(ERR_WARN, "networking only supported in Unix version");
3611 exit(0); /* never reached */
3617 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3618 InitArtworkConfig(); /* needed before forking sound child process */
3623 InitRND(NEW_RANDOMIZE);
3624 InitSimpleRND(NEW_RANDOMIZE);
3629 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3632 InitEventFilter(FilterMouseMotionEvents);
3634 InitElementPropertiesStatic();
3635 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3640 InitLevelArtworkInfo();
3642 InitImages(); /* needs to know current level directory */
3643 InitSound(NULL); /* needs to know current level directory */
3644 InitMusic(NULL); /* needs to know current level directory */
3646 InitGfxBackground();
3648 if (global.autoplay_leveldir)
3654 game_status = GAME_MODE_MAIN;
3658 InitNetworkServer();
3661 void CloseAllAndExit(int exit_value)
3666 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3669 FreeTileClipmasks();
3671 CloseVideoDisplay();
3672 ClosePlatformDependentStuff();