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;
757 set_graphic_parameters(i, image->parameter);
759 /* now check if no animation frames are outside of the loaded image */
761 if (graphic_info[i].bitmap == NULL)
762 continue; /* skip check for optional images that are undefined */
765 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
766 if (src_x < 0 || src_y < 0 ||
767 src_x + TILEX > src_bitmap->width ||
768 src_y + TILEY > src_bitmap->height)
770 Error(ERR_RETURN_LINE, "-");
771 Error(ERR_RETURN, "warning: error found in config file:");
772 Error(ERR_RETURN, "- config file: '%s'",
773 getImageConfigFilename());
774 Error(ERR_RETURN, "- config token: '%s'",
775 getTokenFromImageID(i));
776 Error(ERR_RETURN, "- image file: '%s'",
777 src_bitmap->source_filename);
779 "error: first animation frame out of bounds (%d, %d)",
781 Error(ERR_RETURN, "custom graphic rejected for this element/action");
783 if (i == fallback_graphic)
784 Error(ERR_EXIT, "fatal error: no fallback graphic available");
786 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
787 Error(ERR_RETURN_LINE, "-");
789 set_graphic_parameters(i, fallback_image->default_parameter);
790 graphic_info[i].bitmap = fallback_bitmap;
793 last_frame = graphic_info[i].anim_frames - 1;
794 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
795 if (src_x < 0 || src_y < 0 ||
796 src_x + TILEX > src_bitmap->width ||
797 src_y + TILEY > src_bitmap->height)
799 Error(ERR_RETURN_LINE, "-");
800 Error(ERR_RETURN, "warning: error found in config file:");
801 Error(ERR_RETURN, "- config file: '%s'",
802 getImageConfigFilename());
803 Error(ERR_RETURN, "- config token: '%s'",
804 getTokenFromImageID(i));
805 Error(ERR_RETURN, "- image file: '%s'",
806 src_bitmap->source_filename);
808 "error: last animation frame (%d) out of bounds (%d, %d)",
809 last_frame, src_x, src_y);
810 Error(ERR_RETURN, "custom graphic rejected for this element/action");
812 if (i == fallback_graphic)
813 Error(ERR_EXIT, "fatal error: no fallback graphic available");
815 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
816 Error(ERR_RETURN_LINE, "-");
818 set_graphic_parameters(i, fallback_image->default_parameter);
819 graphic_info[i].bitmap = fallback_bitmap;
822 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
823 /* currently we need only a tile clip mask from the first frame */
824 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
826 if (copy_clipmask_gc == None)
828 clip_gc_values.graphics_exposures = False;
829 clip_gc_valuemask = GCGraphicsExposures;
830 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
831 clip_gc_valuemask, &clip_gc_values);
834 graphic_info[i].clip_mask =
835 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
837 src_pixmap = src_bitmap->clip_mask;
838 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
839 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
841 clip_gc_values.graphics_exposures = False;
842 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
843 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
845 graphic_info[i].clip_gc =
846 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
850 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
851 if (copy_clipmask_gc)
852 XFreeGC(display, copy_clipmask_gc);
854 clipmasks_initialized = TRUE;
858 static void InitElementSoundInfo()
860 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
861 int num_property_mappings = getSoundListPropertyMappingSize();
864 /* set values to -1 to identify later as "uninitialized" values */
865 for (i=0; i < MAX_NUM_ELEMENTS; i++)
866 for (act=0; act < NUM_ACTIONS; act++)
867 element_info[i].sound[act] = -1;
869 /* initialize element/sound mapping from static configuration */
870 for (i=0; element_to_sound[i].element > -1; i++)
872 int element = element_to_sound[i].element;
873 int action = element_to_sound[i].action;
874 int sound = element_to_sound[i].sound;
875 boolean is_class = element_to_sound[i].is_class;
878 action = ACTION_DEFAULT;
881 element_info[element].sound[action] = sound;
883 for (j=0; j < MAX_NUM_ELEMENTS; j++)
884 if (strcmp(element_info[j].class_name,
885 element_info[element].class_name) == 0)
886 element_info[j].sound[action] = sound;
889 /* initialize element class/sound mapping from dynamic configuration */
890 for (i=0; i < num_property_mappings; i++)
892 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
893 int action = property_mapping[i].ext1_index;
894 int sound = property_mapping[i].artwork_index;
896 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
900 action = ACTION_DEFAULT;
902 for (j=0; j < MAX_NUM_ELEMENTS; j++)
903 if (strcmp(element_info[j].class_name,
904 element_info[element_class].class_name) == 0)
905 element_info[j].sound[action] = sound;
908 /* initialize element/sound mapping from dynamic configuration */
909 for (i=0; i < num_property_mappings; i++)
911 int element = property_mapping[i].base_index;
912 int action = property_mapping[i].ext1_index;
913 int sound = property_mapping[i].artwork_index;
915 if (element >= MAX_NUM_ELEMENTS)
919 action = ACTION_DEFAULT;
921 element_info[element].sound[action] = sound;
924 /* now set all '-1' values to element specific default values */
925 for (i=0; i<MAX_NUM_ELEMENTS; i++)
927 for (act=0; act < NUM_ACTIONS; act++)
929 /* generic default action sound (defined by "[default]" directive) */
930 int default_action_sound = element_info[EL_DEFAULT].sound[act];
932 /* look for special default action sound (classic game specific) */
933 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
934 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
935 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
936 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
937 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
938 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
940 /* look for element specific default sound (independent from action) */
941 if (element_info[i].sound[ACTION_DEFAULT] != -1)
942 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
944 /* no sound for this specific action -- use default action sound */
945 if (element_info[i].sound[act] == -1)
946 element_info[i].sound[act] = default_action_sound;
951 static void set_sound_parameters(int sound, char **parameter_raw)
953 int parameter[NUM_SND_ARGS];
956 /* get integer values from string parameters */
957 for (i=0; i < NUM_SND_ARGS; i++)
959 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
960 sound_config_suffix[i].type);
962 /* explicit loop mode setting in configuration overrides default value */
963 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
964 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
967 static void InitSoundInfo()
969 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
970 int num_property_mappings = getSoundListPropertyMappingSize();
971 int *sound_effect_properties;
972 int num_sounds = getSoundListSize();
975 if (sound_info != NULL)
978 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
979 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
981 /* initialize sound effect for all elements to "no sound" */
982 for (i=0; i<MAX_NUM_ELEMENTS; i++)
983 for (j=0; j<NUM_ACTIONS; j++)
984 element_info[i].sound[j] = SND_UNDEFINED;
986 for (i=0; i<num_sounds; i++)
988 struct FileInfo *sound = getSoundListEntry(i);
989 int len_effect_text = strlen(sound->token);
991 sound_effect_properties[i] = ACTION_OTHER;
992 sound_info[i].loop = FALSE;
994 /* determine all loop sounds and identify certain sound classes */
996 for (j=0; element_action_info[j].suffix; j++)
998 int len_action_text = strlen(element_action_info[j].suffix);
1000 if (len_action_text < len_effect_text &&
1001 strcmp(&sound->token[len_effect_text - len_action_text],
1002 element_action_info[j].suffix) == 0)
1004 sound_effect_properties[i] = element_action_info[j].value;
1006 if (element_action_info[j].is_loop_sound)
1007 sound_info[i].loop = TRUE;
1011 /* associate elements and some selected sound actions */
1013 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1015 if (element_info[j].class_name)
1017 int len_class_text = strlen(element_info[j].class_name);
1019 if (len_class_text + 1 < len_effect_text &&
1020 strncmp(sound->token,
1021 element_info[j].class_name, len_class_text) == 0 &&
1022 sound->token[len_class_text] == '.')
1024 int sound_action_value = sound_effect_properties[i];
1026 element_info[j].sound[sound_action_value] = i;
1031 set_sound_parameters(i, sound->parameter);
1034 free(sound_effect_properties);
1036 /* initialize element/sound mapping from dynamic configuration */
1037 for (i=0; i < num_property_mappings; i++)
1039 int element = property_mapping[i].base_index;
1040 int action = property_mapping[i].ext1_index;
1041 int sound = property_mapping[i].artwork_index;
1044 action = ACTION_DEFAULT;
1046 element_info[element].sound[action] = sound;
1052 int element = EL_CUSTOM_11;
1055 while (element_action_info[j].suffix)
1057 printf("element %d, sound action '%s' == %d\n",
1058 element, element_action_info[j].suffix,
1059 element_info[element].sound[j]);
1064 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1070 int element = EL_SAND;
1071 int sound_action = ACTION_DIGGING;
1074 while (element_action_info[j].suffix)
1076 if (element_action_info[j].value == sound_action)
1077 printf("element %d, sound action '%s' == %d\n",
1078 element, element_action_info[j].suffix,
1079 element_info[element].sound[sound_action]);
1086 static void ReinitializeGraphics()
1088 InitGraphicInfo(); /* graphic properties mapping */
1089 InitElementGraphicInfo(); /* element game graphic mapping */
1090 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1092 InitElementSmallImages(); /* create editor and preview images */
1093 InitFontGraphicInfo(); /* initialize text drawing functions */
1095 SetMainBackgroundImage(IMG_BACKGROUND);
1096 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1102 static void ReinitializeSounds()
1104 InitSoundInfo(); /* sound properties mapping */
1105 InitElementSoundInfo(); /* element game sound mapping */
1107 InitPlaySoundLevel(); /* internal game sound settings */
1110 static void ReinitializeMusic()
1112 /* currently nothing to do */
1115 void InitElementPropertiesStatic()
1117 static int ep_diggable[] =
1122 EL_SP_BUGGY_BASE_ACTIVATING,
1125 EL_INVISIBLE_SAND_ACTIVE,
1127 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1131 EL_SP_BUGGY_BASE_ACTIVE,
1136 static int ep_collectible[] =
1153 EL_DYNABOMB_INCREASE_NUMBER,
1154 EL_DYNABOMB_INCREASE_SIZE,
1155 EL_DYNABOMB_INCREASE_POWER,
1169 static int ep_dont_run_into[] =
1171 /* same elements as in 'ep_dont_touch' */
1177 /* same elements as in 'ep_dont_collide_with' */
1189 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1191 EL_SP_BUGGY_BASE_ACTIVE,
1198 static int ep_dont_collide_with[] =
1200 /* same elements as in 'ep_dont_touch' */
1216 static int ep_dont_touch[] =
1225 static int ep_indestructible[] =
1229 EL_ACID_POOL_TOPLEFT,
1230 EL_ACID_POOL_TOPRIGHT,
1231 EL_ACID_POOL_BOTTOMLEFT,
1232 EL_ACID_POOL_BOTTOM,
1233 EL_ACID_POOL_BOTTOMRIGHT,
1234 EL_SP_HARDWARE_GRAY,
1235 EL_SP_HARDWARE_GREEN,
1236 EL_SP_HARDWARE_BLUE,
1238 EL_SP_HARDWARE_YELLOW,
1239 EL_SP_HARDWARE_BASE_1,
1240 EL_SP_HARDWARE_BASE_2,
1241 EL_SP_HARDWARE_BASE_3,
1242 EL_SP_HARDWARE_BASE_4,
1243 EL_SP_HARDWARE_BASE_5,
1244 EL_SP_HARDWARE_BASE_6,
1245 EL_INVISIBLE_STEELWALL,
1246 EL_INVISIBLE_STEELWALL_ACTIVE,
1247 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1248 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1249 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1250 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1251 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1252 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1253 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1254 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1255 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1256 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1257 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1258 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1260 EL_LIGHT_SWITCH_ACTIVE,
1261 EL_SIGN_EXCLAMATION,
1262 EL_SIGN_RADIOACTIVITY,
1273 EL_STEELWALL_SLANTED,
1296 EL_SWITCHGATE_OPENING,
1297 EL_SWITCHGATE_CLOSED,
1298 EL_SWITCHGATE_CLOSING,
1300 EL_SWITCHGATE_SWITCH_UP,
1301 EL_SWITCHGATE_SWITCH_DOWN,
1304 EL_TIMEGATE_OPENING,
1306 EL_TIMEGATE_CLOSING,
1309 EL_TIMEGATE_SWITCH_ACTIVE,
1314 EL_TUBE_VERTICAL_LEFT,
1315 EL_TUBE_VERTICAL_RIGHT,
1316 EL_TUBE_HORIZONTAL_UP,
1317 EL_TUBE_HORIZONTAL_DOWN,
1325 static int ep_slippery[] =
1339 EL_ROBOT_WHEEL_ACTIVE,
1345 EL_ACID_POOL_TOPLEFT,
1346 EL_ACID_POOL_TOPRIGHT,
1356 EL_STEELWALL_SLANTED,
1362 static int ep_can_change[] =
1367 static int ep_can_move[] =
1389 static int ep_can_fall[] =
1404 EL_BD_MAGIC_WALL_FULL,
1417 static int ep_can_smash_player[] =
1442 static int ep_can_smash_enemies[] =
1450 static int ep_can_smash_everything[] =
1458 static int ep_can_explode_by_fire[] =
1460 /* same elements as in 'ep_can_explode_impact' */
1465 /* same elements as in 'ep_can_explode_smashed' */
1474 EL_DYNABOMB_PLAYER_1_ACTIVE,
1475 EL_DYNABOMB_PLAYER_2_ACTIVE,
1476 EL_DYNABOMB_PLAYER_3_ACTIVE,
1477 EL_DYNABOMB_PLAYER_4_ACTIVE,
1478 EL_DYNABOMB_INCREASE_NUMBER,
1479 EL_DYNABOMB_INCREASE_SIZE,
1480 EL_DYNABOMB_INCREASE_POWER,
1481 EL_SP_DISK_RED_ACTIVE,
1491 static int ep_can_explode_smashed[] =
1493 /* same elements as in 'ep_can_explode_impact' */
1506 static int ep_can_explode_impact[] =
1514 static int ep_walkable_over[] =
1518 EL_SOKOBAN_FIELD_EMPTY,
1535 static int ep_walkable_inside[] =
1540 EL_TUBE_VERTICAL_LEFT,
1541 EL_TUBE_VERTICAL_RIGHT,
1542 EL_TUBE_HORIZONTAL_UP,
1543 EL_TUBE_HORIZONTAL_DOWN,
1551 static int ep_walkable_under[] =
1556 static int ep_passable_over[] =
1571 static int ep_passable_inside[] =
1577 EL_SP_PORT_HORIZONTAL,
1578 EL_SP_PORT_VERTICAL,
1580 EL_SP_GRAVITY_PORT_LEFT,
1581 EL_SP_GRAVITY_PORT_RIGHT,
1582 EL_SP_GRAVITY_PORT_UP,
1583 EL_SP_GRAVITY_PORT_DOWN,
1587 static int ep_passable_under[] =
1592 static int ep_pushable[] =
1604 EL_SOKOBAN_FIELD_FULL,
1611 static int ep_can_be_crumbled[] =
1620 static int ep_player[] =
1629 static int ep_can_pass_magic_wall[] =
1642 static int ep_switchable[] =
1646 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1647 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1648 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1649 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1650 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1651 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1652 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1653 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1654 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1655 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1656 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1657 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1658 EL_SWITCHGATE_SWITCH_UP,
1659 EL_SWITCHGATE_SWITCH_DOWN,
1661 EL_LIGHT_SWITCH_ACTIVE,
1663 EL_BALLOON_SWITCH_LEFT,
1664 EL_BALLOON_SWITCH_RIGHT,
1665 EL_BALLOON_SWITCH_UP,
1666 EL_BALLOON_SWITCH_DOWN,
1667 EL_BALLOON_SWITCH_ANY,
1673 static int ep_bd_element[] =
1702 static int ep_sp_element[] =
1710 EL_SP_HARDWARE_GRAY,
1718 EL_SP_GRAVITY_PORT_RIGHT,
1719 EL_SP_GRAVITY_PORT_DOWN,
1720 EL_SP_GRAVITY_PORT_LEFT,
1721 EL_SP_GRAVITY_PORT_UP,
1726 EL_SP_PORT_VERTICAL,
1727 EL_SP_PORT_HORIZONTAL,
1733 EL_SP_HARDWARE_BASE_1,
1734 EL_SP_HARDWARE_GREEN,
1735 EL_SP_HARDWARE_BLUE,
1737 EL_SP_HARDWARE_YELLOW,
1738 EL_SP_HARDWARE_BASE_2,
1739 EL_SP_HARDWARE_BASE_3,
1740 EL_SP_HARDWARE_BASE_4,
1741 EL_SP_HARDWARE_BASE_5,
1742 EL_SP_HARDWARE_BASE_6,
1745 /* additional elements that appeared in newer Supaplex levels */
1747 /* more than one murphy in a level results in an inactive clone */
1749 /* runtime elements*/
1750 EL_SP_DISK_RED_ACTIVE,
1751 EL_SP_TERMINAL_ACTIVE,
1752 EL_SP_BUGGY_BASE_ACTIVATING,
1753 EL_SP_BUGGY_BASE_ACTIVE,
1757 static int ep_sb_element[] =
1762 EL_SOKOBAN_FIELD_EMPTY,
1763 EL_SOKOBAN_FIELD_FULL,
1765 EL_INVISIBLE_STEELWALL,
1769 static int ep_gem[] =
1780 static int ep_food_dark_yamyam[] =
1807 static int ep_food_penguin[] =
1820 static int ep_food_pig[] =
1831 static int ep_historic_wall[] =
1856 EL_EXPANDABLE_WALL_HORIZONTAL,
1857 EL_EXPANDABLE_WALL_VERTICAL,
1858 EL_EXPANDABLE_WALL_ANY,
1859 EL_EXPANDABLE_WALL_GROWING,
1866 EL_SP_HARDWARE_GRAY,
1867 EL_SP_HARDWARE_GREEN,
1868 EL_SP_HARDWARE_BLUE,
1870 EL_SP_HARDWARE_YELLOW,
1871 EL_SP_HARDWARE_BASE_1,
1872 EL_SP_HARDWARE_BASE_2,
1873 EL_SP_HARDWARE_BASE_3,
1874 EL_SP_HARDWARE_BASE_4,
1875 EL_SP_HARDWARE_BASE_5,
1876 EL_SP_HARDWARE_BASE_6,
1878 EL_SP_TERMINAL_ACTIVE,
1881 EL_INVISIBLE_STEELWALL,
1882 EL_INVISIBLE_STEELWALL_ACTIVE,
1884 EL_INVISIBLE_WALL_ACTIVE,
1885 EL_STEELWALL_SLANTED,
1901 static int ep_historic_solid[] =
1905 EL_EXPANDABLE_WALL_HORIZONTAL,
1906 EL_EXPANDABLE_WALL_VERTICAL,
1907 EL_EXPANDABLE_WALL_ANY,
1920 EL_QUICKSAND_FILLING,
1921 EL_QUICKSAND_EMPTYING,
1923 EL_MAGIC_WALL_ACTIVE,
1924 EL_MAGIC_WALL_EMPTYING,
1925 EL_MAGIC_WALL_FILLING,
1929 EL_BD_MAGIC_WALL_ACTIVE,
1930 EL_BD_MAGIC_WALL_EMPTYING,
1931 EL_BD_MAGIC_WALL_FULL,
1932 EL_BD_MAGIC_WALL_FILLING,
1933 EL_BD_MAGIC_WALL_DEAD,
1942 EL_SP_TERMINAL_ACTIVE,
1946 EL_INVISIBLE_WALL_ACTIVE,
1947 EL_SWITCHGATE_SWITCH_UP,
1948 EL_SWITCHGATE_SWITCH_DOWN,
1950 EL_TIMEGATE_SWITCH_ACTIVE,
1962 /* the following elements are a direct copy of "indestructible" elements,
1963 except "EL_ACID", which is "indestructible", but not "solid"! */
1968 EL_ACID_POOL_TOPLEFT,
1969 EL_ACID_POOL_TOPRIGHT,
1970 EL_ACID_POOL_BOTTOMLEFT,
1971 EL_ACID_POOL_BOTTOM,
1972 EL_ACID_POOL_BOTTOMRIGHT,
1973 EL_SP_HARDWARE_GRAY,
1974 EL_SP_HARDWARE_GREEN,
1975 EL_SP_HARDWARE_BLUE,
1977 EL_SP_HARDWARE_YELLOW,
1978 EL_SP_HARDWARE_BASE_1,
1979 EL_SP_HARDWARE_BASE_2,
1980 EL_SP_HARDWARE_BASE_3,
1981 EL_SP_HARDWARE_BASE_4,
1982 EL_SP_HARDWARE_BASE_5,
1983 EL_SP_HARDWARE_BASE_6,
1984 EL_INVISIBLE_STEELWALL,
1985 EL_INVISIBLE_STEELWALL_ACTIVE,
1986 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1987 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1988 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1989 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1990 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1991 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1992 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1993 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1994 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1995 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1996 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1997 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1999 EL_LIGHT_SWITCH_ACTIVE,
2000 EL_SIGN_EXCLAMATION,
2001 EL_SIGN_RADIOACTIVITY,
2012 EL_STEELWALL_SLANTED,
2035 EL_SWITCHGATE_OPENING,
2036 EL_SWITCHGATE_CLOSED,
2037 EL_SWITCHGATE_CLOSING,
2039 EL_TIMEGATE_OPENING,
2041 EL_TIMEGATE_CLOSING,
2045 EL_TUBE_VERTICAL_LEFT,
2046 EL_TUBE_VERTICAL_RIGHT,
2047 EL_TUBE_HORIZONTAL_UP,
2048 EL_TUBE_HORIZONTAL_DOWN,
2056 static int ep_classic_enemy[] =
2072 static int ep_belt[] =
2074 EL_CONVEYOR_BELT_1_LEFT,
2075 EL_CONVEYOR_BELT_1_MIDDLE,
2076 EL_CONVEYOR_BELT_1_RIGHT,
2077 EL_CONVEYOR_BELT_2_LEFT,
2078 EL_CONVEYOR_BELT_2_MIDDLE,
2079 EL_CONVEYOR_BELT_2_RIGHT,
2080 EL_CONVEYOR_BELT_3_LEFT,
2081 EL_CONVEYOR_BELT_3_MIDDLE,
2082 EL_CONVEYOR_BELT_3_RIGHT,
2083 EL_CONVEYOR_BELT_4_LEFT,
2084 EL_CONVEYOR_BELT_4_MIDDLE,
2085 EL_CONVEYOR_BELT_4_RIGHT,
2089 static int ep_belt_active[] =
2091 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2092 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2093 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2094 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2095 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2096 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2097 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2098 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2099 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2100 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2101 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2102 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2106 static int ep_belt_switch[] =
2108 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2109 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2110 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2111 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2112 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2113 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2114 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2115 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2116 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2117 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2118 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2119 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2123 static int ep_tube[] =
2130 EL_TUBE_HORIZONTAL_UP,
2131 EL_TUBE_HORIZONTAL_DOWN,
2133 EL_TUBE_VERTICAL_LEFT,
2134 EL_TUBE_VERTICAL_RIGHT,
2139 static int ep_keygate[] =
2160 static int ep_amoeboid[] =
2170 static int ep_amoebalive[] =
2179 static int ep_has_content[] =
2189 static int ep_active_bomb[] =
2192 EL_DYNABOMB_PLAYER_1_ACTIVE,
2193 EL_DYNABOMB_PLAYER_2_ACTIVE,
2194 EL_DYNABOMB_PLAYER_3_ACTIVE,
2195 EL_DYNABOMB_PLAYER_4_ACTIVE,
2196 EL_SP_DISK_RED_ACTIVE,
2200 static int ep_inactive[] =
2237 EL_INVISIBLE_STEELWALL,
2245 EL_WALL_EMERALD_YELLOW,
2246 EL_DYNABOMB_INCREASE_NUMBER,
2247 EL_DYNABOMB_INCREASE_SIZE,
2248 EL_DYNABOMB_INCREASE_POWER,
2252 EL_SOKOBAN_FIELD_EMPTY,
2253 EL_SOKOBAN_FIELD_FULL,
2254 EL_WALL_EMERALD_RED,
2255 EL_WALL_EMERALD_PURPLE,
2256 EL_ACID_POOL_TOPLEFT,
2257 EL_ACID_POOL_TOPRIGHT,
2258 EL_ACID_POOL_BOTTOMLEFT,
2259 EL_ACID_POOL_BOTTOM,
2260 EL_ACID_POOL_BOTTOMRIGHT,
2264 EL_BD_MAGIC_WALL_DEAD,
2265 EL_AMOEBA_TO_DIAMOND,
2273 EL_SP_GRAVITY_PORT_RIGHT,
2274 EL_SP_GRAVITY_PORT_DOWN,
2275 EL_SP_GRAVITY_PORT_LEFT,
2276 EL_SP_GRAVITY_PORT_UP,
2277 EL_SP_PORT_HORIZONTAL,
2278 EL_SP_PORT_VERTICAL,
2289 EL_SP_HARDWARE_GRAY,
2290 EL_SP_HARDWARE_GREEN,
2291 EL_SP_HARDWARE_BLUE,
2293 EL_SP_HARDWARE_YELLOW,
2294 EL_SP_HARDWARE_BASE_1,
2295 EL_SP_HARDWARE_BASE_2,
2296 EL_SP_HARDWARE_BASE_3,
2297 EL_SP_HARDWARE_BASE_4,
2298 EL_SP_HARDWARE_BASE_5,
2299 EL_SP_HARDWARE_BASE_6,
2300 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2301 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2302 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2303 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2304 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2305 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2306 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2307 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2308 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2309 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2310 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2311 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2312 EL_SIGN_EXCLAMATION,
2313 EL_SIGN_RADIOACTIVITY,
2324 EL_STEELWALL_SLANTED,
2344 } element_properties[] =
2346 { ep_diggable, EP_DIGGABLE },
2347 { ep_collectible, EP_COLLECTIBLE },
2348 { ep_dont_run_into, EP_DONT_RUN_INTO },
2349 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2350 { ep_dont_touch, EP_DONT_TOUCH },
2351 { ep_indestructible, EP_INDESTRUCTIBLE },
2352 { ep_slippery, EP_SLIPPERY },
2353 { ep_can_change, EP_CAN_CHANGE },
2354 { ep_can_move, EP_CAN_MOVE },
2355 { ep_can_fall, EP_CAN_FALL },
2356 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2357 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2358 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2359 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2360 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2361 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2362 { ep_walkable_over, EP_WALKABLE_OVER },
2363 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2364 { ep_walkable_under, EP_WALKABLE_UNDER },
2365 { ep_passable_over, EP_PASSABLE_OVER },
2366 { ep_passable_inside, EP_PASSABLE_INSIDE },
2367 { ep_passable_under, EP_PASSABLE_UNDER },
2368 { ep_pushable, EP_PUSHABLE },
2370 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2372 { ep_player, EP_PLAYER },
2373 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2374 { ep_switchable, EP_SWITCHABLE },
2375 { ep_bd_element, EP_BD_ELEMENT },
2376 { ep_sp_element, EP_SP_ELEMENT },
2377 { ep_sb_element, EP_SB_ELEMENT },
2379 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2380 { ep_food_penguin, EP_FOOD_PENGUIN },
2381 { ep_food_pig, EP_FOOD_PIG },
2382 { ep_historic_wall, EP_HISTORIC_WALL },
2383 { ep_historic_solid, EP_HISTORIC_SOLID },
2384 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2385 { ep_belt, EP_BELT },
2386 { ep_belt_active, EP_BELT_ACTIVE },
2387 { ep_belt_switch, EP_BELT_SWITCH },
2388 { ep_tube, EP_TUBE },
2389 { ep_keygate, EP_KEYGATE },
2390 { ep_amoeboid, EP_AMOEBOID },
2391 { ep_amoebalive, EP_AMOEBALIVE },
2392 { ep_has_content, EP_HAS_CONTENT },
2393 { ep_active_bomb, EP_ACTIVE_BOMB },
2394 { ep_inactive, EP_INACTIVE },
2399 static int copy_properties[][5] =
2403 EL_BUG_LEFT, EL_BUG_RIGHT,
2404 EL_BUG_UP, EL_BUG_DOWN
2408 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2409 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2413 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2414 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2418 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2419 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2423 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2424 EL_PACMAN_UP, EL_PACMAN_DOWN
2434 /* always start with reliable default values (element has no properties) */
2435 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2436 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2437 SET_PROPERTY(i, j, FALSE);
2439 /* set all base element properties from above array definitions */
2440 for (i=0; element_properties[i].elements != NULL; i++)
2441 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2442 SET_PROPERTY((element_properties[i].elements)[j],
2443 element_properties[i].property, TRUE);
2445 /* copy properties to some elements that are only stored in level file */
2446 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2447 for (j=0; copy_properties[j][0] != -1; j++)
2448 if (HAS_PROPERTY(copy_properties[j][0], i))
2449 for (k=1; k<=4; k++)
2450 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2453 void InitElementPropertiesEngine(int engine_version)
2456 static int active_properties[] =
2461 EP_DONT_COLLIDE_WITH,
2465 EP_CAN_PASS_MAGIC_WALL,
2470 EP_CAN_EXPLODE_BY_FIRE,
2483 EP_EM_SLIPPERY_WALL,
2488 static int no_wall_properties[] =
2493 EP_DONT_COLLIDE_WITH,
2496 EP_CAN_SMASH_PLAYER,
2497 EP_CAN_SMASH_ENEMIES,
2498 EP_CAN_SMASH_EVERYTHING,
2505 EP_FOOD_DARK_YAMYAM,
2521 InitElementPropertiesStatic();
2524 /* set all special, combined or engine dependent element properties */
2525 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2528 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2529 SET_PROPERTY(i, j, FALSE);
2532 /* ---------- INACTIVE ------------------------------------------------- */
2533 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2534 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2536 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2537 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2538 IS_WALKABLE_INSIDE(i) ||
2539 IS_WALKABLE_UNDER(i)));
2541 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2542 IS_PASSABLE_INSIDE(i) ||
2543 IS_PASSABLE_UNDER(i)));
2545 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2546 IS_PASSABLE_OVER(i)));
2548 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2549 IS_PASSABLE_INSIDE(i)));
2551 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2552 IS_PASSABLE_UNDER(i)));
2554 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2557 /* ---------- SNAPPABLE ------------------------------------------------ */
2558 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2559 IS_COLLECTIBLE(i) ||
2563 /* ---------- WALL ----------------------------------------------------- */
2564 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2566 for (j=0; no_wall_properties[j] != -1; j++)
2567 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2568 i >= EL_FIRST_RUNTIME_UNREAL)
2569 SET_PROPERTY(i, EP_WALL, FALSE);
2571 if (IS_HISTORIC_WALL(i))
2572 SET_PROPERTY(i, EP_WALL, TRUE);
2574 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2575 if (engine_version < VERSION_IDENT(2,2,0))
2576 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2578 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2580 !IS_COLLECTIBLE(i)));
2582 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2584 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2585 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2587 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2588 IS_INDESTRUCTIBLE(i)));
2590 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2592 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2593 else if (engine_version < VERSION_IDENT(2,2,0))
2594 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2596 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2597 !IS_WALKABLE_OVER(i) &&
2598 !IS_WALKABLE_UNDER(i)));
2600 if (IS_CUSTOM_ELEMENT(i))
2602 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2604 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2605 if (DONT_COLLIDE_WITH(i))
2606 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2608 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2609 if (CAN_SMASH_EVERYTHING(i))
2610 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2611 if (CAN_SMASH_ENEMIES(i))
2612 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2615 /* ---------- CAN_SMASH ------------------------------------------------ */
2616 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2617 CAN_SMASH_ENEMIES(i) ||
2618 CAN_SMASH_EVERYTHING(i)));
2620 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2621 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2622 CAN_EXPLODE_SMASHED(i) ||
2623 CAN_EXPLODE_BY_FIRE(i)));
2627 /* determine inactive elements (used for engine main loop optimization) */
2628 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2630 boolean active = FALSE;
2632 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2634 if (HAS_PROPERTY(i, j))
2640 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2645 /* dynamically adjust element properties according to game engine version */
2647 static int ep_em_slippery_wall[] =
2652 EL_EXPANDABLE_WALL_HORIZONTAL,
2653 EL_EXPANDABLE_WALL_VERTICAL,
2654 EL_EXPANDABLE_WALL_ANY,
2658 /* special EM style gems behaviour */
2659 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2660 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2661 level.em_slippery_gems);
2663 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2664 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2665 (level.em_slippery_gems &&
2666 engine_version > VERSION_IDENT(2,0,1)));
2670 /* dynamically adjust element properties according to game engine version */
2672 if (engine_version < RELEASE_IDENT(2,2,0,7))
2675 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2677 int element = EL_CUSTOM_START + i;
2679 element_info[element].push_delay_fixed = 2;
2680 element_info[element].push_delay_random = 8;
2686 static void InitGlobal()
2688 global.autoplay_leveldir = NULL;
2690 global.frames_per_second = 0;
2691 global.fps_slowdown = FALSE;
2692 global.fps_slowdown_factor = 1;
2695 void Execute_Command(char *command)
2697 if (strcmp(command, "print graphicsinfo.conf") == 0)
2701 printf("# You can configure additional/alternative image files here.\n");
2702 printf("# (The images below are default and therefore commented out.)\n");
2704 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2706 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2709 for (i=0; image_config[i].token != NULL; i++)
2711 getFormattedSetupEntry(image_config[i].token,
2712 image_config[i].value));
2716 else if (strcmp(command, "print soundsinfo.conf") == 0)
2720 printf("# You can configure additional/alternative sound files here.\n");
2721 printf("# (The sounds below are default and therefore commented out.)\n");
2723 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2725 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2728 for (i=0; sound_config[i].token != NULL; i++)
2730 getFormattedSetupEntry(sound_config[i].token,
2731 sound_config[i].value));
2735 else if (strcmp(command, "print musicinfo.conf") == 0)
2737 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2739 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2741 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2745 else if (strncmp(command, "dump level ", 11) == 0)
2747 char *filename = &command[11];
2749 if (access(filename, F_OK) != 0)
2750 Error(ERR_EXIT, "cannot open file '%s'", filename);
2752 LoadLevelFromFilename(&level, filename);
2757 else if (strncmp(command, "dump tape ", 10) == 0)
2759 char *filename = &command[10];
2761 if (access(filename, F_OK) != 0)
2762 Error(ERR_EXIT, "cannot open file '%s'", filename);
2764 LoadTapeFromFilename(filename);
2769 else if (strncmp(command, "autoplay ", 9) == 0)
2771 char *str_copy = getStringCopy(&command[9]);
2772 char *str_ptr = strchr(str_copy, ' ');
2774 global.autoplay_leveldir = str_copy;
2775 global.autoplay_level_nr = -1;
2777 if (str_ptr != NULL)
2779 *str_ptr++ = '\0'; /* terminate leveldir string */
2780 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2785 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2789 static void InitSetup()
2791 LoadSetup(); /* global setup info */
2793 /* set some options from setup file */
2795 if (setup.options.verbose)
2796 options.verbose = TRUE;
2799 static void InitPlayerInfo()
2803 /* choose default local player */
2804 local_player = &stored_player[0];
2806 for (i=0; i<MAX_PLAYERS; i++)
2807 stored_player[i].connected = FALSE;
2809 local_player->connected = TRUE;
2812 static void InitArtworkInfo()
2817 static char *get_string_in_brackets(char *string)
2819 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2821 sprintf(string_in_brackets, "[%s]", string);
2823 return string_in_brackets;
2827 static char *get_element_class_token(int element)
2829 char *element_class_name = element_info[element].class_name;
2830 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2832 sprintf(element_class_token, "[%s]", element_class_name);
2834 return element_class_token;
2837 static char *get_action_class_token(int action)
2839 char *action_class_name = &element_action_info[action].suffix[1];
2840 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2842 sprintf(action_class_token, "[%s]", action_class_name);
2844 return action_class_token;
2848 static void InitArtworkConfig()
2850 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2851 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2852 static char *action_id_suffix[NUM_ACTIONS + 1];
2853 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2854 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2855 static char *dummy[1] = { NULL };
2856 static char *ignore_generic_tokens[] =
2862 static char **ignore_image_tokens, **ignore_sound_tokens;
2863 int num_ignore_generic_tokens;
2864 int num_ignore_image_tokens, num_ignore_sound_tokens;
2867 /* dynamically determine list of generic tokens to be ignored */
2868 num_ignore_generic_tokens = 0;
2869 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2870 num_ignore_generic_tokens++;
2872 /* dynamically determine list of image tokens to be ignored */
2873 num_ignore_image_tokens = num_ignore_generic_tokens;
2874 for (i=0; image_config_vars[i].token != NULL; i++)
2875 num_ignore_image_tokens++;
2876 ignore_image_tokens =
2877 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2878 for (i=0; i < num_ignore_generic_tokens; i++)
2879 ignore_image_tokens[i] = ignore_generic_tokens[i];
2880 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2881 ignore_image_tokens[num_ignore_generic_tokens + i] =
2882 image_config_vars[i].token;
2883 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2885 /* dynamically determine list of sound tokens to be ignored */
2886 num_ignore_sound_tokens = num_ignore_generic_tokens;
2887 ignore_sound_tokens =
2888 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2889 for (i=0; i < num_ignore_generic_tokens; i++)
2890 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2891 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2893 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2894 image_id_prefix[i] = element_info[i].token_name;
2895 for (i=0; i<NUM_FONTS; i++)
2896 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2897 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2899 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2900 sound_id_prefix[i] = element_info[i].token_name;
2901 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2902 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2903 get_string_in_brackets(element_info[i].class_name);
2904 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2906 for (i=0; i<NUM_ACTIONS; i++)
2907 action_id_suffix[i] = element_action_info[i].suffix;
2908 action_id_suffix[NUM_ACTIONS] = NULL;
2910 for (i=0; i<NUM_DIRECTIONS; i++)
2911 direction_id_suffix[i] = element_direction_info[i].suffix;
2912 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2914 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2915 special_id_suffix[i] = special_suffix_info[i].suffix;
2916 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2918 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2919 image_id_prefix, action_id_suffix, direction_id_suffix,
2920 special_id_suffix, ignore_image_tokens);
2921 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2922 sound_id_prefix, action_id_suffix, dummy,
2923 special_id_suffix, ignore_sound_tokens);
2926 static void InitMixer()
2934 char *filename_font_initial = NULL;
2935 Bitmap *bitmap_font_initial = NULL;
2938 /* determine settings for initial font (for displaying startup messages) */
2939 for (i=0; image_config[i].token != NULL; i++)
2941 for (j=0; j < NUM_INITIAL_FONTS; j++)
2943 char font_token[128];
2946 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2947 len_font_token = strlen(font_token);
2949 if (strcmp(image_config[i].token, font_token) == 0)
2950 filename_font_initial = image_config[i].value;
2951 else if (strlen(image_config[i].token) > len_font_token &&
2952 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2954 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2955 font_initial[j].src_x = atoi(image_config[i].value);
2956 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2957 font_initial[j].src_y = atoi(image_config[i].value);
2958 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2959 font_initial[j].width = atoi(image_config[i].value);
2960 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2961 font_initial[j].height = atoi(image_config[i].value);
2966 for (j=0; j < NUM_INITIAL_FONTS; j++)
2968 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2969 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2972 if (filename_font_initial == NULL) /* should not happen */
2973 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2975 /* create additional image buffers for double-buffering */
2976 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2977 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2979 /* initialize screen properties */
2980 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2981 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2983 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2984 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2985 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2987 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2989 for (j=0; j < NUM_INITIAL_FONTS; j++)
2990 font_initial[j].bitmap = bitmap_font_initial;
2992 InitFontGraphicInfo();
2994 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2995 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2997 DrawInitText("Loading graphics:", 120, FC_GREEN);
2999 InitTileClipmasks();
3002 void InitGfxBackground()
3006 drawto = backbuffer;
3007 fieldbuffer = bitmap_db_field;
3008 SetDrawtoField(DRAW_BACKBUFFER);
3010 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3011 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3012 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3013 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3015 for (x=0; x<MAX_BUF_XSIZE; x++)
3016 for (y=0; y<MAX_BUF_YSIZE; y++)
3019 redraw_mask = REDRAW_ALL;
3022 static void InitLevelInfo()
3024 LoadLevelInfo(); /* global level info */
3025 LoadLevelSetup_LastSeries(); /* last played series info */
3026 LoadLevelSetup_SeriesInfo(); /* last played level info */
3029 void InitLevelArtworkInfo()
3031 LoadLevelArtworkInfo();
3034 static void InitImages()
3036 ReloadCustomImages();
3038 LoadCustomElementDescriptions();
3039 LoadSpecialMenuDesignSettings();
3041 ReinitializeGraphics();
3044 static void InitSound()
3046 InitReloadCustomSounds(artwork.snd_current->identifier);
3047 ReinitializeSounds();
3050 static void InitMusic()
3052 InitReloadCustomMusic(artwork.mus_current->identifier);
3053 ReinitializeMusic();
3056 void InitNetworkServer()
3058 #if defined(PLATFORM_UNIX)
3062 if (!options.network)
3065 #if defined(PLATFORM_UNIX)
3066 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3068 if (!ConnectToServer(options.server_host, options.server_port))
3069 Error(ERR_EXIT, "cannot connect to network game server");
3071 SendToServer_PlayerName(setup.player_name);
3072 SendToServer_ProtocolVersion();
3075 SendToServer_NrWanted(nr_wanted);
3079 void ReloadCustomArtwork()
3081 static char *leveldir_current_identifier = NULL;
3082 static boolean last_override_level_graphics = FALSE;
3083 static boolean last_override_level_sounds = FALSE;
3084 static boolean last_override_level_music = FALSE;
3085 /* identifier for new artwork; default: artwork configured in setup */
3086 char *gfx_new_identifier = artwork.gfx_current->identifier;
3087 char *snd_new_identifier = artwork.snd_current->identifier;
3088 char *mus_new_identifier = artwork.mus_current->identifier;
3089 boolean redraw_screen = FALSE;
3091 if (leveldir_current_identifier == NULL)
3092 leveldir_current_identifier = leveldir_current->identifier;
3095 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3096 leveldir_current->graphics_set);
3097 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3098 leveldir_current->identifier);
3102 printf("graphics --> '%s' ('%s')\n",
3103 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3104 printf("sounds --> '%s' ('%s')\n",
3105 artwork.snd_current_identifier, artwork.snd_current->filename);
3106 printf("music --> '%s' ('%s')\n",
3107 artwork.mus_current_identifier, artwork.mus_current->filename);
3110 /* leveldir_current may be invalid (level group, parent link) */
3111 if (!validLevelSeries(leveldir_current))
3114 /* when a new level series was selected, check if there was a change
3115 in custom artwork stored in level series directory */
3116 if (leveldir_current_identifier != leveldir_current->identifier)
3118 char *identifier_old = leveldir_current_identifier;
3119 char *identifier_new = leveldir_current->identifier;
3121 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3122 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3123 gfx_new_identifier = identifier_new;
3124 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3125 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3126 snd_new_identifier = identifier_new;
3127 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3128 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3129 mus_new_identifier = identifier_new;
3131 leveldir_current_identifier = leveldir_current->identifier;
3134 /* custom level artwork configured in level series configuration file
3135 always overrides custom level artwork stored in level series directory
3136 and (level independent) custom artwork configured in setup menue */
3137 if (leveldir_current->graphics_set != NULL)
3138 gfx_new_identifier = leveldir_current->graphics_set;
3139 if (leveldir_current->sounds_set != NULL)
3140 snd_new_identifier = leveldir_current->sounds_set;
3141 if (leveldir_current->music_set != NULL)
3142 mus_new_identifier = leveldir_current->music_set;
3144 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3145 last_override_level_graphics != setup.override_level_graphics)
3148 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3149 artwork.gfx_current_identifier,
3150 artwork.gfx_current->identifier,
3151 gfx_new_identifier);
3154 setLevelArtworkDir(artwork.gfx_first);
3156 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3160 FreeTileClipmasks();
3161 InitTileClipmasks();
3163 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3164 last_override_level_graphics = setup.override_level_graphics;
3166 redraw_screen = TRUE;
3169 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3170 last_override_level_sounds != setup.override_level_sounds)
3173 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3174 artwork.snd_current_identifier,
3175 artwork.snd_current->identifier,
3176 snd_new_identifier);
3179 /* set artwork path to send it to the sound server process */
3180 setLevelArtworkDir(artwork.snd_first);
3182 InitReloadCustomSounds(snd_new_identifier);
3183 ReinitializeSounds();
3185 artwork.snd_current_identifier = artwork.snd_current->identifier;
3186 last_override_level_sounds = setup.override_level_sounds;
3188 redraw_screen = TRUE;
3191 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3192 last_override_level_music != setup.override_level_music)
3194 /* set artwork path to send it to the sound server process */
3195 setLevelArtworkDir(artwork.mus_first);
3197 InitReloadCustomMusic(mus_new_identifier);
3198 ReinitializeMusic();
3200 artwork.mus_current_identifier = artwork.mus_current->identifier;
3201 last_override_level_music = setup.override_level_music;
3203 redraw_screen = TRUE;
3208 InitGfxBackground();
3210 /* force redraw of (open or closed) door graphics */
3211 SetDoorState(DOOR_OPEN_ALL);
3212 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3216 void KeyboardAutoRepeatOffUnlessAutoplay()
3218 if (global.autoplay_leveldir == NULL)
3219 KeyboardAutoRepeatOff();
3223 /* ========================================================================= */
3225 /* ========================================================================= */
3229 InitGlobal(); /* initialize some global variables */
3231 if (options.execute_command)
3232 Execute_Command(options.execute_command);
3234 if (options.serveronly)
3236 #if defined(PLATFORM_UNIX)
3237 NetworkServer(options.server_port, options.serveronly);
3239 Error(ERR_WARN, "networking only supported in Unix version");
3241 exit(0); /* never reached */
3247 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3248 InitArtworkConfig(); /* needed before forking sound child process */
3253 InitRND(NEW_RANDOMIZE);
3254 InitSimpleRND(NEW_RANDOMIZE);
3259 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3262 InitEventFilter(FilterMouseMotionEvents);
3264 InitElementPropertiesStatic();
3269 InitLevelArtworkInfo();
3271 InitImages(); /* needs to know current level directory */
3272 InitSound(); /* needs to know current level directory */
3273 InitMusic(); /* needs to know current level directory */
3275 InitGfxBackground();
3277 if (global.autoplay_leveldir)
3283 game_status = GAME_MODE_MAIN;
3287 InitNetworkServer();
3290 void CloseAllAndExit(int exit_value)
3295 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3298 FreeTileClipmasks();
3300 CloseVideoDisplay();
3301 ClosePlatformDependentStuff();