1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static void InitTileClipmasks()
46 #if defined(TARGET_X11)
47 XGCValues clip_gc_values;
48 unsigned long clip_gc_valuemask;
50 #if defined(TARGET_X11_NATIVE)
60 tile_needs_clipping[] =
62 { GFX_SPIELER1_UP, 4 },
63 { GFX_SPIELER1_DOWN, 4 },
64 { GFX_SPIELER1_LEFT, 4 },
65 { GFX_SPIELER1_RIGHT, 4 },
66 { GFX_SPIELER1_PUSH_LEFT, 4 },
67 { GFX_SPIELER1_PUSH_RIGHT, 4 },
68 { GFX_SPIELER2_UP, 4 },
69 { GFX_SPIELER2_DOWN, 4 },
70 { GFX_SPIELER2_LEFT, 4 },
71 { GFX_SPIELER2_RIGHT, 4 },
72 { GFX_SPIELER2_PUSH_LEFT, 4 },
73 { GFX_SPIELER2_PUSH_RIGHT, 4 },
74 { GFX_SPIELER3_UP, 4 },
75 { GFX_SPIELER3_DOWN, 4 },
76 { GFX_SPIELER3_LEFT, 4 },
77 { GFX_SPIELER3_RIGHT, 4 },
78 { GFX_SPIELER3_PUSH_LEFT, 4 },
79 { GFX_SPIELER3_PUSH_RIGHT, 4 },
80 { GFX_SPIELER4_UP, 4 },
81 { GFX_SPIELER4_DOWN, 4 },
82 { GFX_SPIELER4_LEFT, 4 },
83 { GFX_SPIELER4_RIGHT, 4 },
84 { GFX_SPIELER4_PUSH_LEFT, 4 },
85 { GFX_SPIELER4_PUSH_RIGHT, 4 },
87 { GFX_MURPHY_GO_LEFT, 3 },
88 { GFX_MURPHY_GO_RIGHT, 3 },
89 { GFX_MURPHY_SNAP_UP, 1 },
90 { GFX_MURPHY_SNAP_DOWN, 1 },
91 { GFX_MURPHY_SNAP_RIGHT, 1 },
92 { GFX_MURPHY_SNAP_LEFT, 1 },
93 { GFX_MURPHY_PUSH_RIGHT, 1 },
94 { GFX_MURPHY_PUSH_LEFT, 1 },
99 { GFX_SOKOBAN_OBJEKT, 1 },
100 { GFX_FUNKELN_BLAU, 3 },
101 { GFX_FUNKELN_WEISS, 3 },
102 { GFX2_SHIELD_PASSIVE, 3 },
103 { GFX2_SHIELD_ACTIVE, 3 },
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
113 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114 for (i=0; i<NUM_TILES; i++)
115 tile_clipmask[i] = None;
117 #if defined(TARGET_X11)
118 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119 often very slow when preparing a masked XCopyArea() for big Pixmaps.
120 To prevent this, create small (tile-sized) mask Pixmaps which will then
121 be set much faster with XSetClipOrigin() and speed things up a lot. */
123 clip_gc_values.graphics_exposures = False;
124 clip_gc_valuemask = GCGraphicsExposures;
125 tile_clip_gc = XCreateGC(display, window->drawable,
126 clip_gc_valuemask, &clip_gc_values);
129 for (i=0; i<NUM_BITMAPS; i++)
131 if (pix[i]->clip_mask)
133 clip_gc_values.graphics_exposures = False;
134 clip_gc_values.clip_mask = pix[i]->clip_mask;
135 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137 clip_gc_valuemask, &clip_gc_values);
142 #if defined(TARGET_X11_NATIVE)
145 /* create graphic context structures needed for clipping */
146 clip_gc_values.graphics_exposures = False;
147 clip_gc_valuemask = GCGraphicsExposures;
148 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149 clip_gc_valuemask, &clip_gc_values);
151 /* create only those clipping Pixmaps we really need */
152 for (i=0; tile_needs_clipping[i].start>=0; i++)
156 for (j=0; j<tile_needs_clipping[i].count; j++)
158 int tile = tile_needs_clipping[i].start + j;
164 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165 src_pixmap = src_bitmap->clip_mask;
167 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
170 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171 src_x, src_y, TILEX, TILEY, 0, 0);
175 XFreeGC(display, copy_clipmask_gc);
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
183 void FreeTileClipmasks()
186 #if defined(TARGET_X11)
189 for (i=0; i<NUM_TILES; i++)
191 if (tile_clipmask[i] != None)
193 XFreePixmap(display, tile_clipmask[i]);
194 tile_clipmask[i] = None;
199 XFreeGC(display, tile_clip_gc);
203 for (i=0; i<NUM_BITMAPS; i++)
205 if (pix[i] != NULL && pix[i]->stored_clip_gc)
207 XFreeGC(display, pix[i]->stored_clip_gc);
208 pix[i]->stored_clip_gc = None;
213 #endif /* TARGET_X11 */
219 FreeLevelEditorGadgets();
228 static boolean gadgets_initialized = FALSE;
230 if (gadgets_initialized)
233 CreateLevelEditorGadgets();
237 CreateScreenGadgets();
239 gadgets_initialized = TRUE;
242 void InitElementSmallImages()
244 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
245 int num_property_mappings = getImageListPropertyMappingSize();
248 /* initialize normal images from static configuration */
249 for (i=0; element_to_graphic[i].element > -1; i++)
250 CreateImageWithSmallImages(element_to_graphic[i].graphic);
252 /* initialize special images from static configuration */
253 for (i=0; element_to_special_graphic[i].element > -1; i++)
254 CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
256 /* initialize images from dynamic configuration */
257 for (i=0; i < num_property_mappings; i++)
258 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
259 CreateImageWithSmallImages(property_mapping[i].artwork_index);
262 static int getFontBitmapID(int font_nr)
266 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
267 special = game_status;
268 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
269 special = GFX_SPECIAL_ARG_MAIN;
270 else if (game_status == GAME_MODE_PLAYING)
271 special = GFX_SPECIAL_ARG_DOOR;
274 return font_info[font_nr].special_bitmap_id[special];
279 void InitFontGraphicInfo()
281 static struct FontBitmapInfo *font_bitmap_info = NULL;
282 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
283 int num_property_mappings = getImageListPropertyMappingSize();
284 int num_font_bitmaps = NUM_FONTS;
287 if (graphic_info == NULL) /* still at startup phase */
289 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
294 /* ---------- initialize font graphic definitions ---------- */
296 /* always start with reliable default values (normal font graphics) */
298 for (i=0; i < NUM_FONTS; i++)
299 font_info[i].graphic = IMG_FONT_INITIAL_1;
301 for (i=0; i < NUM_FONTS; i++)
302 font_info[i].graphic = FONT_INITIAL_1;
305 /* initialize normal font/graphic mapping from static configuration */
306 for (i=0; font_to_graphic[i].font_nr > -1; i++)
308 int font_nr = font_to_graphic[i].font_nr;
309 int special = font_to_graphic[i].special;
310 int graphic = font_to_graphic[i].graphic;
315 font_info[font_nr].graphic = graphic;
318 /* always start with reliable default values (special font graphics) */
319 for (i=0; i < NUM_FONTS; i++)
321 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
323 font_info[i].special_graphic[j] = font_info[i].graphic;
324 font_info[i].special_bitmap_id[j] = i;
328 /* initialize special font/graphic mapping from static configuration */
329 for (i=0; font_to_graphic[i].font_nr > -1; i++)
331 int font_nr = font_to_graphic[i].font_nr;
332 int special = font_to_graphic[i].special;
333 int graphic = font_to_graphic[i].graphic;
335 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
337 font_info[font_nr].special_graphic[special] = graphic;
338 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
343 /* initialize special element/graphic mapping from dynamic configuration */
344 for (i=0; i < num_property_mappings; i++)
346 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
347 int special = property_mapping[i].ext3_index;
348 int graphic = property_mapping[i].artwork_index;
353 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
355 font_info[font_nr].special_graphic[special] = graphic;
356 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
361 /* ---------- initialize font bitmap array ---------- */
363 if (font_bitmap_info != NULL)
364 FreeFontInfo(font_bitmap_info);
367 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
369 /* ---------- initialize font bitmap definitions ---------- */
371 for (i=0; i < NUM_FONTS; i++)
373 if (i < NUM_INITIAL_FONTS)
375 font_bitmap_info[i] = font_initial[i];
379 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
381 int font_bitmap_id = font_info[i].special_bitmap_id[j];
382 int graphic = font_info[i].special_graphic[j];
384 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
385 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
387 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
388 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
391 /* copy font relevant information from graphics information */
392 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
393 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
394 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
395 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
396 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
397 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
398 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
400 font_bitmap_info[font_bitmap_id].num_chars =
401 graphic_info[graphic].anim_frames;
402 font_bitmap_info[font_bitmap_id].num_chars_per_line =
403 graphic_info[graphic].anim_frames_per_line;
407 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
410 void InitElementGraphicInfo()
412 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
413 int num_property_mappings = getImageListPropertyMappingSize();
416 /* set values to -1 to identify later as "uninitialized" values */
417 for (i=0; i<MAX_NUM_ELEMENTS; i++)
419 for (act=0; act<NUM_ACTIONS; act++)
421 element_info[i].graphic[act] = -1;
422 element_info[i].crumbled[act] = -1;
424 for (dir=0; dir<NUM_DIRECTIONS; dir++)
426 element_info[i].direction_graphic[act][dir] = -1;
427 element_info[i].direction_crumbled[act][dir] = -1;
432 /* initialize normal element/graphic mapping from static configuration */
433 for (i=0; element_to_graphic[i].element > -1; i++)
435 int element = element_to_graphic[i].element;
436 int action = element_to_graphic[i].action;
437 int direction = element_to_graphic[i].direction;
438 boolean crumbled = element_to_graphic[i].crumbled;
439 int graphic = element_to_graphic[i].graphic;
441 if (graphic_info[graphic].bitmap == NULL)
444 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
445 el2img(element) != -1)
447 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
448 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
450 /* if the base graphic ("emerald", for example) has been redefined,
451 but not the action graphic ("emerald.falling", for example), do not
452 use an existing (in this case considered obsolete) action graphic
453 anymore, but use the automatically determined default graphic */
454 if (base_redefined && !act_dir_redefined)
459 action = ACTION_DEFAULT;
464 element_info[element].direction_crumbled[action][direction] = graphic;
466 element_info[element].crumbled[action] = graphic;
471 element_info[element].direction_graphic[action][direction] = graphic;
473 element_info[element].graphic[action] = graphic;
477 /* initialize normal element/graphic mapping from dynamic configuration */
478 for (i=0; i < num_property_mappings; i++)
480 int element = property_mapping[i].base_index;
481 int action = property_mapping[i].ext1_index;
482 int direction = property_mapping[i].ext2_index;
483 int special = property_mapping[i].ext3_index;
484 int graphic = property_mapping[i].artwork_index;
485 boolean crumbled = FALSE;
487 if (special == GFX_SPECIAL_ARG_CRUMBLED)
493 if (graphic_info[graphic].bitmap == NULL)
496 if (element >= MAX_NUM_ELEMENTS || special != -1)
500 action = ACTION_DEFAULT;
505 for (dir=0; dir<NUM_DIRECTIONS; dir++)
506 element_info[element].direction_crumbled[action][dir] = -1;
509 element_info[element].direction_crumbled[action][direction] = graphic;
511 element_info[element].crumbled[action] = graphic;
516 for (dir=0; dir<NUM_DIRECTIONS; dir++)
517 element_info[element].direction_graphic[action][dir] = -1;
520 element_info[element].direction_graphic[action][direction] = graphic;
522 element_info[element].graphic[action] = graphic;
526 /* now copy all graphics that are defined to be cloned from other graphics */
527 for (i=0; i<MAX_NUM_ELEMENTS; i++)
529 int graphic = element_info[i].graphic[ACTION_DEFAULT];
530 int crumbled_like, diggable_like;
535 crumbled_like = graphic_info[graphic].crumbled_like;
536 diggable_like = graphic_info[graphic].diggable_like;
538 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
540 for (act=0; act<NUM_ACTIONS; act++)
541 element_info[i].crumbled[act] =
542 element_info[crumbled_like].crumbled[act];
543 for (act=0; act<NUM_ACTIONS; act++)
544 for (dir=0; dir<NUM_DIRECTIONS; dir++)
545 element_info[i].direction_crumbled[act][dir] =
546 element_info[crumbled_like].direction_crumbled[act][dir];
549 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
551 element_info[i].graphic[ACTION_DIGGING] =
552 element_info[diggable_like].graphic[ACTION_DIGGING];
553 for (dir=0; dir<NUM_DIRECTIONS; dir++)
554 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
555 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
560 /* now set all undefined/invalid graphics to -1 to set to default after it */
561 for (i=0; i<MAX_NUM_ELEMENTS; i++)
563 for (act=0; act<NUM_ACTIONS; act++)
567 graphic = element_info[i].graphic[act];
568 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
569 element_info[i].graphic[act] = -1;
571 graphic = element_info[i].crumbled[act];
572 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
573 element_info[i].crumbled[act] = -1;
575 for (dir=0; dir<NUM_DIRECTIONS; dir++)
577 graphic = element_info[i].direction_graphic[act][dir];
578 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
579 element_info[i].direction_graphic[act][dir] = -1;
581 graphic = element_info[i].direction_crumbled[act][dir];
582 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
583 element_info[i].direction_crumbled[act][dir] = -1;
589 /* now set all '-1' values to element specific default values */
590 for (i=0; i<MAX_NUM_ELEMENTS; i++)
592 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
593 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
594 int default_direction_graphic[NUM_DIRECTIONS];
595 int default_direction_crumbled[NUM_DIRECTIONS];
597 if (default_graphic == -1)
598 default_graphic = IMG_CHAR_QUESTION;
599 if (default_crumbled == -1)
600 default_crumbled = IMG_EMPTY;
602 for (dir=0; dir<NUM_DIRECTIONS; dir++)
604 default_direction_graphic[dir] =
605 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
606 default_direction_crumbled[dir] =
607 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
609 if (default_direction_graphic[dir] == -1)
610 default_direction_graphic[dir] = default_graphic;
611 if (default_direction_crumbled[dir] == -1)
612 default_direction_crumbled[dir] = default_crumbled;
615 for (act=0; act<NUM_ACTIONS; act++)
617 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
618 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
619 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
620 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
621 act == ACTION_TURNING_FROM_RIGHT ||
622 act == ACTION_TURNING_FROM_UP ||
623 act == ACTION_TURNING_FROM_DOWN);
625 /* generic default action graphic (defined by "[default]" directive) */
626 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
627 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
629 /* look for special default action graphic (classic game specific) */
630 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
631 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
632 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
633 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
634 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
635 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
637 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
638 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
639 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
640 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
641 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
642 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
644 if (default_action_graphic == -1)
645 default_action_graphic = default_graphic;
646 if (default_action_crumbled == -1)
647 default_action_crumbled = default_crumbled;
649 for (dir=0; dir<NUM_DIRECTIONS; dir++)
651 int default_action_direction_graphic = element_info[i].graphic[act];
652 int default_action_direction_crumbled = element_info[i].crumbled[act];
654 /* no graphic for current action -- use default direction graphic */
655 if (default_action_direction_graphic == -1)
656 default_action_direction_graphic =
657 (act_remove ? IMG_EMPTY :
659 element_info[i].direction_graphic[ACTION_TURNING][dir] :
660 default_direction_graphic[dir]);
661 if (default_action_direction_crumbled == -1)
662 default_action_direction_crumbled =
663 (act_remove ? IMG_EMPTY :
665 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
666 default_direction_crumbled[dir]);
668 if (element_info[i].direction_graphic[act][dir] == -1)
669 element_info[i].direction_graphic[act][dir] =
670 default_action_direction_graphic;
671 if (element_info[i].direction_crumbled[act][dir] == -1)
672 element_info[i].direction_crumbled[act][dir] =
673 default_action_direction_crumbled;
676 /* no graphic for this specific action -- use default action graphic */
677 if (element_info[i].graphic[act] == -1)
678 element_info[i].graphic[act] =
679 (act_remove ? IMG_EMPTY :
680 act_turning ? element_info[i].graphic[ACTION_TURNING] :
681 default_action_graphic);
682 if (element_info[i].crumbled[act] == -1)
683 element_info[i].crumbled[act] =
684 (act_remove ? IMG_EMPTY :
685 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
686 default_action_crumbled);
691 /* set animation mode to "none" for each graphic with only 1 frame */
692 for (i=0; i<MAX_NUM_ELEMENTS; i++)
694 for (act=0; act<NUM_ACTIONS; act++)
696 int graphic = element_info[i].graphic[act];
697 int crumbled = element_info[i].crumbled[act];
699 if (graphic_info[graphic].anim_frames == 1)
700 graphic_info[graphic].anim_mode = ANIM_NONE;
701 if (graphic_info[crumbled].anim_frames == 1)
702 graphic_info[crumbled].anim_mode = ANIM_NONE;
704 for (dir=0; dir<NUM_DIRECTIONS; dir++)
706 graphic = element_info[i].direction_graphic[act][dir];
707 crumbled = element_info[i].direction_crumbled[act][dir];
709 if (graphic_info[graphic].anim_frames == 1)
710 graphic_info[graphic].anim_mode = ANIM_NONE;
711 if (graphic_info[crumbled].anim_frames == 1)
712 graphic_info[crumbled].anim_mode = ANIM_NONE;
722 for (i=0; i<MAX_NUM_ELEMENTS; i++)
723 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
724 i != EL_CHAR_QUESTION)
725 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
726 element_info[i].token_name, i);
732 void InitElementSpecialGraphicInfo()
734 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
735 int num_property_mappings = getImageListPropertyMappingSize();
738 /* always start with reliable default values */
739 for (i=0; i < MAX_NUM_ELEMENTS; i++)
740 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
741 element_info[i].special_graphic[j] =
742 element_info[i].graphic[ACTION_DEFAULT];
744 /* initialize special element/graphic mapping from static configuration */
745 for (i=0; element_to_special_graphic[i].element > -1; i++)
747 int element = element_to_special_graphic[i].element;
748 int special = element_to_special_graphic[i].special;
749 int graphic = element_to_special_graphic[i].graphic;
750 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
751 boolean special_redefined = getImageListEntry(graphic)->redefined;
753 /* if the base graphic ("emerald", for example) has been redefined,
754 but not the special graphic ("emerald.EDITOR", for example), do not
755 use an existing (in this case considered obsolete) special graphic
756 anymore, but use the automatically created (down-scaled) graphic */
757 if (base_redefined && !special_redefined)
760 element_info[element].special_graphic[special] = graphic;
763 /* initialize special element/graphic mapping from dynamic configuration */
764 for (i=0; i < num_property_mappings; i++)
766 int element = property_mapping[i].base_index;
767 int special = property_mapping[i].ext3_index;
768 int graphic = property_mapping[i].artwork_index;
770 if (element >= MAX_NUM_ELEMENTS)
773 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
774 element_info[element].special_graphic[special] = graphic;
778 /* now set all undefined/invalid graphics to default */
779 for (i=0; i < MAX_NUM_ELEMENTS; i++)
780 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
781 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
782 element_info[i].special_graphic[j] =
783 element_info[i].graphic[ACTION_DEFAULT];
787 static int get_element_from_token(char *token)
791 for (i=0; i < MAX_NUM_ELEMENTS; i++)
792 if (strcmp(element_info[i].token_name, token) == 0)
798 static void set_graphic_parameters(int graphic, char **parameter_raw)
800 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
801 int parameter[NUM_GFX_ARGS];
802 int anim_frames_per_row = 1, anim_frames_per_col = 1;
803 int anim_frames_per_line = 1;
806 /* get integer values from string parameters */
807 for (i=0; i < NUM_GFX_ARGS; i++)
810 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
811 image_config_suffix[i].type);
813 if (image_config_suffix[i].type == TYPE_TOKEN)
814 parameter[i] = get_element_from_token(parameter_raw[i]);
817 graphic_info[graphic].bitmap = src_bitmap;
819 /* start with reliable default values */
820 graphic_info[graphic].src_x = 0;
821 graphic_info[graphic].src_y = 0;
822 graphic_info[graphic].width = TILEX;
823 graphic_info[graphic].height = TILEY;
824 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
825 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
826 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
827 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
828 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
830 /* optional x and y tile position of animation frame sequence */
831 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
832 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
833 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
834 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
836 /* optional x and y pixel position of animation frame sequence */
837 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
838 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
839 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
840 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
842 /* optional width and height of each animation frame */
843 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
844 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
845 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
846 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
850 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
851 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
854 /* correct x or y offset dependent of vertical or horizontal frame order */
855 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
857 graphic_info[graphic].offset_y =
858 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
859 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
860 anim_frames_per_line = anim_frames_per_col;
862 else /* frames are ordered horizontally */
864 graphic_info[graphic].offset_x =
865 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
866 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
867 anim_frames_per_line = anim_frames_per_row;
870 /* optionally, the x and y offset of frames can be specified directly */
871 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
872 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
873 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
874 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
876 /* automatically determine correct number of frames, if not defined */
877 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
878 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
879 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
880 graphic_info[graphic].anim_frames = anim_frames_per_row;
881 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
882 graphic_info[graphic].anim_frames = anim_frames_per_col;
884 graphic_info[graphic].anim_frames = 1;
886 graphic_info[graphic].anim_frames_per_line =
887 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
888 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
890 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
891 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
892 graphic_info[graphic].anim_delay = 1;
894 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
896 if (graphic_info[graphic].anim_frames == 1)
897 graphic_info[graphic].anim_mode = ANIM_NONE;
900 /* automatically determine correct start frame, if not defined */
901 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
902 graphic_info[graphic].anim_start_frame = 0;
903 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
904 graphic_info[graphic].anim_start_frame =
905 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
907 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
909 /* animation synchronized with global frame counter, not move position */
910 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
912 /* optional element for cloning crumble graphics */
913 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
914 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
916 /* optional element for cloning digging graphics */
917 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
918 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
920 /* optional border size for "crumbling" diggable graphics */
921 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
922 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
924 /* this is only used for toon animations */
925 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
926 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
928 /* this is only used for drawing font characters */
929 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
930 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
932 /* this is only used for drawing envelope graphics */
933 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
936 static void InitGraphicInfo()
938 int fallback_graphic = IMG_CHAR_EXCLAM;
939 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
940 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
941 int num_images = getImageListSize();
944 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
945 static boolean clipmasks_initialized = FALSE;
947 XGCValues clip_gc_values;
948 unsigned long clip_gc_valuemask;
949 GC copy_clipmask_gc = None;
952 if (graphic_info != NULL)
955 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
958 printf("::: graphic_info: %d entries\n", num_images);
961 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
962 if (clipmasks_initialized)
964 for (i=0; i<num_images; i++)
966 if (graphic_info[i].clip_mask)
967 XFreePixmap(display, graphic_info[i].clip_mask);
968 if (graphic_info[i].clip_gc)
969 XFreeGC(display, graphic_info[i].clip_gc);
971 graphic_info[i].clip_mask = None;
972 graphic_info[i].clip_gc = None;
977 for (i=0; i<num_images; i++)
979 struct FileInfo *image = getImageListEntry(i);
982 int first_frame, last_frame;
985 printf("::: image: '%s' [%d]\n", image->token, i);
989 printf("::: image # %d: '%s' ['%s']\n",
991 getTokenFromImageID(i));
994 set_graphic_parameters(i, image->parameter);
996 /* now check if no animation frames are outside of the loaded image */
998 if (graphic_info[i].bitmap == NULL)
999 continue; /* skip check for optional images that are undefined */
1002 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1003 if (src_x < 0 || src_y < 0 ||
1004 src_x + TILEX > src_bitmap->width ||
1005 src_y + TILEY > src_bitmap->height)
1007 Error(ERR_RETURN_LINE, "-");
1008 Error(ERR_RETURN, "warning: error found in config file:");
1009 Error(ERR_RETURN, "- config file: '%s'",
1010 getImageConfigFilename());
1011 Error(ERR_RETURN, "- config token: '%s'",
1012 getTokenFromImageID(i));
1013 Error(ERR_RETURN, "- image file: '%s'",
1014 src_bitmap->source_filename);
1016 "error: first animation frame out of bounds (%d, %d)",
1018 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1020 if (i == fallback_graphic)
1021 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1023 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1024 Error(ERR_RETURN_LINE, "-");
1026 set_graphic_parameters(i, fallback_image->default_parameter);
1027 graphic_info[i].bitmap = fallback_bitmap;
1030 last_frame = graphic_info[i].anim_frames - 1;
1031 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1032 if (src_x < 0 || src_y < 0 ||
1033 src_x + TILEX > src_bitmap->width ||
1034 src_y + TILEY > src_bitmap->height)
1036 Error(ERR_RETURN_LINE, "-");
1037 Error(ERR_RETURN, "warning: error found in config file:");
1038 Error(ERR_RETURN, "- config file: '%s'",
1039 getImageConfigFilename());
1040 Error(ERR_RETURN, "- config token: '%s'",
1041 getTokenFromImageID(i));
1042 Error(ERR_RETURN, "- image file: '%s'",
1043 src_bitmap->source_filename);
1045 "error: last animation frame (%d) out of bounds (%d, %d)",
1046 last_frame, src_x, src_y);
1047 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1049 if (i == fallback_graphic)
1050 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1052 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1053 Error(ERR_RETURN_LINE, "-");
1055 set_graphic_parameters(i, fallback_image->default_parameter);
1056 graphic_info[i].bitmap = fallback_bitmap;
1059 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1060 /* currently we need only a tile clip mask from the first frame */
1061 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1063 if (copy_clipmask_gc == None)
1065 clip_gc_values.graphics_exposures = False;
1066 clip_gc_valuemask = GCGraphicsExposures;
1067 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1068 clip_gc_valuemask, &clip_gc_values);
1071 graphic_info[i].clip_mask =
1072 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1074 src_pixmap = src_bitmap->clip_mask;
1075 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1076 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1078 clip_gc_values.graphics_exposures = False;
1079 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1080 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1082 graphic_info[i].clip_gc =
1083 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1087 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1088 if (copy_clipmask_gc)
1089 XFreeGC(display, copy_clipmask_gc);
1091 clipmasks_initialized = TRUE;
1095 static void InitElementSoundInfo()
1097 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1098 int num_property_mappings = getSoundListPropertyMappingSize();
1101 /* set values to -1 to identify later as "uninitialized" values */
1102 for (i=0; i < MAX_NUM_ELEMENTS; i++)
1103 for (act=0; act < NUM_ACTIONS; act++)
1104 element_info[i].sound[act] = -1;
1106 /* initialize element/sound mapping from static configuration */
1107 for (i=0; element_to_sound[i].element > -1; i++)
1109 int element = element_to_sound[i].element;
1110 int action = element_to_sound[i].action;
1111 int sound = element_to_sound[i].sound;
1112 boolean is_class = element_to_sound[i].is_class;
1115 action = ACTION_DEFAULT;
1118 element_info[element].sound[action] = sound;
1120 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1121 if (strcmp(element_info[j].class_name,
1122 element_info[element].class_name) == 0)
1123 element_info[j].sound[action] = sound;
1126 /* initialize element class/sound mapping from dynamic configuration */
1127 for (i=0; i < num_property_mappings; i++)
1129 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1130 int action = property_mapping[i].ext1_index;
1131 int sound = property_mapping[i].artwork_index;
1133 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1137 action = ACTION_DEFAULT;
1139 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1140 if (strcmp(element_info[j].class_name,
1141 element_info[element_class].class_name) == 0)
1142 element_info[j].sound[action] = sound;
1145 /* initialize element/sound mapping from dynamic configuration */
1146 for (i=0; i < num_property_mappings; i++)
1148 int element = property_mapping[i].base_index;
1149 int action = property_mapping[i].ext1_index;
1150 int sound = property_mapping[i].artwork_index;
1152 if (element >= MAX_NUM_ELEMENTS)
1156 action = ACTION_DEFAULT;
1158 element_info[element].sound[action] = sound;
1161 /* now set all '-1' values to element specific default values */
1162 for (i=0; i<MAX_NUM_ELEMENTS; i++)
1164 for (act=0; act < NUM_ACTIONS; act++)
1166 /* generic default action sound (defined by "[default]" directive) */
1167 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1169 /* look for special default action sound (classic game specific) */
1170 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1171 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1172 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1173 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1174 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1175 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1177 /* look for element specific default sound (independent from action) */
1178 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1179 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1181 /* no sound for this specific action -- use default action sound */
1182 if (element_info[i].sound[act] == -1)
1183 element_info[i].sound[act] = default_action_sound;
1188 static void InitGameModeSoundInfo()
1192 /* set values to -1 to identify later as "uninitialized" values */
1193 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1196 /* initialize gamemode/sound mapping from static configuration */
1197 for (i=0; gamemode_to_sound[i].sound > -1; i++)
1199 int gamemode = gamemode_to_sound[i].gamemode;
1200 int sound = gamemode_to_sound[i].sound;
1203 gamemode = GAME_MODE_DEFAULT;
1205 menu.sound[gamemode] = sound;
1208 /* now set all '-1' values to levelset specific default values */
1209 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1210 if (menu.sound[i] == -1)
1211 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1215 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1216 if (menu.sound[i] != -1)
1217 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1221 static void set_sound_parameters(int sound, char **parameter_raw)
1223 int parameter[NUM_SND_ARGS];
1226 /* get integer values from string parameters */
1227 for (i=0; i < NUM_SND_ARGS; i++)
1229 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1230 sound_config_suffix[i].type);
1232 /* explicit loop mode setting in configuration overrides default value */
1233 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1234 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1237 static void InitSoundInfo()
1240 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1241 int num_property_mappings = getSoundListPropertyMappingSize();
1243 int *sound_effect_properties;
1244 int num_sounds = getSoundListSize();
1247 if (sound_info != NULL)
1250 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1251 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1253 /* initialize sound effect for all elements to "no sound" */
1254 for (i=0; i < MAX_NUM_ELEMENTS; i++)
1255 for (j=0; j < NUM_ACTIONS; j++)
1256 element_info[i].sound[j] = SND_UNDEFINED;
1258 for (i=0; i < num_sounds; i++)
1260 struct FileInfo *sound = getSoundListEntry(i);
1261 int len_effect_text = strlen(sound->token);
1263 sound_effect_properties[i] = ACTION_OTHER;
1264 sound_info[i].loop = FALSE; /* default: play sound only once */
1267 printf("::: sound %d: '%s'\n", i, sound->token);
1270 /* determine all loop sounds and identify certain sound classes */
1272 for (j=0; element_action_info[j].suffix; j++)
1274 int len_action_text = strlen(element_action_info[j].suffix);
1276 if (len_action_text < len_effect_text &&
1277 strcmp(&sound->token[len_effect_text - len_action_text],
1278 element_action_info[j].suffix) == 0)
1280 sound_effect_properties[i] = element_action_info[j].value;
1281 sound_info[i].loop = element_action_info[j].is_loop_sound;
1288 if (strcmp(sound->token, "custom_42") == 0)
1289 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1292 /* associate elements and some selected sound actions */
1294 for (j=0; j < MAX_NUM_ELEMENTS; j++)
1296 if (element_info[j].class_name)
1298 int len_class_text = strlen(element_info[j].class_name);
1300 if (len_class_text + 1 < len_effect_text &&
1301 strncmp(sound->token,
1302 element_info[j].class_name, len_class_text) == 0 &&
1303 sound->token[len_class_text] == '.')
1305 int sound_action_value = sound_effect_properties[i];
1307 element_info[j].sound[sound_action_value] = i;
1312 set_sound_parameters(i, sound->parameter);
1315 free(sound_effect_properties);
1318 /* !!! now handled in InitElementSoundInfo() !!! */
1319 /* initialize element/sound mapping from dynamic configuration */
1320 for (i=0; i < num_property_mappings; i++)
1322 int element = property_mapping[i].base_index;
1323 int action = property_mapping[i].ext1_index;
1324 int sound = property_mapping[i].artwork_index;
1327 action = ACTION_DEFAULT;
1329 printf("::: %d: %d, %d, %d ['%s']\n",
1330 i, element, action, sound, element_info[element].token_name);
1332 element_info[element].sound[action] = sound;
1339 int element = EL_CUSTOM_11;
1342 while (element_action_info[j].suffix)
1344 printf("element %d, sound action '%s' == %d\n",
1345 element, element_action_info[j].suffix,
1346 element_info[element].sound[j]);
1351 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1357 int element = EL_SAND;
1358 int sound_action = ACTION_DIGGING;
1361 while (element_action_info[j].suffix)
1363 if (element_action_info[j].value == sound_action)
1364 printf("element %d, sound action '%s' == %d\n",
1365 element, element_action_info[j].suffix,
1366 element_info[element].sound[sound_action]);
1373 static void InitGameModeMusicInfo()
1375 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1376 int num_property_mappings = getMusicListPropertyMappingSize();
1377 int default_levelset_music = -1;
1380 /* set values to -1 to identify later as "uninitialized" values */
1381 for (i=0; i < MAX_LEVELS; i++)
1382 levelset.music[i] = -1;
1383 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1386 /* initialize gamemode/music mapping from static configuration */
1387 for (i=0; gamemode_to_music[i].music > -1; i++)
1389 int gamemode = gamemode_to_music[i].gamemode;
1390 int music = gamemode_to_music[i].music;
1393 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1397 gamemode = GAME_MODE_DEFAULT;
1399 menu.music[gamemode] = music;
1402 /* initialize gamemode/music mapping from dynamic configuration */
1403 for (i=0; i < num_property_mappings; i++)
1405 int prefix = property_mapping[i].base_index;
1406 int gamemode = property_mapping[i].ext1_index;
1407 int level = property_mapping[i].ext2_index;
1408 int music = property_mapping[i].artwork_index;
1411 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1412 prefix, gamemode, level, music);
1415 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1419 gamemode = GAME_MODE_DEFAULT;
1421 /* level specific music only allowed for in-game music */
1422 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1423 gamemode = GAME_MODE_PLAYING;
1428 default_levelset_music = music;
1431 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1432 levelset.music[level] = music;
1433 if (gamemode != GAME_MODE_PLAYING)
1434 menu.music[gamemode] = music;
1437 /* now set all '-1' values to menu specific default values */
1438 /* (undefined values of "levelset.music[]" might stay at "-1" to
1439 allow dynamic selection of music files from music directory!) */
1440 for (i=0; i < MAX_LEVELS; i++)
1441 if (levelset.music[i] == -1)
1442 levelset.music[i] = default_levelset_music;
1443 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1444 if (menu.music[i] == -1)
1445 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1449 for (i=0; i < MAX_LEVELS; i++)
1450 if (levelset.music[i] != -1)
1451 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1452 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
1453 if (menu.music[i] != -1)
1454 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1458 static void set_music_parameters(int music, char **parameter_raw)
1460 int parameter[NUM_MUS_ARGS];
1463 /* get integer values from string parameters */
1464 for (i=0; i < NUM_MUS_ARGS; i++)
1466 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1467 music_config_suffix[i].type);
1469 /* explicit loop mode setting in configuration overrides default value */
1470 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1471 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1474 static void InitMusicInfo()
1476 int num_music = getMusicListSize();
1479 if (music_info != NULL)
1482 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1484 for (i=0; i < num_music; i++)
1486 struct FileInfo *music = getMusicListEntry(i);
1487 int len_music_text = strlen(music->token);
1489 music_info[i].loop = TRUE; /* default: play music in loop mode */
1491 /* determine all loop music */
1493 for (j=0; music_prefix_info[j].prefix; j++)
1495 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1497 if (len_prefix_text < len_music_text &&
1498 strncmp(music->token,
1499 music_prefix_info[j].prefix, len_prefix_text) == 0)
1501 music_info[i].loop = music_prefix_info[j].is_loop_music;
1507 set_music_parameters(i, music->parameter);
1511 static void ReinitializeGraphics()
1513 InitGraphicInfo(); /* graphic properties mapping */
1514 InitElementGraphicInfo(); /* element game graphic mapping */
1515 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1517 InitElementSmallImages(); /* create editor and preview images */
1518 InitFontGraphicInfo(); /* initialize text drawing functions */
1520 SetMainBackgroundImage(IMG_BACKGROUND);
1521 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1527 static void ReinitializeSounds()
1529 InitSoundInfo(); /* sound properties mapping */
1530 InitElementSoundInfo(); /* element game sound mapping */
1531 InitGameModeSoundInfo(); /* game mode sound mapping */
1533 InitPlayLevelSound(); /* internal game sound settings */
1536 static void ReinitializeMusic()
1538 InitMusicInfo(); /* music properties mapping */
1539 InitGameModeMusicInfo(); /* game mode music mapping */
1542 void InitElementPropertiesStatic()
1544 static int ep_diggable[] =
1549 EL_SP_BUGGY_BASE_ACTIVATING,
1552 EL_INVISIBLE_SAND_ACTIVE,
1554 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1558 EL_SP_BUGGY_BASE_ACTIVE,
1563 static int ep_collectible_only[] =
1580 EL_DYNABOMB_INCREASE_NUMBER,
1581 EL_DYNABOMB_INCREASE_SIZE,
1582 EL_DYNABOMB_INCREASE_POWER,
1599 static int ep_dont_run_into[] =
1601 /* same elements as in 'ep_dont_touch' */
1607 /* same elements as in 'ep_dont_collide_with' */
1619 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1623 EL_SP_BUGGY_BASE_ACTIVE,
1628 static int ep_dont_collide_with[] =
1630 /* same elements as in 'ep_dont_touch' */
1646 static int ep_dont_touch[] =
1655 static int ep_indestructible[] =
1659 EL_ACID_POOL_TOPLEFT,
1660 EL_ACID_POOL_TOPRIGHT,
1661 EL_ACID_POOL_BOTTOMLEFT,
1662 EL_ACID_POOL_BOTTOM,
1663 EL_ACID_POOL_BOTTOMRIGHT,
1664 EL_SP_HARDWARE_GRAY,
1665 EL_SP_HARDWARE_GREEN,
1666 EL_SP_HARDWARE_BLUE,
1668 EL_SP_HARDWARE_YELLOW,
1669 EL_SP_HARDWARE_BASE_1,
1670 EL_SP_HARDWARE_BASE_2,
1671 EL_SP_HARDWARE_BASE_3,
1672 EL_SP_HARDWARE_BASE_4,
1673 EL_SP_HARDWARE_BASE_5,
1674 EL_SP_HARDWARE_BASE_6,
1675 EL_INVISIBLE_STEELWALL,
1676 EL_INVISIBLE_STEELWALL_ACTIVE,
1677 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1678 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1679 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1680 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1681 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1682 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1683 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1684 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1685 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1686 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1687 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1688 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1690 EL_LIGHT_SWITCH_ACTIVE,
1691 EL_SIGN_EXCLAMATION,
1692 EL_SIGN_RADIOACTIVITY,
1703 EL_STEELWALL_SLIPPERY,
1726 EL_SWITCHGATE_OPENING,
1727 EL_SWITCHGATE_CLOSED,
1728 EL_SWITCHGATE_CLOSING,
1730 EL_SWITCHGATE_SWITCH_UP,
1731 EL_SWITCHGATE_SWITCH_DOWN,
1734 EL_TIMEGATE_OPENING,
1736 EL_TIMEGATE_CLOSING,
1739 EL_TIMEGATE_SWITCH_ACTIVE,
1744 EL_TUBE_VERTICAL_LEFT,
1745 EL_TUBE_VERTICAL_RIGHT,
1746 EL_TUBE_HORIZONTAL_UP,
1747 EL_TUBE_HORIZONTAL_DOWN,
1755 static int ep_slippery[] =
1769 EL_ROBOT_WHEEL_ACTIVE,
1775 EL_ACID_POOL_TOPLEFT,
1776 EL_ACID_POOL_TOPRIGHT,
1786 EL_STEELWALL_SLIPPERY,
1792 static int ep_can_change[] =
1797 static int ep_can_move[] =
1819 static int ep_can_fall[] =
1834 EL_BD_MAGIC_WALL_FULL,
1847 static int ep_can_smash_player[] =
1872 static int ep_can_smash_enemies[] =
1880 static int ep_can_smash_everything[] =
1888 static int ep_can_explode_by_fire[] =
1890 /* same elements as in 'ep_can_explode_impact' */
1895 /* same elements as in 'ep_can_explode_smashed' */
1904 EL_DYNABOMB_PLAYER_1_ACTIVE,
1905 EL_DYNABOMB_PLAYER_2_ACTIVE,
1906 EL_DYNABOMB_PLAYER_3_ACTIVE,
1907 EL_DYNABOMB_PLAYER_4_ACTIVE,
1908 EL_DYNABOMB_INCREASE_NUMBER,
1909 EL_DYNABOMB_INCREASE_SIZE,
1910 EL_DYNABOMB_INCREASE_POWER,
1911 EL_SP_DISK_RED_ACTIVE,
1921 static int ep_can_explode_smashed[] =
1923 /* same elements as in 'ep_can_explode_impact' */
1936 static int ep_can_explode_impact[] =
1944 static int ep_walkable_over[] =
1948 EL_SOKOBAN_FIELD_EMPTY,
1966 static int ep_walkable_inside[] =
1971 EL_TUBE_VERTICAL_LEFT,
1972 EL_TUBE_VERTICAL_RIGHT,
1973 EL_TUBE_HORIZONTAL_UP,
1974 EL_TUBE_HORIZONTAL_DOWN,
1982 static int ep_walkable_under[] =
1987 static int ep_passable_over[] =
2002 static int ep_passable_inside[] =
2008 EL_SP_PORT_HORIZONTAL,
2009 EL_SP_PORT_VERTICAL,
2011 EL_SP_GRAVITY_PORT_LEFT,
2012 EL_SP_GRAVITY_PORT_RIGHT,
2013 EL_SP_GRAVITY_PORT_UP,
2014 EL_SP_GRAVITY_PORT_DOWN,
2018 static int ep_passable_under[] =
2023 static int ep_droppable[] =
2028 static int ep_can_explode_1x1[] =
2033 static int ep_pushable[] =
2045 EL_SOKOBAN_FIELD_FULL,
2052 static int ep_player[] =
2062 static int ep_can_pass_magic_wall[] =
2075 static int ep_switchable[] =
2079 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2080 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2081 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2082 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2083 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2084 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2085 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2086 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2087 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2088 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2089 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2090 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2091 EL_SWITCHGATE_SWITCH_UP,
2092 EL_SWITCHGATE_SWITCH_DOWN,
2094 EL_LIGHT_SWITCH_ACTIVE,
2096 EL_BALLOON_SWITCH_LEFT,
2097 EL_BALLOON_SWITCH_RIGHT,
2098 EL_BALLOON_SWITCH_UP,
2099 EL_BALLOON_SWITCH_DOWN,
2100 EL_BALLOON_SWITCH_ANY,
2106 static int ep_bd_element[] =
2135 static int ep_sp_element[] =
2137 /* should always be valid */
2146 EL_SP_HARDWARE_GRAY,
2154 EL_SP_GRAVITY_PORT_RIGHT,
2155 EL_SP_GRAVITY_PORT_DOWN,
2156 EL_SP_GRAVITY_PORT_LEFT,
2157 EL_SP_GRAVITY_PORT_UP,
2162 EL_SP_PORT_VERTICAL,
2163 EL_SP_PORT_HORIZONTAL,
2169 EL_SP_HARDWARE_BASE_1,
2170 EL_SP_HARDWARE_GREEN,
2171 EL_SP_HARDWARE_BLUE,
2173 EL_SP_HARDWARE_YELLOW,
2174 EL_SP_HARDWARE_BASE_2,
2175 EL_SP_HARDWARE_BASE_3,
2176 EL_SP_HARDWARE_BASE_4,
2177 EL_SP_HARDWARE_BASE_5,
2178 EL_SP_HARDWARE_BASE_6,
2181 /* additional elements that appeared in newer Supaplex levels */
2183 /* more than one murphy in a level results in an inactive clone */
2185 /* runtime elements*/
2186 EL_SP_DISK_RED_ACTIVE,
2187 EL_SP_TERMINAL_ACTIVE,
2188 EL_SP_BUGGY_BASE_ACTIVATING,
2189 EL_SP_BUGGY_BASE_ACTIVE,
2195 static int ep_sb_element[] =
2200 EL_SOKOBAN_FIELD_EMPTY,
2201 EL_SOKOBAN_FIELD_FULL,
2203 EL_INVISIBLE_STEELWALL,
2207 static int ep_gem[] =
2218 static int ep_food_dark_yamyam[] =
2245 static int ep_food_penguin[] =
2258 static int ep_food_pig[] =
2269 static int ep_historic_wall[] =
2294 EL_EXPANDABLE_WALL_HORIZONTAL,
2295 EL_EXPANDABLE_WALL_VERTICAL,
2296 EL_EXPANDABLE_WALL_ANY,
2297 EL_EXPANDABLE_WALL_GROWING,
2304 EL_SP_HARDWARE_GRAY,
2305 EL_SP_HARDWARE_GREEN,
2306 EL_SP_HARDWARE_BLUE,
2308 EL_SP_HARDWARE_YELLOW,
2309 EL_SP_HARDWARE_BASE_1,
2310 EL_SP_HARDWARE_BASE_2,
2311 EL_SP_HARDWARE_BASE_3,
2312 EL_SP_HARDWARE_BASE_4,
2313 EL_SP_HARDWARE_BASE_5,
2314 EL_SP_HARDWARE_BASE_6,
2316 EL_SP_TERMINAL_ACTIVE,
2319 EL_INVISIBLE_STEELWALL,
2320 EL_INVISIBLE_STEELWALL_ACTIVE,
2322 EL_INVISIBLE_WALL_ACTIVE,
2323 EL_STEELWALL_SLIPPERY,
2339 static int ep_historic_solid[] =
2343 EL_EXPANDABLE_WALL_HORIZONTAL,
2344 EL_EXPANDABLE_WALL_VERTICAL,
2345 EL_EXPANDABLE_WALL_ANY,
2358 EL_QUICKSAND_FILLING,
2359 EL_QUICKSAND_EMPTYING,
2361 EL_MAGIC_WALL_ACTIVE,
2362 EL_MAGIC_WALL_EMPTYING,
2363 EL_MAGIC_WALL_FILLING,
2367 EL_BD_MAGIC_WALL_ACTIVE,
2368 EL_BD_MAGIC_WALL_EMPTYING,
2369 EL_BD_MAGIC_WALL_FULL,
2370 EL_BD_MAGIC_WALL_FILLING,
2371 EL_BD_MAGIC_WALL_DEAD,
2380 EL_SP_TERMINAL_ACTIVE,
2384 EL_INVISIBLE_WALL_ACTIVE,
2385 EL_SWITCHGATE_SWITCH_UP,
2386 EL_SWITCHGATE_SWITCH_DOWN,
2388 EL_TIMEGATE_SWITCH_ACTIVE,
2400 /* the following elements are a direct copy of "indestructible" elements,
2401 except "EL_ACID", which is "indestructible", but not "solid"! */
2406 EL_ACID_POOL_TOPLEFT,
2407 EL_ACID_POOL_TOPRIGHT,
2408 EL_ACID_POOL_BOTTOMLEFT,
2409 EL_ACID_POOL_BOTTOM,
2410 EL_ACID_POOL_BOTTOMRIGHT,
2411 EL_SP_HARDWARE_GRAY,
2412 EL_SP_HARDWARE_GREEN,
2413 EL_SP_HARDWARE_BLUE,
2415 EL_SP_HARDWARE_YELLOW,
2416 EL_SP_HARDWARE_BASE_1,
2417 EL_SP_HARDWARE_BASE_2,
2418 EL_SP_HARDWARE_BASE_3,
2419 EL_SP_HARDWARE_BASE_4,
2420 EL_SP_HARDWARE_BASE_5,
2421 EL_SP_HARDWARE_BASE_6,
2422 EL_INVISIBLE_STEELWALL,
2423 EL_INVISIBLE_STEELWALL_ACTIVE,
2424 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2425 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2426 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2427 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2428 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2429 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2430 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2431 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2432 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2433 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2434 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2435 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2437 EL_LIGHT_SWITCH_ACTIVE,
2438 EL_SIGN_EXCLAMATION,
2439 EL_SIGN_RADIOACTIVITY,
2450 EL_STEELWALL_SLIPPERY,
2473 EL_SWITCHGATE_OPENING,
2474 EL_SWITCHGATE_CLOSED,
2475 EL_SWITCHGATE_CLOSING,
2477 EL_TIMEGATE_OPENING,
2479 EL_TIMEGATE_CLOSING,
2483 EL_TUBE_VERTICAL_LEFT,
2484 EL_TUBE_VERTICAL_RIGHT,
2485 EL_TUBE_HORIZONTAL_UP,
2486 EL_TUBE_HORIZONTAL_DOWN,
2494 static int ep_classic_enemy[] =
2510 static int ep_belt[] =
2512 EL_CONVEYOR_BELT_1_LEFT,
2513 EL_CONVEYOR_BELT_1_MIDDLE,
2514 EL_CONVEYOR_BELT_1_RIGHT,
2515 EL_CONVEYOR_BELT_2_LEFT,
2516 EL_CONVEYOR_BELT_2_MIDDLE,
2517 EL_CONVEYOR_BELT_2_RIGHT,
2518 EL_CONVEYOR_BELT_3_LEFT,
2519 EL_CONVEYOR_BELT_3_MIDDLE,
2520 EL_CONVEYOR_BELT_3_RIGHT,
2521 EL_CONVEYOR_BELT_4_LEFT,
2522 EL_CONVEYOR_BELT_4_MIDDLE,
2523 EL_CONVEYOR_BELT_4_RIGHT,
2527 static int ep_belt_active[] =
2529 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2530 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2531 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2532 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2533 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2534 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2535 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2536 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2537 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2538 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2539 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2540 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2544 static int ep_belt_switch[] =
2546 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2547 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2548 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2549 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2550 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2551 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2552 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2553 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2554 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2555 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2556 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2557 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2561 static int ep_tube[] =
2568 EL_TUBE_HORIZONTAL_UP,
2569 EL_TUBE_HORIZONTAL_DOWN,
2571 EL_TUBE_VERTICAL_LEFT,
2572 EL_TUBE_VERTICAL_RIGHT,
2577 static int ep_keygate[] =
2598 static int ep_amoeboid[] =
2608 static int ep_amoebalive[] =
2617 static int ep_has_content[] =
2627 static int ep_active_bomb[] =
2630 EL_DYNABOMB_PLAYER_1_ACTIVE,
2631 EL_DYNABOMB_PLAYER_2_ACTIVE,
2632 EL_DYNABOMB_PLAYER_3_ACTIVE,
2633 EL_DYNABOMB_PLAYER_4_ACTIVE,
2634 EL_SP_DISK_RED_ACTIVE,
2638 static int ep_inactive[] =
2675 EL_INVISIBLE_STEELWALL,
2683 EL_WALL_EMERALD_YELLOW,
2684 EL_DYNABOMB_INCREASE_NUMBER,
2685 EL_DYNABOMB_INCREASE_SIZE,
2686 EL_DYNABOMB_INCREASE_POWER,
2690 EL_SOKOBAN_FIELD_EMPTY,
2691 EL_SOKOBAN_FIELD_FULL,
2692 EL_WALL_EMERALD_RED,
2693 EL_WALL_EMERALD_PURPLE,
2694 EL_ACID_POOL_TOPLEFT,
2695 EL_ACID_POOL_TOPRIGHT,
2696 EL_ACID_POOL_BOTTOMLEFT,
2697 EL_ACID_POOL_BOTTOM,
2698 EL_ACID_POOL_BOTTOMRIGHT,
2702 EL_BD_MAGIC_WALL_DEAD,
2703 EL_AMOEBA_TO_DIAMOND,
2711 EL_SP_GRAVITY_PORT_RIGHT,
2712 EL_SP_GRAVITY_PORT_DOWN,
2713 EL_SP_GRAVITY_PORT_LEFT,
2714 EL_SP_GRAVITY_PORT_UP,
2715 EL_SP_PORT_HORIZONTAL,
2716 EL_SP_PORT_VERTICAL,
2727 EL_SP_HARDWARE_GRAY,
2728 EL_SP_HARDWARE_GREEN,
2729 EL_SP_HARDWARE_BLUE,
2731 EL_SP_HARDWARE_YELLOW,
2732 EL_SP_HARDWARE_BASE_1,
2733 EL_SP_HARDWARE_BASE_2,
2734 EL_SP_HARDWARE_BASE_3,
2735 EL_SP_HARDWARE_BASE_4,
2736 EL_SP_HARDWARE_BASE_5,
2737 EL_SP_HARDWARE_BASE_6,
2738 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2739 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2740 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2741 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2742 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2743 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2744 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2745 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2746 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2747 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2748 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2749 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2750 EL_SIGN_EXCLAMATION,
2751 EL_SIGN_RADIOACTIVITY,
2762 EL_STEELWALL_SLIPPERY,
2778 static int ep_em_slippery_wall[] =
2783 static int ep_gfx_crumbled[] =
2796 } element_properties[] =
2798 { ep_diggable, EP_DIGGABLE },
2799 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2800 { ep_dont_run_into, EP_DONT_RUN_INTO },
2801 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2802 { ep_dont_touch, EP_DONT_TOUCH },
2803 { ep_indestructible, EP_INDESTRUCTIBLE },
2804 { ep_slippery, EP_SLIPPERY },
2805 { ep_can_change, EP_CAN_CHANGE },
2806 { ep_can_move, EP_CAN_MOVE },
2807 { ep_can_fall, EP_CAN_FALL },
2808 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2809 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2810 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2811 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2812 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2813 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2814 { ep_walkable_over, EP_WALKABLE_OVER },
2815 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2816 { ep_walkable_under, EP_WALKABLE_UNDER },
2817 { ep_passable_over, EP_PASSABLE_OVER },
2818 { ep_passable_inside, EP_PASSABLE_INSIDE },
2819 { ep_passable_under, EP_PASSABLE_UNDER },
2820 { ep_droppable, EP_DROPPABLE },
2821 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2822 { ep_pushable, EP_PUSHABLE },
2824 { ep_player, EP_PLAYER },
2825 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2826 { ep_switchable, EP_SWITCHABLE },
2827 { ep_bd_element, EP_BD_ELEMENT },
2828 { ep_sp_element, EP_SP_ELEMENT },
2829 { ep_sb_element, EP_SB_ELEMENT },
2831 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2832 { ep_food_penguin, EP_FOOD_PENGUIN },
2833 { ep_food_pig, EP_FOOD_PIG },
2834 { ep_historic_wall, EP_HISTORIC_WALL },
2835 { ep_historic_solid, EP_HISTORIC_SOLID },
2836 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2837 { ep_belt, EP_BELT },
2838 { ep_belt_active, EP_BELT_ACTIVE },
2839 { ep_belt_switch, EP_BELT_SWITCH },
2840 { ep_tube, EP_TUBE },
2841 { ep_keygate, EP_KEYGATE },
2842 { ep_amoeboid, EP_AMOEBOID },
2843 { ep_amoebalive, EP_AMOEBALIVE },
2844 { ep_has_content, EP_HAS_CONTENT },
2845 { ep_active_bomb, EP_ACTIVE_BOMB },
2846 { ep_inactive, EP_INACTIVE },
2848 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2850 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2855 static int copy_properties[][5] =
2859 EL_BUG_LEFT, EL_BUG_RIGHT,
2860 EL_BUG_UP, EL_BUG_DOWN
2864 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2865 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2869 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2870 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2874 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2875 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2879 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2880 EL_PACMAN_UP, EL_PACMAN_DOWN
2890 /* always start with reliable default values (element has no properties) */
2891 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2892 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2893 SET_PROPERTY(i, j, FALSE);
2895 /* set all base element properties from above array definitions */
2896 for (i=0; element_properties[i].elements != NULL; i++)
2897 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2898 SET_PROPERTY((element_properties[i].elements)[j],
2899 element_properties[i].property, TRUE);
2901 /* copy properties to some elements that are only stored in level file */
2902 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2903 for (j=0; copy_properties[j][0] != -1; j++)
2904 if (HAS_PROPERTY(copy_properties[j][0], i))
2905 for (k=1; k<=4; k++)
2906 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2909 void InitElementPropertiesEngine(int engine_version)
2912 static int active_properties[] =
2917 EP_DONT_COLLIDE_WITH,
2921 EP_CAN_PASS_MAGIC_WALL,
2926 EP_CAN_EXPLODE_BY_FIRE,
2939 EP_EM_SLIPPERY_WALL,
2943 static int no_wall_properties[] =
2946 EP_COLLECTIBLE_ONLY,
2948 EP_DONT_COLLIDE_WITH,
2951 EP_CAN_SMASH_PLAYER,
2952 EP_CAN_SMASH_ENEMIES,
2953 EP_CAN_SMASH_EVERYTHING,
2958 EP_FOOD_DARK_YAMYAM,
2974 InitElementPropertiesStatic();
2977 /* set all special, combined or engine dependent element properties */
2978 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2981 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2982 SET_PROPERTY(i, j, FALSE);
2985 /* ---------- INACTIVE ------------------------------------------------- */
2986 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2987 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2989 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2990 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2991 IS_WALKABLE_INSIDE(i) ||
2992 IS_WALKABLE_UNDER(i)));
2994 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2995 IS_PASSABLE_INSIDE(i) ||
2996 IS_PASSABLE_UNDER(i)));
2998 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2999 IS_PASSABLE_OVER(i)));
3001 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3002 IS_PASSABLE_INSIDE(i)));
3004 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3005 IS_PASSABLE_UNDER(i)));
3007 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3010 /* ---------- COLLECTIBLE ---------------------------------------------- */
3011 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3014 /* ---------- SNAPPABLE ------------------------------------------------ */
3015 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3016 IS_COLLECTIBLE(i) ||
3020 /* ---------- WALL ----------------------------------------------------- */
3021 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3023 for (j=0; no_wall_properties[j] != -1; j++)
3024 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3025 i >= EL_FIRST_RUNTIME_UNREAL)
3026 SET_PROPERTY(i, EP_WALL, FALSE);
3028 if (IS_HISTORIC_WALL(i))
3029 SET_PROPERTY(i, EP_WALL, TRUE);
3031 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3032 if (engine_version < VERSION_IDENT(2,2,0,0))
3033 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3035 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3037 !IS_COLLECTIBLE(i)));
3039 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3041 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3042 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3044 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3045 IS_INDESTRUCTIBLE(i)));
3047 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3049 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3050 else if (engine_version < VERSION_IDENT(2,2,0,0))
3051 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3053 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3054 !IS_WALKABLE_OVER(i) &&
3055 !IS_WALKABLE_UNDER(i)));
3057 if (IS_CUSTOM_ELEMENT(i))
3059 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3061 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3062 if (DONT_COLLIDE_WITH(i))
3063 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3065 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3066 if (CAN_SMASH_EVERYTHING(i))
3067 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3068 if (CAN_SMASH_ENEMIES(i))
3069 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3072 /* ---------- CAN_SMASH ------------------------------------------------ */
3073 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3074 CAN_SMASH_ENEMIES(i) ||
3075 CAN_SMASH_EVERYTHING(i)));
3077 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3078 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3079 CAN_EXPLODE_SMASHED(i) ||
3080 CAN_EXPLODE_IMPACT(i)));
3082 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3083 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3084 !CAN_EXPLODE_1X1(i)));
3086 /* ---------- CAN_CHANGE ----------------------------------------------- */
3087 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3088 for (j=0; j < element_info[i].num_change_pages; j++)
3089 if (element_info[i].change_page[j].can_change)
3090 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3092 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3093 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3094 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3098 /* determine inactive elements (used for engine main loop optimization) */
3099 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3101 boolean active = FALSE;
3103 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
3105 if (HAS_PROPERTY(i, j))
3111 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3116 /* dynamically adjust element properties according to game engine version */
3118 static int ep_em_slippery_wall[] =
3123 EL_EXPANDABLE_WALL_HORIZONTAL,
3124 EL_EXPANDABLE_WALL_VERTICAL,
3125 EL_EXPANDABLE_WALL_ANY,
3129 /* special EM style gems behaviour */
3130 for (i=0; ep_em_slippery_wall[i] != -1; i++)
3131 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3132 level.em_slippery_gems);
3134 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3135 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3136 (level.em_slippery_gems &&
3137 engine_version > VERSION_IDENT(2,0,1,0)));
3141 /* set default push delay values (corrected since version 3.0.7-1) */
3142 if (engine_version < VERSION_IDENT(3,0,7,1))
3144 game.default_push_delay_fixed = 2;
3145 game.default_push_delay_random = 8;
3149 game.default_push_delay_fixed = 8;
3150 game.default_push_delay_random = 8;
3153 /* set uninitialized push delay values of custom elements in older levels */
3154 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
3156 int element = EL_CUSTOM_START + i;
3158 if (element_info[element].push_delay_fixed == -1)
3159 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3160 if (element_info[element].push_delay_random == -1)
3161 element_info[element].push_delay_random = game.default_push_delay_random;
3166 static void InitGlobal()
3168 global.autoplay_leveldir = NULL;
3170 global.frames_per_second = 0;
3171 global.fps_slowdown = FALSE;
3172 global.fps_slowdown_factor = 1;
3175 void Execute_Command(char *command)
3177 if (strcmp(command, "print graphicsinfo.conf") == 0)
3181 printf("# You can configure additional/alternative image files here.\n");
3182 printf("# (The images below are default and therefore commented out.)\n");
3184 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3186 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3189 for (i=0; image_config[i].token != NULL; i++)
3191 getFormattedSetupEntry(image_config[i].token,
3192 image_config[i].value));
3196 else if (strcmp(command, "print soundsinfo.conf") == 0)
3200 printf("# You can configure additional/alternative sound files here.\n");
3201 printf("# (The sounds below are default and therefore commented out.)\n");
3203 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3205 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3208 for (i=0; sound_config[i].token != NULL; i++)
3210 getFormattedSetupEntry(sound_config[i].token,
3211 sound_config[i].value));
3215 else if (strcmp(command, "print musicinfo.conf") == 0)
3217 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
3219 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3221 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3225 else if (strncmp(command, "dump level ", 11) == 0)
3227 char *filename = &command[11];
3229 if (access(filename, F_OK) != 0)
3230 Error(ERR_EXIT, "cannot open file '%s'", filename);
3232 LoadLevelFromFilename(&level, filename);
3237 else if (strncmp(command, "dump tape ", 10) == 0)
3239 char *filename = &command[10];
3241 if (access(filename, F_OK) != 0)
3242 Error(ERR_EXIT, "cannot open file '%s'", filename);
3244 LoadTapeFromFilename(filename);
3249 else if (strncmp(command, "autoplay ", 9) == 0)
3251 char *str_copy = getStringCopy(&command[9]);
3252 char *str_ptr = strchr(str_copy, ' ');
3254 global.autoplay_leveldir = str_copy;
3255 global.autoplay_level_nr = -1;
3257 if (str_ptr != NULL)
3259 *str_ptr++ = '\0'; /* terminate leveldir string */
3260 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3265 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3269 static void InitSetup()
3271 LoadSetup(); /* global setup info */
3273 /* set some options from setup file */
3275 if (setup.options.verbose)
3276 options.verbose = TRUE;
3279 static void InitPlayerInfo()
3283 /* choose default local player */
3284 local_player = &stored_player[0];
3286 for (i=0; i<MAX_PLAYERS; i++)
3287 stored_player[i].connected = FALSE;
3289 local_player->connected = TRUE;
3292 static void InitArtworkInfo()
3297 static char *get_string_in_brackets(char *string)
3299 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3301 sprintf(string_in_brackets, "[%s]", string);
3303 return string_in_brackets;
3306 static char *get_level_id_suffix(int id_nr)
3308 char *id_suffix = checked_malloc(1 + 3 + 1);
3310 if (id_nr < 0 || id_nr > 999)
3313 sprintf(id_suffix, ".%03d", id_nr);
3319 static char *get_element_class_token(int element)
3321 char *element_class_name = element_info[element].class_name;
3322 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3324 sprintf(element_class_token, "[%s]", element_class_name);
3326 return element_class_token;
3329 static char *get_action_class_token(int action)
3331 char *action_class_name = &element_action_info[action].suffix[1];
3332 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3334 sprintf(action_class_token, "[%s]", action_class_name);
3336 return action_class_token;
3340 static void InitArtworkConfig()
3342 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3343 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3344 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3345 static char *action_id_suffix[NUM_ACTIONS + 1];
3346 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3347 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3348 static char *level_id_suffix[MAX_LEVELS + 1];
3349 static char *dummy[1] = { NULL };
3350 static char *ignore_generic_tokens[] =
3356 static char **ignore_image_tokens;
3357 static char **ignore_sound_tokens;
3358 static char **ignore_music_tokens;
3359 int num_ignore_generic_tokens;
3360 int num_ignore_image_tokens;
3361 int num_ignore_sound_tokens;
3362 int num_ignore_music_tokens;
3365 /* dynamically determine list of generic tokens to be ignored */
3366 num_ignore_generic_tokens = 0;
3367 for (i=0; ignore_generic_tokens[i] != NULL; i++)
3368 num_ignore_generic_tokens++;
3370 /* dynamically determine list of image tokens to be ignored */
3371 num_ignore_image_tokens = num_ignore_generic_tokens;
3372 for (i=0; image_config_vars[i].token != NULL; i++)
3373 num_ignore_image_tokens++;
3374 ignore_image_tokens =
3375 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3376 for (i=0; i < num_ignore_generic_tokens; i++)
3377 ignore_image_tokens[i] = ignore_generic_tokens[i];
3378 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3379 ignore_image_tokens[num_ignore_generic_tokens + i] =
3380 image_config_vars[i].token;
3381 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3383 /* dynamically determine list of sound tokens to be ignored */
3384 num_ignore_sound_tokens = num_ignore_generic_tokens;
3385 ignore_sound_tokens =
3386 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3387 for (i=0; i < num_ignore_generic_tokens; i++)
3388 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3389 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3391 /* dynamically determine list of music tokens to be ignored */
3392 num_ignore_music_tokens = num_ignore_generic_tokens;
3393 ignore_music_tokens =
3394 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3395 for (i=0; i < num_ignore_generic_tokens; i++)
3396 ignore_music_tokens[i] = ignore_generic_tokens[i];
3397 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3399 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3400 image_id_prefix[i] = element_info[i].token_name;
3401 for (i=0; i < NUM_FONTS; i++)
3402 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3403 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3405 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3406 sound_id_prefix[i] = element_info[i].token_name;
3407 for (i=0; i < MAX_NUM_ELEMENTS; i++)
3408 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3409 get_string_in_brackets(element_info[i].class_name);
3410 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3412 for (i=0; i < NUM_MUSIC_PREFIXES; i++)
3413 music_id_prefix[i] = music_prefix_info[i].prefix;
3414 music_id_prefix[MAX_LEVELS] = NULL;
3416 for (i=0; i < NUM_ACTIONS; i++)
3417 action_id_suffix[i] = element_action_info[i].suffix;
3418 action_id_suffix[NUM_ACTIONS] = NULL;
3420 for (i=0; i < NUM_DIRECTIONS; i++)
3421 direction_id_suffix[i] = element_direction_info[i].suffix;
3422 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3424 for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
3425 special_id_suffix[i] = special_suffix_info[i].suffix;
3426 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3428 for (i=0; i < MAX_LEVELS; i++)
3429 level_id_suffix[i] = get_level_id_suffix(i);
3430 level_id_suffix[MAX_LEVELS] = NULL;
3432 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3433 image_id_prefix, action_id_suffix, direction_id_suffix,
3434 special_id_suffix, ignore_image_tokens);
3435 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3436 sound_id_prefix, action_id_suffix, dummy,
3437 special_id_suffix, ignore_sound_tokens);
3438 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3439 music_id_prefix, special_id_suffix, level_id_suffix,
3440 dummy, ignore_music_tokens);
3443 static void InitMixer()
3451 char *filename_font_initial = NULL;
3452 Bitmap *bitmap_font_initial = NULL;
3455 /* determine settings for initial font (for displaying startup messages) */
3456 for (i=0; image_config[i].token != NULL; i++)
3458 for (j=0; j < NUM_INITIAL_FONTS; j++)
3460 char font_token[128];
3463 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3464 len_font_token = strlen(font_token);
3466 if (strcmp(image_config[i].token, font_token) == 0)
3467 filename_font_initial = image_config[i].value;
3468 else if (strlen(image_config[i].token) > len_font_token &&
3469 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3471 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3472 font_initial[j].src_x = atoi(image_config[i].value);
3473 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3474 font_initial[j].src_y = atoi(image_config[i].value);
3475 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3476 font_initial[j].width = atoi(image_config[i].value);
3477 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3478 font_initial[j].height = atoi(image_config[i].value);
3483 for (j=0; j < NUM_INITIAL_FONTS; j++)
3485 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3486 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3489 if (filename_font_initial == NULL) /* should not happen */
3490 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3492 /* create additional image buffers for double-buffering */
3493 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3494 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3496 /* initialize screen properties */
3497 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3498 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3500 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3501 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3502 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3504 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3506 for (j=0; j < NUM_INITIAL_FONTS; j++)
3507 font_initial[j].bitmap = bitmap_font_initial;
3509 InitFontGraphicInfo();
3511 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3512 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3514 DrawInitText("Loading graphics:", 120, FC_GREEN);
3516 InitTileClipmasks();
3519 void InitGfxBackground()
3523 drawto = backbuffer;
3524 fieldbuffer = bitmap_db_field;
3525 SetDrawtoField(DRAW_BACKBUFFER);
3527 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3528 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3529 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3530 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3532 for (x=0; x<MAX_BUF_XSIZE; x++)
3533 for (y=0; y<MAX_BUF_YSIZE; y++)
3536 redraw_mask = REDRAW_ALL;
3539 static void InitLevelInfo()
3541 LoadLevelInfo(); /* global level info */
3542 LoadLevelSetup_LastSeries(); /* last played series info */
3543 LoadLevelSetup_SeriesInfo(); /* last played level info */
3546 void InitLevelArtworkInfo()
3548 LoadLevelArtworkInfo();
3551 static void InitImages()
3554 setLevelArtworkDir(artwork.gfx_first);
3558 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3559 leveldir_current->identifier,
3560 artwork.gfx_current_identifier,
3561 artwork.gfx_current->identifier,
3562 leveldir_current->graphics_set,
3563 leveldir_current->graphics_path);
3566 ReloadCustomImages();
3568 LoadCustomElementDescriptions();
3569 LoadSpecialMenuDesignSettings();
3571 ReinitializeGraphics();
3574 static void InitSound(char *identifier)
3576 if (identifier == NULL)
3577 identifier = artwork.snd_current->identifier;
3580 /* set artwork path to send it to the sound server process */
3581 setLevelArtworkDir(artwork.snd_first);
3584 InitReloadCustomSounds(identifier);
3585 ReinitializeSounds();
3588 static void InitMusic(char *identifier)
3590 if (identifier == NULL)
3591 identifier = artwork.mus_current->identifier;
3594 /* set artwork path to send it to the sound server process */
3595 setLevelArtworkDir(artwork.mus_first);
3598 InitReloadCustomMusic(identifier);
3599 ReinitializeMusic();
3602 void InitNetworkServer()
3604 #if defined(PLATFORM_UNIX)
3608 if (!options.network)
3611 #if defined(PLATFORM_UNIX)
3612 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3614 if (!ConnectToServer(options.server_host, options.server_port))
3615 Error(ERR_EXIT, "cannot connect to network game server");
3617 SendToServer_PlayerName(setup.player_name);
3618 SendToServer_ProtocolVersion();
3621 SendToServer_NrWanted(nr_wanted);
3625 static char *getNewArtworkIdentifier(int type)
3627 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3628 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3629 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3630 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3631 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3632 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3633 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3634 char *leveldir_identifier = leveldir_current->identifier;
3636 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3637 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3639 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3641 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3642 char *artwork_current_identifier;
3643 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3645 /* leveldir_current may be invalid (level group, parent link) */
3646 if (!validLevelSeries(leveldir_current))
3649 /* 1st step: determine artwork set to be activated in descending order:
3650 --------------------------------------------------------------------
3651 1. setup artwork (when configured to override everything else)
3652 2. artwork set configured in "levelinfo.conf" of current level set
3653 (artwork in level directory will have priority when loading later)
3654 3. artwork in level directory (stored in artwork sub-directory)
3655 4. setup artwork (currently configured in setup menu) */
3657 if (setup_override_artwork)
3658 artwork_current_identifier = setup_artwork_set;
3659 else if (leveldir_artwork_set != NULL)
3660 artwork_current_identifier = leveldir_artwork_set;
3661 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3662 artwork_current_identifier = leveldir_identifier;
3664 artwork_current_identifier = setup_artwork_set;
3667 /* 2nd step: check if it is really needed to reload artwork set
3668 ------------------------------------------------------------ */
3671 if (type == ARTWORK_TYPE_GRAPHICS)
3672 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3673 artwork_new_identifier,
3674 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3675 artwork_current_identifier,
3676 leveldir_current->graphics_set,
3677 leveldir_current->identifier);
3680 /* ---------- reload if level set and also artwork set has changed ------- */
3681 if (leveldir_current_identifier[type] != leveldir_identifier &&
3682 (last_has_level_artwork_set[type] || has_level_artwork_set))
3683 artwork_new_identifier = artwork_current_identifier;
3685 leveldir_current_identifier[type] = leveldir_identifier;
3686 last_has_level_artwork_set[type] = has_level_artwork_set;
3689 if (type == ARTWORK_TYPE_GRAPHICS)
3690 printf("::: 1: '%s'\n", artwork_new_identifier);
3693 /* ---------- reload if "override artwork" setting has changed ----------- */
3694 if (last_override_level_artwork[type] != setup_override_artwork)
3695 artwork_new_identifier = artwork_current_identifier;
3697 last_override_level_artwork[type] = setup_override_artwork;
3700 if (type == ARTWORK_TYPE_GRAPHICS)
3701 printf("::: 2: '%s'\n", artwork_new_identifier);
3704 /* ---------- reload if current artwork identifier has changed ----------- */
3705 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3706 artwork_current_identifier) != 0)
3707 artwork_new_identifier = artwork_current_identifier;
3709 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3712 if (type == ARTWORK_TYPE_GRAPHICS)
3713 printf("::: 3: '%s'\n", artwork_new_identifier);
3716 /* ---------- do not reload directly after starting ---------------------- */
3717 if (!initialized[type])
3718 artwork_new_identifier = NULL;
3720 initialized[type] = TRUE;
3723 if (type == ARTWORK_TYPE_GRAPHICS)
3724 printf("::: 4: '%s'\n", artwork_new_identifier);
3728 if (type == ARTWORK_TYPE_GRAPHICS)
3729 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3730 artwork.gfx_current_identifier, artwork_current_identifier,
3731 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3732 artwork_new_identifier);
3735 return artwork_new_identifier;
3738 void ReloadCustomArtwork()
3740 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3741 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3742 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3743 boolean redraw_screen = FALSE;
3745 if (gfx_new_identifier != NULL)
3748 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3749 artwork.gfx_current_identifier,
3751 artwork.gfx_current->identifier,
3752 leveldir_current->graphics_set);
3755 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3760 printf("... '%s'\n",
3761 leveldir_current->graphics_set);
3764 FreeTileClipmasks();
3765 InitTileClipmasks();
3767 redraw_screen = TRUE;
3770 if (snd_new_identifier != NULL)
3772 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3774 InitSound(snd_new_identifier);
3776 redraw_screen = TRUE;
3779 if (mus_new_identifier != NULL)
3781 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3783 InitMusic(mus_new_identifier);
3785 redraw_screen = TRUE;
3790 InitGfxBackground();
3792 /* force redraw of (open or closed) door graphics */
3793 SetDoorState(DOOR_OPEN_ALL);
3794 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3798 void KeyboardAutoRepeatOffUnlessAutoplay()
3800 if (global.autoplay_leveldir == NULL)
3801 KeyboardAutoRepeatOff();
3805 /* ========================================================================= */
3807 /* ========================================================================= */
3811 InitGlobal(); /* initialize some global variables */
3813 if (options.execute_command)
3814 Execute_Command(options.execute_command);
3816 if (options.serveronly)
3818 #if defined(PLATFORM_UNIX)
3819 NetworkServer(options.server_port, options.serveronly);
3821 Error(ERR_WARN, "networking only supported in Unix version");
3823 exit(0); /* never reached */
3829 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3830 InitArtworkConfig(); /* needed before forking sound child process */
3835 InitRND(NEW_RANDOMIZE);
3836 InitSimpleRND(NEW_RANDOMIZE);
3841 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3844 InitEventFilter(FilterMouseMotionEvents);
3846 InitElementPropertiesStatic();
3847 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3852 InitLevelArtworkInfo();
3854 InitImages(); /* needs to know current level directory */
3855 InitSound(NULL); /* needs to know current level directory */
3856 InitMusic(NULL); /* needs to know current level directory */
3858 InitGfxBackground();
3860 if (global.autoplay_leveldir)
3866 game_status = GAME_MODE_MAIN;
3870 InitNetworkServer();
3873 void CloseAllAndExit(int exit_value)
3878 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3881 FreeTileClipmasks();
3883 CloseVideoDisplay();
3884 ClosePlatformDependentStuff();