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()
970 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
971 int num_property_mappings = getSoundListPropertyMappingSize();
973 int *sound_effect_properties;
974 int num_sounds = getSoundListSize();
977 if (sound_info != NULL)
980 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
981 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
983 /* initialize sound effect for all elements to "no sound" */
984 for (i=0; i<MAX_NUM_ELEMENTS; i++)
985 for (j=0; j<NUM_ACTIONS; j++)
986 element_info[i].sound[j] = SND_UNDEFINED;
988 for (i=0; i<num_sounds; i++)
990 struct FileInfo *sound = getSoundListEntry(i);
991 int len_effect_text = strlen(sound->token);
993 sound_effect_properties[i] = ACTION_OTHER;
994 sound_info[i].loop = FALSE;
996 /* determine all loop sounds and identify certain sound classes */
998 for (j=0; element_action_info[j].suffix; j++)
1000 int len_action_text = strlen(element_action_info[j].suffix);
1002 if (len_action_text < len_effect_text &&
1003 strcmp(&sound->token[len_effect_text - len_action_text],
1004 element_action_info[j].suffix) == 0)
1006 sound_effect_properties[i] = element_action_info[j].value;
1008 if (element_action_info[j].is_loop_sound)
1009 sound_info[i].loop = TRUE;
1013 /* associate elements and some selected sound actions */
1015 for (j=0; j<MAX_NUM_ELEMENTS; j++)
1017 if (element_info[j].class_name)
1019 int len_class_text = strlen(element_info[j].class_name);
1021 if (len_class_text + 1 < len_effect_text &&
1022 strncmp(sound->token,
1023 element_info[j].class_name, len_class_text) == 0 &&
1024 sound->token[len_class_text] == '.')
1026 int sound_action_value = sound_effect_properties[i];
1028 element_info[j].sound[sound_action_value] = i;
1033 set_sound_parameters(i, sound->parameter);
1036 free(sound_effect_properties);
1039 /* !!! now handled in InitElementSoundInfo() !!! */
1040 /* initialize element/sound mapping from dynamic configuration */
1041 for (i=0; i < num_property_mappings; i++)
1043 int element = property_mapping[i].base_index;
1044 int action = property_mapping[i].ext1_index;
1045 int sound = property_mapping[i].artwork_index;
1048 action = ACTION_DEFAULT;
1050 printf("::: %d: %d, %d, %d ['%s']\n",
1051 i, element, action, sound, element_info[element].token_name);
1053 element_info[element].sound[action] = sound;
1060 int element = EL_CUSTOM_11;
1063 while (element_action_info[j].suffix)
1065 printf("element %d, sound action '%s' == %d\n",
1066 element, element_action_info[j].suffix,
1067 element_info[element].sound[j]);
1072 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1078 int element = EL_SAND;
1079 int sound_action = ACTION_DIGGING;
1082 while (element_action_info[j].suffix)
1084 if (element_action_info[j].value == sound_action)
1085 printf("element %d, sound action '%s' == %d\n",
1086 element, element_action_info[j].suffix,
1087 element_info[element].sound[sound_action]);
1094 static void ReinitializeGraphics()
1096 InitGraphicInfo(); /* graphic properties mapping */
1097 InitElementGraphicInfo(); /* element game graphic mapping */
1098 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1100 InitElementSmallImages(); /* create editor and preview images */
1101 InitFontGraphicInfo(); /* initialize text drawing functions */
1103 SetMainBackgroundImage(IMG_BACKGROUND);
1104 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1110 static void ReinitializeSounds()
1112 InitSoundInfo(); /* sound properties mapping */
1113 InitElementSoundInfo(); /* element game sound mapping */
1115 InitPlaySoundLevel(); /* internal game sound settings */
1118 static void ReinitializeMusic()
1120 /* currently nothing to do */
1123 void InitElementPropertiesStatic()
1125 static int ep_diggable[] =
1130 EL_SP_BUGGY_BASE_ACTIVATING,
1133 EL_INVISIBLE_SAND_ACTIVE,
1135 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1139 EL_SP_BUGGY_BASE_ACTIVE,
1144 static int ep_collectible[] =
1161 EL_DYNABOMB_INCREASE_NUMBER,
1162 EL_DYNABOMB_INCREASE_SIZE,
1163 EL_DYNABOMB_INCREASE_POWER,
1177 static int ep_dont_run_into[] =
1179 /* same elements as in 'ep_dont_touch' */
1185 /* same elements as in 'ep_dont_collide_with' */
1197 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1199 EL_SP_BUGGY_BASE_ACTIVE,
1206 static int ep_dont_collide_with[] =
1208 /* same elements as in 'ep_dont_touch' */
1224 static int ep_dont_touch[] =
1233 static int ep_indestructible[] =
1237 EL_ACID_POOL_TOPLEFT,
1238 EL_ACID_POOL_TOPRIGHT,
1239 EL_ACID_POOL_BOTTOMLEFT,
1240 EL_ACID_POOL_BOTTOM,
1241 EL_ACID_POOL_BOTTOMRIGHT,
1242 EL_SP_HARDWARE_GRAY,
1243 EL_SP_HARDWARE_GREEN,
1244 EL_SP_HARDWARE_BLUE,
1246 EL_SP_HARDWARE_YELLOW,
1247 EL_SP_HARDWARE_BASE_1,
1248 EL_SP_HARDWARE_BASE_2,
1249 EL_SP_HARDWARE_BASE_3,
1250 EL_SP_HARDWARE_BASE_4,
1251 EL_SP_HARDWARE_BASE_5,
1252 EL_SP_HARDWARE_BASE_6,
1253 EL_INVISIBLE_STEELWALL,
1254 EL_INVISIBLE_STEELWALL_ACTIVE,
1255 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1256 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1257 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1258 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1259 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1260 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1261 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1262 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1263 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1264 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1265 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1266 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1268 EL_LIGHT_SWITCH_ACTIVE,
1269 EL_SIGN_EXCLAMATION,
1270 EL_SIGN_RADIOACTIVITY,
1281 EL_STEELWALL_SLANTED,
1304 EL_SWITCHGATE_OPENING,
1305 EL_SWITCHGATE_CLOSED,
1306 EL_SWITCHGATE_CLOSING,
1308 EL_SWITCHGATE_SWITCH_UP,
1309 EL_SWITCHGATE_SWITCH_DOWN,
1312 EL_TIMEGATE_OPENING,
1314 EL_TIMEGATE_CLOSING,
1317 EL_TIMEGATE_SWITCH_ACTIVE,
1322 EL_TUBE_VERTICAL_LEFT,
1323 EL_TUBE_VERTICAL_RIGHT,
1324 EL_TUBE_HORIZONTAL_UP,
1325 EL_TUBE_HORIZONTAL_DOWN,
1333 static int ep_slippery[] =
1347 EL_ROBOT_WHEEL_ACTIVE,
1353 EL_ACID_POOL_TOPLEFT,
1354 EL_ACID_POOL_TOPRIGHT,
1364 EL_STEELWALL_SLANTED,
1370 static int ep_can_change[] =
1375 static int ep_can_move[] =
1397 static int ep_can_fall[] =
1412 EL_BD_MAGIC_WALL_FULL,
1425 static int ep_can_smash_player[] =
1450 static int ep_can_smash_enemies[] =
1458 static int ep_can_smash_everything[] =
1466 static int ep_can_explode_by_fire[] =
1468 /* same elements as in 'ep_can_explode_impact' */
1473 /* same elements as in 'ep_can_explode_smashed' */
1482 EL_DYNABOMB_PLAYER_1_ACTIVE,
1483 EL_DYNABOMB_PLAYER_2_ACTIVE,
1484 EL_DYNABOMB_PLAYER_3_ACTIVE,
1485 EL_DYNABOMB_PLAYER_4_ACTIVE,
1486 EL_DYNABOMB_INCREASE_NUMBER,
1487 EL_DYNABOMB_INCREASE_SIZE,
1488 EL_DYNABOMB_INCREASE_POWER,
1489 EL_SP_DISK_RED_ACTIVE,
1499 static int ep_can_explode_smashed[] =
1501 /* same elements as in 'ep_can_explode_impact' */
1514 static int ep_can_explode_impact[] =
1522 static int ep_walkable_over[] =
1526 EL_SOKOBAN_FIELD_EMPTY,
1543 static int ep_walkable_inside[] =
1548 EL_TUBE_VERTICAL_LEFT,
1549 EL_TUBE_VERTICAL_RIGHT,
1550 EL_TUBE_HORIZONTAL_UP,
1551 EL_TUBE_HORIZONTAL_DOWN,
1559 static int ep_walkable_under[] =
1564 static int ep_passable_over[] =
1579 static int ep_passable_inside[] =
1585 EL_SP_PORT_HORIZONTAL,
1586 EL_SP_PORT_VERTICAL,
1588 EL_SP_GRAVITY_PORT_LEFT,
1589 EL_SP_GRAVITY_PORT_RIGHT,
1590 EL_SP_GRAVITY_PORT_UP,
1591 EL_SP_GRAVITY_PORT_DOWN,
1595 static int ep_passable_under[] =
1600 static int ep_pushable[] =
1612 EL_SOKOBAN_FIELD_FULL,
1619 static int ep_can_be_crumbled[] =
1628 static int ep_player[] =
1637 static int ep_can_pass_magic_wall[] =
1650 static int ep_switchable[] =
1654 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1655 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1656 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1657 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1658 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1659 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1660 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1661 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1662 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1663 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1664 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1665 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1666 EL_SWITCHGATE_SWITCH_UP,
1667 EL_SWITCHGATE_SWITCH_DOWN,
1669 EL_LIGHT_SWITCH_ACTIVE,
1671 EL_BALLOON_SWITCH_LEFT,
1672 EL_BALLOON_SWITCH_RIGHT,
1673 EL_BALLOON_SWITCH_UP,
1674 EL_BALLOON_SWITCH_DOWN,
1675 EL_BALLOON_SWITCH_ANY,
1681 static int ep_bd_element[] =
1710 static int ep_sp_element[] =
1718 EL_SP_HARDWARE_GRAY,
1726 EL_SP_GRAVITY_PORT_RIGHT,
1727 EL_SP_GRAVITY_PORT_DOWN,
1728 EL_SP_GRAVITY_PORT_LEFT,
1729 EL_SP_GRAVITY_PORT_UP,
1734 EL_SP_PORT_VERTICAL,
1735 EL_SP_PORT_HORIZONTAL,
1741 EL_SP_HARDWARE_BASE_1,
1742 EL_SP_HARDWARE_GREEN,
1743 EL_SP_HARDWARE_BLUE,
1745 EL_SP_HARDWARE_YELLOW,
1746 EL_SP_HARDWARE_BASE_2,
1747 EL_SP_HARDWARE_BASE_3,
1748 EL_SP_HARDWARE_BASE_4,
1749 EL_SP_HARDWARE_BASE_5,
1750 EL_SP_HARDWARE_BASE_6,
1753 /* additional elements that appeared in newer Supaplex levels */
1755 /* more than one murphy in a level results in an inactive clone */
1757 /* runtime elements*/
1758 EL_SP_DISK_RED_ACTIVE,
1759 EL_SP_TERMINAL_ACTIVE,
1760 EL_SP_BUGGY_BASE_ACTIVATING,
1761 EL_SP_BUGGY_BASE_ACTIVE,
1765 static int ep_sb_element[] =
1770 EL_SOKOBAN_FIELD_EMPTY,
1771 EL_SOKOBAN_FIELD_FULL,
1773 EL_INVISIBLE_STEELWALL,
1777 static int ep_gem[] =
1788 static int ep_food_dark_yamyam[] =
1815 static int ep_food_penguin[] =
1828 static int ep_food_pig[] =
1839 static int ep_historic_wall[] =
1864 EL_EXPANDABLE_WALL_HORIZONTAL,
1865 EL_EXPANDABLE_WALL_VERTICAL,
1866 EL_EXPANDABLE_WALL_ANY,
1867 EL_EXPANDABLE_WALL_GROWING,
1874 EL_SP_HARDWARE_GRAY,
1875 EL_SP_HARDWARE_GREEN,
1876 EL_SP_HARDWARE_BLUE,
1878 EL_SP_HARDWARE_YELLOW,
1879 EL_SP_HARDWARE_BASE_1,
1880 EL_SP_HARDWARE_BASE_2,
1881 EL_SP_HARDWARE_BASE_3,
1882 EL_SP_HARDWARE_BASE_4,
1883 EL_SP_HARDWARE_BASE_5,
1884 EL_SP_HARDWARE_BASE_6,
1886 EL_SP_TERMINAL_ACTIVE,
1889 EL_INVISIBLE_STEELWALL,
1890 EL_INVISIBLE_STEELWALL_ACTIVE,
1892 EL_INVISIBLE_WALL_ACTIVE,
1893 EL_STEELWALL_SLANTED,
1909 static int ep_historic_solid[] =
1913 EL_EXPANDABLE_WALL_HORIZONTAL,
1914 EL_EXPANDABLE_WALL_VERTICAL,
1915 EL_EXPANDABLE_WALL_ANY,
1928 EL_QUICKSAND_FILLING,
1929 EL_QUICKSAND_EMPTYING,
1931 EL_MAGIC_WALL_ACTIVE,
1932 EL_MAGIC_WALL_EMPTYING,
1933 EL_MAGIC_WALL_FILLING,
1937 EL_BD_MAGIC_WALL_ACTIVE,
1938 EL_BD_MAGIC_WALL_EMPTYING,
1939 EL_BD_MAGIC_WALL_FULL,
1940 EL_BD_MAGIC_WALL_FILLING,
1941 EL_BD_MAGIC_WALL_DEAD,
1950 EL_SP_TERMINAL_ACTIVE,
1954 EL_INVISIBLE_WALL_ACTIVE,
1955 EL_SWITCHGATE_SWITCH_UP,
1956 EL_SWITCHGATE_SWITCH_DOWN,
1958 EL_TIMEGATE_SWITCH_ACTIVE,
1970 /* the following elements are a direct copy of "indestructible" elements,
1971 except "EL_ACID", which is "indestructible", but not "solid"! */
1976 EL_ACID_POOL_TOPLEFT,
1977 EL_ACID_POOL_TOPRIGHT,
1978 EL_ACID_POOL_BOTTOMLEFT,
1979 EL_ACID_POOL_BOTTOM,
1980 EL_ACID_POOL_BOTTOMRIGHT,
1981 EL_SP_HARDWARE_GRAY,
1982 EL_SP_HARDWARE_GREEN,
1983 EL_SP_HARDWARE_BLUE,
1985 EL_SP_HARDWARE_YELLOW,
1986 EL_SP_HARDWARE_BASE_1,
1987 EL_SP_HARDWARE_BASE_2,
1988 EL_SP_HARDWARE_BASE_3,
1989 EL_SP_HARDWARE_BASE_4,
1990 EL_SP_HARDWARE_BASE_5,
1991 EL_SP_HARDWARE_BASE_6,
1992 EL_INVISIBLE_STEELWALL,
1993 EL_INVISIBLE_STEELWALL_ACTIVE,
1994 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1995 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1996 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1997 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1998 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1999 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2000 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2001 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2002 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2003 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2004 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2005 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2007 EL_LIGHT_SWITCH_ACTIVE,
2008 EL_SIGN_EXCLAMATION,
2009 EL_SIGN_RADIOACTIVITY,
2020 EL_STEELWALL_SLANTED,
2043 EL_SWITCHGATE_OPENING,
2044 EL_SWITCHGATE_CLOSED,
2045 EL_SWITCHGATE_CLOSING,
2047 EL_TIMEGATE_OPENING,
2049 EL_TIMEGATE_CLOSING,
2053 EL_TUBE_VERTICAL_LEFT,
2054 EL_TUBE_VERTICAL_RIGHT,
2055 EL_TUBE_HORIZONTAL_UP,
2056 EL_TUBE_HORIZONTAL_DOWN,
2064 static int ep_classic_enemy[] =
2080 static int ep_belt[] =
2082 EL_CONVEYOR_BELT_1_LEFT,
2083 EL_CONVEYOR_BELT_1_MIDDLE,
2084 EL_CONVEYOR_BELT_1_RIGHT,
2085 EL_CONVEYOR_BELT_2_LEFT,
2086 EL_CONVEYOR_BELT_2_MIDDLE,
2087 EL_CONVEYOR_BELT_2_RIGHT,
2088 EL_CONVEYOR_BELT_3_LEFT,
2089 EL_CONVEYOR_BELT_3_MIDDLE,
2090 EL_CONVEYOR_BELT_3_RIGHT,
2091 EL_CONVEYOR_BELT_4_LEFT,
2092 EL_CONVEYOR_BELT_4_MIDDLE,
2093 EL_CONVEYOR_BELT_4_RIGHT,
2097 static int ep_belt_active[] =
2099 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2100 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2101 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2102 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2103 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2104 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2105 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2106 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2107 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2108 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2109 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2110 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2114 static int ep_belt_switch[] =
2116 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2117 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2118 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2119 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2120 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2121 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2122 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2123 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2124 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2125 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2126 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2127 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2131 static int ep_tube[] =
2138 EL_TUBE_HORIZONTAL_UP,
2139 EL_TUBE_HORIZONTAL_DOWN,
2141 EL_TUBE_VERTICAL_LEFT,
2142 EL_TUBE_VERTICAL_RIGHT,
2147 static int ep_keygate[] =
2168 static int ep_amoeboid[] =
2178 static int ep_amoebalive[] =
2187 static int ep_has_content[] =
2197 static int ep_active_bomb[] =
2200 EL_DYNABOMB_PLAYER_1_ACTIVE,
2201 EL_DYNABOMB_PLAYER_2_ACTIVE,
2202 EL_DYNABOMB_PLAYER_3_ACTIVE,
2203 EL_DYNABOMB_PLAYER_4_ACTIVE,
2204 EL_SP_DISK_RED_ACTIVE,
2208 static int ep_inactive[] =
2245 EL_INVISIBLE_STEELWALL,
2253 EL_WALL_EMERALD_YELLOW,
2254 EL_DYNABOMB_INCREASE_NUMBER,
2255 EL_DYNABOMB_INCREASE_SIZE,
2256 EL_DYNABOMB_INCREASE_POWER,
2260 EL_SOKOBAN_FIELD_EMPTY,
2261 EL_SOKOBAN_FIELD_FULL,
2262 EL_WALL_EMERALD_RED,
2263 EL_WALL_EMERALD_PURPLE,
2264 EL_ACID_POOL_TOPLEFT,
2265 EL_ACID_POOL_TOPRIGHT,
2266 EL_ACID_POOL_BOTTOMLEFT,
2267 EL_ACID_POOL_BOTTOM,
2268 EL_ACID_POOL_BOTTOMRIGHT,
2272 EL_BD_MAGIC_WALL_DEAD,
2273 EL_AMOEBA_TO_DIAMOND,
2281 EL_SP_GRAVITY_PORT_RIGHT,
2282 EL_SP_GRAVITY_PORT_DOWN,
2283 EL_SP_GRAVITY_PORT_LEFT,
2284 EL_SP_GRAVITY_PORT_UP,
2285 EL_SP_PORT_HORIZONTAL,
2286 EL_SP_PORT_VERTICAL,
2297 EL_SP_HARDWARE_GRAY,
2298 EL_SP_HARDWARE_GREEN,
2299 EL_SP_HARDWARE_BLUE,
2301 EL_SP_HARDWARE_YELLOW,
2302 EL_SP_HARDWARE_BASE_1,
2303 EL_SP_HARDWARE_BASE_2,
2304 EL_SP_HARDWARE_BASE_3,
2305 EL_SP_HARDWARE_BASE_4,
2306 EL_SP_HARDWARE_BASE_5,
2307 EL_SP_HARDWARE_BASE_6,
2308 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2309 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2310 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2311 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2312 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2313 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2314 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2315 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2316 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2317 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2318 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2319 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2320 EL_SIGN_EXCLAMATION,
2321 EL_SIGN_RADIOACTIVITY,
2332 EL_STEELWALL_SLANTED,
2352 } element_properties[] =
2354 { ep_diggable, EP_DIGGABLE },
2355 { ep_collectible, EP_COLLECTIBLE },
2356 { ep_dont_run_into, EP_DONT_RUN_INTO },
2357 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2358 { ep_dont_touch, EP_DONT_TOUCH },
2359 { ep_indestructible, EP_INDESTRUCTIBLE },
2360 { ep_slippery, EP_SLIPPERY },
2361 { ep_can_change, EP_CAN_CHANGE },
2362 { ep_can_move, EP_CAN_MOVE },
2363 { ep_can_fall, EP_CAN_FALL },
2364 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2365 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2366 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2367 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2368 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2369 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2370 { ep_walkable_over, EP_WALKABLE_OVER },
2371 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2372 { ep_walkable_under, EP_WALKABLE_UNDER },
2373 { ep_passable_over, EP_PASSABLE_OVER },
2374 { ep_passable_inside, EP_PASSABLE_INSIDE },
2375 { ep_passable_under, EP_PASSABLE_UNDER },
2376 { ep_pushable, EP_PUSHABLE },
2378 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2380 { ep_player, EP_PLAYER },
2381 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2382 { ep_switchable, EP_SWITCHABLE },
2383 { ep_bd_element, EP_BD_ELEMENT },
2384 { ep_sp_element, EP_SP_ELEMENT },
2385 { ep_sb_element, EP_SB_ELEMENT },
2387 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2388 { ep_food_penguin, EP_FOOD_PENGUIN },
2389 { ep_food_pig, EP_FOOD_PIG },
2390 { ep_historic_wall, EP_HISTORIC_WALL },
2391 { ep_historic_solid, EP_HISTORIC_SOLID },
2392 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2393 { ep_belt, EP_BELT },
2394 { ep_belt_active, EP_BELT_ACTIVE },
2395 { ep_belt_switch, EP_BELT_SWITCH },
2396 { ep_tube, EP_TUBE },
2397 { ep_keygate, EP_KEYGATE },
2398 { ep_amoeboid, EP_AMOEBOID },
2399 { ep_amoebalive, EP_AMOEBALIVE },
2400 { ep_has_content, EP_HAS_CONTENT },
2401 { ep_active_bomb, EP_ACTIVE_BOMB },
2402 { ep_inactive, EP_INACTIVE },
2407 static int copy_properties[][5] =
2411 EL_BUG_LEFT, EL_BUG_RIGHT,
2412 EL_BUG_UP, EL_BUG_DOWN
2416 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2417 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2421 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2422 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2426 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2427 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2431 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2432 EL_PACMAN_UP, EL_PACMAN_DOWN
2442 /* always start with reliable default values (element has no properties) */
2443 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2444 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2445 SET_PROPERTY(i, j, FALSE);
2447 /* set all base element properties from above array definitions */
2448 for (i=0; element_properties[i].elements != NULL; i++)
2449 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2450 SET_PROPERTY((element_properties[i].elements)[j],
2451 element_properties[i].property, TRUE);
2453 /* copy properties to some elements that are only stored in level file */
2454 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2455 for (j=0; copy_properties[j][0] != -1; j++)
2456 if (HAS_PROPERTY(copy_properties[j][0], i))
2457 for (k=1; k<=4; k++)
2458 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2461 void InitElementPropertiesEngine(int engine_version)
2464 static int active_properties[] =
2469 EP_DONT_COLLIDE_WITH,
2473 EP_CAN_PASS_MAGIC_WALL,
2478 EP_CAN_EXPLODE_BY_FIRE,
2491 EP_EM_SLIPPERY_WALL,
2496 static int no_wall_properties[] =
2501 EP_DONT_COLLIDE_WITH,
2504 EP_CAN_SMASH_PLAYER,
2505 EP_CAN_SMASH_ENEMIES,
2506 EP_CAN_SMASH_EVERYTHING,
2513 EP_FOOD_DARK_YAMYAM,
2529 InitElementPropertiesStatic();
2532 /* set all special, combined or engine dependent element properties */
2533 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2536 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2537 SET_PROPERTY(i, j, FALSE);
2540 /* ---------- INACTIVE ------------------------------------------------- */
2541 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2542 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2544 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2545 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2546 IS_WALKABLE_INSIDE(i) ||
2547 IS_WALKABLE_UNDER(i)));
2549 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2550 IS_PASSABLE_INSIDE(i) ||
2551 IS_PASSABLE_UNDER(i)));
2553 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2554 IS_PASSABLE_OVER(i)));
2556 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2557 IS_PASSABLE_INSIDE(i)));
2559 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2560 IS_PASSABLE_UNDER(i)));
2562 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2565 /* ---------- SNAPPABLE ------------------------------------------------ */
2566 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2567 IS_COLLECTIBLE(i) ||
2571 /* ---------- WALL ----------------------------------------------------- */
2572 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2574 for (j=0; no_wall_properties[j] != -1; j++)
2575 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2576 i >= EL_FIRST_RUNTIME_UNREAL)
2577 SET_PROPERTY(i, EP_WALL, FALSE);
2579 if (IS_HISTORIC_WALL(i))
2580 SET_PROPERTY(i, EP_WALL, TRUE);
2582 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2583 if (engine_version < VERSION_IDENT(2,2,0))
2584 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2586 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2588 !IS_COLLECTIBLE(i)));
2590 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2592 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2593 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2595 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2596 IS_INDESTRUCTIBLE(i)));
2598 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2600 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2601 else if (engine_version < VERSION_IDENT(2,2,0))
2602 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2604 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2605 !IS_WALKABLE_OVER(i) &&
2606 !IS_WALKABLE_UNDER(i)));
2608 if (IS_CUSTOM_ELEMENT(i))
2610 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2612 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2613 if (DONT_COLLIDE_WITH(i))
2614 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2616 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2617 if (CAN_SMASH_EVERYTHING(i))
2618 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2619 if (CAN_SMASH_ENEMIES(i))
2620 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2623 /* ---------- CAN_SMASH ------------------------------------------------ */
2624 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2625 CAN_SMASH_ENEMIES(i) ||
2626 CAN_SMASH_EVERYTHING(i)));
2628 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2629 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2630 CAN_EXPLODE_SMASHED(i) ||
2631 CAN_EXPLODE_BY_FIRE(i)));
2635 /* determine inactive elements (used for engine main loop optimization) */
2636 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2638 boolean active = FALSE;
2640 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2642 if (HAS_PROPERTY(i, j))
2648 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2653 /* dynamically adjust element properties according to game engine version */
2655 static int ep_em_slippery_wall[] =
2660 EL_EXPANDABLE_WALL_HORIZONTAL,
2661 EL_EXPANDABLE_WALL_VERTICAL,
2662 EL_EXPANDABLE_WALL_ANY,
2666 /* special EM style gems behaviour */
2667 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2668 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2669 level.em_slippery_gems);
2671 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2672 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2673 (level.em_slippery_gems &&
2674 engine_version > VERSION_IDENT(2,0,1)));
2678 /* dynamically adjust element properties according to game engine version */
2680 if (engine_version < RELEASE_IDENT(2,2,0,7))
2683 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2685 int element = EL_CUSTOM_START + i;
2687 element_info[element].push_delay_fixed = 2;
2688 element_info[element].push_delay_random = 8;
2694 static void InitGlobal()
2696 global.autoplay_leveldir = NULL;
2698 global.frames_per_second = 0;
2699 global.fps_slowdown = FALSE;
2700 global.fps_slowdown_factor = 1;
2703 void Execute_Command(char *command)
2705 if (strcmp(command, "print graphicsinfo.conf") == 0)
2709 printf("# You can configure additional/alternative image files here.\n");
2710 printf("# (The images below are default and therefore commented out.)\n");
2712 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2714 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2717 for (i=0; image_config[i].token != NULL; i++)
2719 getFormattedSetupEntry(image_config[i].token,
2720 image_config[i].value));
2724 else if (strcmp(command, "print soundsinfo.conf") == 0)
2728 printf("# You can configure additional/alternative sound files here.\n");
2729 printf("# (The sounds below are default and therefore commented out.)\n");
2731 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2733 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2736 for (i=0; sound_config[i].token != NULL; i++)
2738 getFormattedSetupEntry(sound_config[i].token,
2739 sound_config[i].value));
2743 else if (strcmp(command, "print musicinfo.conf") == 0)
2745 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2747 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2749 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2753 else if (strncmp(command, "dump level ", 11) == 0)
2755 char *filename = &command[11];
2757 if (access(filename, F_OK) != 0)
2758 Error(ERR_EXIT, "cannot open file '%s'", filename);
2760 LoadLevelFromFilename(&level, filename);
2765 else if (strncmp(command, "dump tape ", 10) == 0)
2767 char *filename = &command[10];
2769 if (access(filename, F_OK) != 0)
2770 Error(ERR_EXIT, "cannot open file '%s'", filename);
2772 LoadTapeFromFilename(filename);
2777 else if (strncmp(command, "autoplay ", 9) == 0)
2779 char *str_copy = getStringCopy(&command[9]);
2780 char *str_ptr = strchr(str_copy, ' ');
2782 global.autoplay_leveldir = str_copy;
2783 global.autoplay_level_nr = -1;
2785 if (str_ptr != NULL)
2787 *str_ptr++ = '\0'; /* terminate leveldir string */
2788 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2793 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2797 static void InitSetup()
2799 LoadSetup(); /* global setup info */
2801 /* set some options from setup file */
2803 if (setup.options.verbose)
2804 options.verbose = TRUE;
2807 static void InitPlayerInfo()
2811 /* choose default local player */
2812 local_player = &stored_player[0];
2814 for (i=0; i<MAX_PLAYERS; i++)
2815 stored_player[i].connected = FALSE;
2817 local_player->connected = TRUE;
2820 static void InitArtworkInfo()
2825 static char *get_string_in_brackets(char *string)
2827 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2829 sprintf(string_in_brackets, "[%s]", string);
2831 return string_in_brackets;
2835 static char *get_element_class_token(int element)
2837 char *element_class_name = element_info[element].class_name;
2838 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2840 sprintf(element_class_token, "[%s]", element_class_name);
2842 return element_class_token;
2845 static char *get_action_class_token(int action)
2847 char *action_class_name = &element_action_info[action].suffix[1];
2848 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2850 sprintf(action_class_token, "[%s]", action_class_name);
2852 return action_class_token;
2856 static void InitArtworkConfig()
2858 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2859 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2860 static char *action_id_suffix[NUM_ACTIONS + 1];
2861 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2862 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2863 static char *dummy[1] = { NULL };
2864 static char *ignore_generic_tokens[] =
2870 static char **ignore_image_tokens, **ignore_sound_tokens;
2871 int num_ignore_generic_tokens;
2872 int num_ignore_image_tokens, num_ignore_sound_tokens;
2875 /* dynamically determine list of generic tokens to be ignored */
2876 num_ignore_generic_tokens = 0;
2877 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2878 num_ignore_generic_tokens++;
2880 /* dynamically determine list of image tokens to be ignored */
2881 num_ignore_image_tokens = num_ignore_generic_tokens;
2882 for (i=0; image_config_vars[i].token != NULL; i++)
2883 num_ignore_image_tokens++;
2884 ignore_image_tokens =
2885 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2886 for (i=0; i < num_ignore_generic_tokens; i++)
2887 ignore_image_tokens[i] = ignore_generic_tokens[i];
2888 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2889 ignore_image_tokens[num_ignore_generic_tokens + i] =
2890 image_config_vars[i].token;
2891 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2893 /* dynamically determine list of sound tokens to be ignored */
2894 num_ignore_sound_tokens = num_ignore_generic_tokens;
2895 ignore_sound_tokens =
2896 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2897 for (i=0; i < num_ignore_generic_tokens; i++)
2898 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2899 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2901 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2902 image_id_prefix[i] = element_info[i].token_name;
2903 for (i=0; i<NUM_FONTS; i++)
2904 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2905 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2907 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2908 sound_id_prefix[i] = element_info[i].token_name;
2909 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2910 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2911 get_string_in_brackets(element_info[i].class_name);
2912 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2914 for (i=0; i<NUM_ACTIONS; i++)
2915 action_id_suffix[i] = element_action_info[i].suffix;
2916 action_id_suffix[NUM_ACTIONS] = NULL;
2918 for (i=0; i<NUM_DIRECTIONS; i++)
2919 direction_id_suffix[i] = element_direction_info[i].suffix;
2920 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2922 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2923 special_id_suffix[i] = special_suffix_info[i].suffix;
2924 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2926 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2927 image_id_prefix, action_id_suffix, direction_id_suffix,
2928 special_id_suffix, ignore_image_tokens);
2929 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2930 sound_id_prefix, action_id_suffix, dummy,
2931 special_id_suffix, ignore_sound_tokens);
2934 static void InitMixer()
2942 char *filename_font_initial = NULL;
2943 Bitmap *bitmap_font_initial = NULL;
2946 /* determine settings for initial font (for displaying startup messages) */
2947 for (i=0; image_config[i].token != NULL; i++)
2949 for (j=0; j < NUM_INITIAL_FONTS; j++)
2951 char font_token[128];
2954 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2955 len_font_token = strlen(font_token);
2957 if (strcmp(image_config[i].token, font_token) == 0)
2958 filename_font_initial = image_config[i].value;
2959 else if (strlen(image_config[i].token) > len_font_token &&
2960 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2962 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2963 font_initial[j].src_x = atoi(image_config[i].value);
2964 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2965 font_initial[j].src_y = atoi(image_config[i].value);
2966 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2967 font_initial[j].width = atoi(image_config[i].value);
2968 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2969 font_initial[j].height = atoi(image_config[i].value);
2974 for (j=0; j < NUM_INITIAL_FONTS; j++)
2976 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2977 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2980 if (filename_font_initial == NULL) /* should not happen */
2981 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2983 /* create additional image buffers for double-buffering */
2984 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2985 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2987 /* initialize screen properties */
2988 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2989 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2991 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2992 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2993 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2995 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2997 for (j=0; j < NUM_INITIAL_FONTS; j++)
2998 font_initial[j].bitmap = bitmap_font_initial;
3000 InitFontGraphicInfo();
3002 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
3003 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
3005 DrawInitText("Loading graphics:", 120, FC_GREEN);
3007 InitTileClipmasks();
3010 void InitGfxBackground()
3014 drawto = backbuffer;
3015 fieldbuffer = bitmap_db_field;
3016 SetDrawtoField(DRAW_BACKBUFFER);
3018 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3019 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3020 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3021 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3023 for (x=0; x<MAX_BUF_XSIZE; x++)
3024 for (y=0; y<MAX_BUF_YSIZE; y++)
3027 redraw_mask = REDRAW_ALL;
3030 static void InitLevelInfo()
3032 LoadLevelInfo(); /* global level info */
3033 LoadLevelSetup_LastSeries(); /* last played series info */
3034 LoadLevelSetup_SeriesInfo(); /* last played level info */
3037 void InitLevelArtworkInfo()
3039 LoadLevelArtworkInfo();
3042 static void InitImages()
3044 ReloadCustomImages();
3046 LoadCustomElementDescriptions();
3047 LoadSpecialMenuDesignSettings();
3049 ReinitializeGraphics();
3052 static void InitSound()
3054 InitReloadCustomSounds(artwork.snd_current->identifier);
3055 ReinitializeSounds();
3058 static void InitMusic()
3060 InitReloadCustomMusic(artwork.mus_current->identifier);
3061 ReinitializeMusic();
3064 void InitNetworkServer()
3066 #if defined(PLATFORM_UNIX)
3070 if (!options.network)
3073 #if defined(PLATFORM_UNIX)
3074 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3076 if (!ConnectToServer(options.server_host, options.server_port))
3077 Error(ERR_EXIT, "cannot connect to network game server");
3079 SendToServer_PlayerName(setup.player_name);
3080 SendToServer_ProtocolVersion();
3083 SendToServer_NrWanted(nr_wanted);
3087 void ReloadCustomArtwork()
3089 static char *leveldir_current_identifier = NULL;
3090 static boolean last_override_level_graphics = FALSE;
3091 static boolean last_override_level_sounds = FALSE;
3092 static boolean last_override_level_music = FALSE;
3093 /* identifier for new artwork; default: artwork configured in setup */
3094 char *gfx_new_identifier = artwork.gfx_current->identifier;
3095 char *snd_new_identifier = artwork.snd_current->identifier;
3096 char *mus_new_identifier = artwork.mus_current->identifier;
3097 boolean redraw_screen = FALSE;
3100 if (leveldir_current_identifier == NULL)
3101 leveldir_current_identifier = leveldir_current->identifier;
3105 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3106 leveldir_current->graphics_set);
3107 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3108 leveldir_current->identifier);
3112 printf("graphics --> '%s' ('%s')\n",
3113 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3114 printf("sounds --> '%s' ('%s')\n",
3115 artwork.snd_current_identifier, artwork.snd_current->filename);
3116 printf("music --> '%s' ('%s')\n",
3117 artwork.mus_current_identifier, artwork.mus_current->filename);
3120 /* leveldir_current may be invalid (level group, parent link) */
3121 if (!validLevelSeries(leveldir_current))
3124 /* when a new level series was selected, check if there was a change
3125 in custom artwork stored in level series directory */
3126 if (leveldir_current_identifier != leveldir_current->identifier)
3129 char *identifier_old = leveldir_current_identifier;
3131 char *identifier_new = leveldir_current->identifier;
3134 printf("::: 1: ['%s'] '%s', '%s' [%lx, %lx]\n",
3135 gfx_new_identifier, identifier_old, identifier_new,
3136 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old),
3137 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new));
3141 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new) == NULL)
3142 gfx_new_identifier = GRAPHICS_SUBDIR;
3143 else if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3144 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3145 gfx_new_identifier = identifier_new;
3147 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3148 gfx_new_identifier = identifier_new;
3150 gfx_new_identifier = setup.graphics_set;
3154 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new) == NULL)
3155 snd_new_identifier = SOUNDS_SUBDIR;
3156 else if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3157 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3158 snd_new_identifier = identifier_new;
3160 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3161 snd_new_identifier = identifier_new;
3163 snd_new_identifier = setup.sounds_set;
3167 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) == NULL)
3168 mus_new_identifier = MUSIC_SUBDIR;
3169 else if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3170 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3171 mus_new_identifier = identifier_new;
3173 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3174 mus_new_identifier = identifier_new;
3176 mus_new_identifier = setup.music_set;
3180 printf("::: 2: ['%s'] '%s', '%s'\n",
3181 gfx_new_identifier, identifier_old, identifier_new);
3184 leveldir_current_identifier = leveldir_current->identifier;
3187 /* custom level artwork configured in level series configuration file
3188 always overrides custom level artwork stored in level series directory
3189 and (level independent) custom artwork configured in setup menue */
3190 if (leveldir_current->graphics_set != NULL)
3191 gfx_new_identifier = leveldir_current->graphics_set;
3192 if (leveldir_current->sounds_set != NULL)
3193 snd_new_identifier = leveldir_current->sounds_set;
3194 if (leveldir_current->music_set != NULL)
3195 mus_new_identifier = leveldir_current->music_set;
3198 printf("CHECKING OLD/NEW GFX:\n OLD: '%s'\n NEW: '%s' ['%s', '%s']\n",
3199 artwork.gfx_current_identifier, gfx_new_identifier,
3200 artwork.gfx_current->identifier, leveldir_current->graphics_set);
3203 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3204 last_override_level_graphics != setup.override_level_graphics)
3207 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s']\n",
3208 artwork.gfx_current_identifier,
3210 artwork.gfx_current->identifier);
3214 artwork.gfx_current =
3215 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3218 artwork.gfx_current_identifier = gfx_new_identifier;
3221 setLevelArtworkDir(artwork.gfx_first);
3223 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3227 FreeTileClipmasks();
3228 InitTileClipmasks();
3230 artwork.gfx_current =
3231 getTreeInfoFromIdentifier(artwork.gfx_first, gfx_new_identifier);
3234 printf("::: '%s', %lx\n", gfx_new_identifier, artwork.gfx_current);
3238 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3240 artwork.gfx_current_identifier = gfx_new_identifier;
3241 last_override_level_graphics = setup.override_level_graphics;
3244 printf("DONE RELOADING GFX: '%s' ['%s']\n",
3245 artwork.gfx_current_identifier, artwork.gfx_current->identifier);
3248 redraw_screen = TRUE;
3251 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3252 last_override_level_sounds != setup.override_level_sounds)
3255 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3256 artwork.snd_current_identifier,
3257 artwork.snd_current->identifier,
3258 snd_new_identifier);
3261 /* set artwork path to send it to the sound server process */
3262 setLevelArtworkDir(artwork.snd_first);
3264 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3266 InitReloadCustomSounds(snd_new_identifier);
3267 ReinitializeSounds();
3270 artwork.snd_current =
3271 getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
3272 artwork.snd_current_identifier = artwork.snd_current->identifier;
3274 artwork.snd_current_identifier = snd_new_identifier;
3275 last_override_level_sounds = setup.override_level_sounds;
3277 redraw_screen = TRUE;
3280 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3281 last_override_level_music != setup.override_level_music)
3283 /* set artwork path to send it to the sound server process */
3284 setLevelArtworkDir(artwork.mus_first);
3286 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3288 InitReloadCustomMusic(mus_new_identifier);
3289 ReinitializeMusic();
3292 artwork.mus_current =
3293 getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
3294 artwork.mus_current_identifier = artwork.mus_current->identifier;
3296 artwork.mus_current_identifier = mus_new_identifier;
3297 last_override_level_music = setup.override_level_music;
3299 redraw_screen = TRUE;
3304 InitGfxBackground();
3306 /* force redraw of (open or closed) door graphics */
3307 SetDoorState(DOOR_OPEN_ALL);
3308 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3312 void KeyboardAutoRepeatOffUnlessAutoplay()
3314 if (global.autoplay_leveldir == NULL)
3315 KeyboardAutoRepeatOff();
3319 /* ========================================================================= */
3321 /* ========================================================================= */
3325 InitGlobal(); /* initialize some global variables */
3327 if (options.execute_command)
3328 Execute_Command(options.execute_command);
3330 if (options.serveronly)
3332 #if defined(PLATFORM_UNIX)
3333 NetworkServer(options.server_port, options.serveronly);
3335 Error(ERR_WARN, "networking only supported in Unix version");
3337 exit(0); /* never reached */
3343 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3344 InitArtworkConfig(); /* needed before forking sound child process */
3349 InitRND(NEW_RANDOMIZE);
3350 InitSimpleRND(NEW_RANDOMIZE);
3355 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3358 InitEventFilter(FilterMouseMotionEvents);
3360 InitElementPropertiesStatic();
3365 InitLevelArtworkInfo();
3367 InitImages(); /* needs to know current level directory */
3368 InitSound(); /* needs to know current level directory */
3369 InitMusic(); /* needs to know current level directory */
3371 InitGfxBackground();
3373 if (global.autoplay_leveldir)
3379 game_status = GAME_MODE_MAIN;
3383 InitNetworkServer();
3386 void CloseAllAndExit(int exit_value)
3391 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3394 FreeTileClipmasks();
3396 CloseVideoDisplay();
3397 ClosePlatformDependentStuff();