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);
761 set_graphic_parameters(i, image->parameter);
763 /* now check if no animation frames are outside of the loaded image */
765 if (graphic_info[i].bitmap == NULL)
766 continue; /* skip check for optional images that are undefined */
769 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
770 if (src_x < 0 || src_y < 0 ||
771 src_x + TILEX > src_bitmap->width ||
772 src_y + TILEY > src_bitmap->height)
774 Error(ERR_RETURN_LINE, "-");
775 Error(ERR_RETURN, "warning: error found in config file:");
776 Error(ERR_RETURN, "- config file: '%s'",
777 getImageConfigFilename());
778 Error(ERR_RETURN, "- config token: '%s'",
779 getTokenFromImageID(i));
780 Error(ERR_RETURN, "- image file: '%s'",
781 src_bitmap->source_filename);
783 "error: first animation frame out of bounds (%d, %d)",
785 Error(ERR_RETURN, "custom graphic rejected for this element/action");
787 if (i == fallback_graphic)
788 Error(ERR_EXIT, "fatal error: no fallback graphic available");
790 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
791 Error(ERR_RETURN_LINE, "-");
793 set_graphic_parameters(i, fallback_image->default_parameter);
794 graphic_info[i].bitmap = fallback_bitmap;
797 last_frame = graphic_info[i].anim_frames - 1;
798 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
799 if (src_x < 0 || src_y < 0 ||
800 src_x + TILEX > src_bitmap->width ||
801 src_y + TILEY > src_bitmap->height)
803 Error(ERR_RETURN_LINE, "-");
804 Error(ERR_RETURN, "warning: error found in config file:");
805 Error(ERR_RETURN, "- config file: '%s'",
806 getImageConfigFilename());
807 Error(ERR_RETURN, "- config token: '%s'",
808 getTokenFromImageID(i));
809 Error(ERR_RETURN, "- image file: '%s'",
810 src_bitmap->source_filename);
812 "error: last animation frame (%d) out of bounds (%d, %d)",
813 last_frame, src_x, src_y);
814 Error(ERR_RETURN, "custom graphic rejected for this element/action");
816 if (i == fallback_graphic)
817 Error(ERR_EXIT, "fatal error: no fallback graphic available");
819 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
820 Error(ERR_RETURN_LINE, "-");
822 set_graphic_parameters(i, fallback_image->default_parameter);
823 graphic_info[i].bitmap = fallback_bitmap;
826 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
827 /* currently we need only a tile clip mask from the first frame */
828 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
830 if (copy_clipmask_gc == None)
832 clip_gc_values.graphics_exposures = False;
833 clip_gc_valuemask = GCGraphicsExposures;
834 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
835 clip_gc_valuemask, &clip_gc_values);
838 graphic_info[i].clip_mask =
839 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
841 src_pixmap = src_bitmap->clip_mask;
842 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
843 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
845 clip_gc_values.graphics_exposures = False;
846 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
847 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
849 graphic_info[i].clip_gc =
850 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
854 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
855 if (copy_clipmask_gc)
856 XFreeGC(display, copy_clipmask_gc);
858 clipmasks_initialized = TRUE;
862 static void InitElementSoundInfo()
864 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
865 int num_property_mappings = getSoundListPropertyMappingSize();
868 /* set values to -1 to identify later as "uninitialized" values */
869 for (i=0; i < MAX_NUM_ELEMENTS; i++)
870 for (act=0; act < NUM_ACTIONS; act++)
871 element_info[i].sound[act] = -1;
873 /* initialize element/sound mapping from static configuration */
874 for (i=0; element_to_sound[i].element > -1; i++)
876 int element = element_to_sound[i].element;
877 int action = element_to_sound[i].action;
878 int sound = element_to_sound[i].sound;
879 boolean is_class = element_to_sound[i].is_class;
882 action = ACTION_DEFAULT;
885 element_info[element].sound[action] = sound;
887 for (j=0; j < MAX_NUM_ELEMENTS; j++)
888 if (strcmp(element_info[j].class_name,
889 element_info[element].class_name) == 0)
890 element_info[j].sound[action] = sound;
893 /* initialize element class/sound mapping from dynamic configuration */
894 for (i=0; i < num_property_mappings; i++)
896 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
897 int action = property_mapping[i].ext1_index;
898 int sound = property_mapping[i].artwork_index;
900 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
904 action = ACTION_DEFAULT;
906 for (j=0; j < MAX_NUM_ELEMENTS; j++)
907 if (strcmp(element_info[j].class_name,
908 element_info[element_class].class_name) == 0)
909 element_info[j].sound[action] = sound;
912 /* initialize element/sound mapping from dynamic configuration */
913 for (i=0; i < num_property_mappings; i++)
915 int element = property_mapping[i].base_index;
916 int action = property_mapping[i].ext1_index;
917 int sound = property_mapping[i].artwork_index;
919 if (element >= MAX_NUM_ELEMENTS)
923 action = ACTION_DEFAULT;
925 element_info[element].sound[action] = sound;
928 /* now set all '-1' values to element specific default values */
929 for (i=0; i<MAX_NUM_ELEMENTS; i++)
931 for (act=0; act < NUM_ACTIONS; act++)
933 /* generic default action sound (defined by "[default]" directive) */
934 int default_action_sound = element_info[EL_DEFAULT].sound[act];
936 /* look for special default action sound (classic game specific) */
937 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
938 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
939 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
940 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
941 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
942 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
944 /* look for element specific default sound (independent from action) */
945 if (element_info[i].sound[ACTION_DEFAULT] != -1)
946 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
948 /* no sound for this specific action -- use default action sound */
949 if (element_info[i].sound[act] == -1)
950 element_info[i].sound[act] = default_action_sound;
955 static void set_sound_parameters(int sound, char **parameter_raw)
957 int parameter[NUM_SND_ARGS];
960 /* get integer values from string parameters */
961 for (i=0; i < NUM_SND_ARGS; i++)
963 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
964 sound_config_suffix[i].type);
966 /* explicit loop mode setting in configuration overrides default value */
967 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
968 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
971 static void InitSoundInfo()
974 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
975 int num_property_mappings = getSoundListPropertyMappingSize();
977 int *sound_effect_properties;
978 int num_sounds = getSoundListSize();
981 if (sound_info != NULL)
984 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
985 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
987 /* initialize sound effect for all elements to "no sound" */
988 for (i=0; i<MAX_NUM_ELEMENTS; i++)
989 for (j=0; j<NUM_ACTIONS; j++)
990 element_info[i].sound[j] = SND_UNDEFINED;
992 for (i=0; i<num_sounds; i++)
994 struct FileInfo *sound = getSoundListEntry(i);
995 int len_effect_text = strlen(sound->token);
997 sound_effect_properties[i] = ACTION_OTHER;
998 sound_info[i].loop = FALSE;
1001 printf("::: sound: '%s'\n", sound->token);
1004 /* determine all loop sounds and identify certain sound classes */
1006 for (j=0; element_action_info[j].suffix; j++)
1008 int len_action_text = strlen(element_action_info[j].suffix);
1010 if (len_action_text < len_effect_text &&
1011 strcmp(&sound->token[len_effect_text - len_action_text],
1012 element_action_info[j].suffix) == 0)
1014 sound_effect_properties[i] = element_action_info[j].value;
1016 if (element_action_info[j].is_loop_sound)
1017 sound_info[i].loop = TRUE;
1022 if (strcmp(sound->token, "custom_42") == 0)
1023 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1026 /* associate elements and some selected sound actions */
1028 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1030 if (element_info[j].class_name)
1032 int len_class_text = strlen(element_info[j].class_name);
1034 if (len_class_text + 1 < len_effect_text &&
1035 strncmp(sound->token,
1036 element_info[j].class_name, len_class_text) == 0 &&
1037 sound->token[len_class_text] == '.')
1039 int sound_action_value = sound_effect_properties[i];
1041 element_info[j].sound[sound_action_value] = i;
1046 set_sound_parameters(i, sound->parameter);
1049 free(sound_effect_properties);
1052 /* !!! now handled in InitElementSoundInfo() !!! */
1053 /* initialize element/sound mapping from dynamic configuration */
1054 for (i=0; i < num_property_mappings; i++)
1056 int element = property_mapping[i].base_index;
1057 int action = property_mapping[i].ext1_index;
1058 int sound = property_mapping[i].artwork_index;
1061 action = ACTION_DEFAULT;
1063 printf("::: %d: %d, %d, %d ['%s']\n",
1064 i, element, action, sound, element_info[element].token_name);
1066 element_info[element].sound[action] = sound;
1073 int element = EL_CUSTOM_11;
1076 while (element_action_info[j].suffix)
1078 printf("element %d, sound action '%s' == %d\n",
1079 element, element_action_info[j].suffix,
1080 element_info[element].sound[j]);
1085 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1091 int element = EL_SAND;
1092 int sound_action = ACTION_DIGGING;
1095 while (element_action_info[j].suffix)
1097 if (element_action_info[j].value == sound_action)
1098 printf("element %d, sound action '%s' == %d\n",
1099 element, element_action_info[j].suffix,
1100 element_info[element].sound[sound_action]);
1107 static void ReinitializeGraphics()
1109 InitGraphicInfo(); /* graphic properties mapping */
1110 InitElementGraphicInfo(); /* element game graphic mapping */
1111 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1113 InitElementSmallImages(); /* create editor and preview images */
1114 InitFontGraphicInfo(); /* initialize text drawing functions */
1116 SetMainBackgroundImage(IMG_BACKGROUND);
1117 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1123 static void ReinitializeSounds()
1125 InitSoundInfo(); /* sound properties mapping */
1126 InitElementSoundInfo(); /* element game sound mapping */
1128 InitPlaySoundLevel(); /* internal game sound settings */
1131 static void ReinitializeMusic()
1133 /* currently nothing to do */
1136 void InitElementPropertiesStatic()
1138 static int ep_diggable[] =
1143 EL_SP_BUGGY_BASE_ACTIVATING,
1146 EL_INVISIBLE_SAND_ACTIVE,
1148 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1152 EL_SP_BUGGY_BASE_ACTIVE,
1157 static int ep_collectible[] =
1174 EL_DYNABOMB_INCREASE_NUMBER,
1175 EL_DYNABOMB_INCREASE_SIZE,
1176 EL_DYNABOMB_INCREASE_POWER,
1190 static int ep_dont_run_into[] =
1192 /* same elements as in 'ep_dont_touch' */
1198 /* same elements as in 'ep_dont_collide_with' */
1210 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1212 EL_SP_BUGGY_BASE_ACTIVE,
1219 static int ep_dont_collide_with[] =
1221 /* same elements as in 'ep_dont_touch' */
1237 static int ep_dont_touch[] =
1246 static int ep_indestructible[] =
1250 EL_ACID_POOL_TOPLEFT,
1251 EL_ACID_POOL_TOPRIGHT,
1252 EL_ACID_POOL_BOTTOMLEFT,
1253 EL_ACID_POOL_BOTTOM,
1254 EL_ACID_POOL_BOTTOMRIGHT,
1255 EL_SP_HARDWARE_GRAY,
1256 EL_SP_HARDWARE_GREEN,
1257 EL_SP_HARDWARE_BLUE,
1259 EL_SP_HARDWARE_YELLOW,
1260 EL_SP_HARDWARE_BASE_1,
1261 EL_SP_HARDWARE_BASE_2,
1262 EL_SP_HARDWARE_BASE_3,
1263 EL_SP_HARDWARE_BASE_4,
1264 EL_SP_HARDWARE_BASE_5,
1265 EL_SP_HARDWARE_BASE_6,
1266 EL_INVISIBLE_STEELWALL,
1267 EL_INVISIBLE_STEELWALL_ACTIVE,
1268 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1269 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1270 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1271 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1272 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1273 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1274 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1275 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1276 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1277 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1278 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1279 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1281 EL_LIGHT_SWITCH_ACTIVE,
1282 EL_SIGN_EXCLAMATION,
1283 EL_SIGN_RADIOACTIVITY,
1294 EL_STEELWALL_SLANTED,
1317 EL_SWITCHGATE_OPENING,
1318 EL_SWITCHGATE_CLOSED,
1319 EL_SWITCHGATE_CLOSING,
1321 EL_SWITCHGATE_SWITCH_UP,
1322 EL_SWITCHGATE_SWITCH_DOWN,
1325 EL_TIMEGATE_OPENING,
1327 EL_TIMEGATE_CLOSING,
1330 EL_TIMEGATE_SWITCH_ACTIVE,
1335 EL_TUBE_VERTICAL_LEFT,
1336 EL_TUBE_VERTICAL_RIGHT,
1337 EL_TUBE_HORIZONTAL_UP,
1338 EL_TUBE_HORIZONTAL_DOWN,
1346 static int ep_slippery[] =
1360 EL_ROBOT_WHEEL_ACTIVE,
1366 EL_ACID_POOL_TOPLEFT,
1367 EL_ACID_POOL_TOPRIGHT,
1377 EL_STEELWALL_SLANTED,
1383 static int ep_can_change[] =
1388 static int ep_can_move[] =
1410 static int ep_can_fall[] =
1425 EL_BD_MAGIC_WALL_FULL,
1438 static int ep_can_smash_player[] =
1463 static int ep_can_smash_enemies[] =
1471 static int ep_can_smash_everything[] =
1479 static int ep_can_explode_by_fire[] =
1481 /* same elements as in 'ep_can_explode_impact' */
1486 /* same elements as in 'ep_can_explode_smashed' */
1495 EL_DYNABOMB_PLAYER_1_ACTIVE,
1496 EL_DYNABOMB_PLAYER_2_ACTIVE,
1497 EL_DYNABOMB_PLAYER_3_ACTIVE,
1498 EL_DYNABOMB_PLAYER_4_ACTIVE,
1499 EL_DYNABOMB_INCREASE_NUMBER,
1500 EL_DYNABOMB_INCREASE_SIZE,
1501 EL_DYNABOMB_INCREASE_POWER,
1502 EL_SP_DISK_RED_ACTIVE,
1512 static int ep_can_explode_smashed[] =
1514 /* same elements as in 'ep_can_explode_impact' */
1527 static int ep_can_explode_impact[] =
1535 static int ep_walkable_over[] =
1539 EL_SOKOBAN_FIELD_EMPTY,
1556 static int ep_walkable_inside[] =
1561 EL_TUBE_VERTICAL_LEFT,
1562 EL_TUBE_VERTICAL_RIGHT,
1563 EL_TUBE_HORIZONTAL_UP,
1564 EL_TUBE_HORIZONTAL_DOWN,
1572 static int ep_walkable_under[] =
1577 static int ep_passable_over[] =
1592 static int ep_passable_inside[] =
1598 EL_SP_PORT_HORIZONTAL,
1599 EL_SP_PORT_VERTICAL,
1601 EL_SP_GRAVITY_PORT_LEFT,
1602 EL_SP_GRAVITY_PORT_RIGHT,
1603 EL_SP_GRAVITY_PORT_UP,
1604 EL_SP_GRAVITY_PORT_DOWN,
1608 static int ep_passable_under[] =
1613 static int ep_pushable[] =
1625 EL_SOKOBAN_FIELD_FULL,
1632 static int ep_can_be_crumbled[] =
1641 static int ep_player[] =
1650 static int ep_can_pass_magic_wall[] =
1663 static int ep_switchable[] =
1667 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1668 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1669 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1670 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1671 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1672 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1673 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1674 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1675 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1676 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1677 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1678 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1679 EL_SWITCHGATE_SWITCH_UP,
1680 EL_SWITCHGATE_SWITCH_DOWN,
1682 EL_LIGHT_SWITCH_ACTIVE,
1684 EL_BALLOON_SWITCH_LEFT,
1685 EL_BALLOON_SWITCH_RIGHT,
1686 EL_BALLOON_SWITCH_UP,
1687 EL_BALLOON_SWITCH_DOWN,
1688 EL_BALLOON_SWITCH_ANY,
1694 static int ep_bd_element[] =
1723 static int ep_sp_element[] =
1731 EL_SP_HARDWARE_GRAY,
1739 EL_SP_GRAVITY_PORT_RIGHT,
1740 EL_SP_GRAVITY_PORT_DOWN,
1741 EL_SP_GRAVITY_PORT_LEFT,
1742 EL_SP_GRAVITY_PORT_UP,
1747 EL_SP_PORT_VERTICAL,
1748 EL_SP_PORT_HORIZONTAL,
1754 EL_SP_HARDWARE_BASE_1,
1755 EL_SP_HARDWARE_GREEN,
1756 EL_SP_HARDWARE_BLUE,
1758 EL_SP_HARDWARE_YELLOW,
1759 EL_SP_HARDWARE_BASE_2,
1760 EL_SP_HARDWARE_BASE_3,
1761 EL_SP_HARDWARE_BASE_4,
1762 EL_SP_HARDWARE_BASE_5,
1763 EL_SP_HARDWARE_BASE_6,
1766 /* additional elements that appeared in newer Supaplex levels */
1768 /* more than one murphy in a level results in an inactive clone */
1770 /* runtime elements*/
1771 EL_SP_DISK_RED_ACTIVE,
1772 EL_SP_TERMINAL_ACTIVE,
1773 EL_SP_BUGGY_BASE_ACTIVATING,
1774 EL_SP_BUGGY_BASE_ACTIVE,
1778 static int ep_sb_element[] =
1783 EL_SOKOBAN_FIELD_EMPTY,
1784 EL_SOKOBAN_FIELD_FULL,
1786 EL_INVISIBLE_STEELWALL,
1790 static int ep_gem[] =
1801 static int ep_food_dark_yamyam[] =
1828 static int ep_food_penguin[] =
1841 static int ep_food_pig[] =
1852 static int ep_historic_wall[] =
1877 EL_EXPANDABLE_WALL_HORIZONTAL,
1878 EL_EXPANDABLE_WALL_VERTICAL,
1879 EL_EXPANDABLE_WALL_ANY,
1880 EL_EXPANDABLE_WALL_GROWING,
1887 EL_SP_HARDWARE_GRAY,
1888 EL_SP_HARDWARE_GREEN,
1889 EL_SP_HARDWARE_BLUE,
1891 EL_SP_HARDWARE_YELLOW,
1892 EL_SP_HARDWARE_BASE_1,
1893 EL_SP_HARDWARE_BASE_2,
1894 EL_SP_HARDWARE_BASE_3,
1895 EL_SP_HARDWARE_BASE_4,
1896 EL_SP_HARDWARE_BASE_5,
1897 EL_SP_HARDWARE_BASE_6,
1899 EL_SP_TERMINAL_ACTIVE,
1902 EL_INVISIBLE_STEELWALL,
1903 EL_INVISIBLE_STEELWALL_ACTIVE,
1905 EL_INVISIBLE_WALL_ACTIVE,
1906 EL_STEELWALL_SLANTED,
1922 static int ep_historic_solid[] =
1926 EL_EXPANDABLE_WALL_HORIZONTAL,
1927 EL_EXPANDABLE_WALL_VERTICAL,
1928 EL_EXPANDABLE_WALL_ANY,
1941 EL_QUICKSAND_FILLING,
1942 EL_QUICKSAND_EMPTYING,
1944 EL_MAGIC_WALL_ACTIVE,
1945 EL_MAGIC_WALL_EMPTYING,
1946 EL_MAGIC_WALL_FILLING,
1950 EL_BD_MAGIC_WALL_ACTIVE,
1951 EL_BD_MAGIC_WALL_EMPTYING,
1952 EL_BD_MAGIC_WALL_FULL,
1953 EL_BD_MAGIC_WALL_FILLING,
1954 EL_BD_MAGIC_WALL_DEAD,
1963 EL_SP_TERMINAL_ACTIVE,
1967 EL_INVISIBLE_WALL_ACTIVE,
1968 EL_SWITCHGATE_SWITCH_UP,
1969 EL_SWITCHGATE_SWITCH_DOWN,
1971 EL_TIMEGATE_SWITCH_ACTIVE,
1983 /* the following elements are a direct copy of "indestructible" elements,
1984 except "EL_ACID", which is "indestructible", but not "solid"! */
1989 EL_ACID_POOL_TOPLEFT,
1990 EL_ACID_POOL_TOPRIGHT,
1991 EL_ACID_POOL_BOTTOMLEFT,
1992 EL_ACID_POOL_BOTTOM,
1993 EL_ACID_POOL_BOTTOMRIGHT,
1994 EL_SP_HARDWARE_GRAY,
1995 EL_SP_HARDWARE_GREEN,
1996 EL_SP_HARDWARE_BLUE,
1998 EL_SP_HARDWARE_YELLOW,
1999 EL_SP_HARDWARE_BASE_1,
2000 EL_SP_HARDWARE_BASE_2,
2001 EL_SP_HARDWARE_BASE_3,
2002 EL_SP_HARDWARE_BASE_4,
2003 EL_SP_HARDWARE_BASE_5,
2004 EL_SP_HARDWARE_BASE_6,
2005 EL_INVISIBLE_STEELWALL,
2006 EL_INVISIBLE_STEELWALL_ACTIVE,
2007 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2008 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2009 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2010 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2011 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2012 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2013 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2014 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2015 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2016 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2017 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2018 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2020 EL_LIGHT_SWITCH_ACTIVE,
2021 EL_SIGN_EXCLAMATION,
2022 EL_SIGN_RADIOACTIVITY,
2033 EL_STEELWALL_SLANTED,
2056 EL_SWITCHGATE_OPENING,
2057 EL_SWITCHGATE_CLOSED,
2058 EL_SWITCHGATE_CLOSING,
2060 EL_TIMEGATE_OPENING,
2062 EL_TIMEGATE_CLOSING,
2066 EL_TUBE_VERTICAL_LEFT,
2067 EL_TUBE_VERTICAL_RIGHT,
2068 EL_TUBE_HORIZONTAL_UP,
2069 EL_TUBE_HORIZONTAL_DOWN,
2077 static int ep_classic_enemy[] =
2093 static int ep_belt[] =
2095 EL_CONVEYOR_BELT_1_LEFT,
2096 EL_CONVEYOR_BELT_1_MIDDLE,
2097 EL_CONVEYOR_BELT_1_RIGHT,
2098 EL_CONVEYOR_BELT_2_LEFT,
2099 EL_CONVEYOR_BELT_2_MIDDLE,
2100 EL_CONVEYOR_BELT_2_RIGHT,
2101 EL_CONVEYOR_BELT_3_LEFT,
2102 EL_CONVEYOR_BELT_3_MIDDLE,
2103 EL_CONVEYOR_BELT_3_RIGHT,
2104 EL_CONVEYOR_BELT_4_LEFT,
2105 EL_CONVEYOR_BELT_4_MIDDLE,
2106 EL_CONVEYOR_BELT_4_RIGHT,
2110 static int ep_belt_active[] =
2112 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2113 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2114 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2115 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2116 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2117 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2118 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2119 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2120 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2121 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2122 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2123 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2127 static int ep_belt_switch[] =
2129 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2130 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2131 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2132 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2133 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2134 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2135 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2136 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2137 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2138 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2139 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2140 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2144 static int ep_tube[] =
2151 EL_TUBE_HORIZONTAL_UP,
2152 EL_TUBE_HORIZONTAL_DOWN,
2154 EL_TUBE_VERTICAL_LEFT,
2155 EL_TUBE_VERTICAL_RIGHT,
2160 static int ep_keygate[] =
2181 static int ep_amoeboid[] =
2191 static int ep_amoebalive[] =
2200 static int ep_has_content[] =
2210 static int ep_active_bomb[] =
2213 EL_DYNABOMB_PLAYER_1_ACTIVE,
2214 EL_DYNABOMB_PLAYER_2_ACTIVE,
2215 EL_DYNABOMB_PLAYER_3_ACTIVE,
2216 EL_DYNABOMB_PLAYER_4_ACTIVE,
2217 EL_SP_DISK_RED_ACTIVE,
2221 static int ep_inactive[] =
2258 EL_INVISIBLE_STEELWALL,
2266 EL_WALL_EMERALD_YELLOW,
2267 EL_DYNABOMB_INCREASE_NUMBER,
2268 EL_DYNABOMB_INCREASE_SIZE,
2269 EL_DYNABOMB_INCREASE_POWER,
2273 EL_SOKOBAN_FIELD_EMPTY,
2274 EL_SOKOBAN_FIELD_FULL,
2275 EL_WALL_EMERALD_RED,
2276 EL_WALL_EMERALD_PURPLE,
2277 EL_ACID_POOL_TOPLEFT,
2278 EL_ACID_POOL_TOPRIGHT,
2279 EL_ACID_POOL_BOTTOMLEFT,
2280 EL_ACID_POOL_BOTTOM,
2281 EL_ACID_POOL_BOTTOMRIGHT,
2285 EL_BD_MAGIC_WALL_DEAD,
2286 EL_AMOEBA_TO_DIAMOND,
2294 EL_SP_GRAVITY_PORT_RIGHT,
2295 EL_SP_GRAVITY_PORT_DOWN,
2296 EL_SP_GRAVITY_PORT_LEFT,
2297 EL_SP_GRAVITY_PORT_UP,
2298 EL_SP_PORT_HORIZONTAL,
2299 EL_SP_PORT_VERTICAL,
2310 EL_SP_HARDWARE_GRAY,
2311 EL_SP_HARDWARE_GREEN,
2312 EL_SP_HARDWARE_BLUE,
2314 EL_SP_HARDWARE_YELLOW,
2315 EL_SP_HARDWARE_BASE_1,
2316 EL_SP_HARDWARE_BASE_2,
2317 EL_SP_HARDWARE_BASE_3,
2318 EL_SP_HARDWARE_BASE_4,
2319 EL_SP_HARDWARE_BASE_5,
2320 EL_SP_HARDWARE_BASE_6,
2321 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2322 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2323 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2324 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2325 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2326 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2327 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2328 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2329 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2330 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2331 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2332 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2333 EL_SIGN_EXCLAMATION,
2334 EL_SIGN_RADIOACTIVITY,
2345 EL_STEELWALL_SLANTED,
2365 } element_properties[] =
2367 { ep_diggable, EP_DIGGABLE },
2368 { ep_collectible, EP_COLLECTIBLE },
2369 { ep_dont_run_into, EP_DONT_RUN_INTO },
2370 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2371 { ep_dont_touch, EP_DONT_TOUCH },
2372 { ep_indestructible, EP_INDESTRUCTIBLE },
2373 { ep_slippery, EP_SLIPPERY },
2374 { ep_can_change, EP_CAN_CHANGE },
2375 { ep_can_move, EP_CAN_MOVE },
2376 { ep_can_fall, EP_CAN_FALL },
2377 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2378 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2379 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2380 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2381 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2382 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2383 { ep_walkable_over, EP_WALKABLE_OVER },
2384 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2385 { ep_walkable_under, EP_WALKABLE_UNDER },
2386 { ep_passable_over, EP_PASSABLE_OVER },
2387 { ep_passable_inside, EP_PASSABLE_INSIDE },
2388 { ep_passable_under, EP_PASSABLE_UNDER },
2389 { ep_pushable, EP_PUSHABLE },
2391 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2393 { ep_player, EP_PLAYER },
2394 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2395 { ep_switchable, EP_SWITCHABLE },
2396 { ep_bd_element, EP_BD_ELEMENT },
2397 { ep_sp_element, EP_SP_ELEMENT },
2398 { ep_sb_element, EP_SB_ELEMENT },
2400 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2401 { ep_food_penguin, EP_FOOD_PENGUIN },
2402 { ep_food_pig, EP_FOOD_PIG },
2403 { ep_historic_wall, EP_HISTORIC_WALL },
2404 { ep_historic_solid, EP_HISTORIC_SOLID },
2405 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2406 { ep_belt, EP_BELT },
2407 { ep_belt_active, EP_BELT_ACTIVE },
2408 { ep_belt_switch, EP_BELT_SWITCH },
2409 { ep_tube, EP_TUBE },
2410 { ep_keygate, EP_KEYGATE },
2411 { ep_amoeboid, EP_AMOEBOID },
2412 { ep_amoebalive, EP_AMOEBALIVE },
2413 { ep_has_content, EP_HAS_CONTENT },
2414 { ep_active_bomb, EP_ACTIVE_BOMB },
2415 { ep_inactive, EP_INACTIVE },
2420 static int copy_properties[][5] =
2424 EL_BUG_LEFT, EL_BUG_RIGHT,
2425 EL_BUG_UP, EL_BUG_DOWN
2429 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2430 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2434 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2435 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2439 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2440 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2444 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2445 EL_PACMAN_UP, EL_PACMAN_DOWN
2455 /* always start with reliable default values (element has no properties) */
2456 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2457 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2458 SET_PROPERTY(i, j, FALSE);
2460 /* set all base element properties from above array definitions */
2461 for (i=0; element_properties[i].elements != NULL; i++)
2462 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2463 SET_PROPERTY((element_properties[i].elements)[j],
2464 element_properties[i].property, TRUE);
2466 /* copy properties to some elements that are only stored in level file */
2467 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2468 for (j=0; copy_properties[j][0] != -1; j++)
2469 if (HAS_PROPERTY(copy_properties[j][0], i))
2470 for (k=1; k<=4; k++)
2471 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2474 void InitElementPropertiesEngine(int engine_version)
2477 static int active_properties[] =
2482 EP_DONT_COLLIDE_WITH,
2486 EP_CAN_PASS_MAGIC_WALL,
2491 EP_CAN_EXPLODE_BY_FIRE,
2504 EP_EM_SLIPPERY_WALL,
2509 static int no_wall_properties[] =
2514 EP_DONT_COLLIDE_WITH,
2517 EP_CAN_SMASH_PLAYER,
2518 EP_CAN_SMASH_ENEMIES,
2519 EP_CAN_SMASH_EVERYTHING,
2526 EP_FOOD_DARK_YAMYAM,
2542 InitElementPropertiesStatic();
2545 /* set all special, combined or engine dependent element properties */
2546 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2549 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2550 SET_PROPERTY(i, j, FALSE);
2553 /* ---------- INACTIVE ------------------------------------------------- */
2554 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2555 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2557 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2558 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2559 IS_WALKABLE_INSIDE(i) ||
2560 IS_WALKABLE_UNDER(i)));
2562 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2563 IS_PASSABLE_INSIDE(i) ||
2564 IS_PASSABLE_UNDER(i)));
2566 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2567 IS_PASSABLE_OVER(i)));
2569 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2570 IS_PASSABLE_INSIDE(i)));
2572 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2573 IS_PASSABLE_UNDER(i)));
2575 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2578 /* ---------- SNAPPABLE ------------------------------------------------ */
2579 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2580 IS_COLLECTIBLE(i) ||
2584 /* ---------- WALL ----------------------------------------------------- */
2585 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2587 for (j=0; no_wall_properties[j] != -1; j++)
2588 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2589 i >= EL_FIRST_RUNTIME_UNREAL)
2590 SET_PROPERTY(i, EP_WALL, FALSE);
2592 if (IS_HISTORIC_WALL(i))
2593 SET_PROPERTY(i, EP_WALL, TRUE);
2595 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2596 if (engine_version < VERSION_IDENT(2,2,0))
2597 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2599 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2601 !IS_COLLECTIBLE(i)));
2603 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2605 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2606 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2608 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2609 IS_INDESTRUCTIBLE(i)));
2611 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2613 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2614 else if (engine_version < VERSION_IDENT(2,2,0))
2615 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2617 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2618 !IS_WALKABLE_OVER(i) &&
2619 !IS_WALKABLE_UNDER(i)));
2621 if (IS_CUSTOM_ELEMENT(i))
2623 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2625 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2626 if (DONT_COLLIDE_WITH(i))
2627 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2629 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2630 if (CAN_SMASH_EVERYTHING(i))
2631 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2632 if (CAN_SMASH_ENEMIES(i))
2633 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2636 /* ---------- CAN_SMASH ------------------------------------------------ */
2637 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2638 CAN_SMASH_ENEMIES(i) ||
2639 CAN_SMASH_EVERYTHING(i)));
2641 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2642 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2643 CAN_EXPLODE_SMASHED(i) ||
2644 CAN_EXPLODE_IMPACT(i)));
2648 /* determine inactive elements (used for engine main loop optimization) */
2649 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2651 boolean active = FALSE;
2653 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2655 if (HAS_PROPERTY(i, j))
2661 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2666 /* dynamically adjust element properties according to game engine version */
2668 static int ep_em_slippery_wall[] =
2673 EL_EXPANDABLE_WALL_HORIZONTAL,
2674 EL_EXPANDABLE_WALL_VERTICAL,
2675 EL_EXPANDABLE_WALL_ANY,
2679 /* special EM style gems behaviour */
2680 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2681 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2682 level.em_slippery_gems);
2684 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2685 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2686 (level.em_slippery_gems &&
2687 engine_version > VERSION_IDENT(2,0,1)));
2691 /* dynamically adjust element properties according to game engine version */
2693 if (engine_version < RELEASE_IDENT(2,2,0,7))
2696 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2698 int element = EL_CUSTOM_START + i;
2700 element_info[element].push_delay_fixed = 2;
2701 element_info[element].push_delay_random = 8;
2707 static void InitGlobal()
2709 global.autoplay_leveldir = NULL;
2711 global.frames_per_second = 0;
2712 global.fps_slowdown = FALSE;
2713 global.fps_slowdown_factor = 1;
2716 void Execute_Command(char *command)
2718 if (strcmp(command, "print graphicsinfo.conf") == 0)
2722 printf("# You can configure additional/alternative image files here.\n");
2723 printf("# (The images below are default and therefore commented out.)\n");
2725 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2727 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2730 for (i=0; image_config[i].token != NULL; i++)
2732 getFormattedSetupEntry(image_config[i].token,
2733 image_config[i].value));
2737 else if (strcmp(command, "print soundsinfo.conf") == 0)
2741 printf("# You can configure additional/alternative sound files here.\n");
2742 printf("# (The sounds below are default and therefore commented out.)\n");
2744 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2746 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2749 for (i=0; sound_config[i].token != NULL; i++)
2751 getFormattedSetupEntry(sound_config[i].token,
2752 sound_config[i].value));
2756 else if (strcmp(command, "print musicinfo.conf") == 0)
2758 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2760 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2762 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2766 else if (strncmp(command, "dump level ", 11) == 0)
2768 char *filename = &command[11];
2770 if (access(filename, F_OK) != 0)
2771 Error(ERR_EXIT, "cannot open file '%s'", filename);
2773 LoadLevelFromFilename(&level, filename);
2778 else if (strncmp(command, "dump tape ", 10) == 0)
2780 char *filename = &command[10];
2782 if (access(filename, F_OK) != 0)
2783 Error(ERR_EXIT, "cannot open file '%s'", filename);
2785 LoadTapeFromFilename(filename);
2790 else if (strncmp(command, "autoplay ", 9) == 0)
2792 char *str_copy = getStringCopy(&command[9]);
2793 char *str_ptr = strchr(str_copy, ' ');
2795 global.autoplay_leveldir = str_copy;
2796 global.autoplay_level_nr = -1;
2798 if (str_ptr != NULL)
2800 *str_ptr++ = '\0'; /* terminate leveldir string */
2801 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2806 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2810 static void InitSetup()
2812 LoadSetup(); /* global setup info */
2814 /* set some options from setup file */
2816 if (setup.options.verbose)
2817 options.verbose = TRUE;
2820 static void InitPlayerInfo()
2824 /* choose default local player */
2825 local_player = &stored_player[0];
2827 for (i=0; i<MAX_PLAYERS; i++)
2828 stored_player[i].connected = FALSE;
2830 local_player->connected = TRUE;
2833 static void InitArtworkInfo()
2838 static char *get_string_in_brackets(char *string)
2840 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2842 sprintf(string_in_brackets, "[%s]", string);
2844 return string_in_brackets;
2848 static char *get_element_class_token(int element)
2850 char *element_class_name = element_info[element].class_name;
2851 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2853 sprintf(element_class_token, "[%s]", element_class_name);
2855 return element_class_token;
2858 static char *get_action_class_token(int action)
2860 char *action_class_name = &element_action_info[action].suffix[1];
2861 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2863 sprintf(action_class_token, "[%s]", action_class_name);
2865 return action_class_token;
2869 static void InitArtworkConfig()
2871 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2872 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2873 static char *action_id_suffix[NUM_ACTIONS + 1];
2874 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2875 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2876 static char *dummy[1] = { NULL };
2877 static char *ignore_generic_tokens[] =
2883 static char **ignore_image_tokens, **ignore_sound_tokens;
2884 int num_ignore_generic_tokens;
2885 int num_ignore_image_tokens, num_ignore_sound_tokens;
2888 /* dynamically determine list of generic tokens to be ignored */
2889 num_ignore_generic_tokens = 0;
2890 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2891 num_ignore_generic_tokens++;
2893 /* dynamically determine list of image tokens to be ignored */
2894 num_ignore_image_tokens = num_ignore_generic_tokens;
2895 for (i=0; image_config_vars[i].token != NULL; i++)
2896 num_ignore_image_tokens++;
2897 ignore_image_tokens =
2898 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2899 for (i=0; i < num_ignore_generic_tokens; i++)
2900 ignore_image_tokens[i] = ignore_generic_tokens[i];
2901 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2902 ignore_image_tokens[num_ignore_generic_tokens + i] =
2903 image_config_vars[i].token;
2904 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2906 /* dynamically determine list of sound tokens to be ignored */
2907 num_ignore_sound_tokens = num_ignore_generic_tokens;
2908 ignore_sound_tokens =
2909 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2910 for (i=0; i < num_ignore_generic_tokens; i++)
2911 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2912 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2914 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2915 image_id_prefix[i] = element_info[i].token_name;
2916 for (i=0; i<NUM_FONTS; i++)
2917 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2918 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2920 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2921 sound_id_prefix[i] = element_info[i].token_name;
2922 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2923 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2924 get_string_in_brackets(element_info[i].class_name);
2925 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2927 for (i=0; i<NUM_ACTIONS; i++)
2928 action_id_suffix[i] = element_action_info[i].suffix;
2929 action_id_suffix[NUM_ACTIONS] = NULL;
2931 for (i=0; i<NUM_DIRECTIONS; i++)
2932 direction_id_suffix[i] = element_direction_info[i].suffix;
2933 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2935 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2936 special_id_suffix[i] = special_suffix_info[i].suffix;
2937 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2939 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2940 image_id_prefix, action_id_suffix, direction_id_suffix,
2941 special_id_suffix, ignore_image_tokens);
2942 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2943 sound_id_prefix, action_id_suffix, dummy,
2944 special_id_suffix, ignore_sound_tokens);
2947 static void InitMixer()
2955 char *filename_font_initial = NULL;
2956 Bitmap *bitmap_font_initial = NULL;
2959 /* determine settings for initial font (for displaying startup messages) */
2960 for (i=0; image_config[i].token != NULL; i++)
2962 for (j=0; j < NUM_INITIAL_FONTS; j++)
2964 char font_token[128];
2967 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2968 len_font_token = strlen(font_token);
2970 if (strcmp(image_config[i].token, font_token) == 0)
2971 filename_font_initial = image_config[i].value;
2972 else if (strlen(image_config[i].token) > len_font_token &&
2973 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2975 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2976 font_initial[j].src_x = atoi(image_config[i].value);
2977 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2978 font_initial[j].src_y = atoi(image_config[i].value);
2979 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2980 font_initial[j].width = atoi(image_config[i].value);
2981 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2982 font_initial[j].height = atoi(image_config[i].value);
2987 for (j=0; j < NUM_INITIAL_FONTS; j++)
2989 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2990 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2993 if (filename_font_initial == NULL) /* should not happen */
2994 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2996 /* create additional image buffers for double-buffering */
2997 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2998 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3000 /* initialize screen properties */
3001 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3002 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3004 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3005 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3006 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3008 bitmap_font_initial = LoadCustomImage(filename_font_initial);
3010 for (j=0; j < NUM_INITIAL_FONTS; j++)
3011 font_initial[j].bitmap = bitmap_font_initial;
3013 InitFontGraphicInfo();
3015 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
3016 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
3018 DrawInitText("Loading graphics:", 120, FC_GREEN);
3020 InitTileClipmasks();
3023 void InitGfxBackground()
3027 drawto = backbuffer;
3028 fieldbuffer = bitmap_db_field;
3029 SetDrawtoField(DRAW_BACKBUFFER);
3031 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3032 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3033 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3034 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3036 for (x=0; x<MAX_BUF_XSIZE; x++)
3037 for (y=0; y<MAX_BUF_YSIZE; y++)
3040 redraw_mask = REDRAW_ALL;
3043 static void InitLevelInfo()
3045 LoadLevelInfo(); /* global level info */
3046 LoadLevelSetup_LastSeries(); /* last played series info */
3047 LoadLevelSetup_SeriesInfo(); /* last played level info */
3050 void InitLevelArtworkInfo()
3052 LoadLevelArtworkInfo();
3055 static void InitImages()
3058 setLevelArtworkDir(artwork.gfx_first);
3062 printf("::: InitImages ['%s', '%s'] ['%s', '%s']\n",
3063 artwork.gfx_current_identifier,
3064 artwork.gfx_current->identifier,
3065 leveldir_current->graphics_set,
3066 leveldir_current->graphics_path);
3069 ReloadCustomImages();
3071 LoadCustomElementDescriptions();
3072 LoadSpecialMenuDesignSettings();
3074 ReinitializeGraphics();
3077 static void InitSound()
3079 setLevelArtworkDir(artwork.snd_first);
3081 InitReloadCustomSounds(artwork.snd_current->identifier);
3082 ReinitializeSounds();
3085 static void InitMusic()
3087 setLevelArtworkDir(artwork.mus_first);
3089 InitReloadCustomMusic(artwork.mus_current->identifier);
3090 ReinitializeMusic();
3093 void InitNetworkServer()
3095 #if defined(PLATFORM_UNIX)
3099 if (!options.network)
3102 #if defined(PLATFORM_UNIX)
3103 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3105 if (!ConnectToServer(options.server_host, options.server_port))
3106 Error(ERR_EXIT, "cannot connect to network game server");
3108 SendToServer_PlayerName(setup.player_name);
3109 SendToServer_ProtocolVersion();
3112 SendToServer_NrWanted(nr_wanted);
3116 void ReloadCustomArtwork()
3118 static char *leveldir_current_identifier = NULL;
3119 static boolean last_override_level_graphics = FALSE;
3120 static boolean last_override_level_sounds = FALSE;
3121 static boolean last_override_level_music = FALSE;
3122 static boolean last_own_level_graphics_set = FALSE;
3123 static boolean last_own_level_sounds_set = FALSE;
3124 static boolean last_own_level_music_set = FALSE;
3125 boolean level_graphics_set_changed = FALSE;
3126 boolean level_sounds_set_changed = FALSE;
3127 boolean level_music_set_changed = FALSE;
3128 /* identifier for new artwork; default: artwork configured in setup */
3130 char *gfx_new_identifier = artwork.gfx_current->identifier;
3131 char *snd_new_identifier = artwork.snd_current->identifier;
3132 char *mus_new_identifier = artwork.mus_current->identifier;
3134 char *gfx_new_identifier = artwork.gfx_current_identifier;
3135 char *snd_new_identifier = artwork.snd_current_identifier;
3136 char *mus_new_identifier = artwork.mus_current_identifier;
3138 boolean redraw_screen = FALSE;
3141 if (leveldir_current_identifier == NULL)
3142 leveldir_current_identifier = leveldir_current->identifier;
3146 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3147 leveldir_current->graphics_set);
3148 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3149 leveldir_current->identifier);
3153 printf("graphics --> '%s' ('%s')\n",
3154 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3155 printf("sounds --> '%s' ('%s')\n",
3156 artwork.snd_current_identifier, artwork.snd_current->filename);
3157 printf("music --> '%s' ('%s')\n",
3158 artwork.mus_current_identifier, artwork.mus_current->filename);
3161 /* leveldir_current may be invalid (level group, parent link) */
3162 if (!validLevelSeries(leveldir_current))
3165 /* when a new level series was selected, check if there was a change
3166 in custom artwork stored in level series directory */
3167 if (1 || leveldir_current_identifier != leveldir_current->identifier)
3170 char *identifier_old = leveldir_current_identifier;
3172 char *identifier_new = leveldir_current->identifier;
3175 printf("::: 1: ['%s'] '%s', '%s' [%lx, %lx]\n",
3176 gfx_new_identifier, identifier_old, identifier_new,
3177 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old),
3178 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new));
3182 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new) == NULL)
3183 gfx_new_identifier = GRAPHICS_SUBDIR;
3184 else if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3185 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3186 gfx_new_identifier = identifier_new;
3188 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3189 gfx_new_identifier = identifier_new;
3191 gfx_new_identifier = setup.graphics_set;
3195 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new) == NULL)
3196 snd_new_identifier = SOUNDS_SUBDIR;
3197 else if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3198 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3199 snd_new_identifier = identifier_new;
3201 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3202 snd_new_identifier = identifier_new;
3204 snd_new_identifier = setup.sounds_set;
3208 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) == NULL)
3209 mus_new_identifier = MUSIC_SUBDIR;
3210 else if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3211 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3212 mus_new_identifier = identifier_new;
3214 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3215 mus_new_identifier = identifier_new;
3217 mus_new_identifier = setup.music_set;
3221 printf("::: 2: ['%s'] '%s', '%s'\n",
3222 gfx_new_identifier, identifier_old, identifier_new);
3226 leveldir_current_identifier = leveldir_current->identifier;
3230 /* custom level artwork configured in level series configuration file
3231 always overrides custom level artwork stored in level series directory
3232 and (level independent) custom artwork configured in setup menu */
3233 if (leveldir_current->graphics_set != NULL)
3234 gfx_new_identifier = leveldir_current->graphics_set;
3235 if (leveldir_current->sounds_set != NULL)
3236 snd_new_identifier = leveldir_current->sounds_set;
3237 if (leveldir_current->music_set != NULL)
3238 mus_new_identifier = leveldir_current->music_set;
3240 if (leveldir_current_identifier != leveldir_current->identifier)
3242 if (last_own_level_graphics_set || leveldir_current->graphics_set != NULL)
3243 level_graphics_set_changed = TRUE;
3245 if (last_own_level_sounds_set || leveldir_current->sounds_set != NULL)
3246 level_sounds_set_changed = TRUE;
3248 if (last_own_level_music_set || leveldir_current->music_set != NULL)
3249 level_music_set_changed = TRUE;
3251 last_own_level_graphics_set = (leveldir_current->graphics_set != NULL);
3252 last_own_level_sounds_set = (leveldir_current->sounds_set != NULL);
3253 last_own_level_music_set = (leveldir_current->music_set != NULL);
3257 leveldir_current_identifier = leveldir_current->identifier;
3260 if (setup.override_level_graphics)
3261 gfx_new_identifier = artwork.gfx_current->identifier;
3262 if (setup.override_level_sounds)
3263 snd_new_identifier = artwork.snd_current->identifier;
3264 if (setup.override_level_music)
3265 mus_new_identifier = artwork.mus_current->identifier;
3269 printf("CHECKING OLD/NEW GFX:\n OLD: '%s'\n NEW: '%s' ['%s', '%s'] [%d]\n",
3270 artwork.gfx_current_identifier, gfx_new_identifier,
3271 artwork.gfx_current->identifier, leveldir_current->graphics_set,
3272 level_graphics_set_changed);
3275 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3276 last_override_level_graphics != setup.override_level_graphics ||
3277 level_graphics_set_changed)
3280 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s']\n",
3281 artwork.gfx_current_identifier,
3283 artwork.gfx_current->identifier);
3287 artwork.gfx_current =
3288 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3291 artwork.gfx_current_identifier = gfx_new_identifier;
3295 setLevelArtworkDir(artwork.gfx_first);
3298 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3303 printf("::: %d\n", menu.list_size[GAME_MODE_LEVELS]);
3306 FreeTileClipmasks();
3307 InitTileClipmasks();
3309 artwork.gfx_current =
3310 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3313 printf("::: '%s', %lx\n", gfx_new_identifier, artwork.gfx_current);
3317 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3319 artwork.gfx_current_identifier = gfx_new_identifier;
3320 last_override_level_graphics = setup.override_level_graphics;
3323 printf("DONE RELOADING GFX: '%s' ['%s']\n",
3324 artwork.gfx_current_identifier, artwork.gfx_current->identifier);
3327 redraw_screen = TRUE;
3330 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3331 last_override_level_sounds != setup.override_level_sounds ||
3332 level_sounds_set_changed)
3335 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3336 artwork.snd_current_identifier,
3337 artwork.snd_current->identifier,
3338 snd_new_identifier);
3341 /* set artwork path to send it to the sound server process */
3342 setLevelArtworkDir(artwork.snd_first);
3344 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3346 InitReloadCustomSounds(snd_new_identifier);
3347 ReinitializeSounds();
3350 artwork.snd_current =
3351 getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
3352 artwork.snd_current_identifier = artwork.snd_current->identifier;
3354 artwork.snd_current_identifier = snd_new_identifier;
3355 last_override_level_sounds = setup.override_level_sounds;
3357 redraw_screen = TRUE;
3360 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3361 last_override_level_music != setup.override_level_music ||
3362 level_music_set_changed)
3364 /* set artwork path to send it to the sound server process */
3365 setLevelArtworkDir(artwork.mus_first);
3367 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3369 InitReloadCustomMusic(mus_new_identifier);
3370 ReinitializeMusic();
3373 artwork.mus_current =
3374 getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
3375 artwork.mus_current_identifier = artwork.mus_current->identifier;
3377 artwork.mus_current_identifier = mus_new_identifier;
3378 last_override_level_music = setup.override_level_music;
3380 redraw_screen = TRUE;
3385 InitGfxBackground();
3387 /* force redraw of (open or closed) door graphics */
3388 SetDoorState(DOOR_OPEN_ALL);
3389 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3393 void KeyboardAutoRepeatOffUnlessAutoplay()
3395 if (global.autoplay_leveldir == NULL)
3396 KeyboardAutoRepeatOff();
3400 /* ========================================================================= */
3402 /* ========================================================================= */
3406 InitGlobal(); /* initialize some global variables */
3408 if (options.execute_command)
3409 Execute_Command(options.execute_command);
3411 if (options.serveronly)
3413 #if defined(PLATFORM_UNIX)
3414 NetworkServer(options.server_port, options.serveronly);
3416 Error(ERR_WARN, "networking only supported in Unix version");
3418 exit(0); /* never reached */
3424 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3425 InitArtworkConfig(); /* needed before forking sound child process */
3430 InitRND(NEW_RANDOMIZE);
3431 InitSimpleRND(NEW_RANDOMIZE);
3436 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3439 InitEventFilter(FilterMouseMotionEvents);
3441 InitElementPropertiesStatic();
3446 InitLevelArtworkInfo();
3448 InitImages(); /* needs to know current level directory */
3449 InitSound(); /* needs to know current level directory */
3450 InitMusic(); /* needs to know current level directory */
3452 InitGfxBackground();
3454 if (global.autoplay_leveldir)
3460 game_status = GAME_MODE_MAIN;
3464 InitNetworkServer();
3467 void CloseAllAndExit(int exit_value)
3472 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3475 FreeTileClipmasks();
3477 CloseVideoDisplay();
3478 ClosePlatformDependentStuff();