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; /* default: play sound only once */
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 InitLevelsetMusicInfo()
1340 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1341 int num_property_mappings = getMusicListPropertyMappingSize();
1344 /* set values to -1 to identify later as "uninitialized" values */
1345 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1346 for (j=0; j < MAX_LEVELS; j++)
1347 levelset.music[i][j] = -1;
1350 /* initialize gamemode/music mapping from static configuration */
1351 for (i=0; gamemode_to_music[i].element > -1; i++)
1353 int gamemode = gamemode_to_music[i].gamemode;
1354 int level = gamemode_to_music[i].level;
1355 int music = gamemode_to_music[i].music;
1363 levelset.music[gamemode][level] = music;
1367 /* initialize gamemode/music mapping from dynamic configuration */
1368 for (i=0; i < num_property_mappings; i++)
1370 int prefix = property_mapping[i].base_index;
1371 int gamemode = property_mapping[i].ext1_index;
1372 int level = property_mapping[i].ext2_index;
1373 int music = property_mapping[i].artwork_index;
1375 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1384 levelset.music[gamemode][level] = music;
1387 /* now set all '-1' values to levelset specific default values */
1388 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1390 for (j=0; j < MAX_LEVELS; j++)
1392 /* generic default music */
1393 int default_music = levelset.music[i][0]; /* may still be -1 */
1395 /* no music for this specific game mode and level -- use default music */
1396 if (levelset.music[i][j] == -1)
1397 levelset.music[i][j] = default_music;
1403 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1404 for (j=0; j < MAX_LEVELS; j++)
1405 if (levelset.music[i][j] != -1)
1406 printf("::: levelset.music[%d][%d] == %d\n",
1407 i, j, levelset.music[i][j]);
1411 static void set_music_parameters(int music, char **parameter_raw)
1413 int parameter[NUM_MUS_ARGS];
1416 /* get integer values from string parameters */
1417 for (i=0; i < NUM_MUS_ARGS; i++)
1419 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1420 music_config_suffix[i].type);
1422 /* explicit loop mode setting in configuration overrides default value */
1423 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1424 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1427 static void InitMusicInfo()
1429 int num_music = getMusicListSize();
1432 if (music_info != NULL)
1435 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1437 for (i=0; i < num_music; i++)
1439 struct FileInfo *music = getMusicListEntry(i);
1440 int len_music_text = strlen(music->token);
1442 music_info[i].loop = TRUE; /* default: play music in loop mode */
1444 /* determine all loop music */
1446 for (j=0; music_prefix_info[j].prefix; j++)
1448 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1450 if (len_prefix_text < len_music_text &&
1451 strncmp(music->token,
1452 music_prefix_info[j].prefix, len_prefix_text) == 0)
1454 music_info[i].loop = music_prefix_info[j].is_loop_music;
1460 set_music_parameters(i, music->parameter);
1464 static void ReinitializeGraphics()
1466 InitGraphicInfo(); /* graphic properties mapping */
1467 InitElementGraphicInfo(); /* element game graphic mapping */
1468 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1470 InitElementSmallImages(); /* create editor and preview images */
1471 InitFontGraphicInfo(); /* initialize text drawing functions */
1473 SetMainBackgroundImage(IMG_BACKGROUND);
1474 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1480 static void ReinitializeSounds()
1482 InitSoundInfo(); /* sound properties mapping */
1483 InitElementSoundInfo(); /* element game sound mapping */
1485 InitPlayLevelSound(); /* internal game sound settings */
1488 static void ReinitializeMusic()
1490 InitMusicInfo(); /* music properties mapping */
1491 InitLevelsetMusicInfo(); /* levelset music mapping */
1494 void InitElementPropertiesStatic()
1496 static int ep_diggable[] =
1501 EL_SP_BUGGY_BASE_ACTIVATING,
1504 EL_INVISIBLE_SAND_ACTIVE,
1506 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1510 EL_SP_BUGGY_BASE_ACTIVE,
1515 static int ep_collectible_only[] =
1532 EL_DYNABOMB_INCREASE_NUMBER,
1533 EL_DYNABOMB_INCREASE_SIZE,
1534 EL_DYNABOMB_INCREASE_POWER,
1551 static int ep_dont_run_into[] =
1553 /* same elements as in 'ep_dont_touch' */
1559 /* same elements as in 'ep_dont_collide_with' */
1571 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1575 EL_SP_BUGGY_BASE_ACTIVE,
1580 static int ep_dont_collide_with[] =
1582 /* same elements as in 'ep_dont_touch' */
1598 static int ep_dont_touch[] =
1607 static int ep_indestructible[] =
1611 EL_ACID_POOL_TOPLEFT,
1612 EL_ACID_POOL_TOPRIGHT,
1613 EL_ACID_POOL_BOTTOMLEFT,
1614 EL_ACID_POOL_BOTTOM,
1615 EL_ACID_POOL_BOTTOMRIGHT,
1616 EL_SP_HARDWARE_GRAY,
1617 EL_SP_HARDWARE_GREEN,
1618 EL_SP_HARDWARE_BLUE,
1620 EL_SP_HARDWARE_YELLOW,
1621 EL_SP_HARDWARE_BASE_1,
1622 EL_SP_HARDWARE_BASE_2,
1623 EL_SP_HARDWARE_BASE_3,
1624 EL_SP_HARDWARE_BASE_4,
1625 EL_SP_HARDWARE_BASE_5,
1626 EL_SP_HARDWARE_BASE_6,
1627 EL_INVISIBLE_STEELWALL,
1628 EL_INVISIBLE_STEELWALL_ACTIVE,
1629 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1630 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1631 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1632 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1633 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1634 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1635 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1636 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1637 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1638 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1639 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1640 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1642 EL_LIGHT_SWITCH_ACTIVE,
1643 EL_SIGN_EXCLAMATION,
1644 EL_SIGN_RADIOACTIVITY,
1655 EL_STEELWALL_SLIPPERY,
1678 EL_SWITCHGATE_OPENING,
1679 EL_SWITCHGATE_CLOSED,
1680 EL_SWITCHGATE_CLOSING,
1682 EL_SWITCHGATE_SWITCH_UP,
1683 EL_SWITCHGATE_SWITCH_DOWN,
1686 EL_TIMEGATE_OPENING,
1688 EL_TIMEGATE_CLOSING,
1691 EL_TIMEGATE_SWITCH_ACTIVE,
1696 EL_TUBE_VERTICAL_LEFT,
1697 EL_TUBE_VERTICAL_RIGHT,
1698 EL_TUBE_HORIZONTAL_UP,
1699 EL_TUBE_HORIZONTAL_DOWN,
1707 static int ep_slippery[] =
1721 EL_ROBOT_WHEEL_ACTIVE,
1727 EL_ACID_POOL_TOPLEFT,
1728 EL_ACID_POOL_TOPRIGHT,
1738 EL_STEELWALL_SLIPPERY,
1744 static int ep_can_change[] =
1749 static int ep_can_move[] =
1771 static int ep_can_fall[] =
1786 EL_BD_MAGIC_WALL_FULL,
1799 static int ep_can_smash_player[] =
1824 static int ep_can_smash_enemies[] =
1832 static int ep_can_smash_everything[] =
1840 static int ep_can_explode_by_fire[] =
1842 /* same elements as in 'ep_can_explode_impact' */
1847 /* same elements as in 'ep_can_explode_smashed' */
1856 EL_DYNABOMB_PLAYER_1_ACTIVE,
1857 EL_DYNABOMB_PLAYER_2_ACTIVE,
1858 EL_DYNABOMB_PLAYER_3_ACTIVE,
1859 EL_DYNABOMB_PLAYER_4_ACTIVE,
1860 EL_DYNABOMB_INCREASE_NUMBER,
1861 EL_DYNABOMB_INCREASE_SIZE,
1862 EL_DYNABOMB_INCREASE_POWER,
1863 EL_SP_DISK_RED_ACTIVE,
1873 static int ep_can_explode_smashed[] =
1875 /* same elements as in 'ep_can_explode_impact' */
1888 static int ep_can_explode_impact[] =
1896 static int ep_walkable_over[] =
1900 EL_SOKOBAN_FIELD_EMPTY,
1918 static int ep_walkable_inside[] =
1923 EL_TUBE_VERTICAL_LEFT,
1924 EL_TUBE_VERTICAL_RIGHT,
1925 EL_TUBE_HORIZONTAL_UP,
1926 EL_TUBE_HORIZONTAL_DOWN,
1934 static int ep_walkable_under[] =
1939 static int ep_passable_over[] =
1954 static int ep_passable_inside[] =
1960 EL_SP_PORT_HORIZONTAL,
1961 EL_SP_PORT_VERTICAL,
1963 EL_SP_GRAVITY_PORT_LEFT,
1964 EL_SP_GRAVITY_PORT_RIGHT,
1965 EL_SP_GRAVITY_PORT_UP,
1966 EL_SP_GRAVITY_PORT_DOWN,
1970 static int ep_passable_under[] =
1975 static int ep_droppable[] =
1980 static int ep_can_explode_1x1[] =
1985 static int ep_pushable[] =
1997 EL_SOKOBAN_FIELD_FULL,
2004 static int ep_player[] =
2014 static int ep_can_pass_magic_wall[] =
2027 static int ep_switchable[] =
2031 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2032 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2033 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2034 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2035 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2036 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2037 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2038 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2039 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2040 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2041 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2042 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2043 EL_SWITCHGATE_SWITCH_UP,
2044 EL_SWITCHGATE_SWITCH_DOWN,
2046 EL_LIGHT_SWITCH_ACTIVE,
2048 EL_BALLOON_SWITCH_LEFT,
2049 EL_BALLOON_SWITCH_RIGHT,
2050 EL_BALLOON_SWITCH_UP,
2051 EL_BALLOON_SWITCH_DOWN,
2052 EL_BALLOON_SWITCH_ANY,
2058 static int ep_bd_element[] =
2087 static int ep_sp_element[] =
2089 /* should always be valid */
2098 EL_SP_HARDWARE_GRAY,
2106 EL_SP_GRAVITY_PORT_RIGHT,
2107 EL_SP_GRAVITY_PORT_DOWN,
2108 EL_SP_GRAVITY_PORT_LEFT,
2109 EL_SP_GRAVITY_PORT_UP,
2114 EL_SP_PORT_VERTICAL,
2115 EL_SP_PORT_HORIZONTAL,
2121 EL_SP_HARDWARE_BASE_1,
2122 EL_SP_HARDWARE_GREEN,
2123 EL_SP_HARDWARE_BLUE,
2125 EL_SP_HARDWARE_YELLOW,
2126 EL_SP_HARDWARE_BASE_2,
2127 EL_SP_HARDWARE_BASE_3,
2128 EL_SP_HARDWARE_BASE_4,
2129 EL_SP_HARDWARE_BASE_5,
2130 EL_SP_HARDWARE_BASE_6,
2133 /* additional elements that appeared in newer Supaplex levels */
2135 /* more than one murphy in a level results in an inactive clone */
2137 /* runtime elements*/
2138 EL_SP_DISK_RED_ACTIVE,
2139 EL_SP_TERMINAL_ACTIVE,
2140 EL_SP_BUGGY_BASE_ACTIVATING,
2141 EL_SP_BUGGY_BASE_ACTIVE,
2147 static int ep_sb_element[] =
2152 EL_SOKOBAN_FIELD_EMPTY,
2153 EL_SOKOBAN_FIELD_FULL,
2155 EL_INVISIBLE_STEELWALL,
2159 static int ep_gem[] =
2170 static int ep_food_dark_yamyam[] =
2197 static int ep_food_penguin[] =
2210 static int ep_food_pig[] =
2221 static int ep_historic_wall[] =
2246 EL_EXPANDABLE_WALL_HORIZONTAL,
2247 EL_EXPANDABLE_WALL_VERTICAL,
2248 EL_EXPANDABLE_WALL_ANY,
2249 EL_EXPANDABLE_WALL_GROWING,
2256 EL_SP_HARDWARE_GRAY,
2257 EL_SP_HARDWARE_GREEN,
2258 EL_SP_HARDWARE_BLUE,
2260 EL_SP_HARDWARE_YELLOW,
2261 EL_SP_HARDWARE_BASE_1,
2262 EL_SP_HARDWARE_BASE_2,
2263 EL_SP_HARDWARE_BASE_3,
2264 EL_SP_HARDWARE_BASE_4,
2265 EL_SP_HARDWARE_BASE_5,
2266 EL_SP_HARDWARE_BASE_6,
2268 EL_SP_TERMINAL_ACTIVE,
2271 EL_INVISIBLE_STEELWALL,
2272 EL_INVISIBLE_STEELWALL_ACTIVE,
2274 EL_INVISIBLE_WALL_ACTIVE,
2275 EL_STEELWALL_SLIPPERY,
2291 static int ep_historic_solid[] =
2295 EL_EXPANDABLE_WALL_HORIZONTAL,
2296 EL_EXPANDABLE_WALL_VERTICAL,
2297 EL_EXPANDABLE_WALL_ANY,
2310 EL_QUICKSAND_FILLING,
2311 EL_QUICKSAND_EMPTYING,
2313 EL_MAGIC_WALL_ACTIVE,
2314 EL_MAGIC_WALL_EMPTYING,
2315 EL_MAGIC_WALL_FILLING,
2319 EL_BD_MAGIC_WALL_ACTIVE,
2320 EL_BD_MAGIC_WALL_EMPTYING,
2321 EL_BD_MAGIC_WALL_FULL,
2322 EL_BD_MAGIC_WALL_FILLING,
2323 EL_BD_MAGIC_WALL_DEAD,
2332 EL_SP_TERMINAL_ACTIVE,
2336 EL_INVISIBLE_WALL_ACTIVE,
2337 EL_SWITCHGATE_SWITCH_UP,
2338 EL_SWITCHGATE_SWITCH_DOWN,
2340 EL_TIMEGATE_SWITCH_ACTIVE,
2352 /* the following elements are a direct copy of "indestructible" elements,
2353 except "EL_ACID", which is "indestructible", but not "solid"! */
2358 EL_ACID_POOL_TOPLEFT,
2359 EL_ACID_POOL_TOPRIGHT,
2360 EL_ACID_POOL_BOTTOMLEFT,
2361 EL_ACID_POOL_BOTTOM,
2362 EL_ACID_POOL_BOTTOMRIGHT,
2363 EL_SP_HARDWARE_GRAY,
2364 EL_SP_HARDWARE_GREEN,
2365 EL_SP_HARDWARE_BLUE,
2367 EL_SP_HARDWARE_YELLOW,
2368 EL_SP_HARDWARE_BASE_1,
2369 EL_SP_HARDWARE_BASE_2,
2370 EL_SP_HARDWARE_BASE_3,
2371 EL_SP_HARDWARE_BASE_4,
2372 EL_SP_HARDWARE_BASE_5,
2373 EL_SP_HARDWARE_BASE_6,
2374 EL_INVISIBLE_STEELWALL,
2375 EL_INVISIBLE_STEELWALL_ACTIVE,
2376 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2377 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2378 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2379 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2380 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2381 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2382 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2383 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2384 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2385 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2386 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2387 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2389 EL_LIGHT_SWITCH_ACTIVE,
2390 EL_SIGN_EXCLAMATION,
2391 EL_SIGN_RADIOACTIVITY,
2402 EL_STEELWALL_SLIPPERY,
2425 EL_SWITCHGATE_OPENING,
2426 EL_SWITCHGATE_CLOSED,
2427 EL_SWITCHGATE_CLOSING,
2429 EL_TIMEGATE_OPENING,
2431 EL_TIMEGATE_CLOSING,
2435 EL_TUBE_VERTICAL_LEFT,
2436 EL_TUBE_VERTICAL_RIGHT,
2437 EL_TUBE_HORIZONTAL_UP,
2438 EL_TUBE_HORIZONTAL_DOWN,
2446 static int ep_classic_enemy[] =
2462 static int ep_belt[] =
2464 EL_CONVEYOR_BELT_1_LEFT,
2465 EL_CONVEYOR_BELT_1_MIDDLE,
2466 EL_CONVEYOR_BELT_1_RIGHT,
2467 EL_CONVEYOR_BELT_2_LEFT,
2468 EL_CONVEYOR_BELT_2_MIDDLE,
2469 EL_CONVEYOR_BELT_2_RIGHT,
2470 EL_CONVEYOR_BELT_3_LEFT,
2471 EL_CONVEYOR_BELT_3_MIDDLE,
2472 EL_CONVEYOR_BELT_3_RIGHT,
2473 EL_CONVEYOR_BELT_4_LEFT,
2474 EL_CONVEYOR_BELT_4_MIDDLE,
2475 EL_CONVEYOR_BELT_4_RIGHT,
2479 static int ep_belt_active[] =
2481 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2482 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2483 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2484 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2485 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2486 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2487 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2488 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2489 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2490 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2491 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2492 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2496 static int ep_belt_switch[] =
2498 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2499 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2500 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2501 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2502 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2503 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2504 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2505 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2506 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2507 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2508 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2509 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2513 static int ep_tube[] =
2520 EL_TUBE_HORIZONTAL_UP,
2521 EL_TUBE_HORIZONTAL_DOWN,
2523 EL_TUBE_VERTICAL_LEFT,
2524 EL_TUBE_VERTICAL_RIGHT,
2529 static int ep_keygate[] =
2550 static int ep_amoeboid[] =
2560 static int ep_amoebalive[] =
2569 static int ep_has_content[] =
2579 static int ep_active_bomb[] =
2582 EL_DYNABOMB_PLAYER_1_ACTIVE,
2583 EL_DYNABOMB_PLAYER_2_ACTIVE,
2584 EL_DYNABOMB_PLAYER_3_ACTIVE,
2585 EL_DYNABOMB_PLAYER_4_ACTIVE,
2586 EL_SP_DISK_RED_ACTIVE,
2590 static int ep_inactive[] =
2627 EL_INVISIBLE_STEELWALL,
2635 EL_WALL_EMERALD_YELLOW,
2636 EL_DYNABOMB_INCREASE_NUMBER,
2637 EL_DYNABOMB_INCREASE_SIZE,
2638 EL_DYNABOMB_INCREASE_POWER,
2642 EL_SOKOBAN_FIELD_EMPTY,
2643 EL_SOKOBAN_FIELD_FULL,
2644 EL_WALL_EMERALD_RED,
2645 EL_WALL_EMERALD_PURPLE,
2646 EL_ACID_POOL_TOPLEFT,
2647 EL_ACID_POOL_TOPRIGHT,
2648 EL_ACID_POOL_BOTTOMLEFT,
2649 EL_ACID_POOL_BOTTOM,
2650 EL_ACID_POOL_BOTTOMRIGHT,
2654 EL_BD_MAGIC_WALL_DEAD,
2655 EL_AMOEBA_TO_DIAMOND,
2663 EL_SP_GRAVITY_PORT_RIGHT,
2664 EL_SP_GRAVITY_PORT_DOWN,
2665 EL_SP_GRAVITY_PORT_LEFT,
2666 EL_SP_GRAVITY_PORT_UP,
2667 EL_SP_PORT_HORIZONTAL,
2668 EL_SP_PORT_VERTICAL,
2679 EL_SP_HARDWARE_GRAY,
2680 EL_SP_HARDWARE_GREEN,
2681 EL_SP_HARDWARE_BLUE,
2683 EL_SP_HARDWARE_YELLOW,
2684 EL_SP_HARDWARE_BASE_1,
2685 EL_SP_HARDWARE_BASE_2,
2686 EL_SP_HARDWARE_BASE_3,
2687 EL_SP_HARDWARE_BASE_4,
2688 EL_SP_HARDWARE_BASE_5,
2689 EL_SP_HARDWARE_BASE_6,
2690 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2691 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2692 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2693 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2694 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2695 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2696 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2697 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2698 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2699 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2700 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2701 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2702 EL_SIGN_EXCLAMATION,
2703 EL_SIGN_RADIOACTIVITY,
2714 EL_STEELWALL_SLIPPERY,
2730 static int ep_em_slippery_wall[] =
2735 static int ep_gfx_crumbled[] =
2748 } element_properties[] =
2750 { ep_diggable, EP_DIGGABLE },
2751 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2752 { ep_dont_run_into, EP_DONT_RUN_INTO },
2753 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2754 { ep_dont_touch, EP_DONT_TOUCH },
2755 { ep_indestructible, EP_INDESTRUCTIBLE },
2756 { ep_slippery, EP_SLIPPERY },
2757 { ep_can_change, EP_CAN_CHANGE },
2758 { ep_can_move, EP_CAN_MOVE },
2759 { ep_can_fall, EP_CAN_FALL },
2760 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2761 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2762 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2763 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2764 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2765 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2766 { ep_walkable_over, EP_WALKABLE_OVER },
2767 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2768 { ep_walkable_under, EP_WALKABLE_UNDER },
2769 { ep_passable_over, EP_PASSABLE_OVER },
2770 { ep_passable_inside, EP_PASSABLE_INSIDE },
2771 { ep_passable_under, EP_PASSABLE_UNDER },
2772 { ep_droppable, EP_DROPPABLE },
2773 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2774 { ep_pushable, EP_PUSHABLE },
2776 { ep_player, EP_PLAYER },
2777 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2778 { ep_switchable, EP_SWITCHABLE },
2779 { ep_bd_element, EP_BD_ELEMENT },
2780 { ep_sp_element, EP_SP_ELEMENT },
2781 { ep_sb_element, EP_SB_ELEMENT },
2783 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2784 { ep_food_penguin, EP_FOOD_PENGUIN },
2785 { ep_food_pig, EP_FOOD_PIG },
2786 { ep_historic_wall, EP_HISTORIC_WALL },
2787 { ep_historic_solid, EP_HISTORIC_SOLID },
2788 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2789 { ep_belt, EP_BELT },
2790 { ep_belt_active, EP_BELT_ACTIVE },
2791 { ep_belt_switch, EP_BELT_SWITCH },
2792 { ep_tube, EP_TUBE },
2793 { ep_keygate, EP_KEYGATE },
2794 { ep_amoeboid, EP_AMOEBOID },
2795 { ep_amoebalive, EP_AMOEBALIVE },
2796 { ep_has_content, EP_HAS_CONTENT },
2797 { ep_active_bomb, EP_ACTIVE_BOMB },
2798 { ep_inactive, EP_INACTIVE },
2800 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2802 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2807 static int copy_properties[][5] =
2811 EL_BUG_LEFT, EL_BUG_RIGHT,
2812 EL_BUG_UP, EL_BUG_DOWN
2816 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2817 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2821 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2822 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2826 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2827 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2831 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2832 EL_PACMAN_UP, EL_PACMAN_DOWN
2842 /* always start with reliable default values (element has no properties) */
2843 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2844 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2845 SET_PROPERTY(i, j, FALSE);
2847 /* set all base element properties from above array definitions */
2848 for (i=0; element_properties[i].elements != NULL; i++)
2849 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2850 SET_PROPERTY((element_properties[i].elements)[j],
2851 element_properties[i].property, TRUE);
2853 /* copy properties to some elements that are only stored in level file */
2854 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2855 for (j=0; copy_properties[j][0] != -1; j++)
2856 if (HAS_PROPERTY(copy_properties[j][0], i))
2857 for (k=1; k<=4; k++)
2858 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2861 void InitElementPropertiesEngine(int engine_version)
2864 static int active_properties[] =
2869 EP_DONT_COLLIDE_WITH,
2873 EP_CAN_PASS_MAGIC_WALL,
2878 EP_CAN_EXPLODE_BY_FIRE,
2891 EP_EM_SLIPPERY_WALL,
2895 static int no_wall_properties[] =
2898 EP_COLLECTIBLE_ONLY,
2900 EP_DONT_COLLIDE_WITH,
2903 EP_CAN_SMASH_PLAYER,
2904 EP_CAN_SMASH_ENEMIES,
2905 EP_CAN_SMASH_EVERYTHING,
2910 EP_FOOD_DARK_YAMYAM,
2926 InitElementPropertiesStatic();
2929 /* set all special, combined or engine dependent element properties */
2930 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2933 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2934 SET_PROPERTY(i, j, FALSE);
2937 /* ---------- INACTIVE ------------------------------------------------- */
2938 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2939 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2941 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2942 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2943 IS_WALKABLE_INSIDE(i) ||
2944 IS_WALKABLE_UNDER(i)));
2946 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2947 IS_PASSABLE_INSIDE(i) ||
2948 IS_PASSABLE_UNDER(i)));
2950 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2951 IS_PASSABLE_OVER(i)));
2953 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2954 IS_PASSABLE_INSIDE(i)));
2956 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2957 IS_PASSABLE_UNDER(i)));
2959 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2962 /* ---------- COLLECTIBLE ---------------------------------------------- */
2963 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
2966 /* ---------- SNAPPABLE ------------------------------------------------ */
2967 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2968 IS_COLLECTIBLE(i) ||
2972 /* ---------- WALL ----------------------------------------------------- */
2973 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2975 for (j=0; no_wall_properties[j] != -1; j++)
2976 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2977 i >= EL_FIRST_RUNTIME_UNREAL)
2978 SET_PROPERTY(i, EP_WALL, FALSE);
2980 if (IS_HISTORIC_WALL(i))
2981 SET_PROPERTY(i, EP_WALL, TRUE);
2983 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2984 if (engine_version < VERSION_IDENT(2,2,0,0))
2985 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2987 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2989 !IS_COLLECTIBLE(i)));
2991 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2993 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2994 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2996 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2997 IS_INDESTRUCTIBLE(i)));
2999 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3001 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3002 else if (engine_version < VERSION_IDENT(2,2,0,0))
3003 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3005 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3006 !IS_WALKABLE_OVER(i) &&
3007 !IS_WALKABLE_UNDER(i)));
3009 if (IS_CUSTOM_ELEMENT(i))
3011 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3013 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3014 if (DONT_COLLIDE_WITH(i))
3015 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3017 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3018 if (CAN_SMASH_EVERYTHING(i))
3019 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3020 if (CAN_SMASH_ENEMIES(i))
3021 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3024 /* ---------- CAN_SMASH ------------------------------------------------ */
3025 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3026 CAN_SMASH_ENEMIES(i) ||
3027 CAN_SMASH_EVERYTHING(i)));
3029 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3030 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3031 CAN_EXPLODE_SMASHED(i) ||
3032 CAN_EXPLODE_IMPACT(i)));
3034 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3035 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3036 !CAN_EXPLODE_1X1(i)));
3038 /* ---------- CAN_CHANGE ----------------------------------------------- */
3039 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3040 for (j=0; j < element_info[i].num_change_pages; j++)
3041 if (element_info[i].change_page[j].can_change)
3042 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3044 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3045 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3046 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3050 /* determine inactive elements (used for engine main loop optimization) */
3051 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3053 boolean active = FALSE;
3055 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
3057 if (HAS_PROPERTY(i, j))
3063 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3068 /* dynamically adjust element properties according to game engine version */
3070 static int ep_em_slippery_wall[] =
3075 EL_EXPANDABLE_WALL_HORIZONTAL,
3076 EL_EXPANDABLE_WALL_VERTICAL,
3077 EL_EXPANDABLE_WALL_ANY,
3081 /* special EM style gems behaviour */
3082 for (i=0; ep_em_slippery_wall[i] != -1; i++)
3083 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3084 level.em_slippery_gems);
3086 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3087 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3088 (level.em_slippery_gems &&
3089 engine_version > VERSION_IDENT(2,0,1,0)));
3093 /* set default push delay values (corrected since version 3.0.7-1) */
3094 if (engine_version < VERSION_IDENT(3,0,7,1))
3096 game.default_push_delay_fixed = 2;
3097 game.default_push_delay_random = 8;
3101 game.default_push_delay_fixed = 8;
3102 game.default_push_delay_random = 8;
3105 /* set uninitialized push delay values of custom elements in older levels */
3106 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
3108 int element = EL_CUSTOM_START + i;
3110 if (element_info[element].push_delay_fixed == -1)
3111 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3112 if (element_info[element].push_delay_random == -1)
3113 element_info[element].push_delay_random = game.default_push_delay_random;
3118 static void InitGlobal()
3120 global.autoplay_leveldir = NULL;
3122 global.frames_per_second = 0;
3123 global.fps_slowdown = FALSE;
3124 global.fps_slowdown_factor = 1;
3127 void Execute_Command(char *command)
3129 if (strcmp(command, "print graphicsinfo.conf") == 0)
3133 printf("# You can configure additional/alternative image files here.\n");
3134 printf("# (The images below are default and therefore commented out.)\n");
3136 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3138 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3141 for (i=0; image_config[i].token != NULL; i++)
3143 getFormattedSetupEntry(image_config[i].token,
3144 image_config[i].value));
3148 else if (strcmp(command, "print soundsinfo.conf") == 0)
3152 printf("# You can configure additional/alternative sound files here.\n");
3153 printf("# (The sounds below are default and therefore commented out.)\n");
3155 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3157 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3160 for (i=0; sound_config[i].token != NULL; i++)
3162 getFormattedSetupEntry(sound_config[i].token,
3163 sound_config[i].value));
3167 else if (strcmp(command, "print musicinfo.conf") == 0)
3169 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
3171 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3173 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3177 else if (strncmp(command, "dump level ", 11) == 0)
3179 char *filename = &command[11];
3181 if (access(filename, F_OK) != 0)
3182 Error(ERR_EXIT, "cannot open file '%s'", filename);
3184 LoadLevelFromFilename(&level, filename);
3189 else if (strncmp(command, "dump tape ", 10) == 0)
3191 char *filename = &command[10];
3193 if (access(filename, F_OK) != 0)
3194 Error(ERR_EXIT, "cannot open file '%s'", filename);
3196 LoadTapeFromFilename(filename);
3201 else if (strncmp(command, "autoplay ", 9) == 0)
3203 char *str_copy = getStringCopy(&command[9]);
3204 char *str_ptr = strchr(str_copy, ' ');
3206 global.autoplay_leveldir = str_copy;
3207 global.autoplay_level_nr = -1;
3209 if (str_ptr != NULL)
3211 *str_ptr++ = '\0'; /* terminate leveldir string */
3212 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3217 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3221 static void InitSetup()
3223 LoadSetup(); /* global setup info */
3225 /* set some options from setup file */
3227 if (setup.options.verbose)
3228 options.verbose = TRUE;
3231 static void InitPlayerInfo()
3235 /* choose default local player */
3236 local_player = &stored_player[0];
3238 for (i=0; i<MAX_PLAYERS; i++)
3239 stored_player[i].connected = FALSE;
3241 local_player->connected = TRUE;
3244 static void InitArtworkInfo()
3249 static char *get_string_in_brackets(char *string)
3251 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3253 sprintf(string_in_brackets, "[%s]", string);
3255 return string_in_brackets;
3258 static char *get_level_id_suffix(int id_nr)
3260 char *id_suffix = checked_malloc(1 + 3 + 1);
3262 if (id_nr < 0 || id_nr > 999)
3265 sprintf(id_suffix, ".%03d", id_nr);
3271 static char *get_element_class_token(int element)
3273 char *element_class_name = element_info[element].class_name;
3274 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3276 sprintf(element_class_token, "[%s]", element_class_name);
3278 return element_class_token;
3281 static char *get_action_class_token(int action)
3283 char *action_class_name = &element_action_info[action].suffix[1];
3284 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3286 sprintf(action_class_token, "[%s]", action_class_name);
3288 return action_class_token;
3292 static void InitArtworkConfig()
3294 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3295 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3296 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3297 static char *action_id_suffix[NUM_ACTIONS + 1];
3298 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3299 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3300 static char *level_id_suffix[MAX_LEVELS + 1];
3301 static char *dummy[1] = { NULL };
3302 static char *ignore_generic_tokens[] =
3308 static char **ignore_image_tokens;
3309 static char **ignore_sound_tokens;
3310 static char **ignore_music_tokens;
3311 int num_ignore_generic_tokens;
3312 int num_ignore_image_tokens;
3313 int num_ignore_sound_tokens;
3314 int num_ignore_music_tokens;
3317 /* dynamically determine list of generic tokens to be ignored */
3318 num_ignore_generic_tokens = 0;
3319 for (i=0; ignore_generic_tokens[i] != NULL; i++)
3320 num_ignore_generic_tokens++;
3322 /* dynamically determine list of image tokens to be ignored */
3323 num_ignore_image_tokens = num_ignore_generic_tokens;
3324 for (i=0; image_config_vars[i].token != NULL; i++)
3325 num_ignore_image_tokens++;
3326 ignore_image_tokens =
3327 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3328 for (i=0; i < num_ignore_generic_tokens; i++)
3329 ignore_image_tokens[i] = ignore_generic_tokens[i];
3330 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3331 ignore_image_tokens[num_ignore_generic_tokens + i] =
3332 image_config_vars[i].token;
3333 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3335 /* dynamically determine list of sound tokens to be ignored */
3336 num_ignore_sound_tokens = num_ignore_generic_tokens;
3337 ignore_sound_tokens =
3338 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3339 for (i=0; i < num_ignore_generic_tokens; i++)
3340 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3341 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3343 /* dynamically determine list of music tokens to be ignored */
3344 num_ignore_music_tokens = num_ignore_generic_tokens;
3345 ignore_music_tokens =
3346 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3347 for (i=0; i < num_ignore_generic_tokens; i++)
3348 ignore_music_tokens[i] = ignore_generic_tokens[i];
3349 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3351 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3352 image_id_prefix[i] = element_info[i].token_name;
3353 for (i=0; i < NUM_FONTS; i++)
3354 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3355 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3357 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3358 sound_id_prefix[i] = element_info[i].token_name;
3359 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3360 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3361 get_string_in_brackets(element_info[i].class_name);
3362 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3364 for (i=0; i < NUM_MUSIC_PREFIXES; i++)
3365 music_id_prefix[i] = music_prefix_info[i].prefix;
3366 music_id_prefix[MAX_LEVELS] = NULL;
3368 for (i=0; i < NUM_ACTIONS; i++)
3369 action_id_suffix[i] = element_action_info[i].suffix;
3370 action_id_suffix[NUM_ACTIONS] = NULL;
3372 for (i=0; i < NUM_DIRECTIONS; i++)
3373 direction_id_suffix[i] = element_direction_info[i].suffix;
3374 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3376 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
3377 special_id_suffix[i] = special_suffix_info[i].suffix;
3378 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3380 for (i=0; i < MAX_LEVELS; i++)
3381 level_id_suffix[i] = get_level_id_suffix(i);
3382 level_id_suffix[MAX_LEVELS] = NULL;
3384 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3385 image_id_prefix, action_id_suffix, direction_id_suffix,
3386 special_id_suffix, ignore_image_tokens);
3387 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3388 sound_id_prefix, action_id_suffix, dummy,
3389 special_id_suffix, ignore_sound_tokens);
3390 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3391 music_id_prefix, special_id_suffix, level_id_suffix,
3392 dummy, ignore_music_tokens);
3395 static void InitMixer()
3403 char *filename_font_initial = NULL;
3404 Bitmap *bitmap_font_initial = NULL;
3407 /* determine settings for initial font (for displaying startup messages) */
3408 for (i=0; image_config[i].token != NULL; i++)
3410 for (j=0; j < NUM_INITIAL_FONTS; j++)
3412 char font_token[128];
3415 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3416 len_font_token = strlen(font_token);
3418 if (strcmp(image_config[i].token, font_token) == 0)
3419 filename_font_initial = image_config[i].value;
3420 else if (strlen(image_config[i].token) > len_font_token &&
3421 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3423 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3424 font_initial[j].src_x = atoi(image_config[i].value);
3425 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3426 font_initial[j].src_y = atoi(image_config[i].value);
3427 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3428 font_initial[j].width = atoi(image_config[i].value);
3429 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3430 font_initial[j].height = atoi(image_config[i].value);
3435 for (j=0; j < NUM_INITIAL_FONTS; j++)
3437 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3438 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3441 if (filename_font_initial == NULL) /* should not happen */
3442 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3444 /* create additional image buffers for double-buffering */
3445 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3446 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3448 /* initialize screen properties */
3449 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3450 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3452 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3453 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3454 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3456 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3458 for (j=0; j < NUM_INITIAL_FONTS; j++)
3459 font_initial[j].bitmap = bitmap_font_initial;
3461 InitFontGraphicInfo();
3463 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3464 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3466 DrawInitText("Loading graphics:", 120, FC_GREEN);
3468 InitTileClipmasks();
3471 void InitGfxBackground()
3475 drawto = backbuffer;
3476 fieldbuffer = bitmap_db_field;
3477 SetDrawtoField(DRAW_BACKBUFFER);
3479 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3480 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3481 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3482 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3484 for (x=0; x<MAX_BUF_XSIZE; x++)
3485 for (y=0; y<MAX_BUF_YSIZE; y++)
3488 redraw_mask = REDRAW_ALL;
3491 static void InitLevelInfo()
3493 LoadLevelInfo(); /* global level info */
3494 LoadLevelSetup_LastSeries(); /* last played series info */
3495 LoadLevelSetup_SeriesInfo(); /* last played level info */
3498 void InitLevelArtworkInfo()
3500 LoadLevelArtworkInfo();
3503 static void InitImages()
3506 setLevelArtworkDir(artwork.gfx_first);
3510 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3511 leveldir_current->identifier,
3512 artwork.gfx_current_identifier,
3513 artwork.gfx_current->identifier,
3514 leveldir_current->graphics_set,
3515 leveldir_current->graphics_path);
3518 ReloadCustomImages();
3520 LoadCustomElementDescriptions();
3521 LoadSpecialMenuDesignSettings();
3523 ReinitializeGraphics();
3526 static void InitSound(char *identifier)
3528 if (identifier == NULL)
3529 identifier = artwork.snd_current->identifier;
3532 /* set artwork path to send it to the sound server process */
3533 setLevelArtworkDir(artwork.snd_first);
3536 InitReloadCustomSounds(identifier);
3537 ReinitializeSounds();
3540 static void InitMusic(char *identifier)
3542 if (identifier == NULL)
3543 identifier = artwork.mus_current->identifier;
3546 /* set artwork path to send it to the sound server process */
3547 setLevelArtworkDir(artwork.mus_first);
3550 InitReloadCustomMusic(identifier);
3551 ReinitializeMusic();
3554 void InitNetworkServer()
3556 #if defined(PLATFORM_UNIX)
3560 if (!options.network)
3563 #if defined(PLATFORM_UNIX)
3564 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3566 if (!ConnectToServer(options.server_host, options.server_port))
3567 Error(ERR_EXIT, "cannot connect to network game server");
3569 SendToServer_PlayerName(setup.player_name);
3570 SendToServer_ProtocolVersion();
3573 SendToServer_NrWanted(nr_wanted);
3577 static char *getNewArtworkIdentifier(int type)
3579 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3580 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3581 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3582 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3583 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3584 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3585 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3586 char *leveldir_identifier = leveldir_current->identifier;
3588 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3589 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3591 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3593 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3594 char *artwork_current_identifier;
3595 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3597 /* leveldir_current may be invalid (level group, parent link) */
3598 if (!validLevelSeries(leveldir_current))
3601 /* 1st step: determine artwork set to be activated in descending order:
3602 --------------------------------------------------------------------
3603 1. setup artwork (when configured to override everything else)
3604 2. artwork set configured in "levelinfo.conf" of current level set
3605 (artwork in level directory will have priority when loading later)
3606 3. artwork in level directory (stored in artwork sub-directory)
3607 4. setup artwork (currently configured in setup menu) */
3609 if (setup_override_artwork)
3610 artwork_current_identifier = setup_artwork_set;
3611 else if (leveldir_artwork_set != NULL)
3612 artwork_current_identifier = leveldir_artwork_set;
3613 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3614 artwork_current_identifier = leveldir_identifier;
3616 artwork_current_identifier = setup_artwork_set;
3619 /* 2nd step: check if it is really needed to reload artwork set
3620 ------------------------------------------------------------ */
3623 if (type == ARTWORK_TYPE_GRAPHICS)
3624 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3625 artwork_new_identifier,
3626 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3627 artwork_current_identifier,
3628 leveldir_current->graphics_set,
3629 leveldir_current->identifier);
3632 /* ---------- reload if level set and also artwork set has changed ------- */
3633 if (leveldir_current_identifier[type] != leveldir_identifier &&
3634 (last_has_level_artwork_set[type] || has_level_artwork_set))
3635 artwork_new_identifier = artwork_current_identifier;
3637 leveldir_current_identifier[type] = leveldir_identifier;
3638 last_has_level_artwork_set[type] = has_level_artwork_set;
3641 if (type == ARTWORK_TYPE_GRAPHICS)
3642 printf("::: 1: '%s'\n", artwork_new_identifier);
3645 /* ---------- reload if "override artwork" setting has changed ----------- */
3646 if (last_override_level_artwork[type] != setup_override_artwork)
3647 artwork_new_identifier = artwork_current_identifier;
3649 last_override_level_artwork[type] = setup_override_artwork;
3652 if (type == ARTWORK_TYPE_GRAPHICS)
3653 printf("::: 2: '%s'\n", artwork_new_identifier);
3656 /* ---------- reload if current artwork identifier has changed ----------- */
3657 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3658 artwork_current_identifier) != 0)
3659 artwork_new_identifier = artwork_current_identifier;
3661 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3664 if (type == ARTWORK_TYPE_GRAPHICS)
3665 printf("::: 3: '%s'\n", artwork_new_identifier);
3668 /* ---------- do not reload directly after starting ---------------------- */
3669 if (!initialized[type])
3670 artwork_new_identifier = NULL;
3672 initialized[type] = TRUE;
3675 if (type == ARTWORK_TYPE_GRAPHICS)
3676 printf("::: 4: '%s'\n", artwork_new_identifier);
3680 if (type == ARTWORK_TYPE_GRAPHICS)
3681 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3682 artwork.gfx_current_identifier, artwork_current_identifier,
3683 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3684 artwork_new_identifier);
3687 return artwork_new_identifier;
3690 void ReloadCustomArtwork()
3692 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3693 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3694 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3695 boolean redraw_screen = FALSE;
3697 if (gfx_new_identifier != NULL)
3700 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3701 artwork.gfx_current_identifier,
3703 artwork.gfx_current->identifier,
3704 leveldir_current->graphics_set);
3707 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3712 printf("... '%s'\n",
3713 leveldir_current->graphics_set);
3716 FreeTileClipmasks();
3717 InitTileClipmasks();
3719 redraw_screen = TRUE;
3722 if (snd_new_identifier != NULL)
3724 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3726 InitSound(snd_new_identifier);
3728 redraw_screen = TRUE;
3731 if (mus_new_identifier != NULL)
3733 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3735 InitMusic(mus_new_identifier);
3737 redraw_screen = TRUE;
3742 InitGfxBackground();
3744 /* force redraw of (open or closed) door graphics */
3745 SetDoorState(DOOR_OPEN_ALL);
3746 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3750 void KeyboardAutoRepeatOffUnlessAutoplay()
3752 if (global.autoplay_leveldir == NULL)
3753 KeyboardAutoRepeatOff();
3757 /* ========================================================================= */
3759 /* ========================================================================= */
3763 InitGlobal(); /* initialize some global variables */
3765 if (options.execute_command)
3766 Execute_Command(options.execute_command);
3768 if (options.serveronly)
3770 #if defined(PLATFORM_UNIX)
3771 NetworkServer(options.server_port, options.serveronly);
3773 Error(ERR_WARN, "networking only supported in Unix version");
3775 exit(0); /* never reached */
3781 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3782 InitArtworkConfig(); /* needed before forking sound child process */
3787 InitRND(NEW_RANDOMIZE);
3788 InitSimpleRND(NEW_RANDOMIZE);
3793 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3796 InitEventFilter(FilterMouseMotionEvents);
3798 InitElementPropertiesStatic();
3799 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3804 InitLevelArtworkInfo();
3806 InitImages(); /* needs to know current level directory */
3807 InitSound(NULL); /* needs to know current level directory */
3808 InitMusic(NULL); /* needs to know current level directory */
3810 InitGfxBackground();
3812 if (global.autoplay_leveldir)
3818 game_status = GAME_MODE_MAIN;
3822 InitNetworkServer();
3825 void CloseAllAndExit(int exit_value)
3830 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3833 FreeTileClipmasks();
3835 CloseVideoDisplay();
3836 ClosePlatformDependentStuff();