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 = (act == ACTION_DIGGING ||
618 act == ACTION_SNAPPING ||
619 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 */
829 graphic_info[graphic].anim_delay_fixed = 0;
830 graphic_info[graphic].anim_delay_random = 0;
831 graphic_info[graphic].post_delay_fixed = 0;
832 graphic_info[graphic].post_delay_random = 0;
834 /* optional x and y tile position of animation frame sequence */
835 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
836 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
837 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
838 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
840 /* optional x and y pixel position of animation frame sequence */
841 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
842 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
843 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
844 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
846 /* optional width and height of each animation frame */
847 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
848 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
849 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
850 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
854 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
855 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
858 /* correct x or y offset dependent of vertical or horizontal frame order */
859 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
861 graphic_info[graphic].offset_y =
862 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
863 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
864 anim_frames_per_line = anim_frames_per_col;
866 else /* frames are ordered horizontally */
868 graphic_info[graphic].offset_x =
869 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
870 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
871 anim_frames_per_line = anim_frames_per_row;
874 /* optionally, the x and y offset of frames can be specified directly */
875 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
876 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
877 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
878 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
880 /* automatically determine correct number of frames, if not defined */
881 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
882 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
883 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
884 graphic_info[graphic].anim_frames = anim_frames_per_row;
885 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
886 graphic_info[graphic].anim_frames = anim_frames_per_col;
888 graphic_info[graphic].anim_frames = 1;
890 graphic_info[graphic].anim_frames_per_line =
891 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
892 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
894 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
895 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
896 graphic_info[graphic].anim_delay = 1;
898 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
900 if (graphic_info[graphic].anim_frames == 1)
901 graphic_info[graphic].anim_mode = ANIM_NONE;
904 /* automatically determine correct start frame, if not defined */
905 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
906 graphic_info[graphic].anim_start_frame = 0;
907 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
908 graphic_info[graphic].anim_start_frame =
909 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
911 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
913 /* animation synchronized with global frame counter, not move position */
914 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
916 /* optional element for cloning crumble graphics */
917 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
918 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
920 /* optional element for cloning digging graphics */
921 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
922 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
924 /* optional border size for "crumbling" diggable graphics */
925 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
926 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
928 /* this is only used for player "boring" and "sleeping" actions */
929 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
930 graphic_info[graphic].anim_delay_fixed =
931 parameter[GFX_ARG_ANIM_DELAY_FIXED];
932 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
933 graphic_info[graphic].anim_delay_random =
934 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
935 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
936 graphic_info[graphic].post_delay_fixed =
937 parameter[GFX_ARG_POST_DELAY_FIXED];
938 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
939 graphic_info[graphic].post_delay_random =
940 parameter[GFX_ARG_POST_DELAY_RANDOM];
942 /* this is only used for toon animations */
943 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
944 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
946 /* this is only used for drawing font characters */
947 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
948 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
950 /* this is only used for drawing envelope graphics */
951 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
954 static void InitGraphicInfo()
956 int fallback_graphic = IMG_CHAR_EXCLAM;
957 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
958 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
959 int num_images = getImageListSize();
962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
963 static boolean clipmasks_initialized = FALSE;
965 XGCValues clip_gc_values;
966 unsigned long clip_gc_valuemask;
967 GC copy_clipmask_gc = None;
970 checked_free(graphic_info);
972 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
975 printf("::: graphic_info: %d entries\n", num_images);
978 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
979 if (clipmasks_initialized)
981 for (i = 0; i < num_images; i++)
983 if (graphic_info[i].clip_mask)
984 XFreePixmap(display, graphic_info[i].clip_mask);
985 if (graphic_info[i].clip_gc)
986 XFreeGC(display, graphic_info[i].clip_gc);
988 graphic_info[i].clip_mask = None;
989 graphic_info[i].clip_gc = None;
994 for (i = 0; i < num_images; i++)
996 struct FileInfo *image = getImageListEntry(i);
999 int first_frame, last_frame;
1002 printf("::: image: '%s' [%d]\n", image->token, i);
1006 printf("::: image # %d: '%s' ['%s']\n",
1008 getTokenFromImageID(i));
1011 set_graphic_parameters(i, image->parameter);
1013 /* now check if no animation frames are outside of the loaded image */
1015 if (graphic_info[i].bitmap == NULL)
1016 continue; /* skip check for optional images that are undefined */
1019 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1020 if (src_x < 0 || src_y < 0 ||
1021 src_x + TILEX > src_bitmap->width ||
1022 src_y + TILEY > src_bitmap->height)
1024 Error(ERR_RETURN_LINE, "-");
1025 Error(ERR_RETURN, "warning: error found in config file:");
1026 Error(ERR_RETURN, "- config file: '%s'",
1027 getImageConfigFilename());
1028 Error(ERR_RETURN, "- config token: '%s'",
1029 getTokenFromImageID(i));
1030 Error(ERR_RETURN, "- image file: '%s'",
1031 src_bitmap->source_filename);
1033 "error: first animation frame out of bounds (%d, %d)",
1035 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1037 if (i == fallback_graphic)
1038 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1040 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1041 Error(ERR_RETURN_LINE, "-");
1043 set_graphic_parameters(i, fallback_image->default_parameter);
1044 graphic_info[i].bitmap = fallback_bitmap;
1047 last_frame = graphic_info[i].anim_frames - 1;
1048 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1049 if (src_x < 0 || src_y < 0 ||
1050 src_x + TILEX > src_bitmap->width ||
1051 src_y + TILEY > src_bitmap->height)
1053 Error(ERR_RETURN_LINE, "-");
1054 Error(ERR_RETURN, "warning: error found in config file:");
1055 Error(ERR_RETURN, "- config file: '%s'",
1056 getImageConfigFilename());
1057 Error(ERR_RETURN, "- config token: '%s'",
1058 getTokenFromImageID(i));
1059 Error(ERR_RETURN, "- image file: '%s'",
1060 src_bitmap->source_filename);
1062 "error: last animation frame (%d) out of bounds (%d, %d)",
1063 last_frame, src_x, src_y);
1064 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1066 if (i == fallback_graphic)
1067 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1069 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1070 Error(ERR_RETURN_LINE, "-");
1072 set_graphic_parameters(i, fallback_image->default_parameter);
1073 graphic_info[i].bitmap = fallback_bitmap;
1076 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1077 /* currently we need only a tile clip mask from the first frame */
1078 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1080 if (copy_clipmask_gc == None)
1082 clip_gc_values.graphics_exposures = False;
1083 clip_gc_valuemask = GCGraphicsExposures;
1084 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1085 clip_gc_valuemask, &clip_gc_values);
1088 graphic_info[i].clip_mask =
1089 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1091 src_pixmap = src_bitmap->clip_mask;
1092 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1093 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1095 clip_gc_values.graphics_exposures = False;
1096 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1097 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1099 graphic_info[i].clip_gc =
1100 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1104 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1105 if (copy_clipmask_gc)
1106 XFreeGC(display, copy_clipmask_gc);
1108 clipmasks_initialized = TRUE;
1112 static void InitElementSoundInfo()
1114 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1115 int num_property_mappings = getSoundListPropertyMappingSize();
1118 /* set values to -1 to identify later as "uninitialized" values */
1119 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1120 for (act = 0; act < NUM_ACTIONS; act++)
1121 element_info[i].sound[act] = -1;
1123 /* initialize element/sound mapping from static configuration */
1124 for (i = 0; element_to_sound[i].element > -1; i++)
1126 int element = element_to_sound[i].element;
1127 int action = element_to_sound[i].action;
1128 int sound = element_to_sound[i].sound;
1129 boolean is_class = element_to_sound[i].is_class;
1132 action = ACTION_DEFAULT;
1135 element_info[element].sound[action] = sound;
1137 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1138 if (strcmp(element_info[j].class_name,
1139 element_info[element].class_name) == 0)
1140 element_info[j].sound[action] = sound;
1143 /* initialize element class/sound mapping from dynamic configuration */
1144 for (i = 0; i < num_property_mappings; i++)
1146 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1147 int action = property_mapping[i].ext1_index;
1148 int sound = property_mapping[i].artwork_index;
1150 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1154 action = ACTION_DEFAULT;
1156 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1157 if (strcmp(element_info[j].class_name,
1158 element_info[element_class].class_name) == 0)
1159 element_info[j].sound[action] = sound;
1162 /* initialize element/sound mapping from dynamic configuration */
1163 for (i = 0; i < num_property_mappings; i++)
1165 int element = property_mapping[i].base_index;
1166 int action = property_mapping[i].ext1_index;
1167 int sound = property_mapping[i].artwork_index;
1169 if (element >= MAX_NUM_ELEMENTS)
1173 action = ACTION_DEFAULT;
1175 element_info[element].sound[action] = sound;
1178 /* now set all '-1' values to element specific default values */
1179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1181 for (act = 0; act < NUM_ACTIONS; act++)
1183 /* generic default action sound (defined by "[default]" directive) */
1184 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1186 /* look for special default action sound (classic game specific) */
1187 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1188 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1189 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1190 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1191 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1192 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1194 /* !!! there's no such thing as a "default action sound" !!! */
1196 /* look for element specific default sound (independent from action) */
1197 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1198 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1201 /* no sound for this specific action -- use default action sound */
1202 if (element_info[i].sound[act] == -1)
1203 element_info[i].sound[act] = default_action_sound;
1208 static void InitGameModeSoundInfo()
1212 /* set values to -1 to identify later as "uninitialized" values */
1213 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1216 /* initialize gamemode/sound mapping from static configuration */
1217 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1219 int gamemode = gamemode_to_sound[i].gamemode;
1220 int sound = gamemode_to_sound[i].sound;
1223 gamemode = GAME_MODE_DEFAULT;
1225 menu.sound[gamemode] = sound;
1228 /* now set all '-1' values to levelset specific default values */
1229 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1230 if (menu.sound[i] == -1)
1231 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1235 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1236 if (menu.sound[i] != -1)
1237 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1241 static void set_sound_parameters(int sound, char **parameter_raw)
1243 int parameter[NUM_SND_ARGS];
1246 /* get integer values from string parameters */
1247 for (i = 0; i < NUM_SND_ARGS; i++)
1249 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1250 sound_config_suffix[i].type);
1252 /* explicit loop mode setting in configuration overrides default value */
1253 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1254 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1257 static void InitSoundInfo()
1260 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1261 int num_property_mappings = getSoundListPropertyMappingSize();
1263 int *sound_effect_properties;
1264 int num_sounds = getSoundListSize();
1267 checked_free(sound_info);
1269 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1270 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1272 /* initialize sound effect for all elements to "no sound" */
1273 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1274 for (j = 0; j < NUM_ACTIONS; j++)
1275 element_info[i].sound[j] = SND_UNDEFINED;
1277 for (i = 0; i < num_sounds; i++)
1279 struct FileInfo *sound = getSoundListEntry(i);
1280 int len_effect_text = strlen(sound->token);
1282 sound_effect_properties[i] = ACTION_OTHER;
1283 sound_info[i].loop = FALSE; /* default: play sound only once */
1286 printf("::: sound %d: '%s'\n", i, sound->token);
1289 /* determine all loop sounds and identify certain sound classes */
1291 for (j = 0; element_action_info[j].suffix; j++)
1293 int len_action_text = strlen(element_action_info[j].suffix);
1295 if (len_action_text < len_effect_text &&
1296 strcmp(&sound->token[len_effect_text - len_action_text],
1297 element_action_info[j].suffix) == 0)
1299 sound_effect_properties[i] = element_action_info[j].value;
1300 sound_info[i].loop = element_action_info[j].is_loop_sound;
1307 if (strcmp(sound->token, "custom_42") == 0)
1308 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1311 /* associate elements and some selected sound actions */
1313 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1315 if (element_info[j].class_name)
1317 int len_class_text = strlen(element_info[j].class_name);
1319 if (len_class_text + 1 < len_effect_text &&
1320 strncmp(sound->token,
1321 element_info[j].class_name, len_class_text) == 0 &&
1322 sound->token[len_class_text] == '.')
1324 int sound_action_value = sound_effect_properties[i];
1326 element_info[j].sound[sound_action_value] = i;
1331 set_sound_parameters(i, sound->parameter);
1334 free(sound_effect_properties);
1337 /* !!! now handled in InitElementSoundInfo() !!! */
1338 /* initialize element/sound mapping from dynamic configuration */
1339 for (i = 0; i < num_property_mappings; i++)
1341 int element = property_mapping[i].base_index;
1342 int action = property_mapping[i].ext1_index;
1343 int sound = property_mapping[i].artwork_index;
1346 action = ACTION_DEFAULT;
1348 printf("::: %d: %d, %d, %d ['%s']\n",
1349 i, element, action, sound, element_info[element].token_name);
1351 element_info[element].sound[action] = sound;
1358 int element = EL_CUSTOM_11;
1361 while (element_action_info[j].suffix)
1363 printf("element %d, sound action '%s' == %d\n",
1364 element, element_action_info[j].suffix,
1365 element_info[element].sound[j]);
1370 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1376 int element = EL_SAND;
1377 int sound_action = ACTION_DIGGING;
1380 while (element_action_info[j].suffix)
1382 if (element_action_info[j].value == sound_action)
1383 printf("element %d, sound action '%s' == %d\n",
1384 element, element_action_info[j].suffix,
1385 element_info[element].sound[sound_action]);
1392 static void InitGameModeMusicInfo()
1394 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1395 int num_property_mappings = getMusicListPropertyMappingSize();
1396 int default_levelset_music = -1;
1399 /* set values to -1 to identify later as "uninitialized" values */
1400 for (i = 0; i < MAX_LEVELS; i++)
1401 levelset.music[i] = -1;
1402 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1405 /* initialize gamemode/music mapping from static configuration */
1406 for (i = 0; gamemode_to_music[i].music > -1; i++)
1408 int gamemode = gamemode_to_music[i].gamemode;
1409 int music = gamemode_to_music[i].music;
1412 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1416 gamemode = GAME_MODE_DEFAULT;
1418 menu.music[gamemode] = music;
1421 /* initialize gamemode/music mapping from dynamic configuration */
1422 for (i = 0; i < num_property_mappings; i++)
1424 int prefix = property_mapping[i].base_index;
1425 int gamemode = property_mapping[i].ext1_index;
1426 int level = property_mapping[i].ext2_index;
1427 int music = property_mapping[i].artwork_index;
1430 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1431 prefix, gamemode, level, music);
1434 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1438 gamemode = GAME_MODE_DEFAULT;
1440 /* level specific music only allowed for in-game music */
1441 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1442 gamemode = GAME_MODE_PLAYING;
1447 default_levelset_music = music;
1450 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1451 levelset.music[level] = music;
1452 if (gamemode != GAME_MODE_PLAYING)
1453 menu.music[gamemode] = music;
1456 /* now set all '-1' values to menu specific default values */
1457 /* (undefined values of "levelset.music[]" might stay at "-1" to
1458 allow dynamic selection of music files from music directory!) */
1459 for (i = 0; i < MAX_LEVELS; i++)
1460 if (levelset.music[i] == -1)
1461 levelset.music[i] = default_levelset_music;
1462 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1463 if (menu.music[i] == -1)
1464 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1468 for (i = 0; i < MAX_LEVELS; i++)
1469 if (levelset.music[i] != -1)
1470 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1471 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1472 if (menu.music[i] != -1)
1473 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1477 static void set_music_parameters(int music, char **parameter_raw)
1479 int parameter[NUM_MUS_ARGS];
1482 /* get integer values from string parameters */
1483 for (i = 0; i < NUM_MUS_ARGS; i++)
1485 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1486 music_config_suffix[i].type);
1488 /* explicit loop mode setting in configuration overrides default value */
1489 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1490 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1493 static void InitMusicInfo()
1495 int num_music = getMusicListSize();
1498 checked_free(music_info);
1500 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1502 for (i = 0; i < num_music; i++)
1504 struct FileInfo *music = getMusicListEntry(i);
1505 int len_music_text = strlen(music->token);
1507 music_info[i].loop = TRUE; /* default: play music in loop mode */
1509 /* determine all loop music */
1511 for (j = 0; music_prefix_info[j].prefix; j++)
1513 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1515 if (len_prefix_text < len_music_text &&
1516 strncmp(music->token,
1517 music_prefix_info[j].prefix, len_prefix_text) == 0)
1519 music_info[i].loop = music_prefix_info[j].is_loop_music;
1525 set_music_parameters(i, music->parameter);
1529 static void ReinitializeGraphics()
1531 InitGraphicInfo(); /* graphic properties mapping */
1532 InitElementGraphicInfo(); /* element game graphic mapping */
1533 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1535 InitElementSmallImages(); /* create editor and preview images */
1536 InitFontGraphicInfo(); /* initialize text drawing functions */
1538 SetMainBackgroundImage(IMG_BACKGROUND);
1539 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1545 static void ReinitializeSounds()
1547 InitSoundInfo(); /* sound properties mapping */
1548 InitElementSoundInfo(); /* element game sound mapping */
1549 InitGameModeSoundInfo(); /* game mode sound mapping */
1551 InitPlayLevelSound(); /* internal game sound settings */
1554 static void ReinitializeMusic()
1556 InitMusicInfo(); /* music properties mapping */
1557 InitGameModeMusicInfo(); /* game mode music mapping */
1560 void InitElementPropertiesStatic()
1562 static int ep_diggable[] =
1567 EL_SP_BUGGY_BASE_ACTIVATING,
1570 EL_INVISIBLE_SAND_ACTIVE,
1572 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1576 EL_SP_BUGGY_BASE_ACTIVE,
1581 static int ep_collectible_only[] =
1598 EL_DYNABOMB_INCREASE_NUMBER,
1599 EL_DYNABOMB_INCREASE_SIZE,
1600 EL_DYNABOMB_INCREASE_POWER,
1617 static int ep_dont_run_into[] =
1619 /* same elements as in 'ep_dont_touch' */
1625 /* same elements as in 'ep_dont_collide_with' */
1637 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1641 EL_SP_BUGGY_BASE_ACTIVE,
1646 static int ep_dont_collide_with[] =
1648 /* same elements as in 'ep_dont_touch' */
1664 static int ep_dont_touch[] =
1673 static int ep_indestructible[] =
1677 EL_ACID_POOL_TOPLEFT,
1678 EL_ACID_POOL_TOPRIGHT,
1679 EL_ACID_POOL_BOTTOMLEFT,
1680 EL_ACID_POOL_BOTTOM,
1681 EL_ACID_POOL_BOTTOMRIGHT,
1682 EL_SP_HARDWARE_GRAY,
1683 EL_SP_HARDWARE_GREEN,
1684 EL_SP_HARDWARE_BLUE,
1686 EL_SP_HARDWARE_YELLOW,
1687 EL_SP_HARDWARE_BASE_1,
1688 EL_SP_HARDWARE_BASE_2,
1689 EL_SP_HARDWARE_BASE_3,
1690 EL_SP_HARDWARE_BASE_4,
1691 EL_SP_HARDWARE_BASE_5,
1692 EL_SP_HARDWARE_BASE_6,
1693 EL_INVISIBLE_STEELWALL,
1694 EL_INVISIBLE_STEELWALL_ACTIVE,
1695 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1696 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1697 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1698 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1699 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1700 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1701 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1702 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1703 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1704 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1705 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1706 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1708 EL_LIGHT_SWITCH_ACTIVE,
1709 EL_SIGN_EXCLAMATION,
1710 EL_SIGN_RADIOACTIVITY,
1721 EL_STEELWALL_SLIPPERY,
1744 EL_SWITCHGATE_OPENING,
1745 EL_SWITCHGATE_CLOSED,
1746 EL_SWITCHGATE_CLOSING,
1748 EL_SWITCHGATE_SWITCH_UP,
1749 EL_SWITCHGATE_SWITCH_DOWN,
1752 EL_TIMEGATE_OPENING,
1754 EL_TIMEGATE_CLOSING,
1757 EL_TIMEGATE_SWITCH_ACTIVE,
1762 EL_TUBE_VERTICAL_LEFT,
1763 EL_TUBE_VERTICAL_RIGHT,
1764 EL_TUBE_HORIZONTAL_UP,
1765 EL_TUBE_HORIZONTAL_DOWN,
1773 static int ep_slippery[] =
1787 EL_ROBOT_WHEEL_ACTIVE,
1793 EL_ACID_POOL_TOPLEFT,
1794 EL_ACID_POOL_TOPRIGHT,
1804 EL_STEELWALL_SLIPPERY,
1810 static int ep_can_change[] =
1815 static int ep_can_move[] =
1838 static int ep_can_fall[] =
1853 EL_BD_MAGIC_WALL_FULL,
1866 static int ep_can_smash_player[] =
1891 static int ep_can_smash_enemies[] =
1899 static int ep_can_smash_everything[] =
1907 static int ep_can_explode_by_fire[] =
1909 /* same elements as in 'ep_can_explode_impact' */
1914 /* same elements as in 'ep_can_explode_smashed' */
1923 EL_DYNABOMB_PLAYER_1_ACTIVE,
1924 EL_DYNABOMB_PLAYER_2_ACTIVE,
1925 EL_DYNABOMB_PLAYER_3_ACTIVE,
1926 EL_DYNABOMB_PLAYER_4_ACTIVE,
1927 EL_DYNABOMB_INCREASE_NUMBER,
1928 EL_DYNABOMB_INCREASE_SIZE,
1929 EL_DYNABOMB_INCREASE_POWER,
1930 EL_SP_DISK_RED_ACTIVE,
1940 static int ep_can_explode_smashed[] =
1942 /* same elements as in 'ep_can_explode_impact' */
1955 static int ep_can_explode_impact[] =
1963 static int ep_walkable_over[] =
1967 EL_SOKOBAN_FIELD_EMPTY,
1985 static int ep_walkable_inside[] =
1990 EL_TUBE_VERTICAL_LEFT,
1991 EL_TUBE_VERTICAL_RIGHT,
1992 EL_TUBE_HORIZONTAL_UP,
1993 EL_TUBE_HORIZONTAL_DOWN,
2001 static int ep_walkable_under[] =
2006 static int ep_passable_over[] =
2021 static int ep_passable_inside[] =
2027 EL_SP_PORT_HORIZONTAL,
2028 EL_SP_PORT_VERTICAL,
2030 EL_SP_GRAVITY_PORT_LEFT,
2031 EL_SP_GRAVITY_PORT_RIGHT,
2032 EL_SP_GRAVITY_PORT_UP,
2033 EL_SP_GRAVITY_PORT_DOWN,
2037 static int ep_passable_under[] =
2042 static int ep_droppable[] =
2047 static int ep_can_explode_1x1[] =
2052 static int ep_pushable[] =
2064 EL_SOKOBAN_FIELD_FULL,
2071 static int ep_player[] =
2081 static int ep_can_pass_magic_wall[] =
2094 static int ep_switchable[] =
2098 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2099 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2100 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2101 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2102 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2103 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2104 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2105 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2106 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2107 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2108 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2109 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2110 EL_SWITCHGATE_SWITCH_UP,
2111 EL_SWITCHGATE_SWITCH_DOWN,
2113 EL_LIGHT_SWITCH_ACTIVE,
2115 EL_BALLOON_SWITCH_LEFT,
2116 EL_BALLOON_SWITCH_RIGHT,
2117 EL_BALLOON_SWITCH_UP,
2118 EL_BALLOON_SWITCH_DOWN,
2119 EL_BALLOON_SWITCH_ANY,
2125 static int ep_bd_element[] =
2154 static int ep_sp_element[] =
2156 /* should always be valid */
2165 EL_SP_HARDWARE_GRAY,
2173 EL_SP_GRAVITY_PORT_RIGHT,
2174 EL_SP_GRAVITY_PORT_DOWN,
2175 EL_SP_GRAVITY_PORT_LEFT,
2176 EL_SP_GRAVITY_PORT_UP,
2181 EL_SP_PORT_VERTICAL,
2182 EL_SP_PORT_HORIZONTAL,
2188 EL_SP_HARDWARE_BASE_1,
2189 EL_SP_HARDWARE_GREEN,
2190 EL_SP_HARDWARE_BLUE,
2192 EL_SP_HARDWARE_YELLOW,
2193 EL_SP_HARDWARE_BASE_2,
2194 EL_SP_HARDWARE_BASE_3,
2195 EL_SP_HARDWARE_BASE_4,
2196 EL_SP_HARDWARE_BASE_5,
2197 EL_SP_HARDWARE_BASE_6,
2200 /* additional elements that appeared in newer Supaplex levels */
2202 /* more than one murphy in a level results in an inactive clone */
2204 /* runtime elements*/
2205 EL_SP_DISK_RED_ACTIVE,
2206 EL_SP_TERMINAL_ACTIVE,
2207 EL_SP_BUGGY_BASE_ACTIVATING,
2208 EL_SP_BUGGY_BASE_ACTIVE,
2214 static int ep_sb_element[] =
2219 EL_SOKOBAN_FIELD_EMPTY,
2220 EL_SOKOBAN_FIELD_FULL,
2222 EL_INVISIBLE_STEELWALL,
2226 static int ep_gem[] =
2237 static int ep_food_dark_yamyam[] =
2264 static int ep_food_penguin[] =
2277 static int ep_food_pig[] =
2288 static int ep_historic_wall[] =
2313 EL_EXPANDABLE_WALL_HORIZONTAL,
2314 EL_EXPANDABLE_WALL_VERTICAL,
2315 EL_EXPANDABLE_WALL_ANY,
2316 EL_EXPANDABLE_WALL_GROWING,
2323 EL_SP_HARDWARE_GRAY,
2324 EL_SP_HARDWARE_GREEN,
2325 EL_SP_HARDWARE_BLUE,
2327 EL_SP_HARDWARE_YELLOW,
2328 EL_SP_HARDWARE_BASE_1,
2329 EL_SP_HARDWARE_BASE_2,
2330 EL_SP_HARDWARE_BASE_3,
2331 EL_SP_HARDWARE_BASE_4,
2332 EL_SP_HARDWARE_BASE_5,
2333 EL_SP_HARDWARE_BASE_6,
2335 EL_SP_TERMINAL_ACTIVE,
2338 EL_INVISIBLE_STEELWALL,
2339 EL_INVISIBLE_STEELWALL_ACTIVE,
2341 EL_INVISIBLE_WALL_ACTIVE,
2342 EL_STEELWALL_SLIPPERY,
2358 static int ep_historic_solid[] =
2362 EL_EXPANDABLE_WALL_HORIZONTAL,
2363 EL_EXPANDABLE_WALL_VERTICAL,
2364 EL_EXPANDABLE_WALL_ANY,
2377 EL_QUICKSAND_FILLING,
2378 EL_QUICKSAND_EMPTYING,
2380 EL_MAGIC_WALL_ACTIVE,
2381 EL_MAGIC_WALL_EMPTYING,
2382 EL_MAGIC_WALL_FILLING,
2386 EL_BD_MAGIC_WALL_ACTIVE,
2387 EL_BD_MAGIC_WALL_EMPTYING,
2388 EL_BD_MAGIC_WALL_FULL,
2389 EL_BD_MAGIC_WALL_FILLING,
2390 EL_BD_MAGIC_WALL_DEAD,
2399 EL_SP_TERMINAL_ACTIVE,
2403 EL_INVISIBLE_WALL_ACTIVE,
2404 EL_SWITCHGATE_SWITCH_UP,
2405 EL_SWITCHGATE_SWITCH_DOWN,
2407 EL_TIMEGATE_SWITCH_ACTIVE,
2419 /* the following elements are a direct copy of "indestructible" elements,
2420 except "EL_ACID", which is "indestructible", but not "solid"! */
2425 EL_ACID_POOL_TOPLEFT,
2426 EL_ACID_POOL_TOPRIGHT,
2427 EL_ACID_POOL_BOTTOMLEFT,
2428 EL_ACID_POOL_BOTTOM,
2429 EL_ACID_POOL_BOTTOMRIGHT,
2430 EL_SP_HARDWARE_GRAY,
2431 EL_SP_HARDWARE_GREEN,
2432 EL_SP_HARDWARE_BLUE,
2434 EL_SP_HARDWARE_YELLOW,
2435 EL_SP_HARDWARE_BASE_1,
2436 EL_SP_HARDWARE_BASE_2,
2437 EL_SP_HARDWARE_BASE_3,
2438 EL_SP_HARDWARE_BASE_4,
2439 EL_SP_HARDWARE_BASE_5,
2440 EL_SP_HARDWARE_BASE_6,
2441 EL_INVISIBLE_STEELWALL,
2442 EL_INVISIBLE_STEELWALL_ACTIVE,
2443 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2444 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2445 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2446 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2447 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2448 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2449 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2450 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2451 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2452 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2453 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2454 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2456 EL_LIGHT_SWITCH_ACTIVE,
2457 EL_SIGN_EXCLAMATION,
2458 EL_SIGN_RADIOACTIVITY,
2469 EL_STEELWALL_SLIPPERY,
2492 EL_SWITCHGATE_OPENING,
2493 EL_SWITCHGATE_CLOSED,
2494 EL_SWITCHGATE_CLOSING,
2496 EL_TIMEGATE_OPENING,
2498 EL_TIMEGATE_CLOSING,
2502 EL_TUBE_VERTICAL_LEFT,
2503 EL_TUBE_VERTICAL_RIGHT,
2504 EL_TUBE_HORIZONTAL_UP,
2505 EL_TUBE_HORIZONTAL_DOWN,
2513 static int ep_classic_enemy[] =
2529 static int ep_belt[] =
2531 EL_CONVEYOR_BELT_1_LEFT,
2532 EL_CONVEYOR_BELT_1_MIDDLE,
2533 EL_CONVEYOR_BELT_1_RIGHT,
2534 EL_CONVEYOR_BELT_2_LEFT,
2535 EL_CONVEYOR_BELT_2_MIDDLE,
2536 EL_CONVEYOR_BELT_2_RIGHT,
2537 EL_CONVEYOR_BELT_3_LEFT,
2538 EL_CONVEYOR_BELT_3_MIDDLE,
2539 EL_CONVEYOR_BELT_3_RIGHT,
2540 EL_CONVEYOR_BELT_4_LEFT,
2541 EL_CONVEYOR_BELT_4_MIDDLE,
2542 EL_CONVEYOR_BELT_4_RIGHT,
2546 static int ep_belt_active[] =
2548 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2549 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2550 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2551 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2552 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2553 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2554 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2555 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2556 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2557 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2558 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2559 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2563 static int ep_belt_switch[] =
2565 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2566 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2567 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2568 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2569 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2570 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2571 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2572 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2573 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2574 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2575 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2576 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2580 static int ep_tube[] =
2587 EL_TUBE_HORIZONTAL_UP,
2588 EL_TUBE_HORIZONTAL_DOWN,
2590 EL_TUBE_VERTICAL_LEFT,
2591 EL_TUBE_VERTICAL_RIGHT,
2596 static int ep_keygate[] =
2617 static int ep_amoeboid[] =
2627 static int ep_amoebalive[] =
2636 static int ep_has_content[] =
2646 static int ep_active_bomb[] =
2649 EL_DYNABOMB_PLAYER_1_ACTIVE,
2650 EL_DYNABOMB_PLAYER_2_ACTIVE,
2651 EL_DYNABOMB_PLAYER_3_ACTIVE,
2652 EL_DYNABOMB_PLAYER_4_ACTIVE,
2653 EL_SP_DISK_RED_ACTIVE,
2657 static int ep_inactive[] =
2694 EL_INVISIBLE_STEELWALL,
2702 EL_WALL_EMERALD_YELLOW,
2703 EL_DYNABOMB_INCREASE_NUMBER,
2704 EL_DYNABOMB_INCREASE_SIZE,
2705 EL_DYNABOMB_INCREASE_POWER,
2709 EL_SOKOBAN_FIELD_EMPTY,
2710 EL_SOKOBAN_FIELD_FULL,
2711 EL_WALL_EMERALD_RED,
2712 EL_WALL_EMERALD_PURPLE,
2713 EL_ACID_POOL_TOPLEFT,
2714 EL_ACID_POOL_TOPRIGHT,
2715 EL_ACID_POOL_BOTTOMLEFT,
2716 EL_ACID_POOL_BOTTOM,
2717 EL_ACID_POOL_BOTTOMRIGHT,
2721 EL_BD_MAGIC_WALL_DEAD,
2722 EL_AMOEBA_TO_DIAMOND,
2730 EL_SP_GRAVITY_PORT_RIGHT,
2731 EL_SP_GRAVITY_PORT_DOWN,
2732 EL_SP_GRAVITY_PORT_LEFT,
2733 EL_SP_GRAVITY_PORT_UP,
2734 EL_SP_PORT_HORIZONTAL,
2735 EL_SP_PORT_VERTICAL,
2746 EL_SP_HARDWARE_GRAY,
2747 EL_SP_HARDWARE_GREEN,
2748 EL_SP_HARDWARE_BLUE,
2750 EL_SP_HARDWARE_YELLOW,
2751 EL_SP_HARDWARE_BASE_1,
2752 EL_SP_HARDWARE_BASE_2,
2753 EL_SP_HARDWARE_BASE_3,
2754 EL_SP_HARDWARE_BASE_4,
2755 EL_SP_HARDWARE_BASE_5,
2756 EL_SP_HARDWARE_BASE_6,
2757 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2758 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2759 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2760 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2761 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2762 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2763 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2764 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2765 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2766 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2767 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2768 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2769 EL_SIGN_EXCLAMATION,
2770 EL_SIGN_RADIOACTIVITY,
2781 EL_STEELWALL_SLIPPERY,
2797 static int ep_em_slippery_wall[] =
2802 static int ep_gfx_crumbled[] =
2815 } element_properties[] =
2817 { ep_diggable, EP_DIGGABLE },
2818 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
2819 { ep_dont_run_into, EP_DONT_RUN_INTO },
2820 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2821 { ep_dont_touch, EP_DONT_TOUCH },
2822 { ep_indestructible, EP_INDESTRUCTIBLE },
2823 { ep_slippery, EP_SLIPPERY },
2824 { ep_can_change, EP_CAN_CHANGE },
2825 { ep_can_move, EP_CAN_MOVE },
2826 { ep_can_fall, EP_CAN_FALL },
2827 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2828 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2829 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2830 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2831 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2832 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2833 { ep_walkable_over, EP_WALKABLE_OVER },
2834 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2835 { ep_walkable_under, EP_WALKABLE_UNDER },
2836 { ep_passable_over, EP_PASSABLE_OVER },
2837 { ep_passable_inside, EP_PASSABLE_INSIDE },
2838 { ep_passable_under, EP_PASSABLE_UNDER },
2839 { ep_droppable, EP_DROPPABLE },
2840 { ep_can_explode_1x1, EP_CAN_EXPLODE_1X1 },
2841 { ep_pushable, EP_PUSHABLE },
2843 { ep_player, EP_PLAYER },
2844 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2845 { ep_switchable, EP_SWITCHABLE },
2846 { ep_bd_element, EP_BD_ELEMENT },
2847 { ep_sp_element, EP_SP_ELEMENT },
2848 { ep_sb_element, EP_SB_ELEMENT },
2850 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2851 { ep_food_penguin, EP_FOOD_PENGUIN },
2852 { ep_food_pig, EP_FOOD_PIG },
2853 { ep_historic_wall, EP_HISTORIC_WALL },
2854 { ep_historic_solid, EP_HISTORIC_SOLID },
2855 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2856 { ep_belt, EP_BELT },
2857 { ep_belt_active, EP_BELT_ACTIVE },
2858 { ep_belt_switch, EP_BELT_SWITCH },
2859 { ep_tube, EP_TUBE },
2860 { ep_keygate, EP_KEYGATE },
2861 { ep_amoeboid, EP_AMOEBOID },
2862 { ep_amoebalive, EP_AMOEBALIVE },
2863 { ep_has_content, EP_HAS_CONTENT },
2864 { ep_active_bomb, EP_ACTIVE_BOMB },
2865 { ep_inactive, EP_INACTIVE },
2867 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
2869 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
2874 static int copy_properties[][5] =
2878 EL_BUG_LEFT, EL_BUG_RIGHT,
2879 EL_BUG_UP, EL_BUG_DOWN
2883 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2884 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2888 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2889 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2893 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2894 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2898 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2899 EL_PACMAN_UP, EL_PACMAN_DOWN
2909 /* always start with reliable default values (element has no properties) */
2910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2911 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
2912 SET_PROPERTY(i, j, FALSE);
2914 /* set all base element properties from above array definitions */
2915 for (i = 0; element_properties[i].elements != NULL; i++)
2916 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
2917 SET_PROPERTY((element_properties[i].elements)[j],
2918 element_properties[i].property, TRUE);
2920 /* copy properties to some elements that are only stored in level file */
2921 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
2922 for (j = 0; copy_properties[j][0] != -1; j++)
2923 if (HAS_PROPERTY(copy_properties[j][0], i))
2924 for (k = 1; k <= 4; k++)
2925 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2928 void InitElementPropertiesEngine(int engine_version)
2931 static int active_properties[] =
2936 EP_DONT_COLLIDE_WITH,
2940 EP_CAN_PASS_MAGIC_WALL,
2945 EP_CAN_EXPLODE_BY_FIRE,
2958 EP_EM_SLIPPERY_WALL,
2962 static int no_wall_properties[] =
2965 EP_COLLECTIBLE_ONLY,
2967 EP_DONT_COLLIDE_WITH,
2970 EP_CAN_SMASH_PLAYER,
2971 EP_CAN_SMASH_ENEMIES,
2972 EP_CAN_SMASH_EVERYTHING,
2977 EP_FOOD_DARK_YAMYAM,
2993 InitElementPropertiesStatic();
2996 /* set all special, combined or engine dependent element properties */
2997 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3000 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3001 SET_PROPERTY(i, j, FALSE);
3004 /* ---------- INACTIVE ------------------------------------------------- */
3005 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
3006 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3008 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3009 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3010 IS_WALKABLE_INSIDE(i) ||
3011 IS_WALKABLE_UNDER(i)));
3013 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3014 IS_PASSABLE_INSIDE(i) ||
3015 IS_PASSABLE_UNDER(i)));
3017 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3018 IS_PASSABLE_OVER(i)));
3020 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3021 IS_PASSABLE_INSIDE(i)));
3023 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3024 IS_PASSABLE_UNDER(i)));
3026 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3029 /* ---------- COLLECTIBLE ---------------------------------------------- */
3030 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3033 /* ---------- SNAPPABLE ------------------------------------------------ */
3034 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3035 IS_COLLECTIBLE(i) ||
3039 /* ---------- WALL ----------------------------------------------------- */
3040 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3042 for (j = 0; no_wall_properties[j] != -1; j++)
3043 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3044 i >= EL_FIRST_RUNTIME_UNREAL)
3045 SET_PROPERTY(i, EP_WALL, FALSE);
3047 if (IS_HISTORIC_WALL(i))
3048 SET_PROPERTY(i, EP_WALL, TRUE);
3050 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3051 if (engine_version < VERSION_IDENT(2,2,0,0))
3052 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3054 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3056 !IS_COLLECTIBLE(i)));
3058 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3060 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3061 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3063 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3064 IS_INDESTRUCTIBLE(i)));
3066 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3068 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3069 else if (engine_version < VERSION_IDENT(2,2,0,0))
3070 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3072 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3073 !IS_WALKABLE_OVER(i) &&
3074 !IS_WALKABLE_UNDER(i)));
3076 if (IS_CUSTOM_ELEMENT(i))
3078 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3080 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3081 if (DONT_COLLIDE_WITH(i))
3082 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3084 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3085 if (CAN_SMASH_EVERYTHING(i))
3086 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3087 if (CAN_SMASH_ENEMIES(i))
3088 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3091 /* ---------- CAN_SMASH ------------------------------------------------ */
3092 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3093 CAN_SMASH_ENEMIES(i) ||
3094 CAN_SMASH_EVERYTHING(i)));
3096 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3097 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3098 CAN_EXPLODE_SMASHED(i) ||
3099 CAN_EXPLODE_IMPACT(i)));
3101 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3102 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3103 !CAN_EXPLODE_1X1(i)));
3105 /* ---------- CAN_CHANGE ----------------------------------------------- */
3106 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3107 for (j = 0; j < element_info[i].num_change_pages; j++)
3108 if (element_info[i].change_page[j].can_change)
3109 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3111 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3112 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3113 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3117 /* determine inactive elements (used for engine main loop optimization) */
3118 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3120 boolean active = FALSE;
3122 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3124 if (HAS_PROPERTY(i, j))
3130 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3135 /* dynamically adjust element properties according to game engine version */
3137 static int ep_em_slippery_wall[] =
3142 EL_EXPANDABLE_WALL_HORIZONTAL,
3143 EL_EXPANDABLE_WALL_VERTICAL,
3144 EL_EXPANDABLE_WALL_ANY,
3148 /* special EM style gems behaviour */
3149 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3150 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3151 level.em_slippery_gems);
3153 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3154 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3155 (level.em_slippery_gems &&
3156 engine_version > VERSION_IDENT(2,0,1,0)));
3160 /* set default push delay values (corrected since version 3.0.7-1) */
3161 if (engine_version < VERSION_IDENT(3,0,7,1))
3163 game.default_push_delay_fixed = 2;
3164 game.default_push_delay_random = 8;
3168 game.default_push_delay_fixed = 8;
3169 game.default_push_delay_random = 8;
3172 /* set uninitialized push delay values of custom elements in older levels */
3173 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3175 int element = EL_CUSTOM_START + i;
3177 if (element_info[element].push_delay_fixed == -1)
3178 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3179 if (element_info[element].push_delay_random == -1)
3180 element_info[element].push_delay_random = game.default_push_delay_random;
3185 static void InitGlobal()
3187 global.autoplay_leveldir = NULL;
3189 global.frames_per_second = 0;
3190 global.fps_slowdown = FALSE;
3191 global.fps_slowdown_factor = 1;
3194 void Execute_Command(char *command)
3198 if (strcmp(command, "print graphicsinfo.conf") == 0)
3200 printf("# You can configure additional/alternative image files here.\n");
3201 printf("# (The entries below are default and therefore commented out.)\n");
3203 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3205 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3208 for (i = 0; image_config[i].token != NULL; i++)
3209 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3210 image_config[i].value));
3214 else if (strcmp(command, "print soundsinfo.conf") == 0)
3216 printf("# You can configure additional/alternative sound files here.\n");
3217 printf("# (The entries below are default and therefore commented out.)\n");
3219 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3221 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3224 for (i = 0; sound_config[i].token != NULL; i++)
3225 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3226 sound_config[i].value));
3230 else if (strcmp(command, "print musicinfo.conf") == 0)
3232 printf("# You can configure additional/alternative music files here.\n");
3233 printf("# (The entries below are default and therefore commented out.)\n");
3235 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3237 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3240 for (i = 0; music_config[i].token != NULL; i++)
3241 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3242 music_config[i].value));
3246 else if (strcmp(command, "print editorsetup.conf") == 0)
3248 printf("# You can configure your personal editor element list here.\n");
3249 printf("# (The entries below are default and therefore commented out.)\n");
3252 PrintEditorElementList();
3256 else if (strcmp(command, "print helpanim.conf") == 0)
3258 printf("# You can configure different element help animations here.\n");
3259 printf("# (The entries below are default and therefore commented out.)\n");
3262 for (i = 0; helpanim_config[i].token != NULL; i++)
3264 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3265 helpanim_config[i].value));
3267 if (strcmp(helpanim_config[i].token, "end") == 0)
3273 else if (strcmp(command, "print helptext.conf") == 0)
3275 printf("# You can configure different element help text here.\n");
3276 printf("# (The entries below are default and therefore commented out.)\n");
3279 for (i = 0; helptext_config[i].token != NULL; i++)
3280 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3281 helptext_config[i].value));
3285 else if (strncmp(command, "dump level ", 11) == 0)
3287 char *filename = &command[11];
3289 if (access(filename, F_OK) != 0)
3290 Error(ERR_EXIT, "cannot open file '%s'", filename);
3292 LoadLevelFromFilename(&level, filename);
3297 else if (strncmp(command, "dump tape ", 10) == 0)
3299 char *filename = &command[10];
3301 if (access(filename, F_OK) != 0)
3302 Error(ERR_EXIT, "cannot open file '%s'", filename);
3304 LoadTapeFromFilename(filename);
3309 else if (strncmp(command, "autoplay ", 9) == 0)
3311 char *str_copy = getStringCopy(&command[9]);
3312 char *str_ptr = strchr(str_copy, ' ');
3314 global.autoplay_leveldir = str_copy;
3315 global.autoplay_level_nr = -1;
3317 if (str_ptr != NULL)
3319 *str_ptr++ = '\0'; /* terminate leveldir string */
3320 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3325 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3329 static void InitSetup()
3331 LoadSetup(); /* global setup info */
3333 /* set some options from setup file */
3335 if (setup.options.verbose)
3336 options.verbose = TRUE;
3339 static void InitPlayerInfo()
3343 /* choose default local player */
3344 local_player = &stored_player[0];
3346 for (i = 0; i < MAX_PLAYERS; i++)
3347 stored_player[i].connected = FALSE;
3349 local_player->connected = TRUE;
3352 static void InitArtworkInfo()
3357 static char *get_string_in_brackets(char *string)
3359 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3361 sprintf(string_in_brackets, "[%s]", string);
3363 return string_in_brackets;
3366 static char *get_level_id_suffix(int id_nr)
3368 char *id_suffix = checked_malloc(1 + 3 + 1);
3370 if (id_nr < 0 || id_nr > 999)
3373 sprintf(id_suffix, ".%03d", id_nr);
3379 static char *get_element_class_token(int element)
3381 char *element_class_name = element_info[element].class_name;
3382 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3384 sprintf(element_class_token, "[%s]", element_class_name);
3386 return element_class_token;
3389 static char *get_action_class_token(int action)
3391 char *action_class_name = &element_action_info[action].suffix[1];
3392 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3394 sprintf(action_class_token, "[%s]", action_class_name);
3396 return action_class_token;
3400 static void InitArtworkConfig()
3402 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3403 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3404 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3405 static char *action_id_suffix[NUM_ACTIONS + 1];
3406 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3407 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3408 static char *level_id_suffix[MAX_LEVELS + 1];
3409 static char *dummy[1] = { NULL };
3410 static char *ignore_generic_tokens[] =
3416 static char **ignore_image_tokens;
3417 static char **ignore_sound_tokens;
3418 static char **ignore_music_tokens;
3419 int num_ignore_generic_tokens;
3420 int num_ignore_image_tokens;
3421 int num_ignore_sound_tokens;
3422 int num_ignore_music_tokens;
3425 /* dynamically determine list of generic tokens to be ignored */
3426 num_ignore_generic_tokens = 0;
3427 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3428 num_ignore_generic_tokens++;
3430 /* dynamically determine list of image tokens to be ignored */
3431 num_ignore_image_tokens = num_ignore_generic_tokens;
3432 for (i = 0; image_config_vars[i].token != NULL; i++)
3433 num_ignore_image_tokens++;
3434 ignore_image_tokens =
3435 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3436 for (i = 0; i < num_ignore_generic_tokens; i++)
3437 ignore_image_tokens[i] = ignore_generic_tokens[i];
3438 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3439 ignore_image_tokens[num_ignore_generic_tokens + i] =
3440 image_config_vars[i].token;
3441 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3443 /* dynamically determine list of sound tokens to be ignored */
3444 num_ignore_sound_tokens = num_ignore_generic_tokens;
3445 ignore_sound_tokens =
3446 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3447 for (i = 0; i < num_ignore_generic_tokens; i++)
3448 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3449 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3451 /* dynamically determine list of music tokens to be ignored */
3452 num_ignore_music_tokens = num_ignore_generic_tokens;
3453 ignore_music_tokens =
3454 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3455 for (i = 0; i < num_ignore_generic_tokens; i++)
3456 ignore_music_tokens[i] = ignore_generic_tokens[i];
3457 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3459 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3460 image_id_prefix[i] = element_info[i].token_name;
3461 for (i = 0; i < NUM_FONTS; i++)
3462 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3463 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3465 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3466 sound_id_prefix[i] = element_info[i].token_name;
3467 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3468 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3469 get_string_in_brackets(element_info[i].class_name);
3470 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3472 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3473 music_id_prefix[i] = music_prefix_info[i].prefix;
3474 music_id_prefix[MAX_LEVELS] = NULL;
3476 for (i = 0; i < NUM_ACTIONS; i++)
3477 action_id_suffix[i] = element_action_info[i].suffix;
3478 action_id_suffix[NUM_ACTIONS] = NULL;
3480 for (i = 0; i < NUM_DIRECTIONS; i++)
3481 direction_id_suffix[i] = element_direction_info[i].suffix;
3482 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3484 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3485 special_id_suffix[i] = special_suffix_info[i].suffix;
3486 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3488 for (i = 0; i < MAX_LEVELS; i++)
3489 level_id_suffix[i] = get_level_id_suffix(i);
3490 level_id_suffix[MAX_LEVELS] = NULL;
3492 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3493 image_id_prefix, action_id_suffix, direction_id_suffix,
3494 special_id_suffix, ignore_image_tokens);
3495 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3496 sound_id_prefix, action_id_suffix, dummy,
3497 special_id_suffix, ignore_sound_tokens);
3498 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3499 music_id_prefix, special_id_suffix, level_id_suffix,
3500 dummy, ignore_music_tokens);
3503 static void InitMixer()
3511 char *filename_font_initial = NULL;
3512 Bitmap *bitmap_font_initial = NULL;
3515 /* determine settings for initial font (for displaying startup messages) */
3516 for (i = 0; image_config[i].token != NULL; i++)
3518 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3520 char font_token[128];
3523 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3524 len_font_token = strlen(font_token);
3526 if (strcmp(image_config[i].token, font_token) == 0)
3527 filename_font_initial = image_config[i].value;
3528 else if (strlen(image_config[i].token) > len_font_token &&
3529 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3531 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3532 font_initial[j].src_x = atoi(image_config[i].value);
3533 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3534 font_initial[j].src_y = atoi(image_config[i].value);
3535 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3536 font_initial[j].width = atoi(image_config[i].value);
3537 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3538 font_initial[j].height = atoi(image_config[i].value);
3543 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3545 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3546 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3549 if (filename_font_initial == NULL) /* should not happen */
3550 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3552 /* create additional image buffers for double-buffering */
3553 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3554 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3556 /* initialize screen properties */
3557 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3558 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3560 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3561 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3562 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3564 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3566 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3567 font_initial[j].bitmap = bitmap_font_initial;
3569 InitFontGraphicInfo();
3571 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3572 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3574 DrawInitText("Loading graphics:", 120, FC_GREEN);
3576 InitTileClipmasks();
3579 void InitGfxBackground()
3583 drawto = backbuffer;
3584 fieldbuffer = bitmap_db_field;
3585 SetDrawtoField(DRAW_BACKBUFFER);
3587 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3588 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3589 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3590 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3592 for (x = 0; x < MAX_BUF_XSIZE; x++)
3593 for (y = 0; y < MAX_BUF_YSIZE; y++)
3596 redraw_mask = REDRAW_ALL;
3599 static void InitLevelInfo()
3601 LoadLevelInfo(); /* global level info */
3602 LoadLevelSetup_LastSeries(); /* last played series info */
3603 LoadLevelSetup_SeriesInfo(); /* last played level info */
3606 void InitLevelArtworkInfo()
3608 LoadLevelArtworkInfo();
3611 static void InitImages()
3614 setLevelArtworkDir(artwork.gfx_first);
3618 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3619 leveldir_current->identifier,
3620 artwork.gfx_current_identifier,
3621 artwork.gfx_current->identifier,
3622 leveldir_current->graphics_set,
3623 leveldir_current->graphics_path);
3626 ReloadCustomImages();
3628 LoadCustomElementDescriptions();
3629 LoadSpecialMenuDesignSettings();
3631 ReinitializeGraphics();
3634 static void InitSound(char *identifier)
3636 if (identifier == NULL)
3637 identifier = artwork.snd_current->identifier;
3640 /* set artwork path to send it to the sound server process */
3641 setLevelArtworkDir(artwork.snd_first);
3644 InitReloadCustomSounds(identifier);
3645 ReinitializeSounds();
3648 static void InitMusic(char *identifier)
3650 if (identifier == NULL)
3651 identifier = artwork.mus_current->identifier;
3654 /* set artwork path to send it to the sound server process */
3655 setLevelArtworkDir(artwork.mus_first);
3658 InitReloadCustomMusic(identifier);
3659 ReinitializeMusic();
3662 void InitNetworkServer()
3664 #if defined(PLATFORM_UNIX)
3668 if (!options.network)
3671 #if defined(PLATFORM_UNIX)
3672 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3674 if (!ConnectToServer(options.server_host, options.server_port))
3675 Error(ERR_EXIT, "cannot connect to network game server");
3677 SendToServer_PlayerName(setup.player_name);
3678 SendToServer_ProtocolVersion();
3681 SendToServer_NrWanted(nr_wanted);
3685 static char *getNewArtworkIdentifier(int type)
3687 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3688 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3689 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3690 static boolean initialized[3] = { FALSE, FALSE, FALSE };
3691 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3692 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3693 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3694 char *leveldir_identifier = leveldir_current->identifier;
3696 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3697 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3699 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3701 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3702 char *artwork_current_identifier;
3703 char *artwork_new_identifier = NULL; /* default: nothing has changed */
3705 /* leveldir_current may be invalid (level group, parent link) */
3706 if (!validLevelSeries(leveldir_current))
3709 /* 1st step: determine artwork set to be activated in descending order:
3710 --------------------------------------------------------------------
3711 1. setup artwork (when configured to override everything else)
3712 2. artwork set configured in "levelinfo.conf" of current level set
3713 (artwork in level directory will have priority when loading later)
3714 3. artwork in level directory (stored in artwork sub-directory)
3715 4. setup artwork (currently configured in setup menu) */
3717 if (setup_override_artwork)
3718 artwork_current_identifier = setup_artwork_set;
3719 else if (leveldir_artwork_set != NULL)
3720 artwork_current_identifier = leveldir_artwork_set;
3721 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3722 artwork_current_identifier = leveldir_identifier;
3724 artwork_current_identifier = setup_artwork_set;
3727 /* 2nd step: check if it is really needed to reload artwork set
3728 ------------------------------------------------------------ */
3731 if (type == ARTWORK_TYPE_GRAPHICS)
3732 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3733 artwork_new_identifier,
3734 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3735 artwork_current_identifier,
3736 leveldir_current->graphics_set,
3737 leveldir_current->identifier);
3740 /* ---------- reload if level set and also artwork set has changed ------- */
3741 if (leveldir_current_identifier[type] != leveldir_identifier &&
3742 (last_has_level_artwork_set[type] || has_level_artwork_set))
3743 artwork_new_identifier = artwork_current_identifier;
3745 leveldir_current_identifier[type] = leveldir_identifier;
3746 last_has_level_artwork_set[type] = has_level_artwork_set;
3749 if (type == ARTWORK_TYPE_GRAPHICS)
3750 printf("::: 1: '%s'\n", artwork_new_identifier);
3753 /* ---------- reload if "override artwork" setting has changed ----------- */
3754 if (last_override_level_artwork[type] != setup_override_artwork)
3755 artwork_new_identifier = artwork_current_identifier;
3757 last_override_level_artwork[type] = setup_override_artwork;
3760 if (type == ARTWORK_TYPE_GRAPHICS)
3761 printf("::: 2: '%s'\n", artwork_new_identifier);
3764 /* ---------- reload if current artwork identifier has changed ----------- */
3765 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3766 artwork_current_identifier) != 0)
3767 artwork_new_identifier = artwork_current_identifier;
3769 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3772 if (type == ARTWORK_TYPE_GRAPHICS)
3773 printf("::: 3: '%s'\n", artwork_new_identifier);
3776 /* ---------- do not reload directly after starting ---------------------- */
3777 if (!initialized[type])
3778 artwork_new_identifier = NULL;
3780 initialized[type] = TRUE;
3783 if (type == ARTWORK_TYPE_GRAPHICS)
3784 printf("::: 4: '%s'\n", artwork_new_identifier);
3788 if (type == ARTWORK_TYPE_GRAPHICS)
3789 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3790 artwork.gfx_current_identifier, artwork_current_identifier,
3791 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3792 artwork_new_identifier);
3795 return artwork_new_identifier;
3798 void ReloadCustomArtwork()
3800 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3801 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3802 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3803 boolean redraw_screen = FALSE;
3805 if (gfx_new_identifier != NULL)
3808 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3809 artwork.gfx_current_identifier,
3811 artwork.gfx_current->identifier,
3812 leveldir_current->graphics_set);
3815 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3820 printf("... '%s'\n",
3821 leveldir_current->graphics_set);
3824 FreeTileClipmasks();
3825 InitTileClipmasks();
3827 redraw_screen = TRUE;
3830 if (snd_new_identifier != NULL)
3832 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3834 InitSound(snd_new_identifier);
3836 redraw_screen = TRUE;
3839 if (mus_new_identifier != NULL)
3841 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3843 InitMusic(mus_new_identifier);
3845 redraw_screen = TRUE;
3850 InitGfxBackground();
3852 /* force redraw of (open or closed) door graphics */
3853 SetDoorState(DOOR_OPEN_ALL);
3854 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3858 void KeyboardAutoRepeatOffUnlessAutoplay()
3860 if (global.autoplay_leveldir == NULL)
3861 KeyboardAutoRepeatOff();
3865 /* ========================================================================= */
3867 /* ========================================================================= */
3871 InitGlobal(); /* initialize some global variables */
3873 if (options.execute_command)
3874 Execute_Command(options.execute_command);
3876 if (options.serveronly)
3878 #if defined(PLATFORM_UNIX)
3879 NetworkServer(options.server_port, options.serveronly);
3881 Error(ERR_WARN, "networking only supported in Unix version");
3883 exit(0); /* never reached */
3889 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3890 InitArtworkConfig(); /* needed before forking sound child process */
3895 InitRND(NEW_RANDOMIZE);
3896 InitSimpleRND(NEW_RANDOMIZE);
3901 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3904 InitEventFilter(FilterMouseMotionEvents);
3906 InitElementPropertiesStatic();
3907 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
3912 InitLevelArtworkInfo();
3914 InitImages(); /* needs to know current level directory */
3915 InitSound(NULL); /* needs to know current level directory */
3916 InitMusic(NULL); /* needs to know current level directory */
3918 InitGfxBackground();
3920 if (global.autoplay_leveldir)
3926 game_status = GAME_MODE_MAIN;
3930 InitNetworkServer();
3933 void CloseAllAndExit(int exit_value)
3938 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3941 FreeTileClipmasks();
3943 CloseVideoDisplay();
3944 ClosePlatformDependentStuff();