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"
28 #include "conf_e2g.c" /* include auto-generated data structure definitions */
29 #include "conf_esg.c" /* include auto-generated data structure definitions */
30 #include "conf_e2s.c" /* include auto-generated data structure definitions */
31 #include "conf_fnt.c" /* include auto-generated data structure definitions */
34 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
40 static void InitTileClipmasks()
43 #if defined(TARGET_X11)
44 XGCValues clip_gc_values;
45 unsigned long clip_gc_valuemask;
47 #if defined(TARGET_X11_NATIVE)
57 tile_needs_clipping[] =
59 { GFX_SPIELER1_UP, 4 },
60 { GFX_SPIELER1_DOWN, 4 },
61 { GFX_SPIELER1_LEFT, 4 },
62 { GFX_SPIELER1_RIGHT, 4 },
63 { GFX_SPIELER1_PUSH_LEFT, 4 },
64 { GFX_SPIELER1_PUSH_RIGHT, 4 },
65 { GFX_SPIELER2_UP, 4 },
66 { GFX_SPIELER2_DOWN, 4 },
67 { GFX_SPIELER2_LEFT, 4 },
68 { GFX_SPIELER2_RIGHT, 4 },
69 { GFX_SPIELER2_PUSH_LEFT, 4 },
70 { GFX_SPIELER2_PUSH_RIGHT, 4 },
71 { GFX_SPIELER3_UP, 4 },
72 { GFX_SPIELER3_DOWN, 4 },
73 { GFX_SPIELER3_LEFT, 4 },
74 { GFX_SPIELER3_RIGHT, 4 },
75 { GFX_SPIELER3_PUSH_LEFT, 4 },
76 { GFX_SPIELER3_PUSH_RIGHT, 4 },
77 { GFX_SPIELER4_UP, 4 },
78 { GFX_SPIELER4_DOWN, 4 },
79 { GFX_SPIELER4_LEFT, 4 },
80 { GFX_SPIELER4_RIGHT, 4 },
81 { GFX_SPIELER4_PUSH_LEFT, 4 },
82 { GFX_SPIELER4_PUSH_RIGHT, 4 },
84 { GFX_MURPHY_GO_LEFT, 3 },
85 { GFX_MURPHY_GO_RIGHT, 3 },
86 { GFX_MURPHY_SNAP_UP, 1 },
87 { GFX_MURPHY_SNAP_DOWN, 1 },
88 { GFX_MURPHY_SNAP_RIGHT, 1 },
89 { GFX_MURPHY_SNAP_LEFT, 1 },
90 { GFX_MURPHY_PUSH_RIGHT, 1 },
91 { GFX_MURPHY_PUSH_LEFT, 1 },
96 { GFX_SOKOBAN_OBJEKT, 1 },
97 { GFX_FUNKELN_BLAU, 3 },
98 { GFX_FUNKELN_WEISS, 3 },
99 { GFX2_SHIELD_PASSIVE, 3 },
100 { GFX2_SHIELD_ACTIVE, 3 },
105 #endif /* TARGET_X11_NATIVE */
106 #endif /* TARGET_X11 */
110 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
111 for (i=0; i<NUM_TILES; i++)
112 tile_clipmask[i] = None;
114 #if defined(TARGET_X11)
115 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
116 often very slow when preparing a masked XCopyArea() for big Pixmaps.
117 To prevent this, create small (tile-sized) mask Pixmaps which will then
118 be set much faster with XSetClipOrigin() and speed things up a lot. */
120 clip_gc_values.graphics_exposures = False;
121 clip_gc_valuemask = GCGraphicsExposures;
122 tile_clip_gc = XCreateGC(display, window->drawable,
123 clip_gc_valuemask, &clip_gc_values);
126 for (i=0; i<NUM_BITMAPS; i++)
128 if (pix[i]->clip_mask)
130 clip_gc_values.graphics_exposures = False;
131 clip_gc_values.clip_mask = pix[i]->clip_mask;
132 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
133 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
134 clip_gc_valuemask, &clip_gc_values);
139 #if defined(TARGET_X11_NATIVE)
142 /* create graphic context structures needed for clipping */
143 clip_gc_values.graphics_exposures = False;
144 clip_gc_valuemask = GCGraphicsExposures;
145 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
146 clip_gc_valuemask, &clip_gc_values);
148 /* create only those clipping Pixmaps we really need */
149 for (i=0; tile_needs_clipping[i].start>=0; i++)
153 for (j=0; j<tile_needs_clipping[i].count; j++)
155 int tile = tile_needs_clipping[i].start + j;
161 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
162 src_pixmap = src_bitmap->clip_mask;
164 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
167 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
168 src_x, src_y, TILEX, TILEY, 0, 0);
172 XFreeGC(display, copy_clipmask_gc);
175 #endif /* TARGET_X11_NATIVE */
176 #endif /* TARGET_X11 */
180 void FreeTileClipmasks()
183 #if defined(TARGET_X11)
186 for (i=0; i<NUM_TILES; i++)
188 if (tile_clipmask[i] != None)
190 XFreePixmap(display, tile_clipmask[i]);
191 tile_clipmask[i] = None;
196 XFreeGC(display, tile_clip_gc);
200 for (i=0; i<NUM_BITMAPS; i++)
202 if (pix[i] != NULL && pix[i]->stored_clip_gc)
204 XFreeGC(display, pix[i]->stored_clip_gc);
205 pix[i]->stored_clip_gc = None;
210 #endif /* TARGET_X11 */
216 FreeLevelEditorGadgets();
225 static boolean gadgets_initialized = FALSE;
227 if (gadgets_initialized)
230 CreateLevelEditorGadgets();
234 CreateScreenGadgets();
236 gadgets_initialized = TRUE;
239 void InitElementSmallImages()
241 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
242 int num_property_mappings = getImageListPropertyMappingSize();
245 /* initialize normal images from static configuration */
246 for (i=0; element_to_graphic[i].element > -1; i++)
247 CreateImageWithSmallImages(element_to_graphic[i].graphic);
249 /* initialize special images from static configuration */
250 for (i=0; element_to_special_graphic[i].element > -1; i++)
251 CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
253 /* initialize images from dynamic configuration */
254 for (i=0; i < num_property_mappings; i++)
255 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
256 CreateImageWithSmallImages(property_mapping[i].artwork_index);
259 static int getFontBitmapID(int font_nr)
263 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
264 special = game_status;
265 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
266 special = GFX_SPECIAL_ARG_MAIN;
267 else if (game_status == GAME_MODE_PLAYING)
268 special = GFX_SPECIAL_ARG_DOOR;
271 return font_info[font_nr].special_bitmap_id[special];
276 void InitFontGraphicInfo()
278 static struct FontBitmapInfo *font_bitmap_info = NULL;
279 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
280 int num_property_mappings = getImageListPropertyMappingSize();
281 int num_font_bitmaps = NUM_FONTS;
284 if (graphic_info == NULL) /* still at startup phase */
286 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
291 /* ---------- initialize font graphic definitions ---------- */
293 /* always start with reliable default values (normal font graphics) */
294 for (i=0; i < NUM_FONTS; i++)
295 font_info[i].graphic = FONT_INITIAL_1;
297 /* initialize normal font/graphic mapping from static configuration */
298 for (i=0; font_to_graphic[i].font_nr > -1; i++)
300 int font_nr = font_to_graphic[i].font_nr;
301 int special = font_to_graphic[i].special;
302 int graphic = font_to_graphic[i].graphic;
307 font_info[font_nr].graphic = graphic;
310 /* always start with reliable default values (special font graphics) */
311 for (i=0; i < NUM_FONTS; i++)
313 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
315 font_info[i].special_graphic[j] = font_info[i].graphic;
316 font_info[i].special_bitmap_id[j] = i;
320 /* initialize special font/graphic mapping from static configuration */
321 for (i=0; font_to_graphic[i].font_nr > -1; i++)
323 int font_nr = font_to_graphic[i].font_nr;
324 int special = font_to_graphic[i].special;
325 int graphic = font_to_graphic[i].graphic;
327 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
329 font_info[font_nr].special_graphic[special] = graphic;
330 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
335 /* initialize special element/graphic mapping from dynamic configuration */
336 for (i=0; i < num_property_mappings; i++)
338 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
339 int special = property_mapping[i].ext3_index;
340 int graphic = property_mapping[i].artwork_index;
345 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
347 font_info[font_nr].special_graphic[special] = graphic;
348 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
353 /* ---------- initialize font bitmap array ---------- */
355 if (font_bitmap_info != NULL)
356 FreeFontInfo(font_bitmap_info);
359 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
361 /* ---------- initialize font bitmap definitions ---------- */
363 for (i=0; i < NUM_FONTS; i++)
365 if (i < NUM_INITIAL_FONTS)
367 font_bitmap_info[i] = font_initial[i];
371 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
373 int font_bitmap_id = font_info[i].special_bitmap_id[j];
374 int graphic = font_info[i].special_graphic[j];
376 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
377 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
379 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
380 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
383 /* copy font relevant information from graphics information */
384 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
385 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
386 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
387 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
388 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
389 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
390 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
392 font_bitmap_info[font_bitmap_id].num_chars =
393 graphic_info[graphic].anim_frames;
394 font_bitmap_info[font_bitmap_id].num_chars_per_line =
395 graphic_info[graphic].anim_frames_per_line;
399 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
402 void InitElementGraphicInfo()
404 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
405 int num_property_mappings = getImageListPropertyMappingSize();
408 /* set values to -1 to identify later as "uninitialized" values */
409 for (i=0; i<MAX_NUM_ELEMENTS; i++)
411 for (act=0; act<NUM_ACTIONS; act++)
413 element_info[i].graphic[act] = -1;
415 for (dir=0; dir<NUM_DIRECTIONS; dir++)
416 element_info[i].direction_graphic[act][dir] = -1;
420 /* initialize normal element/graphic mapping from static configuration */
421 for (i=0; element_to_graphic[i].element > -1; i++)
423 int element = element_to_graphic[i].element;
424 int action = element_to_graphic[i].action;
425 int direction = element_to_graphic[i].direction;
426 int graphic = element_to_graphic[i].graphic;
428 if (graphic_info[graphic].bitmap == NULL)
431 if ((action > -1 || direction > -1) && el2img(element) != -1)
433 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
434 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
436 /* if the base graphic ("emerald", for example) has been redefined,
437 but not the action graphic ("emerald.falling", for example), do not
438 use an existing (in this case considered obsolete) action graphic
439 anymore, but use the automatically determined default graphic */
440 if (base_redefined && !act_dir_redefined)
445 action = ACTION_DEFAULT;
448 element_info[element].direction_graphic[action][direction] = graphic;
450 element_info[element].graphic[action] = graphic;
453 /* initialize normal element/graphic mapping from dynamic configuration */
454 for (i=0; i < num_property_mappings; i++)
456 int element = property_mapping[i].base_index;
457 int action = property_mapping[i].ext1_index;
458 int direction = property_mapping[i].ext2_index;
459 int special = property_mapping[i].ext3_index;
460 int graphic = property_mapping[i].artwork_index;
462 if (graphic_info[graphic].bitmap == NULL)
465 if (element >= MAX_NUM_ELEMENTS || special != -1)
469 action = ACTION_DEFAULT;
472 for (dir=0; dir<NUM_DIRECTIONS; dir++)
473 element_info[element].direction_graphic[action][dir] = -1;
476 element_info[element].direction_graphic[action][direction] = graphic;
478 element_info[element].graphic[action] = graphic;
481 /* now set all '-1' values to element specific default values */
482 for (i=0; i<MAX_NUM_ELEMENTS; i++)
484 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
485 int default_direction_graphic[NUM_DIRECTIONS];
487 if (default_graphic == -1)
488 default_graphic = IMG_CHAR_QUESTION;
490 for (dir=0; dir<NUM_DIRECTIONS; dir++)
492 default_direction_graphic[dir] =
493 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
495 if (default_direction_graphic[dir] == -1)
496 default_direction_graphic[dir] = default_graphic;
499 for (act=0; act<NUM_ACTIONS; act++)
501 boolean act_remove = (act == ACTION_DIGGING ||
502 act == ACTION_SNAPPING ||
503 act == ACTION_COLLECTING);
505 /* generic default action graphic (defined by "[default]" directive) */
506 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
508 /* look for special default action graphic (classic game specific) */
509 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
510 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
511 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
512 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
513 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
514 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
516 if (default_action_graphic == -1)
517 default_action_graphic = default_graphic;
519 for (dir=0; dir<NUM_DIRECTIONS; dir++)
521 int default_action_direction_graphic = element_info[i].graphic[act];
523 /* no graphic for current action -- use default direction graphic */
524 if (default_action_direction_graphic == -1)
525 default_action_direction_graphic =
526 (act_remove ? IMG_EMPTY : default_direction_graphic[dir]);
528 if (element_info[i].direction_graphic[act][dir] == -1)
529 element_info[i].direction_graphic[act][dir] =
530 default_action_direction_graphic;
533 /* no graphic for this specific action -- use default action graphic */
534 if (element_info[i].graphic[act] == -1)
535 element_info[i].graphic[act] =
536 (act_remove ? IMG_EMPTY : default_action_graphic);
544 for (i=0; i<MAX_NUM_ELEMENTS; i++)
545 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
546 i != EL_CHAR_QUESTION)
547 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
548 element_info[i].token_name, i);
554 void InitElementSpecialGraphicInfo()
556 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
557 int num_property_mappings = getImageListPropertyMappingSize();
560 /* always start with reliable default values */
561 for (i=0; i < MAX_NUM_ELEMENTS; i++)
562 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
563 element_info[i].special_graphic[j] =
564 element_info[i].graphic[ACTION_DEFAULT];
566 /* initialize special element/graphic mapping from static configuration */
567 for (i=0; element_to_special_graphic[i].element > -1; i++)
569 int element = element_to_special_graphic[i].element;
570 int special = element_to_special_graphic[i].special;
571 int graphic = element_to_special_graphic[i].graphic;
572 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
573 boolean special_redefined = getImageListEntry(graphic)->redefined;
575 /* if the base graphic ("emerald", for example) has been redefined,
576 but not the special graphic ("emerald.EDITOR", for example), do not
577 use an existing (in this case considered obsolete) special graphic
578 anymore, but use the automatically created (down-scaled) graphic */
579 if (base_redefined && !special_redefined)
582 element_info[element].special_graphic[special] = graphic;
585 /* initialize special element/graphic mapping from dynamic configuration */
586 for (i=0; i < num_property_mappings; i++)
588 int element = property_mapping[i].base_index;
589 int special = property_mapping[i].ext3_index;
590 int graphic = property_mapping[i].artwork_index;
592 if (element >= MAX_NUM_ELEMENTS)
595 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
596 element_info[element].special_graphic[special] = graphic;
600 static void set_graphic_parameters(int graphic, char **parameter_raw)
602 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
603 int parameter[NUM_GFX_ARGS];
604 int anim_frames_per_row = 1, anim_frames_per_col = 1;
605 int anim_frames_per_line = 1;
608 /* get integer values from string parameters */
609 for (i=0; i < NUM_GFX_ARGS; i++)
611 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
612 image_config_suffix[i].type);
614 graphic_info[graphic].bitmap = src_bitmap;
616 /* start with reliable default values */
617 graphic_info[graphic].src_x = 0;
618 graphic_info[graphic].src_y = 0;
619 graphic_info[graphic].width = TILEX;
620 graphic_info[graphic].height = TILEY;
621 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
622 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
624 /* optional x and y tile position of animation frame sequence */
625 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
626 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
627 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
628 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
630 /* optional x and y pixel position of animation frame sequence */
631 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
632 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
633 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
634 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
636 /* optional width and height of each animation frame */
637 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
638 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
639 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
640 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
644 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
645 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
648 /* correct x or y offset dependent of vertical or horizontal frame order */
649 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
651 graphic_info[graphic].offset_y =
652 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
653 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
654 anim_frames_per_line = anim_frames_per_col;
656 else /* frames are ordered horizontally */
658 graphic_info[graphic].offset_x =
659 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
660 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
661 anim_frames_per_line = anim_frames_per_row;
664 /* optionally, the x and y offset of frames can be specified directly */
665 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
666 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
667 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
668 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
670 /* automatically determine correct number of frames, if not defined */
671 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
672 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
673 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
674 graphic_info[graphic].anim_frames = anim_frames_per_row;
675 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
676 graphic_info[graphic].anim_frames = anim_frames_per_col;
678 graphic_info[graphic].anim_frames = 1;
680 graphic_info[graphic].anim_frames_per_line =
681 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
682 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
684 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
685 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
686 graphic_info[graphic].anim_delay = 1;
688 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
689 if (graphic_info[graphic].anim_frames == 1)
690 graphic_info[graphic].anim_mode = ANIM_NONE;
692 /* automatically determine correct start frame, if not defined */
693 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
694 graphic_info[graphic].anim_start_frame = 0;
695 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
696 graphic_info[graphic].anim_start_frame =
697 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
699 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
701 /* animation synchronized with global frame counter, not move position */
702 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
704 /* this is only used for toon animations */
705 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
706 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
708 /* this is only used for drawing font characters */
709 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
710 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
713 static void InitGraphicInfo()
715 int fallback_graphic = IMG_CHAR_EXCLAM;
716 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
717 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
718 int num_images = getImageListSize();
721 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
722 static boolean clipmasks_initialized = FALSE;
724 XGCValues clip_gc_values;
725 unsigned long clip_gc_valuemask;
726 GC copy_clipmask_gc = None;
729 if (graphic_info != NULL)
732 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
734 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
735 if (clipmasks_initialized)
737 for (i=0; i<num_images; i++)
739 if (graphic_info[i].clip_mask)
740 XFreePixmap(display, graphic_info[i].clip_mask);
741 if (graphic_info[i].clip_gc)
742 XFreeGC(display, graphic_info[i].clip_gc);
744 graphic_info[i].clip_mask = None;
745 graphic_info[i].clip_gc = None;
750 for (i=0; i<num_images; i++)
752 struct FileInfo *image = getImageListEntry(i);
755 int first_frame, last_frame;
758 printf("::: image: '%s'\n", image->token);
762 printf("::: image # %d: '%s' ['%s']\n",
764 getTokenFromImageID(i));
767 set_graphic_parameters(i, image->parameter);
769 /* now check if no animation frames are outside of the loaded image */
771 if (graphic_info[i].bitmap == NULL)
772 continue; /* skip check for optional images that are undefined */
775 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
776 if (src_x < 0 || src_y < 0 ||
777 src_x + TILEX > src_bitmap->width ||
778 src_y + TILEY > src_bitmap->height)
780 Error(ERR_RETURN_LINE, "-");
781 Error(ERR_RETURN, "warning: error found in config file:");
782 Error(ERR_RETURN, "- config file: '%s'",
783 getImageConfigFilename());
784 Error(ERR_RETURN, "- config token: '%s'",
785 getTokenFromImageID(i));
786 Error(ERR_RETURN, "- image file: '%s'",
787 src_bitmap->source_filename);
789 "error: first animation frame out of bounds (%d, %d)",
791 Error(ERR_RETURN, "custom graphic rejected for this element/action");
793 if (i == fallback_graphic)
794 Error(ERR_EXIT, "fatal error: no fallback graphic available");
796 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
797 Error(ERR_RETURN_LINE, "-");
799 set_graphic_parameters(i, fallback_image->default_parameter);
800 graphic_info[i].bitmap = fallback_bitmap;
803 last_frame = graphic_info[i].anim_frames - 1;
804 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
805 if (src_x < 0 || src_y < 0 ||
806 src_x + TILEX > src_bitmap->width ||
807 src_y + TILEY > src_bitmap->height)
809 Error(ERR_RETURN_LINE, "-");
810 Error(ERR_RETURN, "warning: error found in config file:");
811 Error(ERR_RETURN, "- config file: '%s'",
812 getImageConfigFilename());
813 Error(ERR_RETURN, "- config token: '%s'",
814 getTokenFromImageID(i));
815 Error(ERR_RETURN, "- image file: '%s'",
816 src_bitmap->source_filename);
818 "error: last animation frame (%d) out of bounds (%d, %d)",
819 last_frame, src_x, src_y);
820 Error(ERR_RETURN, "custom graphic rejected for this element/action");
822 if (i == fallback_graphic)
823 Error(ERR_EXIT, "fatal error: no fallback graphic available");
825 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
826 Error(ERR_RETURN_LINE, "-");
828 set_graphic_parameters(i, fallback_image->default_parameter);
829 graphic_info[i].bitmap = fallback_bitmap;
832 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
833 /* currently we need only a tile clip mask from the first frame */
834 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
836 if (copy_clipmask_gc == None)
838 clip_gc_values.graphics_exposures = False;
839 clip_gc_valuemask = GCGraphicsExposures;
840 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
841 clip_gc_valuemask, &clip_gc_values);
844 graphic_info[i].clip_mask =
845 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
847 src_pixmap = src_bitmap->clip_mask;
848 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
849 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
851 clip_gc_values.graphics_exposures = False;
852 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
853 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
855 graphic_info[i].clip_gc =
856 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
860 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
861 if (copy_clipmask_gc)
862 XFreeGC(display, copy_clipmask_gc);
864 clipmasks_initialized = TRUE;
868 static void InitElementSoundInfo()
870 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
871 int num_property_mappings = getSoundListPropertyMappingSize();
874 /* set values to -1 to identify later as "uninitialized" values */
875 for (i=0; i < MAX_NUM_ELEMENTS; i++)
876 for (act=0; act < NUM_ACTIONS; act++)
877 element_info[i].sound[act] = -1;
879 /* initialize element/sound mapping from static configuration */
880 for (i=0; element_to_sound[i].element > -1; i++)
882 int element = element_to_sound[i].element;
883 int action = element_to_sound[i].action;
884 int sound = element_to_sound[i].sound;
885 boolean is_class = element_to_sound[i].is_class;
888 action = ACTION_DEFAULT;
891 element_info[element].sound[action] = sound;
893 for (j=0; j < MAX_NUM_ELEMENTS; j++)
894 if (strcmp(element_info[j].class_name,
895 element_info[element].class_name) == 0)
896 element_info[j].sound[action] = sound;
899 /* initialize element class/sound mapping from dynamic configuration */
900 for (i=0; i < num_property_mappings; i++)
902 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
903 int action = property_mapping[i].ext1_index;
904 int sound = property_mapping[i].artwork_index;
906 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
910 action = ACTION_DEFAULT;
912 for (j=0; j < MAX_NUM_ELEMENTS; j++)
913 if (strcmp(element_info[j].class_name,
914 element_info[element_class].class_name) == 0)
915 element_info[j].sound[action] = sound;
918 /* initialize element/sound mapping from dynamic configuration */
919 for (i=0; i < num_property_mappings; i++)
921 int element = property_mapping[i].base_index;
922 int action = property_mapping[i].ext1_index;
923 int sound = property_mapping[i].artwork_index;
925 if (element >= MAX_NUM_ELEMENTS)
929 action = ACTION_DEFAULT;
931 element_info[element].sound[action] = sound;
934 /* now set all '-1' values to element specific default values */
935 for (i=0; i<MAX_NUM_ELEMENTS; i++)
937 for (act=0; act < NUM_ACTIONS; act++)
939 /* generic default action sound (defined by "[default]" directive) */
940 int default_action_sound = element_info[EL_DEFAULT].sound[act];
942 /* look for special default action sound (classic game specific) */
943 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
944 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
945 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
946 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
947 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
948 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
950 /* look for element specific default sound (independent from action) */
951 if (element_info[i].sound[ACTION_DEFAULT] != -1)
952 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
954 /* no sound for this specific action -- use default action sound */
955 if (element_info[i].sound[act] == -1)
956 element_info[i].sound[act] = default_action_sound;
961 static void set_sound_parameters(int sound, char **parameter_raw)
963 int parameter[NUM_SND_ARGS];
966 /* get integer values from string parameters */
967 for (i=0; i < NUM_SND_ARGS; i++)
969 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
970 sound_config_suffix[i].type);
972 /* explicit loop mode setting in configuration overrides default value */
973 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
974 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
977 static void InitSoundInfo()
980 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
981 int num_property_mappings = getSoundListPropertyMappingSize();
983 int *sound_effect_properties;
984 int num_sounds = getSoundListSize();
987 if (sound_info != NULL)
990 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
991 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
993 /* initialize sound effect for all elements to "no sound" */
994 for (i=0; i<MAX_NUM_ELEMENTS; i++)
995 for (j=0; j<NUM_ACTIONS; j++)
996 element_info[i].sound[j] = SND_UNDEFINED;
998 for (i=0; i<num_sounds; i++)
1000 struct FileInfo *sound = getSoundListEntry(i);
1001 int len_effect_text = strlen(sound->token);
1003 sound_effect_properties[i] = ACTION_OTHER;
1004 sound_info[i].loop = FALSE;
1007 printf("::: sound %d: '%s'\n", i, sound->token);
1010 /* determine all loop sounds and identify certain sound classes */
1012 for (j=0; element_action_info[j].suffix; j++)
1014 int len_action_text = strlen(element_action_info[j].suffix);
1016 if (len_action_text < len_effect_text &&
1017 strcmp(&sound->token[len_effect_text - len_action_text],
1018 element_action_info[j].suffix) == 0)
1020 sound_effect_properties[i] = element_action_info[j].value;
1021 sound_info[i].loop = element_action_info[j].is_loop_sound;
1028 if (strcmp(sound->token, "custom_42") == 0)
1029 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1032 /* associate elements and some selected sound actions */
1034 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1036 if (element_info[j].class_name)
1038 int len_class_text = strlen(element_info[j].class_name);
1040 if (len_class_text + 1 < len_effect_text &&
1041 strncmp(sound->token,
1042 element_info[j].class_name, len_class_text) == 0 &&
1043 sound->token[len_class_text] == '.')
1045 int sound_action_value = sound_effect_properties[i];
1047 element_info[j].sound[sound_action_value] = i;
1052 set_sound_parameters(i, sound->parameter);
1055 free(sound_effect_properties);
1058 /* !!! now handled in InitElementSoundInfo() !!! */
1059 /* initialize element/sound mapping from dynamic configuration */
1060 for (i=0; i < num_property_mappings; i++)
1062 int element = property_mapping[i].base_index;
1063 int action = property_mapping[i].ext1_index;
1064 int sound = property_mapping[i].artwork_index;
1067 action = ACTION_DEFAULT;
1069 printf("::: %d: %d, %d, %d ['%s']\n",
1070 i, element, action, sound, element_info[element].token_name);
1072 element_info[element].sound[action] = sound;
1079 int element = EL_CUSTOM_11;
1082 while (element_action_info[j].suffix)
1084 printf("element %d, sound action '%s' == %d\n",
1085 element, element_action_info[j].suffix,
1086 element_info[element].sound[j]);
1091 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1097 int element = EL_SAND;
1098 int sound_action = ACTION_DIGGING;
1101 while (element_action_info[j].suffix)
1103 if (element_action_info[j].value == sound_action)
1104 printf("element %d, sound action '%s' == %d\n",
1105 element, element_action_info[j].suffix,
1106 element_info[element].sound[sound_action]);
1113 static void ReinitializeGraphics()
1115 InitGraphicInfo(); /* graphic properties mapping */
1116 InitElementGraphicInfo(); /* element game graphic mapping */
1117 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1119 InitElementSmallImages(); /* create editor and preview images */
1120 InitFontGraphicInfo(); /* initialize text drawing functions */
1122 SetMainBackgroundImage(IMG_BACKGROUND);
1123 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1129 static void ReinitializeSounds()
1131 InitSoundInfo(); /* sound properties mapping */
1132 InitElementSoundInfo(); /* element game sound mapping */
1134 InitPlaySoundLevel(); /* internal game sound settings */
1137 static void ReinitializeMusic()
1139 /* currently nothing to do */
1142 void InitElementPropertiesStatic()
1144 static int ep_diggable[] =
1149 EL_SP_BUGGY_BASE_ACTIVATING,
1152 EL_INVISIBLE_SAND_ACTIVE,
1154 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1158 EL_SP_BUGGY_BASE_ACTIVE,
1163 static int ep_collectible[] =
1180 EL_DYNABOMB_INCREASE_NUMBER,
1181 EL_DYNABOMB_INCREASE_SIZE,
1182 EL_DYNABOMB_INCREASE_POWER,
1196 static int ep_dont_run_into[] =
1198 /* same elements as in 'ep_dont_touch' */
1204 /* same elements as in 'ep_dont_collide_with' */
1216 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1218 EL_SP_BUGGY_BASE_ACTIVE,
1225 static int ep_dont_collide_with[] =
1227 /* same elements as in 'ep_dont_touch' */
1243 static int ep_dont_touch[] =
1252 static int ep_indestructible[] =
1256 EL_ACID_POOL_TOPLEFT,
1257 EL_ACID_POOL_TOPRIGHT,
1258 EL_ACID_POOL_BOTTOMLEFT,
1259 EL_ACID_POOL_BOTTOM,
1260 EL_ACID_POOL_BOTTOMRIGHT,
1261 EL_SP_HARDWARE_GRAY,
1262 EL_SP_HARDWARE_GREEN,
1263 EL_SP_HARDWARE_BLUE,
1265 EL_SP_HARDWARE_YELLOW,
1266 EL_SP_HARDWARE_BASE_1,
1267 EL_SP_HARDWARE_BASE_2,
1268 EL_SP_HARDWARE_BASE_3,
1269 EL_SP_HARDWARE_BASE_4,
1270 EL_SP_HARDWARE_BASE_5,
1271 EL_SP_HARDWARE_BASE_6,
1272 EL_INVISIBLE_STEELWALL,
1273 EL_INVISIBLE_STEELWALL_ACTIVE,
1274 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1275 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1276 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1277 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1278 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1279 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1280 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1281 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1282 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1283 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1284 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1285 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1287 EL_LIGHT_SWITCH_ACTIVE,
1288 EL_SIGN_EXCLAMATION,
1289 EL_SIGN_RADIOACTIVITY,
1300 EL_STEELWALL_SLANTED,
1323 EL_SWITCHGATE_OPENING,
1324 EL_SWITCHGATE_CLOSED,
1325 EL_SWITCHGATE_CLOSING,
1327 EL_SWITCHGATE_SWITCH_UP,
1328 EL_SWITCHGATE_SWITCH_DOWN,
1331 EL_TIMEGATE_OPENING,
1333 EL_TIMEGATE_CLOSING,
1336 EL_TIMEGATE_SWITCH_ACTIVE,
1341 EL_TUBE_VERTICAL_LEFT,
1342 EL_TUBE_VERTICAL_RIGHT,
1343 EL_TUBE_HORIZONTAL_UP,
1344 EL_TUBE_HORIZONTAL_DOWN,
1352 static int ep_slippery[] =
1366 EL_ROBOT_WHEEL_ACTIVE,
1372 EL_ACID_POOL_TOPLEFT,
1373 EL_ACID_POOL_TOPRIGHT,
1383 EL_STEELWALL_SLANTED,
1389 static int ep_can_change[] =
1394 static int ep_can_move[] =
1416 static int ep_can_fall[] =
1431 EL_BD_MAGIC_WALL_FULL,
1444 static int ep_can_smash_player[] =
1469 static int ep_can_smash_enemies[] =
1477 static int ep_can_smash_everything[] =
1485 static int ep_can_explode_by_fire[] =
1487 /* same elements as in 'ep_can_explode_impact' */
1492 /* same elements as in 'ep_can_explode_smashed' */
1501 EL_DYNABOMB_PLAYER_1_ACTIVE,
1502 EL_DYNABOMB_PLAYER_2_ACTIVE,
1503 EL_DYNABOMB_PLAYER_3_ACTIVE,
1504 EL_DYNABOMB_PLAYER_4_ACTIVE,
1505 EL_DYNABOMB_INCREASE_NUMBER,
1506 EL_DYNABOMB_INCREASE_SIZE,
1507 EL_DYNABOMB_INCREASE_POWER,
1508 EL_SP_DISK_RED_ACTIVE,
1518 static int ep_can_explode_smashed[] =
1520 /* same elements as in 'ep_can_explode_impact' */
1533 static int ep_can_explode_impact[] =
1541 static int ep_walkable_over[] =
1545 EL_SOKOBAN_FIELD_EMPTY,
1562 static int ep_walkable_inside[] =
1567 EL_TUBE_VERTICAL_LEFT,
1568 EL_TUBE_VERTICAL_RIGHT,
1569 EL_TUBE_HORIZONTAL_UP,
1570 EL_TUBE_HORIZONTAL_DOWN,
1578 static int ep_walkable_under[] =
1583 static int ep_passable_over[] =
1598 static int ep_passable_inside[] =
1604 EL_SP_PORT_HORIZONTAL,
1605 EL_SP_PORT_VERTICAL,
1607 EL_SP_GRAVITY_PORT_LEFT,
1608 EL_SP_GRAVITY_PORT_RIGHT,
1609 EL_SP_GRAVITY_PORT_UP,
1610 EL_SP_GRAVITY_PORT_DOWN,
1614 static int ep_passable_under[] =
1619 static int ep_pushable[] =
1631 EL_SOKOBAN_FIELD_FULL,
1638 static int ep_can_be_crumbled[] =
1647 static int ep_player[] =
1656 static int ep_can_pass_magic_wall[] =
1669 static int ep_switchable[] =
1673 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1674 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1675 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1676 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1677 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1678 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1679 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1680 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1681 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1682 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1683 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1684 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1685 EL_SWITCHGATE_SWITCH_UP,
1686 EL_SWITCHGATE_SWITCH_DOWN,
1688 EL_LIGHT_SWITCH_ACTIVE,
1690 EL_BALLOON_SWITCH_LEFT,
1691 EL_BALLOON_SWITCH_RIGHT,
1692 EL_BALLOON_SWITCH_UP,
1693 EL_BALLOON_SWITCH_DOWN,
1694 EL_BALLOON_SWITCH_ANY,
1700 static int ep_bd_element[] =
1729 static int ep_sp_element[] =
1737 EL_SP_HARDWARE_GRAY,
1745 EL_SP_GRAVITY_PORT_RIGHT,
1746 EL_SP_GRAVITY_PORT_DOWN,
1747 EL_SP_GRAVITY_PORT_LEFT,
1748 EL_SP_GRAVITY_PORT_UP,
1753 EL_SP_PORT_VERTICAL,
1754 EL_SP_PORT_HORIZONTAL,
1760 EL_SP_HARDWARE_BASE_1,
1761 EL_SP_HARDWARE_GREEN,
1762 EL_SP_HARDWARE_BLUE,
1764 EL_SP_HARDWARE_YELLOW,
1765 EL_SP_HARDWARE_BASE_2,
1766 EL_SP_HARDWARE_BASE_3,
1767 EL_SP_HARDWARE_BASE_4,
1768 EL_SP_HARDWARE_BASE_5,
1769 EL_SP_HARDWARE_BASE_6,
1772 /* additional elements that appeared in newer Supaplex levels */
1774 /* more than one murphy in a level results in an inactive clone */
1776 /* runtime elements*/
1777 EL_SP_DISK_RED_ACTIVE,
1778 EL_SP_TERMINAL_ACTIVE,
1779 EL_SP_BUGGY_BASE_ACTIVATING,
1780 EL_SP_BUGGY_BASE_ACTIVE,
1784 static int ep_sb_element[] =
1789 EL_SOKOBAN_FIELD_EMPTY,
1790 EL_SOKOBAN_FIELD_FULL,
1792 EL_INVISIBLE_STEELWALL,
1796 static int ep_gem[] =
1807 static int ep_food_dark_yamyam[] =
1834 static int ep_food_penguin[] =
1847 static int ep_food_pig[] =
1858 static int ep_historic_wall[] =
1883 EL_EXPANDABLE_WALL_HORIZONTAL,
1884 EL_EXPANDABLE_WALL_VERTICAL,
1885 EL_EXPANDABLE_WALL_ANY,
1886 EL_EXPANDABLE_WALL_GROWING,
1893 EL_SP_HARDWARE_GRAY,
1894 EL_SP_HARDWARE_GREEN,
1895 EL_SP_HARDWARE_BLUE,
1897 EL_SP_HARDWARE_YELLOW,
1898 EL_SP_HARDWARE_BASE_1,
1899 EL_SP_HARDWARE_BASE_2,
1900 EL_SP_HARDWARE_BASE_3,
1901 EL_SP_HARDWARE_BASE_4,
1902 EL_SP_HARDWARE_BASE_5,
1903 EL_SP_HARDWARE_BASE_6,
1905 EL_SP_TERMINAL_ACTIVE,
1908 EL_INVISIBLE_STEELWALL,
1909 EL_INVISIBLE_STEELWALL_ACTIVE,
1911 EL_INVISIBLE_WALL_ACTIVE,
1912 EL_STEELWALL_SLANTED,
1928 static int ep_historic_solid[] =
1932 EL_EXPANDABLE_WALL_HORIZONTAL,
1933 EL_EXPANDABLE_WALL_VERTICAL,
1934 EL_EXPANDABLE_WALL_ANY,
1947 EL_QUICKSAND_FILLING,
1948 EL_QUICKSAND_EMPTYING,
1950 EL_MAGIC_WALL_ACTIVE,
1951 EL_MAGIC_WALL_EMPTYING,
1952 EL_MAGIC_WALL_FILLING,
1956 EL_BD_MAGIC_WALL_ACTIVE,
1957 EL_BD_MAGIC_WALL_EMPTYING,
1958 EL_BD_MAGIC_WALL_FULL,
1959 EL_BD_MAGIC_WALL_FILLING,
1960 EL_BD_MAGIC_WALL_DEAD,
1969 EL_SP_TERMINAL_ACTIVE,
1973 EL_INVISIBLE_WALL_ACTIVE,
1974 EL_SWITCHGATE_SWITCH_UP,
1975 EL_SWITCHGATE_SWITCH_DOWN,
1977 EL_TIMEGATE_SWITCH_ACTIVE,
1989 /* the following elements are a direct copy of "indestructible" elements,
1990 except "EL_ACID", which is "indestructible", but not "solid"! */
1995 EL_ACID_POOL_TOPLEFT,
1996 EL_ACID_POOL_TOPRIGHT,
1997 EL_ACID_POOL_BOTTOMLEFT,
1998 EL_ACID_POOL_BOTTOM,
1999 EL_ACID_POOL_BOTTOMRIGHT,
2000 EL_SP_HARDWARE_GRAY,
2001 EL_SP_HARDWARE_GREEN,
2002 EL_SP_HARDWARE_BLUE,
2004 EL_SP_HARDWARE_YELLOW,
2005 EL_SP_HARDWARE_BASE_1,
2006 EL_SP_HARDWARE_BASE_2,
2007 EL_SP_HARDWARE_BASE_3,
2008 EL_SP_HARDWARE_BASE_4,
2009 EL_SP_HARDWARE_BASE_5,
2010 EL_SP_HARDWARE_BASE_6,
2011 EL_INVISIBLE_STEELWALL,
2012 EL_INVISIBLE_STEELWALL_ACTIVE,
2013 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2014 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2015 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2016 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2017 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2018 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2019 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2020 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2021 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2022 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2023 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2024 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2026 EL_LIGHT_SWITCH_ACTIVE,
2027 EL_SIGN_EXCLAMATION,
2028 EL_SIGN_RADIOACTIVITY,
2039 EL_STEELWALL_SLANTED,
2062 EL_SWITCHGATE_OPENING,
2063 EL_SWITCHGATE_CLOSED,
2064 EL_SWITCHGATE_CLOSING,
2066 EL_TIMEGATE_OPENING,
2068 EL_TIMEGATE_CLOSING,
2072 EL_TUBE_VERTICAL_LEFT,
2073 EL_TUBE_VERTICAL_RIGHT,
2074 EL_TUBE_HORIZONTAL_UP,
2075 EL_TUBE_HORIZONTAL_DOWN,
2083 static int ep_classic_enemy[] =
2099 static int ep_belt[] =
2101 EL_CONVEYOR_BELT_1_LEFT,
2102 EL_CONVEYOR_BELT_1_MIDDLE,
2103 EL_CONVEYOR_BELT_1_RIGHT,
2104 EL_CONVEYOR_BELT_2_LEFT,
2105 EL_CONVEYOR_BELT_2_MIDDLE,
2106 EL_CONVEYOR_BELT_2_RIGHT,
2107 EL_CONVEYOR_BELT_3_LEFT,
2108 EL_CONVEYOR_BELT_3_MIDDLE,
2109 EL_CONVEYOR_BELT_3_RIGHT,
2110 EL_CONVEYOR_BELT_4_LEFT,
2111 EL_CONVEYOR_BELT_4_MIDDLE,
2112 EL_CONVEYOR_BELT_4_RIGHT,
2116 static int ep_belt_active[] =
2118 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2119 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2120 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2121 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2122 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2123 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2124 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2125 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2126 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2127 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2128 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2129 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2133 static int ep_belt_switch[] =
2135 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2136 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2137 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2138 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2139 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2140 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2141 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2142 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2143 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2144 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2145 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2146 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2150 static int ep_tube[] =
2157 EL_TUBE_HORIZONTAL_UP,
2158 EL_TUBE_HORIZONTAL_DOWN,
2160 EL_TUBE_VERTICAL_LEFT,
2161 EL_TUBE_VERTICAL_RIGHT,
2166 static int ep_keygate[] =
2187 static int ep_amoeboid[] =
2197 static int ep_amoebalive[] =
2206 static int ep_has_content[] =
2216 static int ep_active_bomb[] =
2219 EL_DYNABOMB_PLAYER_1_ACTIVE,
2220 EL_DYNABOMB_PLAYER_2_ACTIVE,
2221 EL_DYNABOMB_PLAYER_3_ACTIVE,
2222 EL_DYNABOMB_PLAYER_4_ACTIVE,
2223 EL_SP_DISK_RED_ACTIVE,
2227 static int ep_inactive[] =
2264 EL_INVISIBLE_STEELWALL,
2272 EL_WALL_EMERALD_YELLOW,
2273 EL_DYNABOMB_INCREASE_NUMBER,
2274 EL_DYNABOMB_INCREASE_SIZE,
2275 EL_DYNABOMB_INCREASE_POWER,
2279 EL_SOKOBAN_FIELD_EMPTY,
2280 EL_SOKOBAN_FIELD_FULL,
2281 EL_WALL_EMERALD_RED,
2282 EL_WALL_EMERALD_PURPLE,
2283 EL_ACID_POOL_TOPLEFT,
2284 EL_ACID_POOL_TOPRIGHT,
2285 EL_ACID_POOL_BOTTOMLEFT,
2286 EL_ACID_POOL_BOTTOM,
2287 EL_ACID_POOL_BOTTOMRIGHT,
2291 EL_BD_MAGIC_WALL_DEAD,
2292 EL_AMOEBA_TO_DIAMOND,
2300 EL_SP_GRAVITY_PORT_RIGHT,
2301 EL_SP_GRAVITY_PORT_DOWN,
2302 EL_SP_GRAVITY_PORT_LEFT,
2303 EL_SP_GRAVITY_PORT_UP,
2304 EL_SP_PORT_HORIZONTAL,
2305 EL_SP_PORT_VERTICAL,
2316 EL_SP_HARDWARE_GRAY,
2317 EL_SP_HARDWARE_GREEN,
2318 EL_SP_HARDWARE_BLUE,
2320 EL_SP_HARDWARE_YELLOW,
2321 EL_SP_HARDWARE_BASE_1,
2322 EL_SP_HARDWARE_BASE_2,
2323 EL_SP_HARDWARE_BASE_3,
2324 EL_SP_HARDWARE_BASE_4,
2325 EL_SP_HARDWARE_BASE_5,
2326 EL_SP_HARDWARE_BASE_6,
2327 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2328 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2329 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2330 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2331 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2332 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2333 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2334 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2335 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2336 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2337 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2338 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2339 EL_SIGN_EXCLAMATION,
2340 EL_SIGN_RADIOACTIVITY,
2351 EL_STEELWALL_SLANTED,
2371 } element_properties[] =
2373 { ep_diggable, EP_DIGGABLE },
2374 { ep_collectible, EP_COLLECTIBLE },
2375 { ep_dont_run_into, EP_DONT_RUN_INTO },
2376 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2377 { ep_dont_touch, EP_DONT_TOUCH },
2378 { ep_indestructible, EP_INDESTRUCTIBLE },
2379 { ep_slippery, EP_SLIPPERY },
2380 { ep_can_change, EP_CAN_CHANGE },
2381 { ep_can_move, EP_CAN_MOVE },
2382 { ep_can_fall, EP_CAN_FALL },
2383 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2384 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2385 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2386 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2387 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2388 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2389 { ep_walkable_over, EP_WALKABLE_OVER },
2390 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2391 { ep_walkable_under, EP_WALKABLE_UNDER },
2392 { ep_passable_over, EP_PASSABLE_OVER },
2393 { ep_passable_inside, EP_PASSABLE_INSIDE },
2394 { ep_passable_under, EP_PASSABLE_UNDER },
2395 { ep_pushable, EP_PUSHABLE },
2397 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2399 { ep_player, EP_PLAYER },
2400 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2401 { ep_switchable, EP_SWITCHABLE },
2402 { ep_bd_element, EP_BD_ELEMENT },
2403 { ep_sp_element, EP_SP_ELEMENT },
2404 { ep_sb_element, EP_SB_ELEMENT },
2406 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2407 { ep_food_penguin, EP_FOOD_PENGUIN },
2408 { ep_food_pig, EP_FOOD_PIG },
2409 { ep_historic_wall, EP_HISTORIC_WALL },
2410 { ep_historic_solid, EP_HISTORIC_SOLID },
2411 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2412 { ep_belt, EP_BELT },
2413 { ep_belt_active, EP_BELT_ACTIVE },
2414 { ep_belt_switch, EP_BELT_SWITCH },
2415 { ep_tube, EP_TUBE },
2416 { ep_keygate, EP_KEYGATE },
2417 { ep_amoeboid, EP_AMOEBOID },
2418 { ep_amoebalive, EP_AMOEBALIVE },
2419 { ep_has_content, EP_HAS_CONTENT },
2420 { ep_active_bomb, EP_ACTIVE_BOMB },
2421 { ep_inactive, EP_INACTIVE },
2426 static int copy_properties[][5] =
2430 EL_BUG_LEFT, EL_BUG_RIGHT,
2431 EL_BUG_UP, EL_BUG_DOWN
2435 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2436 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2440 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2441 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2445 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2446 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2450 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2451 EL_PACMAN_UP, EL_PACMAN_DOWN
2461 /* always start with reliable default values (element has no properties) */
2462 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2463 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2464 SET_PROPERTY(i, j, FALSE);
2466 /* set all base element properties from above array definitions */
2467 for (i=0; element_properties[i].elements != NULL; i++)
2468 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2469 SET_PROPERTY((element_properties[i].elements)[j],
2470 element_properties[i].property, TRUE);
2472 /* copy properties to some elements that are only stored in level file */
2473 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2474 for (j=0; copy_properties[j][0] != -1; j++)
2475 if (HAS_PROPERTY(copy_properties[j][0], i))
2476 for (k=1; k<=4; k++)
2477 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2480 void InitElementPropertiesEngine(int engine_version)
2483 static int active_properties[] =
2488 EP_DONT_COLLIDE_WITH,
2492 EP_CAN_PASS_MAGIC_WALL,
2497 EP_CAN_EXPLODE_BY_FIRE,
2510 EP_EM_SLIPPERY_WALL,
2515 static int no_wall_properties[] =
2520 EP_DONT_COLLIDE_WITH,
2523 EP_CAN_SMASH_PLAYER,
2524 EP_CAN_SMASH_ENEMIES,
2525 EP_CAN_SMASH_EVERYTHING,
2532 EP_FOOD_DARK_YAMYAM,
2548 InitElementPropertiesStatic();
2551 /* set all special, combined or engine dependent element properties */
2552 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2555 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2556 SET_PROPERTY(i, j, FALSE);
2559 /* ---------- INACTIVE ------------------------------------------------- */
2560 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2561 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2563 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2564 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2565 IS_WALKABLE_INSIDE(i) ||
2566 IS_WALKABLE_UNDER(i)));
2568 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2569 IS_PASSABLE_INSIDE(i) ||
2570 IS_PASSABLE_UNDER(i)));
2572 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2573 IS_PASSABLE_OVER(i)));
2575 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2576 IS_PASSABLE_INSIDE(i)));
2578 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2579 IS_PASSABLE_UNDER(i)));
2581 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2584 /* ---------- SNAPPABLE ------------------------------------------------ */
2585 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2586 IS_COLLECTIBLE(i) ||
2590 /* ---------- WALL ----------------------------------------------------- */
2591 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2593 for (j=0; no_wall_properties[j] != -1; j++)
2594 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2595 i >= EL_FIRST_RUNTIME_UNREAL)
2596 SET_PROPERTY(i, EP_WALL, FALSE);
2598 if (IS_HISTORIC_WALL(i))
2599 SET_PROPERTY(i, EP_WALL, TRUE);
2601 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2602 if (engine_version < VERSION_IDENT(2,2,0))
2603 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2605 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2607 !IS_COLLECTIBLE(i)));
2609 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2611 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2612 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2614 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2615 IS_INDESTRUCTIBLE(i)));
2617 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2619 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2620 else if (engine_version < VERSION_IDENT(2,2,0))
2621 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2623 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2624 !IS_WALKABLE_OVER(i) &&
2625 !IS_WALKABLE_UNDER(i)));
2627 if (IS_CUSTOM_ELEMENT(i))
2629 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2631 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2632 if (DONT_COLLIDE_WITH(i))
2633 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2635 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2636 if (CAN_SMASH_EVERYTHING(i))
2637 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2638 if (CAN_SMASH_ENEMIES(i))
2639 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2642 /* ---------- CAN_SMASH ------------------------------------------------ */
2643 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2644 CAN_SMASH_ENEMIES(i) ||
2645 CAN_SMASH_EVERYTHING(i)));
2647 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2648 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2649 CAN_EXPLODE_SMASHED(i) ||
2650 CAN_EXPLODE_IMPACT(i)));
2654 /* determine inactive elements (used for engine main loop optimization) */
2655 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2657 boolean active = FALSE;
2659 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2661 if (HAS_PROPERTY(i, j))
2667 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2672 /* dynamically adjust element properties according to game engine version */
2674 static int ep_em_slippery_wall[] =
2679 EL_EXPANDABLE_WALL_HORIZONTAL,
2680 EL_EXPANDABLE_WALL_VERTICAL,
2681 EL_EXPANDABLE_WALL_ANY,
2685 /* special EM style gems behaviour */
2686 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2687 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2688 level.em_slippery_gems);
2690 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2691 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2692 (level.em_slippery_gems &&
2693 engine_version > VERSION_IDENT(2,0,1)));
2697 /* dynamically adjust element properties according to game engine version */
2699 if (engine_version < RELEASE_IDENT(2,2,0,7))
2702 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2704 int element = EL_CUSTOM_START + i;
2706 element_info[element].push_delay_fixed = 2;
2707 element_info[element].push_delay_random = 8;
2713 static void InitGlobal()
2715 global.autoplay_leveldir = NULL;
2717 global.frames_per_second = 0;
2718 global.fps_slowdown = FALSE;
2719 global.fps_slowdown_factor = 1;
2722 void Execute_Command(char *command)
2724 if (strcmp(command, "print graphicsinfo.conf") == 0)
2728 printf("# You can configure additional/alternative image files here.\n");
2729 printf("# (The images below are default and therefore commented out.)\n");
2731 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2733 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2736 for (i=0; image_config[i].token != NULL; i++)
2738 getFormattedSetupEntry(image_config[i].token,
2739 image_config[i].value));
2743 else if (strcmp(command, "print soundsinfo.conf") == 0)
2747 printf("# You can configure additional/alternative sound files here.\n");
2748 printf("# (The sounds below are default and therefore commented out.)\n");
2750 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2752 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2755 for (i=0; sound_config[i].token != NULL; i++)
2757 getFormattedSetupEntry(sound_config[i].token,
2758 sound_config[i].value));
2762 else if (strcmp(command, "print musicinfo.conf") == 0)
2764 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2766 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2768 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2772 else if (strncmp(command, "dump level ", 11) == 0)
2774 char *filename = &command[11];
2776 if (access(filename, F_OK) != 0)
2777 Error(ERR_EXIT, "cannot open file '%s'", filename);
2779 LoadLevelFromFilename(&level, filename);
2784 else if (strncmp(command, "dump tape ", 10) == 0)
2786 char *filename = &command[10];
2788 if (access(filename, F_OK) != 0)
2789 Error(ERR_EXIT, "cannot open file '%s'", filename);
2791 LoadTapeFromFilename(filename);
2796 else if (strncmp(command, "autoplay ", 9) == 0)
2798 char *str_copy = getStringCopy(&command[9]);
2799 char *str_ptr = strchr(str_copy, ' ');
2801 global.autoplay_leveldir = str_copy;
2802 global.autoplay_level_nr = -1;
2804 if (str_ptr != NULL)
2806 *str_ptr++ = '\0'; /* terminate leveldir string */
2807 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2812 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2816 static void InitSetup()
2818 LoadSetup(); /* global setup info */
2820 /* set some options from setup file */
2822 if (setup.options.verbose)
2823 options.verbose = TRUE;
2826 static void InitPlayerInfo()
2830 /* choose default local player */
2831 local_player = &stored_player[0];
2833 for (i=0; i<MAX_PLAYERS; i++)
2834 stored_player[i].connected = FALSE;
2836 local_player->connected = TRUE;
2839 static void InitArtworkInfo()
2844 static char *get_string_in_brackets(char *string)
2846 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2848 sprintf(string_in_brackets, "[%s]", string);
2850 return string_in_brackets;
2854 static char *get_element_class_token(int element)
2856 char *element_class_name = element_info[element].class_name;
2857 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2859 sprintf(element_class_token, "[%s]", element_class_name);
2861 return element_class_token;
2864 static char *get_action_class_token(int action)
2866 char *action_class_name = &element_action_info[action].suffix[1];
2867 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2869 sprintf(action_class_token, "[%s]", action_class_name);
2871 return action_class_token;
2875 static void InitArtworkConfig()
2877 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2878 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2879 static char *action_id_suffix[NUM_ACTIONS + 1];
2880 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2881 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2882 static char *dummy[1] = { NULL };
2883 static char *ignore_generic_tokens[] =
2889 static char **ignore_image_tokens, **ignore_sound_tokens;
2890 int num_ignore_generic_tokens;
2891 int num_ignore_image_tokens, num_ignore_sound_tokens;
2894 /* dynamically determine list of generic tokens to be ignored */
2895 num_ignore_generic_tokens = 0;
2896 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2897 num_ignore_generic_tokens++;
2899 /* dynamically determine list of image tokens to be ignored */
2900 num_ignore_image_tokens = num_ignore_generic_tokens;
2901 for (i=0; image_config_vars[i].token != NULL; i++)
2902 num_ignore_image_tokens++;
2903 ignore_image_tokens =
2904 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2905 for (i=0; i < num_ignore_generic_tokens; i++)
2906 ignore_image_tokens[i] = ignore_generic_tokens[i];
2907 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2908 ignore_image_tokens[num_ignore_generic_tokens + i] =
2909 image_config_vars[i].token;
2910 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2912 /* dynamically determine list of sound tokens to be ignored */
2913 num_ignore_sound_tokens = num_ignore_generic_tokens;
2914 ignore_sound_tokens =
2915 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2916 for (i=0; i < num_ignore_generic_tokens; i++)
2917 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2918 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2920 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2921 image_id_prefix[i] = element_info[i].token_name;
2922 for (i=0; i<NUM_FONTS; i++)
2923 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2924 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2926 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2927 sound_id_prefix[i] = element_info[i].token_name;
2928 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2929 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2930 get_string_in_brackets(element_info[i].class_name);
2931 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2933 for (i=0; i<NUM_ACTIONS; i++)
2934 action_id_suffix[i] = element_action_info[i].suffix;
2935 action_id_suffix[NUM_ACTIONS] = NULL;
2937 for (i=0; i<NUM_DIRECTIONS; i++)
2938 direction_id_suffix[i] = element_direction_info[i].suffix;
2939 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2941 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2942 special_id_suffix[i] = special_suffix_info[i].suffix;
2943 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2945 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2946 image_id_prefix, action_id_suffix, direction_id_suffix,
2947 special_id_suffix, ignore_image_tokens);
2948 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2949 sound_id_prefix, action_id_suffix, dummy,
2950 special_id_suffix, ignore_sound_tokens);
2953 static void InitMixer()
2961 char *filename_font_initial = NULL;
2962 Bitmap *bitmap_font_initial = NULL;
2965 /* determine settings for initial font (for displaying startup messages) */
2966 for (i=0; image_config[i].token != NULL; i++)
2968 for (j=0; j < NUM_INITIAL_FONTS; j++)
2970 char font_token[128];
2973 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2974 len_font_token = strlen(font_token);
2976 if (strcmp(image_config[i].token, font_token) == 0)
2977 filename_font_initial = image_config[i].value;
2978 else if (strlen(image_config[i].token) > len_font_token &&
2979 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2981 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2982 font_initial[j].src_x = atoi(image_config[i].value);
2983 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2984 font_initial[j].src_y = atoi(image_config[i].value);
2985 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2986 font_initial[j].width = atoi(image_config[i].value);
2987 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2988 font_initial[j].height = atoi(image_config[i].value);
2993 for (j=0; j < NUM_INITIAL_FONTS; j++)
2995 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2996 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2999 if (filename_font_initial == NULL) /* should not happen */
3000 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3002 /* create additional image buffers for double-buffering */
3003 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3004 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3006 /* initialize screen properties */
3007 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3008 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3010 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3011 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3012 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3014 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3016 for (j=0; j < NUM_INITIAL_FONTS; j++)
3017 font_initial[j].bitmap = bitmap_font_initial;
3019 InitFontGraphicInfo();
3021 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
3022 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
3024 DrawInitText("Loading graphics:", 120, FC_GREEN);
3026 InitTileClipmasks();
3029 void InitGfxBackground()
3033 drawto = backbuffer;
3034 fieldbuffer = bitmap_db_field;
3035 SetDrawtoField(DRAW_BACKBUFFER);
3037 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3038 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3039 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3040 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3042 for (x=0; x<MAX_BUF_XSIZE; x++)
3043 for (y=0; y<MAX_BUF_YSIZE; y++)
3046 redraw_mask = REDRAW_ALL;
3049 static void InitLevelInfo()
3051 LoadLevelInfo(); /* global level info */
3052 LoadLevelSetup_LastSeries(); /* last played series info */
3053 LoadLevelSetup_SeriesInfo(); /* last played level info */
3056 void InitLevelArtworkInfo()
3058 LoadLevelArtworkInfo();
3061 static void InitImages()
3064 setLevelArtworkDir(artwork.gfx_first);
3068 printf("::: InitImages ['%s', '%s'] ['%s', '%s']\n",
3069 artwork.gfx_current_identifier,
3070 artwork.gfx_current->identifier,
3071 leveldir_current->graphics_set,
3072 leveldir_current->graphics_path);
3075 ReloadCustomImages();
3077 LoadCustomElementDescriptions();
3078 LoadSpecialMenuDesignSettings();
3080 ReinitializeGraphics();
3083 static void InitSound()
3085 setLevelArtworkDir(artwork.snd_first);
3087 InitReloadCustomSounds(artwork.snd_current->identifier);
3088 ReinitializeSounds();
3091 static void InitMusic()
3093 setLevelArtworkDir(artwork.mus_first);
3095 InitReloadCustomMusic(artwork.mus_current->identifier);
3096 ReinitializeMusic();
3099 void InitNetworkServer()
3101 #if defined(PLATFORM_UNIX)
3105 if (!options.network)
3108 #if defined(PLATFORM_UNIX)
3109 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3111 if (!ConnectToServer(options.server_host, options.server_port))
3112 Error(ERR_EXIT, "cannot connect to network game server");
3114 SendToServer_PlayerName(setup.player_name);
3115 SendToServer_ProtocolVersion();
3118 SendToServer_NrWanted(nr_wanted);
3122 void ReloadCustomArtwork()
3124 static char *leveldir_current_identifier = NULL;
3125 static boolean last_override_level_graphics = FALSE;
3126 static boolean last_override_level_sounds = FALSE;
3127 static boolean last_override_level_music = FALSE;
3128 static boolean last_own_level_graphics_set = FALSE;
3129 static boolean last_own_level_sounds_set = FALSE;
3130 static boolean last_own_level_music_set = FALSE;
3131 boolean level_graphics_set_changed = FALSE;
3132 boolean level_sounds_set_changed = FALSE;
3133 boolean level_music_set_changed = FALSE;
3134 /* identifier for new artwork; default: artwork configured in setup */
3136 char *gfx_new_identifier = artwork.gfx_current->identifier;
3137 char *snd_new_identifier = artwork.snd_current->identifier;
3138 char *mus_new_identifier = artwork.mus_current->identifier;
3140 char *gfx_new_identifier = artwork.gfx_current_identifier;
3141 char *snd_new_identifier = artwork.snd_current_identifier;
3142 char *mus_new_identifier = artwork.mus_current_identifier;
3144 boolean redraw_screen = FALSE;
3147 if (leveldir_current_identifier == NULL)
3148 leveldir_current_identifier = leveldir_current->identifier;
3152 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3153 leveldir_current->graphics_set);
3154 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3155 leveldir_current->identifier);
3159 printf("graphics --> '%s' ('%s')\n",
3160 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3161 printf("sounds --> '%s' ('%s')\n",
3162 artwork.snd_current_identifier, artwork.snd_current->filename);
3163 printf("music --> '%s' ('%s')\n",
3164 artwork.mus_current_identifier, artwork.mus_current->filename);
3167 /* leveldir_current may be invalid (level group, parent link) */
3168 if (!validLevelSeries(leveldir_current))
3171 /* when a new level series was selected, check if there was a change
3172 in custom artwork stored in level series directory */
3173 if (1 || leveldir_current_identifier != leveldir_current->identifier)
3176 char *identifier_old = leveldir_current_identifier;
3178 char *identifier_new = leveldir_current->identifier;
3181 printf("::: 1: ['%s'] '%s', '%s' [%lx, %lx]\n",
3182 gfx_new_identifier, identifier_old, identifier_new,
3183 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old),
3184 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new));
3188 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new) == NULL)
3189 gfx_new_identifier = GRAPHICS_SUBDIR;
3190 else if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3191 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3192 gfx_new_identifier = identifier_new;
3194 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3195 gfx_new_identifier = identifier_new;
3197 gfx_new_identifier = setup.graphics_set;
3201 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new) == NULL)
3202 snd_new_identifier = SOUNDS_SUBDIR;
3203 else if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3204 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3205 snd_new_identifier = identifier_new;
3207 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3208 snd_new_identifier = identifier_new;
3210 snd_new_identifier = setup.sounds_set;
3214 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) == NULL)
3215 mus_new_identifier = MUSIC_SUBDIR;
3216 else if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3217 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3218 mus_new_identifier = identifier_new;
3220 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3221 mus_new_identifier = identifier_new;
3223 mus_new_identifier = setup.music_set;
3227 printf("::: 2: ['%s'] '%s', '%s'\n",
3228 gfx_new_identifier, identifier_old, identifier_new);
3232 leveldir_current_identifier = leveldir_current->identifier;
3236 /* custom level artwork configured in level series configuration file
3237 always overrides custom level artwork stored in level series directory
3238 and (level independent) custom artwork configured in setup menu */
3239 if (leveldir_current->graphics_set != NULL)
3240 gfx_new_identifier = leveldir_current->graphics_set;
3241 if (leveldir_current->sounds_set != NULL)
3242 snd_new_identifier = leveldir_current->sounds_set;
3243 if (leveldir_current->music_set != NULL)
3244 mus_new_identifier = leveldir_current->music_set;
3246 if (leveldir_current_identifier != leveldir_current->identifier)
3248 if (last_own_level_graphics_set || leveldir_current->graphics_set != NULL)
3249 level_graphics_set_changed = TRUE;
3251 if (last_own_level_sounds_set || leveldir_current->sounds_set != NULL)
3252 level_sounds_set_changed = TRUE;
3254 if (last_own_level_music_set || leveldir_current->music_set != NULL)
3255 level_music_set_changed = TRUE;
3257 last_own_level_graphics_set = (leveldir_current->graphics_set != NULL);
3258 last_own_level_sounds_set = (leveldir_current->sounds_set != NULL);
3259 last_own_level_music_set = (leveldir_current->music_set != NULL);
3263 leveldir_current_identifier = leveldir_current->identifier;
3266 if (setup.override_level_graphics)
3267 gfx_new_identifier = artwork.gfx_current->identifier;
3268 if (setup.override_level_sounds)
3269 snd_new_identifier = artwork.snd_current->identifier;
3270 if (setup.override_level_music)
3271 mus_new_identifier = artwork.mus_current->identifier;
3275 printf("CHECKING OLD/NEW GFX:\n OLD: '%s'\n NEW: '%s' ['%s', '%s'] [%d]\n",
3276 artwork.gfx_current_identifier, gfx_new_identifier,
3277 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3278 level_graphics_set_changed);
3281 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3282 last_override_level_graphics != setup.override_level_graphics ||
3283 level_graphics_set_changed)
3286 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s']\n",
3287 artwork.gfx_current_identifier,
3289 artwork.gfx_current->identifier);
3293 artwork.gfx_current =
3294 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3297 artwork.gfx_current_identifier = gfx_new_identifier;
3301 setLevelArtworkDir(artwork.gfx_first);
3304 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3309 printf("::: %d\n", menu.list_size[GAME_MODE_LEVELS]);
3312 FreeTileClipmasks();
3313 InitTileClipmasks();
3315 artwork.gfx_current =
3316 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3319 printf("::: '%s', %lx\n", gfx_new_identifier, artwork.gfx_current);
3323 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3325 artwork.gfx_current_identifier = gfx_new_identifier;
3326 last_override_level_graphics = setup.override_level_graphics;
3329 printf("DONE RELOADING GFX: '%s' ['%s']\n",
3330 artwork.gfx_current_identifier, artwork.gfx_current->identifier);
3333 redraw_screen = TRUE;
3336 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3337 last_override_level_sounds != setup.override_level_sounds ||
3338 level_sounds_set_changed)
3341 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3342 artwork.snd_current_identifier,
3343 artwork.snd_current->identifier,
3344 snd_new_identifier);
3347 /* set artwork path to send it to the sound server process */
3348 setLevelArtworkDir(artwork.snd_first);
3350 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3352 InitReloadCustomSounds(snd_new_identifier);
3353 ReinitializeSounds();
3356 artwork.snd_current =
3357 getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
3358 artwork.snd_current_identifier = artwork.snd_current->identifier;
3360 artwork.snd_current_identifier = snd_new_identifier;
3361 last_override_level_sounds = setup.override_level_sounds;
3363 redraw_screen = TRUE;
3366 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3367 last_override_level_music != setup.override_level_music ||
3368 level_music_set_changed)
3370 /* set artwork path to send it to the sound server process */
3371 setLevelArtworkDir(artwork.mus_first);
3373 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3375 InitReloadCustomMusic(mus_new_identifier);
3376 ReinitializeMusic();
3379 artwork.mus_current =
3380 getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
3381 artwork.mus_current_identifier = artwork.mus_current->identifier;
3383 artwork.mus_current_identifier = mus_new_identifier;
3384 last_override_level_music = setup.override_level_music;
3386 redraw_screen = TRUE;
3391 InitGfxBackground();
3393 /* force redraw of (open or closed) door graphics */
3394 SetDoorState(DOOR_OPEN_ALL);
3395 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3399 void KeyboardAutoRepeatOffUnlessAutoplay()
3401 if (global.autoplay_leveldir == NULL)
3402 KeyboardAutoRepeatOff();
3406 /* ========================================================================= */
3408 /* ========================================================================= */
3412 InitGlobal(); /* initialize some global variables */
3414 if (options.execute_command)
3415 Execute_Command(options.execute_command);
3417 if (options.serveronly)
3419 #if defined(PLATFORM_UNIX)
3420 NetworkServer(options.server_port, options.serveronly);
3422 Error(ERR_WARN, "networking only supported in Unix version");
3424 exit(0); /* never reached */
3430 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3431 InitArtworkConfig(); /* needed before forking sound child process */
3436 InitRND(NEW_RANDOMIZE);
3437 InitSimpleRND(NEW_RANDOMIZE);
3442 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3445 InitEventFilter(FilterMouseMotionEvents);
3447 InitElementPropertiesStatic();
3452 InitLevelArtworkInfo();
3454 InitImages(); /* needs to know current level directory */
3455 InitSound(); /* needs to know current level directory */
3456 InitMusic(); /* needs to know current level directory */
3458 InitGfxBackground();
3460 if (global.autoplay_leveldir)
3466 game_status = GAME_MODE_MAIN;
3470 InitNetworkServer();
3473 void CloseAllAndExit(int exit_value)
3478 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3481 FreeTileClipmasks();
3483 CloseVideoDisplay();
3484 ClosePlatformDependentStuff();