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 if (graphic_info == NULL) /* still at startup phase */
419 /* set values to -1 to identify later as "uninitialized" values */
420 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
422 for (act = 0; act < NUM_ACTIONS; act++)
424 element_info[i].graphic[act] = -1;
425 element_info[i].crumbled[act] = -1;
427 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
429 element_info[i].direction_graphic[act][dir] = -1;
430 element_info[i].direction_crumbled[act][dir] = -1;
435 /* initialize normal element/graphic mapping from static configuration */
436 for (i = 0; element_to_graphic[i].element > -1; i++)
438 int element = element_to_graphic[i].element;
439 int action = element_to_graphic[i].action;
440 int direction = element_to_graphic[i].direction;
441 boolean crumbled = element_to_graphic[i].crumbled;
442 int graphic = element_to_graphic[i].graphic;
444 if (graphic_info[graphic].bitmap == NULL)
447 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
448 el2img(element) != -1)
450 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
451 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
453 /* if the base graphic ("emerald", for example) has been redefined,
454 but not the action graphic ("emerald.falling", for example), do not
455 use an existing (in this case considered obsolete) action graphic
456 anymore, but use the automatically determined default graphic */
457 if (base_redefined && !act_dir_redefined)
462 action = ACTION_DEFAULT;
467 element_info[element].direction_crumbled[action][direction] = graphic;
469 element_info[element].crumbled[action] = graphic;
474 element_info[element].direction_graphic[action][direction] = graphic;
476 element_info[element].graphic[action] = graphic;
480 /* initialize normal element/graphic mapping from dynamic configuration */
481 for (i = 0; i < num_property_mappings; i++)
483 int element = property_mapping[i].base_index;
484 int action = property_mapping[i].ext1_index;
485 int direction = property_mapping[i].ext2_index;
486 int special = property_mapping[i].ext3_index;
487 int graphic = property_mapping[i].artwork_index;
488 boolean crumbled = FALSE;
490 if (special == GFX_SPECIAL_ARG_CRUMBLED)
496 if (graphic_info[graphic].bitmap == NULL)
499 if (element >= MAX_NUM_ELEMENTS || special != -1)
503 action = ACTION_DEFAULT;
508 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
509 element_info[element].direction_crumbled[action][dir] = -1;
512 element_info[element].direction_crumbled[action][direction] = graphic;
514 element_info[element].crumbled[action] = graphic;
519 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
520 element_info[element].direction_graphic[action][dir] = -1;
523 element_info[element].direction_graphic[action][direction] = graphic;
525 element_info[element].graphic[action] = graphic;
529 /* now copy all graphics that are defined to be cloned from other graphics */
530 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
532 int graphic = element_info[i].graphic[ACTION_DEFAULT];
533 int crumbled_like, diggable_like;
538 crumbled_like = graphic_info[graphic].crumbled_like;
539 diggable_like = graphic_info[graphic].diggable_like;
541 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
543 for (act = 0; act < NUM_ACTIONS; act++)
544 element_info[i].crumbled[act] =
545 element_info[crumbled_like].crumbled[act];
546 for (act = 0; act < NUM_ACTIONS; act++)
547 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
548 element_info[i].direction_crumbled[act][dir] =
549 element_info[crumbled_like].direction_crumbled[act][dir];
552 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
554 element_info[i].graphic[ACTION_DIGGING] =
555 element_info[diggable_like].graphic[ACTION_DIGGING];
556 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
557 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
558 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
563 /* now set all undefined/invalid graphics to -1 to set to default after it */
564 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
566 for (act = 0; act < NUM_ACTIONS; act++)
570 graphic = element_info[i].graphic[act];
571 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
572 element_info[i].graphic[act] = -1;
574 graphic = element_info[i].crumbled[act];
575 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
576 element_info[i].crumbled[act] = -1;
578 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
580 graphic = element_info[i].direction_graphic[act][dir];
581 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
582 element_info[i].direction_graphic[act][dir] = -1;
584 graphic = element_info[i].direction_crumbled[act][dir];
585 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
586 element_info[i].direction_crumbled[act][dir] = -1;
592 /* now set all '-1' values to element specific default values */
593 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
595 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
596 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
597 int default_direction_graphic[NUM_DIRECTIONS];
598 int default_direction_crumbled[NUM_DIRECTIONS];
600 if (default_graphic == -1)
601 default_graphic = IMG_CHAR_QUESTION;
602 if (default_crumbled == -1)
603 default_crumbled = IMG_EMPTY;
605 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
607 default_direction_graphic[dir] =
608 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
609 default_direction_crumbled[dir] =
610 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
612 if (default_direction_graphic[dir] == -1)
613 default_direction_graphic[dir] = default_graphic;
614 if (default_direction_crumbled[dir] == -1)
615 default_direction_crumbled[dir] = default_crumbled;
618 for (act = 0; act < NUM_ACTIONS; act++)
620 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
621 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
622 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
623 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
624 act == ACTION_TURNING_FROM_RIGHT ||
625 act == ACTION_TURNING_FROM_UP ||
626 act == ACTION_TURNING_FROM_DOWN);
628 /* generic default action graphic (defined by "[default]" directive) */
629 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
630 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
632 /* look for special default action graphic (classic game specific) */
633 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
634 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
635 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
636 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
637 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
638 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
640 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
641 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
642 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
643 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
644 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
645 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
647 if (default_action_graphic == -1)
648 default_action_graphic = default_graphic;
649 if (default_action_crumbled == -1)
650 default_action_crumbled = default_crumbled;
652 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
654 int default_action_direction_graphic = element_info[i].graphic[act];
655 int default_action_direction_crumbled = element_info[i].crumbled[act];
657 /* no graphic for current action -- use default direction graphic */
658 if (default_action_direction_graphic == -1)
659 default_action_direction_graphic =
660 (act_remove ? IMG_EMPTY :
662 element_info[i].direction_graphic[ACTION_TURNING][dir] :
663 default_direction_graphic[dir]);
664 if (default_action_direction_crumbled == -1)
665 default_action_direction_crumbled =
666 (act_remove ? IMG_EMPTY :
668 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
669 default_direction_crumbled[dir]);
671 if (element_info[i].direction_graphic[act][dir] == -1)
672 element_info[i].direction_graphic[act][dir] =
673 default_action_direction_graphic;
674 if (element_info[i].direction_crumbled[act][dir] == -1)
675 element_info[i].direction_crumbled[act][dir] =
676 default_action_direction_crumbled;
679 /* no graphic for this specific action -- use default action graphic */
680 if (element_info[i].graphic[act] == -1)
681 element_info[i].graphic[act] =
682 (act_remove ? IMG_EMPTY :
683 act_turning ? element_info[i].graphic[ACTION_TURNING] :
684 default_action_graphic);
685 if (element_info[i].crumbled[act] == -1)
686 element_info[i].crumbled[act] =
687 (act_remove ? IMG_EMPTY :
688 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
689 default_action_crumbled);
694 /* set animation mode to "none" for each graphic with only 1 frame */
695 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
697 for (act = 0; act < NUM_ACTIONS; act++)
699 int graphic = element_info[i].graphic[act];
700 int crumbled = element_info[i].crumbled[act];
702 if (graphic_info[graphic].anim_frames == 1)
703 graphic_info[graphic].anim_mode = ANIM_NONE;
704 if (graphic_info[crumbled].anim_frames == 1)
705 graphic_info[crumbled].anim_mode = ANIM_NONE;
707 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
709 graphic = element_info[i].direction_graphic[act][dir];
710 crumbled = element_info[i].direction_crumbled[act][dir];
712 if (graphic_info[graphic].anim_frames == 1)
713 graphic_info[graphic].anim_mode = ANIM_NONE;
714 if (graphic_info[crumbled].anim_frames == 1)
715 graphic_info[crumbled].anim_mode = ANIM_NONE;
725 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
726 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
727 i != EL_CHAR_QUESTION)
728 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
729 element_info[i].token_name, i);
735 void InitElementSpecialGraphicInfo()
737 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
738 int num_property_mappings = getImageListPropertyMappingSize();
741 /* always start with reliable default values */
742 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
743 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
744 element_info[i].special_graphic[j] =
745 element_info[i].graphic[ACTION_DEFAULT];
747 /* initialize special element/graphic mapping from static configuration */
748 for (i = 0; element_to_special_graphic[i].element > -1; i++)
750 int element = element_to_special_graphic[i].element;
751 int special = element_to_special_graphic[i].special;
752 int graphic = element_to_special_graphic[i].graphic;
753 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
754 boolean special_redefined = getImageListEntry(graphic)->redefined;
756 /* if the base graphic ("emerald", for example) has been redefined,
757 but not the special graphic ("emerald.EDITOR", for example), do not
758 use an existing (in this case considered obsolete) special graphic
759 anymore, but use the automatically created (down-scaled) graphic */
760 if (base_redefined && !special_redefined)
763 element_info[element].special_graphic[special] = graphic;
766 /* initialize special element/graphic mapping from dynamic configuration */
767 for (i = 0; i < num_property_mappings; i++)
769 int element = property_mapping[i].base_index;
770 int special = property_mapping[i].ext3_index;
771 int graphic = property_mapping[i].artwork_index;
773 if (element >= MAX_NUM_ELEMENTS)
776 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
777 element_info[element].special_graphic[special] = graphic;
781 /* now set all undefined/invalid graphics to default */
782 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
783 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
784 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
785 element_info[i].special_graphic[j] =
786 element_info[i].graphic[ACTION_DEFAULT];
790 static int get_element_from_token(char *token)
794 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
795 if (strcmp(element_info[i].token_name, token) == 0)
801 static void set_graphic_parameters(int graphic, char **parameter_raw)
803 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
804 int parameter[NUM_GFX_ARGS];
805 int anim_frames_per_row = 1, anim_frames_per_col = 1;
806 int anim_frames_per_line = 1;
809 /* get integer values from string parameters */
810 for (i = 0; i < NUM_GFX_ARGS; i++)
813 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
814 image_config_suffix[i].type);
816 if (image_config_suffix[i].type == TYPE_TOKEN)
817 parameter[i] = get_element_from_token(parameter_raw[i]);
820 graphic_info[graphic].bitmap = src_bitmap;
822 /* start with reliable default values */
823 graphic_info[graphic].src_x = 0;
824 graphic_info[graphic].src_y = 0;
825 graphic_info[graphic].width = TILEX;
826 graphic_info[graphic].height = TILEY;
827 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
828 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
829 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
830 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
831 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
832 graphic_info[graphic].anim_delay_fixed = 0;
833 graphic_info[graphic].anim_delay_random = 0;
834 graphic_info[graphic].post_delay_fixed = 0;
835 graphic_info[graphic].post_delay_random = 0;
837 /* optional x and y tile position of animation frame sequence */
838 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
839 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
840 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
841 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
843 /* optional x and y pixel position of animation frame sequence */
844 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
845 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
846 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
847 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
849 /* optional width and height of each animation frame */
850 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
851 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
852 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
853 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
857 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
858 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
861 /* correct x or y offset dependent of vertical or horizontal frame order */
862 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
864 graphic_info[graphic].offset_y =
865 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
866 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
867 anim_frames_per_line = anim_frames_per_col;
869 else /* frames are ordered horizontally */
871 graphic_info[graphic].offset_x =
872 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
873 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
874 anim_frames_per_line = anim_frames_per_row;
877 /* optionally, the x and y offset of frames can be specified directly */
878 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
879 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
880 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
881 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
883 /* automatically determine correct number of frames, if not defined */
884 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
886 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
887 graphic_info[graphic].anim_frames = anim_frames_per_row;
888 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
889 graphic_info[graphic].anim_frames = anim_frames_per_col;
891 graphic_info[graphic].anim_frames = 1;
893 graphic_info[graphic].anim_frames_per_line =
894 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
895 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
897 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
898 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
899 graphic_info[graphic].anim_delay = 1;
901 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
903 if (graphic_info[graphic].anim_frames == 1)
904 graphic_info[graphic].anim_mode = ANIM_NONE;
907 /* automatically determine correct start frame, if not defined */
908 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
909 graphic_info[graphic].anim_start_frame = 0;
910 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
911 graphic_info[graphic].anim_start_frame =
912 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
914 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
916 /* animation synchronized with global frame counter, not move position */
917 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
919 /* optional element for cloning crumble graphics */
920 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
921 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
923 /* optional element for cloning digging graphics */
924 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
925 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
927 /* optional border size for "crumbling" diggable graphics */
928 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
929 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
931 /* this is only used for player "boring" and "sleeping" actions */
932 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
933 graphic_info[graphic].anim_delay_fixed =
934 parameter[GFX_ARG_ANIM_DELAY_FIXED];
935 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
936 graphic_info[graphic].anim_delay_random =
937 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
938 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
939 graphic_info[graphic].post_delay_fixed =
940 parameter[GFX_ARG_POST_DELAY_FIXED];
941 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
942 graphic_info[graphic].post_delay_random =
943 parameter[GFX_ARG_POST_DELAY_RANDOM];
945 /* this is only used for toon animations */
946 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
947 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
949 /* this is only used for drawing font characters */
950 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
951 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
953 /* this is only used for drawing envelope graphics */
954 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
957 static void InitGraphicInfo()
959 int fallback_graphic = IMG_CHAR_EXCLAM;
960 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
961 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
962 int num_images = getImageListSize();
965 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
966 static boolean clipmasks_initialized = FALSE;
968 XGCValues clip_gc_values;
969 unsigned long clip_gc_valuemask;
970 GC copy_clipmask_gc = None;
973 checked_free(graphic_info);
975 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
978 printf("::: graphic_info: %d entries\n", num_images);
981 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
982 if (clipmasks_initialized)
984 for (i = 0; i < num_images; i++)
986 if (graphic_info[i].clip_mask)
987 XFreePixmap(display, graphic_info[i].clip_mask);
988 if (graphic_info[i].clip_gc)
989 XFreeGC(display, graphic_info[i].clip_gc);
991 graphic_info[i].clip_mask = None;
992 graphic_info[i].clip_gc = None;
997 for (i = 0; i < num_images; i++)
999 struct FileInfo *image = getImageListEntry(i);
1002 int first_frame, last_frame;
1005 printf("::: image: '%s' [%d]\n", image->token, i);
1009 printf("::: image # %d: '%s' ['%s']\n",
1011 getTokenFromImageID(i));
1014 set_graphic_parameters(i, image->parameter);
1016 /* now check if no animation frames are outside of the loaded image */
1018 if (graphic_info[i].bitmap == NULL)
1019 continue; /* skip check for optional images that are undefined */
1022 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1023 if (src_x < 0 || src_y < 0 ||
1024 src_x + TILEX > src_bitmap->width ||
1025 src_y + TILEY > src_bitmap->height)
1027 Error(ERR_RETURN_LINE, "-");
1028 Error(ERR_RETURN, "warning: error found in config file:");
1029 Error(ERR_RETURN, "- config file: '%s'",
1030 getImageConfigFilename());
1031 Error(ERR_RETURN, "- config token: '%s'",
1032 getTokenFromImageID(i));
1033 Error(ERR_RETURN, "- image file: '%s'",
1034 src_bitmap->source_filename);
1036 "error: first animation frame out of bounds (%d, %d)",
1038 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1040 if (i == fallback_graphic)
1041 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1043 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1044 Error(ERR_RETURN_LINE, "-");
1046 set_graphic_parameters(i, fallback_image->default_parameter);
1047 graphic_info[i].bitmap = fallback_bitmap;
1050 last_frame = graphic_info[i].anim_frames - 1;
1051 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1052 if (src_x < 0 || src_y < 0 ||
1053 src_x + TILEX > src_bitmap->width ||
1054 src_y + TILEY > src_bitmap->height)
1056 Error(ERR_RETURN_LINE, "-");
1057 Error(ERR_RETURN, "warning: error found in config file:");
1058 Error(ERR_RETURN, "- config file: '%s'",
1059 getImageConfigFilename());
1060 Error(ERR_RETURN, "- config token: '%s'",
1061 getTokenFromImageID(i));
1062 Error(ERR_RETURN, "- image file: '%s'",
1063 src_bitmap->source_filename);
1065 "error: last animation frame (%d) out of bounds (%d, %d)",
1066 last_frame, src_x, src_y);
1067 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1069 if (i == fallback_graphic)
1070 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1072 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1073 Error(ERR_RETURN_LINE, "-");
1075 set_graphic_parameters(i, fallback_image->default_parameter);
1076 graphic_info[i].bitmap = fallback_bitmap;
1079 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1080 /* currently we need only a tile clip mask from the first frame */
1081 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1083 if (copy_clipmask_gc == None)
1085 clip_gc_values.graphics_exposures = False;
1086 clip_gc_valuemask = GCGraphicsExposures;
1087 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1088 clip_gc_valuemask, &clip_gc_values);
1091 graphic_info[i].clip_mask =
1092 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1094 src_pixmap = src_bitmap->clip_mask;
1095 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1096 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1098 clip_gc_values.graphics_exposures = False;
1099 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1100 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1102 graphic_info[i].clip_gc =
1103 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1107 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1108 if (copy_clipmask_gc)
1109 XFreeGC(display, copy_clipmask_gc);
1111 clipmasks_initialized = TRUE;
1115 static void InitElementSoundInfo()
1117 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1118 int num_property_mappings = getSoundListPropertyMappingSize();
1121 /* set values to -1 to identify later as "uninitialized" values */
1122 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1123 for (act = 0; act < NUM_ACTIONS; act++)
1124 element_info[i].sound[act] = -1;
1126 /* initialize element/sound mapping from static configuration */
1127 for (i = 0; element_to_sound[i].element > -1; i++)
1129 int element = element_to_sound[i].element;
1130 int action = element_to_sound[i].action;
1131 int sound = element_to_sound[i].sound;
1132 boolean is_class = element_to_sound[i].is_class;
1135 action = ACTION_DEFAULT;
1138 element_info[element].sound[action] = sound;
1140 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1141 if (strcmp(element_info[j].class_name,
1142 element_info[element].class_name) == 0)
1143 element_info[j].sound[action] = sound;
1146 /* initialize element class/sound mapping from dynamic configuration */
1147 for (i = 0; i < num_property_mappings; i++)
1149 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1150 int action = property_mapping[i].ext1_index;
1151 int sound = property_mapping[i].artwork_index;
1153 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1157 action = ACTION_DEFAULT;
1159 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1160 if (strcmp(element_info[j].class_name,
1161 element_info[element_class].class_name) == 0)
1162 element_info[j].sound[action] = sound;
1165 /* initialize element/sound mapping from dynamic configuration */
1166 for (i = 0; i < num_property_mappings; i++)
1168 int element = property_mapping[i].base_index;
1169 int action = property_mapping[i].ext1_index;
1170 int sound = property_mapping[i].artwork_index;
1172 if (element >= MAX_NUM_ELEMENTS)
1176 action = ACTION_DEFAULT;
1178 element_info[element].sound[action] = sound;
1181 /* now set all '-1' values to element specific default values */
1182 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1184 for (act = 0; act < NUM_ACTIONS; act++)
1186 /* generic default action sound (defined by "[default]" directive) */
1187 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1189 /* look for special default action sound (classic game specific) */
1190 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1191 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1192 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1193 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1194 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1195 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1197 /* !!! there's no such thing as a "default action sound" !!! */
1199 /* look for element specific default sound (independent from action) */
1200 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1201 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1204 /* no sound for this specific action -- use default action sound */
1205 if (element_info[i].sound[act] == -1)
1206 element_info[i].sound[act] = default_action_sound;
1211 static void InitGameModeSoundInfo()
1215 /* set values to -1 to identify later as "uninitialized" values */
1216 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1219 /* initialize gamemode/sound mapping from static configuration */
1220 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1222 int gamemode = gamemode_to_sound[i].gamemode;
1223 int sound = gamemode_to_sound[i].sound;
1226 gamemode = GAME_MODE_DEFAULT;
1228 menu.sound[gamemode] = sound;
1231 /* now set all '-1' values to levelset specific default values */
1232 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1233 if (menu.sound[i] == -1)
1234 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1238 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1239 if (menu.sound[i] != -1)
1240 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1244 static void set_sound_parameters(int sound, char **parameter_raw)
1246 int parameter[NUM_SND_ARGS];
1249 /* get integer values from string parameters */
1250 for (i = 0; i < NUM_SND_ARGS; i++)
1252 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1253 sound_config_suffix[i].type);
1255 /* explicit loop mode setting in configuration overrides default value */
1256 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1257 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1260 static void InitSoundInfo()
1263 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1264 int num_property_mappings = getSoundListPropertyMappingSize();
1266 int *sound_effect_properties;
1267 int num_sounds = getSoundListSize();
1270 checked_free(sound_info);
1272 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1273 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1275 /* initialize sound effect for all elements to "no sound" */
1276 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1277 for (j = 0; j < NUM_ACTIONS; j++)
1278 element_info[i].sound[j] = SND_UNDEFINED;
1280 for (i = 0; i < num_sounds; i++)
1282 struct FileInfo *sound = getSoundListEntry(i);
1283 int len_effect_text = strlen(sound->token);
1285 sound_effect_properties[i] = ACTION_OTHER;
1286 sound_info[i].loop = FALSE; /* default: play sound only once */
1289 printf("::: sound %d: '%s'\n", i, sound->token);
1292 /* determine all loop sounds and identify certain sound classes */
1294 for (j = 0; element_action_info[j].suffix; j++)
1296 int len_action_text = strlen(element_action_info[j].suffix);
1298 if (len_action_text < len_effect_text &&
1299 strcmp(&sound->token[len_effect_text - len_action_text],
1300 element_action_info[j].suffix) == 0)
1302 sound_effect_properties[i] = element_action_info[j].value;
1303 sound_info[i].loop = element_action_info[j].is_loop_sound;
1310 if (strcmp(sound->token, "custom_42") == 0)
1311 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1314 /* associate elements and some selected sound actions */
1316 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1318 if (element_info[j].class_name)
1320 int len_class_text = strlen(element_info[j].class_name);
1322 if (len_class_text + 1 < len_effect_text &&
1323 strncmp(sound->token,
1324 element_info[j].class_name, len_class_text) == 0 &&
1325 sound->token[len_class_text] == '.')
1327 int sound_action_value = sound_effect_properties[i];
1329 element_info[j].sound[sound_action_value] = i;
1334 set_sound_parameters(i, sound->parameter);
1337 free(sound_effect_properties);
1340 /* !!! now handled in InitElementSoundInfo() !!! */
1341 /* initialize element/sound mapping from dynamic configuration */
1342 for (i = 0; i < num_property_mappings; i++)
1344 int element = property_mapping[i].base_index;
1345 int action = property_mapping[i].ext1_index;
1346 int sound = property_mapping[i].artwork_index;
1349 action = ACTION_DEFAULT;
1351 printf("::: %d: %d, %d, %d ['%s']\n",
1352 i, element, action, sound, element_info[element].token_name);
1354 element_info[element].sound[action] = sound;
1361 int element = EL_CUSTOM_11;
1364 while (element_action_info[j].suffix)
1366 printf("element %d, sound action '%s' == %d\n",
1367 element, element_action_info[j].suffix,
1368 element_info[element].sound[j]);
1373 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1379 int element = EL_SAND;
1380 int sound_action = ACTION_DIGGING;
1383 while (element_action_info[j].suffix)
1385 if (element_action_info[j].value == sound_action)
1386 printf("element %d, sound action '%s' == %d\n",
1387 element, element_action_info[j].suffix,
1388 element_info[element].sound[sound_action]);
1395 static void InitGameModeMusicInfo()
1397 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1398 int num_property_mappings = getMusicListPropertyMappingSize();
1399 int default_levelset_music = -1;
1402 /* set values to -1 to identify later as "uninitialized" values */
1403 for (i = 0; i < MAX_LEVELS; i++)
1404 levelset.music[i] = -1;
1405 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1408 /* initialize gamemode/music mapping from static configuration */
1409 for (i = 0; gamemode_to_music[i].music > -1; i++)
1411 int gamemode = gamemode_to_music[i].gamemode;
1412 int music = gamemode_to_music[i].music;
1415 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1419 gamemode = GAME_MODE_DEFAULT;
1421 menu.music[gamemode] = music;
1424 /* initialize gamemode/music mapping from dynamic configuration */
1425 for (i = 0; i < num_property_mappings; i++)
1427 int prefix = property_mapping[i].base_index;
1428 int gamemode = property_mapping[i].ext1_index;
1429 int level = property_mapping[i].ext2_index;
1430 int music = property_mapping[i].artwork_index;
1433 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1434 prefix, gamemode, level, music);
1437 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1441 gamemode = GAME_MODE_DEFAULT;
1443 /* level specific music only allowed for in-game music */
1444 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1445 gamemode = GAME_MODE_PLAYING;
1450 default_levelset_music = music;
1453 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1454 levelset.music[level] = music;
1455 if (gamemode != GAME_MODE_PLAYING)
1456 menu.music[gamemode] = music;
1459 /* now set all '-1' values to menu specific default values */
1460 /* (undefined values of "levelset.music[]" might stay at "-1" to
1461 allow dynamic selection of music files from music directory!) */
1462 for (i = 0; i < MAX_LEVELS; i++)
1463 if (levelset.music[i] == -1)
1464 levelset.music[i] = default_levelset_music;
1465 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1466 if (menu.music[i] == -1)
1467 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1471 for (i = 0; i < MAX_LEVELS; i++)
1472 if (levelset.music[i] != -1)
1473 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1474 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1475 if (menu.music[i] != -1)
1476 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1480 static void set_music_parameters(int music, char **parameter_raw)
1482 int parameter[NUM_MUS_ARGS];
1485 /* get integer values from string parameters */
1486 for (i = 0; i < NUM_MUS_ARGS; i++)
1488 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1489 music_config_suffix[i].type);
1491 /* explicit loop mode setting in configuration overrides default value */
1492 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1493 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1496 static void InitMusicInfo()
1498 int num_music = getMusicListSize();
1501 checked_free(music_info);
1503 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1505 for (i = 0; i < num_music; i++)
1507 struct FileInfo *music = getMusicListEntry(i);
1508 int len_music_text = strlen(music->token);
1510 music_info[i].loop = TRUE; /* default: play music in loop mode */
1512 /* determine all loop music */
1514 for (j = 0; music_prefix_info[j].prefix; j++)
1516 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1518 if (len_prefix_text < len_music_text &&
1519 strncmp(music->token,
1520 music_prefix_info[j].prefix, len_prefix_text) == 0)
1522 music_info[i].loop = music_prefix_info[j].is_loop_music;
1528 set_music_parameters(i, music->parameter);
1532 static void ReinitializeGraphics()
1534 InitGraphicInfo(); /* graphic properties mapping */
1535 InitElementGraphicInfo(); /* element game graphic mapping */
1536 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1538 InitElementSmallImages(); /* create editor and preview images */
1539 InitFontGraphicInfo(); /* initialize text drawing functions */
1541 SetMainBackgroundImage(IMG_BACKGROUND);
1542 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1548 static void ReinitializeSounds()
1550 InitSoundInfo(); /* sound properties mapping */
1551 InitElementSoundInfo(); /* element game sound mapping */
1552 InitGameModeSoundInfo(); /* game mode sound mapping */
1554 InitPlayLevelSound(); /* internal game sound settings */
1557 static void ReinitializeMusic()
1559 InitMusicInfo(); /* music properties mapping */
1560 InitGameModeMusicInfo(); /* game mode music mapping */
1563 void InitElementPropertiesStatic()
1565 static int ep_diggable[] =
1570 EL_SP_BUGGY_BASE_ACTIVATING,
1573 EL_INVISIBLE_SAND_ACTIVE,
1575 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1579 EL_SP_BUGGY_BASE_ACTIVE,
1584 static int ep_collectible_only[] =
1601 EL_DYNABOMB_INCREASE_NUMBER,
1602 EL_DYNABOMB_INCREASE_SIZE,
1603 EL_DYNABOMB_INCREASE_POWER,
1620 static int ep_dont_run_into[] =
1622 /* same elements as in 'ep_dont_touch' */
1628 /* same elements as in 'ep_dont_collide_with' */
1640 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1644 EL_SP_BUGGY_BASE_ACTIVE,
1649 static int ep_dont_collide_with[] =
1651 /* same elements as in 'ep_dont_touch' */
1667 static int ep_dont_touch[] =
1676 static int ep_indestructible[] =
1680 EL_ACID_POOL_TOPLEFT,
1681 EL_ACID_POOL_TOPRIGHT,
1682 EL_ACID_POOL_BOTTOMLEFT,
1683 EL_ACID_POOL_BOTTOM,
1684 EL_ACID_POOL_BOTTOMRIGHT,
1685 EL_SP_HARDWARE_GRAY,
1686 EL_SP_HARDWARE_GREEN,
1687 EL_SP_HARDWARE_BLUE,
1689 EL_SP_HARDWARE_YELLOW,
1690 EL_SP_HARDWARE_BASE_1,
1691 EL_SP_HARDWARE_BASE_2,
1692 EL_SP_HARDWARE_BASE_3,
1693 EL_SP_HARDWARE_BASE_4,
1694 EL_SP_HARDWARE_BASE_5,
1695 EL_SP_HARDWARE_BASE_6,
1696 EL_INVISIBLE_STEELWALL,
1697 EL_INVISIBLE_STEELWALL_ACTIVE,
1698 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1699 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1700 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1701 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1702 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1703 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1704 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1705 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1706 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1707 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1708 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1709 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1711 EL_LIGHT_SWITCH_ACTIVE,
1712 EL_SIGN_EXCLAMATION,
1713 EL_SIGN_RADIOACTIVITY,
1724 EL_STEELWALL_SLIPPERY,
1747 EL_SWITCHGATE_OPENING,
1748 EL_SWITCHGATE_CLOSED,
1749 EL_SWITCHGATE_CLOSING,
1751 EL_SWITCHGATE_SWITCH_UP,
1752 EL_SWITCHGATE_SWITCH_DOWN,
1755 EL_TIMEGATE_OPENING,
1757 EL_TIMEGATE_CLOSING,
1760 EL_TIMEGATE_SWITCH_ACTIVE,
1765 EL_TUBE_VERTICAL_LEFT,
1766 EL_TUBE_VERTICAL_RIGHT,
1767 EL_TUBE_HORIZONTAL_UP,
1768 EL_TUBE_HORIZONTAL_DOWN,
1776 static int ep_slippery[] =
1790 EL_ROBOT_WHEEL_ACTIVE,
1796 EL_ACID_POOL_TOPLEFT,
1797 EL_ACID_POOL_TOPRIGHT,
1807 EL_STEELWALL_SLIPPERY,
1813 static int ep_can_change[] =
1818 static int ep_can_move[] =
1841 static int ep_can_fall[] =
1856 EL_BD_MAGIC_WALL_FULL,
1869 static int ep_can_smash_player[] =
1894 static int ep_can_smash_enemies[] =
1902 static int ep_can_smash_everything[] =
1910 static int ep_can_explode_by_fire[] =
1912 /* same elements as in 'ep_can_explode_impact' */
1917 /* same elements as in 'ep_can_explode_smashed' */
1926 EL_DYNABOMB_PLAYER_1_ACTIVE,
1927 EL_DYNABOMB_PLAYER_2_ACTIVE,
1928 EL_DYNABOMB_PLAYER_3_ACTIVE,
1929 EL_DYNABOMB_PLAYER_4_ACTIVE,
1930 EL_DYNABOMB_INCREASE_NUMBER,
1931 EL_DYNABOMB_INCREASE_SIZE,
1932 EL_DYNABOMB_INCREASE_POWER,
1933 EL_SP_DISK_RED_ACTIVE,
1943 static int ep_can_explode_smashed[] =
1945 /* same elements as in 'ep_can_explode_impact' */
1958 static int ep_can_explode_impact[] =
1966 static int ep_walkable_over[] =
1970 EL_SOKOBAN_FIELD_EMPTY,
1988 static int ep_walkable_inside[] =
1993 EL_TUBE_VERTICAL_LEFT,
1994 EL_TUBE_VERTICAL_RIGHT,
1995 EL_TUBE_HORIZONTAL_UP,
1996 EL_TUBE_HORIZONTAL_DOWN,
2004 static int ep_walkable_under[] =
2009 static int ep_passable_over[] =
2024 static int ep_passable_inside[] =
2030 EL_SP_PORT_HORIZONTAL,
2031 EL_SP_PORT_VERTICAL,
2033 EL_SP_GRAVITY_PORT_LEFT,
2034 EL_SP_GRAVITY_PORT_RIGHT,
2035 EL_SP_GRAVITY_PORT_UP,
2036 EL_SP_GRAVITY_PORT_DOWN,
2040 static int ep_passable_under[] =
2045 static int ep_droppable[] =
2050 static int ep_can_explode_1x1[] =
2055 static int ep_pushable[] =
2067 EL_SOKOBAN_FIELD_FULL,
2074 static int ep_player[] =
2084 static int ep_can_pass_magic_wall[] =
2097 static int ep_switchable[] =
2101 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2102 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2103 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2104 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2105 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2106 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2107 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2108 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2109 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2110 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2111 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2112 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2113 EL_SWITCHGATE_SWITCH_UP,
2114 EL_SWITCHGATE_SWITCH_DOWN,
2116 EL_LIGHT_SWITCH_ACTIVE,
2118 EL_BALLOON_SWITCH_LEFT,
2119 EL_BALLOON_SWITCH_RIGHT,
2120 EL_BALLOON_SWITCH_UP,
2121 EL_BALLOON_SWITCH_DOWN,
2122 EL_BALLOON_SWITCH_ANY,
2128 static int ep_bd_element[] =
2157 static int ep_sp_element[] =
2159 /* should always be valid */
2168 EL_SP_HARDWARE_GRAY,
2176 EL_SP_GRAVITY_PORT_RIGHT,
2177 EL_SP_GRAVITY_PORT_DOWN,
2178 EL_SP_GRAVITY_PORT_LEFT,
2179 EL_SP_GRAVITY_PORT_UP,
2184 EL_SP_PORT_VERTICAL,
2185 EL_SP_PORT_HORIZONTAL,
2191 EL_SP_HARDWARE_BASE_1,
2192 EL_SP_HARDWARE_GREEN,
2193 EL_SP_HARDWARE_BLUE,
2195 EL_SP_HARDWARE_YELLOW,
2196 EL_SP_HARDWARE_BASE_2,
2197 EL_SP_HARDWARE_BASE_3,
2198 EL_SP_HARDWARE_BASE_4,
2199 EL_SP_HARDWARE_BASE_5,
2200 EL_SP_HARDWARE_BASE_6,
2203 /* additional elements that appeared in newer Supaplex levels */
2205 /* more than one murphy in a level results in an inactive clone */
2207 /* runtime elements*/
2208 EL_SP_DISK_RED_ACTIVE,
2209 EL_SP_TERMINAL_ACTIVE,
2210 EL_SP_BUGGY_BASE_ACTIVATING,
2211 EL_SP_BUGGY_BASE_ACTIVE,
2217 static int ep_sb_element[] =
2222 EL_SOKOBAN_FIELD_EMPTY,
2223 EL_SOKOBAN_FIELD_FULL,
2225 EL_INVISIBLE_STEELWALL,
2229 static int ep_gem[] =
2240 static int ep_food_dark_yamyam[] =
2267 static int ep_food_penguin[] =
2280 static int ep_food_pig[] =
2291 static int ep_historic_wall[] =
2316 EL_EXPANDABLE_WALL_HORIZONTAL,
2317 EL_EXPANDABLE_WALL_VERTICAL,
2318 EL_EXPANDABLE_WALL_ANY,
2319 EL_EXPANDABLE_WALL_GROWING,
2326 EL_SP_HARDWARE_GRAY,
2327 EL_SP_HARDWARE_GREEN,
2328 EL_SP_HARDWARE_BLUE,
2330 EL_SP_HARDWARE_YELLOW,
2331 EL_SP_HARDWARE_BASE_1,
2332 EL_SP_HARDWARE_BASE_2,
2333 EL_SP_HARDWARE_BASE_3,
2334 EL_SP_HARDWARE_BASE_4,
2335 EL_SP_HARDWARE_BASE_5,
2336 EL_SP_HARDWARE_BASE_6,
2338 EL_SP_TERMINAL_ACTIVE,
2341 EL_INVISIBLE_STEELWALL,
2342 EL_INVISIBLE_STEELWALL_ACTIVE,
2344 EL_INVISIBLE_WALL_ACTIVE,
2345 EL_STEELWALL_SLIPPERY,
2361 static int ep_historic_solid[] =
2365 EL_EXPANDABLE_WALL_HORIZONTAL,
2366 EL_EXPANDABLE_WALL_VERTICAL,
2367 EL_EXPANDABLE_WALL_ANY,
2380 EL_QUICKSAND_FILLING,
2381 EL_QUICKSAND_EMPTYING,
2383 EL_MAGIC_WALL_ACTIVE,
2384 EL_MAGIC_WALL_EMPTYING,
2385 EL_MAGIC_WALL_FILLING,
2389 EL_BD_MAGIC_WALL_ACTIVE,
2390 EL_BD_MAGIC_WALL_EMPTYING,
2391 EL_BD_MAGIC_WALL_FULL,
2392 EL_BD_MAGIC_WALL_FILLING,
2393 EL_BD_MAGIC_WALL_DEAD,
2402 EL_SP_TERMINAL_ACTIVE,
2406 EL_INVISIBLE_WALL_ACTIVE,
2407 EL_SWITCHGATE_SWITCH_UP,
2408 EL_SWITCHGATE_SWITCH_DOWN,
2410 EL_TIMEGATE_SWITCH_ACTIVE,
2422 /* the following elements are a direct copy of "indestructible" elements,
2423 except "EL_ACID", which is "indestructible", but not "solid"! */
2428 EL_ACID_POOL_TOPLEFT,
2429 EL_ACID_POOL_TOPRIGHT,
2430 EL_ACID_POOL_BOTTOMLEFT,
2431 EL_ACID_POOL_BOTTOM,
2432 EL_ACID_POOL_BOTTOMRIGHT,
2433 EL_SP_HARDWARE_GRAY,
2434 EL_SP_HARDWARE_GREEN,
2435 EL_SP_HARDWARE_BLUE,
2437 EL_SP_HARDWARE_YELLOW,
2438 EL_SP_HARDWARE_BASE_1,
2439 EL_SP_HARDWARE_BASE_2,
2440 EL_SP_HARDWARE_BASE_3,
2441 EL_SP_HARDWARE_BASE_4,
2442 EL_SP_HARDWARE_BASE_5,
2443 EL_SP_HARDWARE_BASE_6,
2444 EL_INVISIBLE_STEELWALL,
2445 EL_INVISIBLE_STEELWALL_ACTIVE,
2446 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2447 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2448 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2449 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2450 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2451 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2452 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2453 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2454 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2455 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2456 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2457 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2459 EL_LIGHT_SWITCH_ACTIVE,
2460 EL_SIGN_EXCLAMATION,
2461 EL_SIGN_RADIOACTIVITY,
2472 EL_STEELWALL_SLIPPERY,
2495 EL_SWITCHGATE_OPENING,
2496 EL_SWITCHGATE_CLOSED,
2497 EL_SWITCHGATE_CLOSING,
2499 EL_TIMEGATE_OPENING,
2501 EL_TIMEGATE_CLOSING,
2505 EL_TUBE_VERTICAL_LEFT,
2506 EL_TUBE_VERTICAL_RIGHT,
2507 EL_TUBE_HORIZONTAL_UP,
2508 EL_TUBE_HORIZONTAL_DOWN,
2516 static int ep_classic_enemy[] =
2532 static int ep_belt[] =
2534 EL_CONVEYOR_BELT_1_LEFT,
2535 EL_CONVEYOR_BELT_1_MIDDLE,
2536 EL_CONVEYOR_BELT_1_RIGHT,
2537 EL_CONVEYOR_BELT_2_LEFT,
2538 EL_CONVEYOR_BELT_2_MIDDLE,
2539 EL_CONVEYOR_BELT_2_RIGHT,
2540 EL_CONVEYOR_BELT_3_LEFT,
2541 EL_CONVEYOR_BELT_3_MIDDLE,
2542 EL_CONVEYOR_BELT_3_RIGHT,
2543 EL_CONVEYOR_BELT_4_LEFT,
2544 EL_CONVEYOR_BELT_4_MIDDLE,
2545 EL_CONVEYOR_BELT_4_RIGHT,
2549 static int ep_belt_active[] =
2551 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2552 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2553 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2554 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2555 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2556 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2557 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2558 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2559 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2560 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2561 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2562 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2566 static int ep_belt_switch[] =
2568 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2569 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2570 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2571 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2572 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2573 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2574 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2575 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2576 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2577 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2578 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2579 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2583 static int ep_tube[] =
2590 EL_TUBE_HORIZONTAL_UP,
2591 EL_TUBE_HORIZONTAL_DOWN,
2593 EL_TUBE_VERTICAL_LEFT,
2594 EL_TUBE_VERTICAL_RIGHT,
2599 static int ep_keygate[] =
2620 static int ep_amoeboid[] =
2630 static int ep_amoebalive[] =
2639 static int ep_has_content[] =
2649 static int ep_active_bomb[] =
2652 EL_DYNABOMB_PLAYER_1_ACTIVE,
2653 EL_DYNABOMB_PLAYER_2_ACTIVE,
2654 EL_DYNABOMB_PLAYER_3_ACTIVE,
2655 EL_DYNABOMB_PLAYER_4_ACTIVE,
2656 EL_SP_DISK_RED_ACTIVE,
2660 static int ep_inactive[] =
2697 EL_INVISIBLE_STEELWALL,
2705 EL_WALL_EMERALD_YELLOW,
2706 EL_DYNABOMB_INCREASE_NUMBER,
2707 EL_DYNABOMB_INCREASE_SIZE,
2708 EL_DYNABOMB_INCREASE_POWER,
2712 EL_SOKOBAN_FIELD_EMPTY,
2713 EL_SOKOBAN_FIELD_FULL,
2714 EL_WALL_EMERALD_RED,
2715 EL_WALL_EMERALD_PURPLE,
2716 EL_ACID_POOL_TOPLEFT,
2717 EL_ACID_POOL_TOPRIGHT,
2718 EL_ACID_POOL_BOTTOMLEFT,
2719 EL_ACID_POOL_BOTTOM,
2720 EL_ACID_POOL_BOTTOMRIGHT,
2724 EL_BD_MAGIC_WALL_DEAD,
2725 EL_AMOEBA_TO_DIAMOND,
2733 EL_SP_GRAVITY_PORT_RIGHT,
2734 EL_SP_GRAVITY_PORT_DOWN,
2735 EL_SP_GRAVITY_PORT_LEFT,
2736 EL_SP_GRAVITY_PORT_UP,
2737 EL_SP_PORT_HORIZONTAL,
2738 EL_SP_PORT_VERTICAL,
2749 EL_SP_HARDWARE_GRAY,
2750 EL_SP_HARDWARE_GREEN,
2751 EL_SP_HARDWARE_BLUE,
2753 EL_SP_HARDWARE_YELLOW,
2754 EL_SP_HARDWARE_BASE_1,
2755 EL_SP_HARDWARE_BASE_2,
2756 EL_SP_HARDWARE_BASE_3,
2757 EL_SP_HARDWARE_BASE_4,
2758 EL_SP_HARDWARE_BASE_5,
2759 EL_SP_HARDWARE_BASE_6,
2760 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2761 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2762 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2763 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2764 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2765 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2766 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2767 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2768 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2769 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2770 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2771 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2772 EL_SIGN_EXCLAMATION,
2773 EL_SIGN_RADIOACTIVITY,
2784 EL_STEELWALL_SLIPPERY,
2800 static int ep_em_slippery_wall[] =
2805 static int ep_gfx_crumbled[] =
2818 } element_properties[] =
2820 { ep_diggable, EP_DIGGABLE },
2821 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2822 { ep_dont_run_into, EP_DONT_RUN_INTO },
2823 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2824 { ep_dont_touch, EP_DONT_TOUCH },
2825 { ep_indestructible, EP_INDESTRUCTIBLE },
2826 { ep_slippery, EP_SLIPPERY },
2827 { ep_can_change, EP_CAN_CHANGE },
2828 { ep_can_move, EP_CAN_MOVE },
2829 { ep_can_fall, EP_CAN_FALL },
2830 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2831 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2832 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2833 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2834 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2835 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2836 { ep_walkable_over, EP_WALKABLE_OVER },
2837 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2838 { ep_walkable_under, EP_WALKABLE_UNDER },
2839 { ep_passable_over, EP_PASSABLE_OVER },
2840 { ep_passable_inside, EP_PASSABLE_INSIDE },
2841 { ep_passable_under, EP_PASSABLE_UNDER },
2842 { ep_droppable, EP_DROPPABLE },
2843 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2844 { ep_pushable, EP_PUSHABLE },
2846 { ep_player, EP_PLAYER },
2847 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2848 { ep_switchable, EP_SWITCHABLE },
2849 { ep_bd_element, EP_BD_ELEMENT },
2850 { ep_sp_element, EP_SP_ELEMENT },
2851 { ep_sb_element, EP_SB_ELEMENT },
2853 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2854 { ep_food_penguin, EP_FOOD_PENGUIN },
2855 { ep_food_pig, EP_FOOD_PIG },
2856 { ep_historic_wall, EP_HISTORIC_WALL },
2857 { ep_historic_solid, EP_HISTORIC_SOLID },
2858 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2859 { ep_belt, EP_BELT },
2860 { ep_belt_active, EP_BELT_ACTIVE },
2861 { ep_belt_switch, EP_BELT_SWITCH },
2862 { ep_tube, EP_TUBE },
2863 { ep_keygate, EP_KEYGATE },
2864 { ep_amoeboid, EP_AMOEBOID },
2865 { ep_amoebalive, EP_AMOEBALIVE },
2866 { ep_has_content, EP_HAS_CONTENT },
2867 { ep_active_bomb, EP_ACTIVE_BOMB },
2868 { ep_inactive, EP_INACTIVE },
2870 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2872 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2877 static int copy_properties[][5] =
2881 EL_BUG_LEFT, EL_BUG_RIGHT,
2882 EL_BUG_UP, EL_BUG_DOWN
2886 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2887 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2891 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2892 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2896 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2897 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2901 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2902 EL_PACMAN_UP, EL_PACMAN_DOWN
2912 /* always start with reliable default values (element has no properties) */
2913 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2914 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
2915 SET_PROPERTY(i, j, FALSE);
2917 /* set all base element properties from above array definitions */
2918 for (i = 0; element_properties[i].elements != NULL; i++)
2919 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
2920 SET_PROPERTY((element_properties[i].elements)[j],
2921 element_properties[i].property, TRUE);
2923 /* copy properties to some elements that are only stored in level file */
2924 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
2925 for (j = 0; copy_properties[j][0] != -1; j++)
2926 if (HAS_PROPERTY(copy_properties[j][0], i))
2927 for (k = 1; k <= 4; k++)
2928 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2931 void InitElementPropertiesEngine(int engine_version)
2934 static int active_properties[] =
2939 EP_DONT_COLLIDE_WITH,
2943 EP_CAN_PASS_MAGIC_WALL,
2948 EP_CAN_EXPLODE_BY_FIRE,
2961 EP_EM_SLIPPERY_WALL,
2965 static int no_wall_properties[] =
2968 EP_COLLECTIBLE_ONLY,
2970 EP_DONT_COLLIDE_WITH,
2973 EP_CAN_SMASH_PLAYER,
2974 EP_CAN_SMASH_ENEMIES,
2975 EP_CAN_SMASH_EVERYTHING,
2980 EP_FOOD_DARK_YAMYAM,
2996 InitElementPropertiesStatic();
2999 /* set all special, combined or engine dependent element properties */
3000 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3003 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3004 SET_PROPERTY(i, j, FALSE);
3007 /* ---------- INACTIVE ------------------------------------------------- */
3008 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
3009 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3011 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3012 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3013 IS_WALKABLE_INSIDE(i) ||
3014 IS_WALKABLE_UNDER(i)));
3016 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3017 IS_PASSABLE_INSIDE(i) ||
3018 IS_PASSABLE_UNDER(i)));
3020 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3021 IS_PASSABLE_OVER(i)));
3023 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3024 IS_PASSABLE_INSIDE(i)));
3026 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3027 IS_PASSABLE_UNDER(i)));
3029 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3032 /* ---------- COLLECTIBLE ---------------------------------------------- */
3033 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3036 /* ---------- SNAPPABLE ------------------------------------------------ */
3037 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3038 IS_COLLECTIBLE(i) ||
3042 /* ---------- WALL ----------------------------------------------------- */
3043 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3045 for (j = 0; no_wall_properties[j] != -1; j++)
3046 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3047 i >= EL_FIRST_RUNTIME_UNREAL)
3048 SET_PROPERTY(i, EP_WALL, FALSE);
3050 if (IS_HISTORIC_WALL(i))
3051 SET_PROPERTY(i, EP_WALL, TRUE);
3053 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3054 if (engine_version < VERSION_IDENT(2,2,0,0))
3055 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3057 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3059 !IS_COLLECTIBLE(i)));
3061 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3063 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3064 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3066 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3067 IS_INDESTRUCTIBLE(i)));
3069 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3071 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3072 else if (engine_version < VERSION_IDENT(2,2,0,0))
3073 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3075 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3076 !IS_WALKABLE_OVER(i) &&
3077 !IS_WALKABLE_UNDER(i)));
3079 if (IS_CUSTOM_ELEMENT(i))
3081 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3083 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3084 if (DONT_COLLIDE_WITH(i))
3085 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3087 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3088 if (CAN_SMASH_EVERYTHING(i))
3089 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3090 if (CAN_SMASH_ENEMIES(i))
3091 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3094 /* ---------- CAN_SMASH ------------------------------------------------ */
3095 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3096 CAN_SMASH_ENEMIES(i) ||
3097 CAN_SMASH_EVERYTHING(i)));
3099 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3100 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3101 CAN_EXPLODE_SMASHED(i) ||
3102 CAN_EXPLODE_IMPACT(i)));
3104 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3105 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3106 !CAN_EXPLODE_1X1(i)));
3108 /* ---------- CAN_CHANGE ----------------------------------------------- */
3109 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3110 for (j = 0; j < element_info[i].num_change_pages; j++)
3111 if (element_info[i].change_page[j].can_change)
3112 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3114 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3115 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3116 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3120 /* determine inactive elements (used for engine main loop optimization) */
3121 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3123 boolean active = FALSE;
3125 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3127 if (HAS_PROPERTY(i, j))
3133 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3138 /* dynamically adjust element properties according to game engine version */
3140 static int ep_em_slippery_wall[] =
3145 EL_EXPANDABLE_WALL_HORIZONTAL,
3146 EL_EXPANDABLE_WALL_VERTICAL,
3147 EL_EXPANDABLE_WALL_ANY,
3151 /* special EM style gems behaviour */
3152 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3153 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3154 level.em_slippery_gems);
3156 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3157 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3158 (level.em_slippery_gems &&
3159 engine_version > VERSION_IDENT(2,0,1,0)));
3163 /* set default push delay values (corrected since version 3.0.7-1) */
3164 if (engine_version < VERSION_IDENT(3,0,7,1))
3166 game.default_push_delay_fixed = 2;
3167 game.default_push_delay_random = 8;
3171 game.default_push_delay_fixed = 8;
3172 game.default_push_delay_random = 8;
3175 /* set uninitialized push delay values of custom elements in older levels */
3176 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3178 int element = EL_CUSTOM_START + i;
3180 if (element_info[element].push_delay_fixed == -1)
3181 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3182 if (element_info[element].push_delay_random == -1)
3183 element_info[element].push_delay_random = game.default_push_delay_random;
3187 /* this is needed because some graphics depend on element properties */
3188 InitElementGraphicInfo();
3191 static void InitGlobal()
3193 global.autoplay_leveldir = NULL;
3195 global.frames_per_second = 0;
3196 global.fps_slowdown = FALSE;
3197 global.fps_slowdown_factor = 1;
3200 void Execute_Command(char *command)
3204 if (strcmp(command, "print graphicsinfo.conf") == 0)
3206 printf("# You can configure additional/alternative image files here.\n");
3207 printf("# (The entries below are default and therefore commented out.)\n");
3209 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3211 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3214 for (i = 0; image_config[i].token != NULL; i++)
3215 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3216 image_config[i].value));
3220 else if (strcmp(command, "print soundsinfo.conf") == 0)
3222 printf("# You can configure additional/alternative sound files here.\n");
3223 printf("# (The entries below are default and therefore commented out.)\n");
3225 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3227 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3230 for (i = 0; sound_config[i].token != NULL; i++)
3231 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3232 sound_config[i].value));
3236 else if (strcmp(command, "print musicinfo.conf") == 0)
3238 printf("# You can configure additional/alternative music files here.\n");
3239 printf("# (The entries below are default and therefore commented out.)\n");
3241 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3243 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3246 for (i = 0; music_config[i].token != NULL; i++)
3247 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3248 music_config[i].value));
3252 else if (strcmp(command, "print editorsetup.conf") == 0)
3254 printf("# You can configure your personal editor element list here.\n");
3255 printf("# (The entries below are default and therefore commented out.)\n");
3258 PrintEditorElementList();
3262 else if (strcmp(command, "print helpanim.conf") == 0)
3264 printf("# You can configure different element help animations here.\n");
3265 printf("# (The entries below are default and therefore commented out.)\n");
3268 for (i = 0; helpanim_config[i].token != NULL; i++)
3270 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3271 helpanim_config[i].value));
3273 if (strcmp(helpanim_config[i].token, "end") == 0)
3279 else if (strcmp(command, "print helptext.conf") == 0)
3281 printf("# You can configure different element help text here.\n");
3282 printf("# (The entries below are default and therefore commented out.)\n");
3285 for (i = 0; helptext_config[i].token != NULL; i++)
3286 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3287 helptext_config[i].value));
3291 else if (strncmp(command, "dump level ", 11) == 0)
3293 char *filename = &command[11];
3295 if (access(filename, F_OK) != 0)
3296 Error(ERR_EXIT, "cannot open file '%s'", filename);
3298 LoadLevelFromFilename(&level, filename);
3303 else if (strncmp(command, "dump tape ", 10) == 0)
3305 char *filename = &command[10];
3307 if (access(filename, F_OK) != 0)
3308 Error(ERR_EXIT, "cannot open file '%s'", filename);
3310 LoadTapeFromFilename(filename);
3315 else if (strncmp(command, "autoplay ", 9) == 0)
3317 char *str_copy = getStringCopy(&command[9]);
3318 char *str_ptr = strchr(str_copy, ' ');
3320 global.autoplay_leveldir = str_copy;
3321 global.autoplay_level_nr = -1;
3323 if (str_ptr != NULL)
3325 *str_ptr++ = '\0'; /* terminate leveldir string */
3326 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3331 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3335 static void InitSetup()
3337 LoadSetup(); /* global setup info */
3339 /* set some options from setup file */
3341 if (setup.options.verbose)
3342 options.verbose = TRUE;
3345 static void InitPlayerInfo()
3349 /* choose default local player */
3350 local_player = &stored_player[0];
3352 for (i = 0; i < MAX_PLAYERS; i++)
3353 stored_player[i].connected = FALSE;
3355 local_player->connected = TRUE;
3358 static void InitArtworkInfo()
3363 static char *get_string_in_brackets(char *string)
3365 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3367 sprintf(string_in_brackets, "[%s]", string);
3369 return string_in_brackets;
3372 static char *get_level_id_suffix(int id_nr)
3374 char *id_suffix = checked_malloc(1 + 3 + 1);
3376 if (id_nr < 0 || id_nr > 999)
3379 sprintf(id_suffix, ".%03d", id_nr);
3385 static char *get_element_class_token(int element)
3387 char *element_class_name = element_info[element].class_name;
3388 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3390 sprintf(element_class_token, "[%s]", element_class_name);
3392 return element_class_token;
3395 static char *get_action_class_token(int action)
3397 char *action_class_name = &element_action_info[action].suffix[1];
3398 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3400 sprintf(action_class_token, "[%s]", action_class_name);
3402 return action_class_token;
3406 static void InitArtworkConfig()
3408 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3409 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3410 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3411 static char *action_id_suffix[NUM_ACTIONS + 1];
3412 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3413 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3414 static char *level_id_suffix[MAX_LEVELS + 1];
3415 static char *dummy[1] = { NULL };
3416 static char *ignore_generic_tokens[] =
3422 static char **ignore_image_tokens;
3423 static char **ignore_sound_tokens;
3424 static char **ignore_music_tokens;
3425 int num_ignore_generic_tokens;
3426 int num_ignore_image_tokens;
3427 int num_ignore_sound_tokens;
3428 int num_ignore_music_tokens;
3431 /* dynamically determine list of generic tokens to be ignored */
3432 num_ignore_generic_tokens = 0;
3433 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3434 num_ignore_generic_tokens++;
3436 /* dynamically determine list of image tokens to be ignored */
3437 num_ignore_image_tokens = num_ignore_generic_tokens;
3438 for (i = 0; image_config_vars[i].token != NULL; i++)
3439 num_ignore_image_tokens++;
3440 ignore_image_tokens =
3441 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3442 for (i = 0; i < num_ignore_generic_tokens; i++)
3443 ignore_image_tokens[i] = ignore_generic_tokens[i];
3444 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3445 ignore_image_tokens[num_ignore_generic_tokens + i] =
3446 image_config_vars[i].token;
3447 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3449 /* dynamically determine list of sound tokens to be ignored */
3450 num_ignore_sound_tokens = num_ignore_generic_tokens;
3451 ignore_sound_tokens =
3452 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3453 for (i = 0; i < num_ignore_generic_tokens; i++)
3454 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3455 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3457 /* dynamically determine list of music tokens to be ignored */
3458 num_ignore_music_tokens = num_ignore_generic_tokens;
3459 ignore_music_tokens =
3460 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3461 for (i = 0; i < num_ignore_generic_tokens; i++)
3462 ignore_music_tokens[i] = ignore_generic_tokens[i];
3463 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3465 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3466 image_id_prefix[i] = element_info[i].token_name;
3467 for (i = 0; i < NUM_FONTS; i++)
3468 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3469 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3471 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3472 sound_id_prefix[i] = element_info[i].token_name;
3473 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3474 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3475 get_string_in_brackets(element_info[i].class_name);
3476 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3478 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3479 music_id_prefix[i] = music_prefix_info[i].prefix;
3480 music_id_prefix[MAX_LEVELS] = NULL;
3482 for (i = 0; i < NUM_ACTIONS; i++)
3483 action_id_suffix[i] = element_action_info[i].suffix;
3484 action_id_suffix[NUM_ACTIONS] = NULL;
3486 for (i = 0; i < NUM_DIRECTIONS; i++)
3487 direction_id_suffix[i] = element_direction_info[i].suffix;
3488 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3490 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3491 special_id_suffix[i] = special_suffix_info[i].suffix;
3492 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3494 for (i = 0; i < MAX_LEVELS; i++)
3495 level_id_suffix[i] = get_level_id_suffix(i);
3496 level_id_suffix[MAX_LEVELS] = NULL;
3498 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3499 image_id_prefix, action_id_suffix, direction_id_suffix,
3500 special_id_suffix, ignore_image_tokens);
3501 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3502 sound_id_prefix, action_id_suffix, dummy,
3503 special_id_suffix, ignore_sound_tokens);
3504 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3505 music_id_prefix, special_id_suffix, level_id_suffix,
3506 dummy, ignore_music_tokens);
3509 static void InitMixer()
3517 char *filename_font_initial = NULL;
3518 Bitmap *bitmap_font_initial = NULL;
3521 /* determine settings for initial font (for displaying startup messages) */
3522 for (i = 0; image_config[i].token != NULL; i++)
3524 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3526 char font_token[128];
3529 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3530 len_font_token = strlen(font_token);
3532 if (strcmp(image_config[i].token, font_token) == 0)
3533 filename_font_initial = image_config[i].value;
3534 else if (strlen(image_config[i].token) > len_font_token &&
3535 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3537 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3538 font_initial[j].src_x = atoi(image_config[i].value);
3539 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3540 font_initial[j].src_y = atoi(image_config[i].value);
3541 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3542 font_initial[j].width = atoi(image_config[i].value);
3543 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3544 font_initial[j].height = atoi(image_config[i].value);
3549 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3551 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3552 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3555 if (filename_font_initial == NULL) /* should not happen */
3556 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3558 /* create additional image buffers for double-buffering */
3559 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3560 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3562 /* initialize screen properties */
3563 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3564 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3566 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3567 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3568 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3570 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3572 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3573 font_initial[j].bitmap = bitmap_font_initial;
3575 InitFontGraphicInfo();
3577 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3578 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3580 DrawInitText("Loading graphics:", 120, FC_GREEN);
3582 InitTileClipmasks();
3585 void InitGfxBackground()
3589 drawto = backbuffer;
3590 fieldbuffer = bitmap_db_field;
3591 SetDrawtoField(DRAW_BACKBUFFER);
3593 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3594 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3595 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3596 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3598 for (x = 0; x < MAX_BUF_XSIZE; x++)
3599 for (y = 0; y < MAX_BUF_YSIZE; y++)
3602 redraw_mask = REDRAW_ALL;
3605 static void InitLevelInfo()
3607 LoadLevelInfo(); /* global level info */
3608 LoadLevelSetup_LastSeries(); /* last played series info */
3609 LoadLevelSetup_SeriesInfo(); /* last played level info */
3612 void InitLevelArtworkInfo()
3614 LoadLevelArtworkInfo();
3617 static void InitImages()
3620 setLevelArtworkDir(artwork.gfx_first);
3624 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3625 leveldir_current->identifier,
3626 artwork.gfx_current_identifier,
3627 artwork.gfx_current->identifier,
3628 leveldir_current->graphics_set,
3629 leveldir_current->graphics_path);
3632 ReloadCustomImages();
3634 LoadCustomElementDescriptions();
3635 LoadSpecialMenuDesignSettings();
3637 ReinitializeGraphics();
3640 static void InitSound(char *identifier)
3642 if (identifier == NULL)
3643 identifier = artwork.snd_current->identifier;
3646 /* set artwork path to send it to the sound server process */
3647 setLevelArtworkDir(artwork.snd_first);
3650 InitReloadCustomSounds(identifier);
3651 ReinitializeSounds();
3654 static void InitMusic(char *identifier)
3656 if (identifier == NULL)
3657 identifier = artwork.mus_current->identifier;
3660 /* set artwork path to send it to the sound server process */
3661 setLevelArtworkDir(artwork.mus_first);
3664 InitReloadCustomMusic(identifier);
3665 ReinitializeMusic();
3668 void InitNetworkServer()
3670 #if defined(PLATFORM_UNIX)
3674 if (!options.network)
3677 #if defined(PLATFORM_UNIX)
3678 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3680 if (!ConnectToServer(options.server_host, options.server_port))
3681 Error(ERR_EXIT, "cannot connect to network game server");
3683 SendToServer_PlayerName(setup.player_name);
3684 SendToServer_ProtocolVersion();
3687 SendToServer_NrWanted(nr_wanted);
3691 static char *getNewArtworkIdentifier(int type)
3693 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3694 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3695 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3696 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3697 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3698 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3699 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3700 char *leveldir_identifier = leveldir_current->identifier;
3702 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3703 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3705 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3707 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3708 char *artwork_current_identifier;
3709 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3711 /* leveldir_current may be invalid (level group, parent link) */
3712 if (!validLevelSeries(leveldir_current))
3715 /* 1st step: determine artwork set to be activated in descending order:
3716 --------------------------------------------------------------------
3717 1. setup artwork (when configured to override everything else)
3718 2. artwork set configured in "levelinfo.conf" of current level set
3719 (artwork in level directory will have priority when loading later)
3720 3. artwork in level directory (stored in artwork sub-directory)
3721 4. setup artwork (currently configured in setup menu) */
3723 if (setup_override_artwork)
3724 artwork_current_identifier = setup_artwork_set;
3725 else if (leveldir_artwork_set != NULL)
3726 artwork_current_identifier = leveldir_artwork_set;
3727 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3728 artwork_current_identifier = leveldir_identifier;
3730 artwork_current_identifier = setup_artwork_set;
3733 /* 2nd step: check if it is really needed to reload artwork set
3734 ------------------------------------------------------------ */
3737 if (type == ARTWORK_TYPE_GRAPHICS)
3738 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3739 artwork_new_identifier,
3740 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3741 artwork_current_identifier,
3742 leveldir_current->graphics_set,
3743 leveldir_current->identifier);
3746 /* ---------- reload if level set and also artwork set has changed ------- */
3747 if (leveldir_current_identifier[type] != leveldir_identifier &&
3748 (last_has_level_artwork_set[type] || has_level_artwork_set))
3749 artwork_new_identifier = artwork_current_identifier;
3751 leveldir_current_identifier[type] = leveldir_identifier;
3752 last_has_level_artwork_set[type] = has_level_artwork_set;
3755 if (type == ARTWORK_TYPE_GRAPHICS)
3756 printf("::: 1: '%s'\n", artwork_new_identifier);
3759 /* ---------- reload if "override artwork" setting has changed ----------- */
3760 if (last_override_level_artwork[type] != setup_override_artwork)
3761 artwork_new_identifier = artwork_current_identifier;
3763 last_override_level_artwork[type] = setup_override_artwork;
3766 if (type == ARTWORK_TYPE_GRAPHICS)
3767 printf("::: 2: '%s'\n", artwork_new_identifier);
3770 /* ---------- reload if current artwork identifier has changed ----------- */
3771 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3772 artwork_current_identifier) != 0)
3773 artwork_new_identifier = artwork_current_identifier;
3775 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3778 if (type == ARTWORK_TYPE_GRAPHICS)
3779 printf("::: 3: '%s'\n", artwork_new_identifier);
3782 /* ---------- do not reload directly after starting ---------------------- */
3783 if (!initialized[type])
3784 artwork_new_identifier = NULL;
3786 initialized[type] = TRUE;
3789 if (type == ARTWORK_TYPE_GRAPHICS)
3790 printf("::: 4: '%s'\n", artwork_new_identifier);
3794 if (type == ARTWORK_TYPE_GRAPHICS)
3795 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3796 artwork.gfx_current_identifier, artwork_current_identifier,
3797 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3798 artwork_new_identifier);
3801 return artwork_new_identifier;
3804 void ReloadCustomArtwork()
3806 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3807 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3808 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3809 boolean redraw_screen = FALSE;
3811 if (gfx_new_identifier != NULL)
3814 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3815 artwork.gfx_current_identifier,
3817 artwork.gfx_current->identifier,
3818 leveldir_current->graphics_set);
3821 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3826 printf("... '%s'\n",
3827 leveldir_current->graphics_set);
3830 FreeTileClipmasks();
3831 InitTileClipmasks();
3833 redraw_screen = TRUE;
3836 if (snd_new_identifier != NULL)
3838 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3840 InitSound(snd_new_identifier);
3842 redraw_screen = TRUE;
3845 if (mus_new_identifier != NULL)
3847 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3849 InitMusic(mus_new_identifier);
3851 redraw_screen = TRUE;
3856 InitGfxBackground();
3858 /* force redraw of (open or closed) door graphics */
3859 SetDoorState(DOOR_OPEN_ALL);
3860 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3864 void KeyboardAutoRepeatOffUnlessAutoplay()
3866 if (global.autoplay_leveldir == NULL)
3867 KeyboardAutoRepeatOff();
3871 /* ========================================================================= */
3873 /* ========================================================================= */
3877 InitGlobal(); /* initialize some global variables */
3879 if (options.execute_command)
3880 Execute_Command(options.execute_command);
3882 if (options.serveronly)
3884 #if defined(PLATFORM_UNIX)
3885 NetworkServer(options.server_port, options.serveronly);
3887 Error(ERR_WARN, "networking only supported in Unix version");
3889 exit(0); /* never reached */
3895 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3896 InitArtworkConfig(); /* needed before forking sound child process */
3901 InitRND(NEW_RANDOMIZE);
3902 InitSimpleRND(NEW_RANDOMIZE);
3907 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3910 InitEventFilter(FilterMouseMotionEvents);
3912 InitElementPropertiesStatic();
3913 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3918 InitLevelArtworkInfo();
3920 InitImages(); /* needs to know current level directory */
3921 InitSound(NULL); /* needs to know current level directory */
3922 InitMusic(NULL); /* needs to know current level directory */
3924 InitGfxBackground();
3926 if (global.autoplay_leveldir)
3932 game_status = GAME_MODE_MAIN;
3936 InitNetworkServer();
3939 void CloseAllAndExit(int exit_value)
3944 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3947 FreeTileClipmasks();
3949 CloseVideoDisplay();
3950 ClosePlatformDependentStuff();