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 dependant 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,
1532 static int ep_walkable_inside[] =
1537 EL_TUBE_VERTICAL_LEFT,
1538 EL_TUBE_VERTICAL_RIGHT,
1539 EL_TUBE_HORIZONTAL_UP,
1540 EL_TUBE_HORIZONTAL_DOWN,
1548 static int ep_walkable_under[] =
1553 static int ep_passable_over[] =
1568 static int ep_passable_inside[] =
1574 EL_SP_PORT_HORIZONTAL,
1575 EL_SP_PORT_VERTICAL,
1577 EL_SP_GRAVITY_PORT_LEFT,
1578 EL_SP_GRAVITY_PORT_RIGHT,
1579 EL_SP_GRAVITY_PORT_UP,
1580 EL_SP_GRAVITY_PORT_DOWN,
1584 static int ep_passable_under[] =
1589 static int ep_pushable[] =
1601 EL_SOKOBAN_FIELD_FULL,
1608 static int ep_can_be_crumbled[] =
1617 static int ep_player[] =
1626 static int ep_can_pass_magic_wall[] =
1639 static int ep_switchable[] =
1643 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1644 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1645 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1646 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1647 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1648 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1649 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1650 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1651 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1652 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1653 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1654 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1655 EL_SWITCHGATE_SWITCH_UP,
1656 EL_SWITCHGATE_SWITCH_DOWN,
1658 EL_LIGHT_SWITCH_ACTIVE,
1660 EL_BALLOON_SWITCH_LEFT,
1661 EL_BALLOON_SWITCH_RIGHT,
1662 EL_BALLOON_SWITCH_UP,
1663 EL_BALLOON_SWITCH_DOWN,
1664 EL_BALLOON_SWITCH_ANY,
1670 static int ep_bd_element[] =
1699 static int ep_sp_element[] =
1707 EL_SP_HARDWARE_GRAY,
1715 EL_SP_GRAVITY_PORT_RIGHT,
1716 EL_SP_GRAVITY_PORT_DOWN,
1717 EL_SP_GRAVITY_PORT_LEFT,
1718 EL_SP_GRAVITY_PORT_UP,
1723 EL_SP_PORT_VERTICAL,
1724 EL_SP_PORT_HORIZONTAL,
1730 EL_SP_HARDWARE_BASE_1,
1731 EL_SP_HARDWARE_GREEN,
1732 EL_SP_HARDWARE_BLUE,
1734 EL_SP_HARDWARE_YELLOW,
1735 EL_SP_HARDWARE_BASE_2,
1736 EL_SP_HARDWARE_BASE_3,
1737 EL_SP_HARDWARE_BASE_4,
1738 EL_SP_HARDWARE_BASE_5,
1739 EL_SP_HARDWARE_BASE_6,
1742 /* additional elements that appeared in newer Supaplex levels */
1744 /* more than one murphy in a level results in an inactive clone */
1746 /* runtime elements*/
1747 EL_SP_DISK_RED_ACTIVE,
1748 EL_SP_TERMINAL_ACTIVE,
1749 EL_SP_BUGGY_BASE_ACTIVATING,
1750 EL_SP_BUGGY_BASE_ACTIVE,
1754 static int ep_sb_element[] =
1759 EL_SOKOBAN_FIELD_EMPTY,
1760 EL_SOKOBAN_FIELD_FULL,
1762 EL_INVISIBLE_STEELWALL,
1766 static int ep_gem[] =
1777 static int ep_food_dark_yamyam[] =
1804 static int ep_food_penguin[] =
1817 static int ep_food_pig[] =
1828 static int ep_historic_wall[] =
1853 EL_EXPANDABLE_WALL_HORIZONTAL,
1854 EL_EXPANDABLE_WALL_VERTICAL,
1855 EL_EXPANDABLE_WALL_ANY,
1856 EL_EXPANDABLE_WALL_GROWING,
1863 EL_SP_HARDWARE_GRAY,
1864 EL_SP_HARDWARE_GREEN,
1865 EL_SP_HARDWARE_BLUE,
1867 EL_SP_HARDWARE_YELLOW,
1868 EL_SP_HARDWARE_BASE_1,
1869 EL_SP_HARDWARE_BASE_2,
1870 EL_SP_HARDWARE_BASE_3,
1871 EL_SP_HARDWARE_BASE_4,
1872 EL_SP_HARDWARE_BASE_5,
1873 EL_SP_HARDWARE_BASE_6,
1875 EL_SP_TERMINAL_ACTIVE,
1878 EL_INVISIBLE_STEELWALL,
1879 EL_INVISIBLE_STEELWALL_ACTIVE,
1881 EL_INVISIBLE_WALL_ACTIVE,
1882 EL_STEELWALL_SLANTED,
1898 static int ep_historic_solid[] =
1902 EL_EXPANDABLE_WALL_HORIZONTAL,
1903 EL_EXPANDABLE_WALL_VERTICAL,
1904 EL_EXPANDABLE_WALL_ANY,
1917 EL_QUICKSAND_FILLING,
1918 EL_QUICKSAND_EMPTYING,
1920 EL_MAGIC_WALL_ACTIVE,
1921 EL_MAGIC_WALL_EMPTYING,
1922 EL_MAGIC_WALL_FILLING,
1926 EL_BD_MAGIC_WALL_ACTIVE,
1927 EL_BD_MAGIC_WALL_EMPTYING,
1928 EL_BD_MAGIC_WALL_FULL,
1929 EL_BD_MAGIC_WALL_FILLING,
1930 EL_BD_MAGIC_WALL_DEAD,
1939 EL_SP_TERMINAL_ACTIVE,
1943 EL_INVISIBLE_WALL_ACTIVE,
1944 EL_SWITCHGATE_SWITCH_UP,
1945 EL_SWITCHGATE_SWITCH_DOWN,
1947 EL_TIMEGATE_SWITCH_ACTIVE,
1959 /* the following elements are a direct copy of "indestructible" elements,
1960 except "EL_ACID", which is "indestructible", but not "solid"! */
1965 EL_ACID_POOL_TOPLEFT,
1966 EL_ACID_POOL_TOPRIGHT,
1967 EL_ACID_POOL_BOTTOMLEFT,
1968 EL_ACID_POOL_BOTTOM,
1969 EL_ACID_POOL_BOTTOMRIGHT,
1970 EL_SP_HARDWARE_GRAY,
1971 EL_SP_HARDWARE_GREEN,
1972 EL_SP_HARDWARE_BLUE,
1974 EL_SP_HARDWARE_YELLOW,
1975 EL_SP_HARDWARE_BASE_1,
1976 EL_SP_HARDWARE_BASE_2,
1977 EL_SP_HARDWARE_BASE_3,
1978 EL_SP_HARDWARE_BASE_4,
1979 EL_SP_HARDWARE_BASE_5,
1980 EL_SP_HARDWARE_BASE_6,
1981 EL_INVISIBLE_STEELWALL,
1982 EL_INVISIBLE_STEELWALL_ACTIVE,
1983 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1984 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1985 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1986 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1987 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1988 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1989 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1990 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1991 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1992 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1993 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1994 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1996 EL_LIGHT_SWITCH_ACTIVE,
1997 EL_SIGN_EXCLAMATION,
1998 EL_SIGN_RADIOACTIVITY,
2009 EL_STEELWALL_SLANTED,
2032 EL_SWITCHGATE_OPENING,
2033 EL_SWITCHGATE_CLOSED,
2034 EL_SWITCHGATE_CLOSING,
2036 EL_TIMEGATE_OPENING,
2038 EL_TIMEGATE_CLOSING,
2042 EL_TUBE_VERTICAL_LEFT,
2043 EL_TUBE_VERTICAL_RIGHT,
2044 EL_TUBE_HORIZONTAL_UP,
2045 EL_TUBE_HORIZONTAL_DOWN,
2053 static int ep_classic_enemy[] =
2069 static int ep_belt[] =
2071 EL_CONVEYOR_BELT_1_LEFT,
2072 EL_CONVEYOR_BELT_1_MIDDLE,
2073 EL_CONVEYOR_BELT_1_RIGHT,
2074 EL_CONVEYOR_BELT_2_LEFT,
2075 EL_CONVEYOR_BELT_2_MIDDLE,
2076 EL_CONVEYOR_BELT_2_RIGHT,
2077 EL_CONVEYOR_BELT_3_LEFT,
2078 EL_CONVEYOR_BELT_3_MIDDLE,
2079 EL_CONVEYOR_BELT_3_RIGHT,
2080 EL_CONVEYOR_BELT_4_LEFT,
2081 EL_CONVEYOR_BELT_4_MIDDLE,
2082 EL_CONVEYOR_BELT_4_RIGHT,
2086 static int ep_belt_active[] =
2088 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2089 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2090 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2091 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2092 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2093 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2094 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2095 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2096 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2097 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2098 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2099 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2103 static int ep_belt_switch[] =
2105 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2106 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2107 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2108 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2109 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2110 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2111 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2112 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2113 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2114 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2115 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2116 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2120 static int ep_tube[] =
2127 EL_TUBE_HORIZONTAL_UP,
2128 EL_TUBE_HORIZONTAL_DOWN,
2130 EL_TUBE_VERTICAL_LEFT,
2131 EL_TUBE_VERTICAL_RIGHT,
2136 static int ep_keygate[] =
2157 static int ep_amoeboid[] =
2167 static int ep_amoebalive[] =
2176 static int ep_has_content[] =
2186 static int ep_active_bomb[] =
2189 EL_DYNABOMB_PLAYER_1_ACTIVE,
2190 EL_DYNABOMB_PLAYER_2_ACTIVE,
2191 EL_DYNABOMB_PLAYER_3_ACTIVE,
2192 EL_DYNABOMB_PLAYER_4_ACTIVE,
2193 EL_SP_DISK_RED_ACTIVE,
2197 static int ep_inactive[] =
2234 EL_INVISIBLE_STEELWALL,
2242 EL_WALL_EMERALD_YELLOW,
2243 EL_DYNABOMB_INCREASE_NUMBER,
2244 EL_DYNABOMB_INCREASE_SIZE,
2245 EL_DYNABOMB_INCREASE_POWER,
2249 EL_SOKOBAN_FIELD_EMPTY,
2250 EL_SOKOBAN_FIELD_FULL,
2251 EL_WALL_EMERALD_RED,
2252 EL_WALL_EMERALD_PURPLE,
2253 EL_ACID_POOL_TOPLEFT,
2254 EL_ACID_POOL_TOPRIGHT,
2255 EL_ACID_POOL_BOTTOMLEFT,
2256 EL_ACID_POOL_BOTTOM,
2257 EL_ACID_POOL_BOTTOMRIGHT,
2261 EL_BD_MAGIC_WALL_DEAD,
2262 EL_AMOEBA_TO_DIAMOND,
2270 EL_SP_GRAVITY_PORT_RIGHT,
2271 EL_SP_GRAVITY_PORT_DOWN,
2272 EL_SP_GRAVITY_PORT_LEFT,
2273 EL_SP_GRAVITY_PORT_UP,
2274 EL_SP_PORT_HORIZONTAL,
2275 EL_SP_PORT_VERTICAL,
2286 EL_SP_HARDWARE_GRAY,
2287 EL_SP_HARDWARE_GREEN,
2288 EL_SP_HARDWARE_BLUE,
2290 EL_SP_HARDWARE_YELLOW,
2291 EL_SP_HARDWARE_BASE_1,
2292 EL_SP_HARDWARE_BASE_2,
2293 EL_SP_HARDWARE_BASE_3,
2294 EL_SP_HARDWARE_BASE_4,
2295 EL_SP_HARDWARE_BASE_5,
2296 EL_SP_HARDWARE_BASE_6,
2297 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2298 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2299 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2300 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2301 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2302 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2303 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2304 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2305 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2306 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2307 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2308 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2309 EL_SIGN_EXCLAMATION,
2310 EL_SIGN_RADIOACTIVITY,
2321 EL_STEELWALL_SLANTED,
2341 } element_properties[] =
2343 { ep_diggable, EP_DIGGABLE },
2344 { ep_collectible, EP_COLLECTIBLE },
2345 { ep_dont_run_into, EP_DONT_RUN_INTO },
2346 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2347 { ep_dont_touch, EP_DONT_TOUCH },
2348 { ep_indestructible, EP_INDESTRUCTIBLE },
2349 { ep_slippery, EP_SLIPPERY },
2350 { ep_can_change, EP_CAN_CHANGE },
2351 { ep_can_move, EP_CAN_MOVE },
2352 { ep_can_fall, EP_CAN_FALL },
2353 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2354 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2355 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2356 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2357 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2358 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2359 { ep_walkable_over, EP_WALKABLE_OVER },
2360 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2361 { ep_walkable_under, EP_WALKABLE_UNDER },
2362 { ep_passable_over, EP_PASSABLE_OVER },
2363 { ep_passable_inside, EP_PASSABLE_INSIDE },
2364 { ep_passable_under, EP_PASSABLE_UNDER },
2365 { ep_pushable, EP_PUSHABLE },
2367 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2369 { ep_player, EP_PLAYER },
2370 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2371 { ep_switchable, EP_SWITCHABLE },
2372 { ep_bd_element, EP_BD_ELEMENT },
2373 { ep_sp_element, EP_SP_ELEMENT },
2374 { ep_sb_element, EP_SB_ELEMENT },
2376 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2377 { ep_food_penguin, EP_FOOD_PENGUIN },
2378 { ep_food_pig, EP_FOOD_PIG },
2379 { ep_historic_wall, EP_HISTORIC_WALL },
2380 { ep_historic_solid, EP_HISTORIC_SOLID },
2381 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2382 { ep_belt, EP_BELT },
2383 { ep_belt_active, EP_BELT_ACTIVE },
2384 { ep_belt_switch, EP_BELT_SWITCH },
2385 { ep_tube, EP_TUBE },
2386 { ep_keygate, EP_KEYGATE },
2387 { ep_amoeboid, EP_AMOEBOID },
2388 { ep_amoebalive, EP_AMOEBALIVE },
2389 { ep_has_content, EP_HAS_CONTENT },
2390 { ep_active_bomb, EP_ACTIVE_BOMB },
2391 { ep_inactive, EP_INACTIVE },
2396 static int copy_properties[][5] =
2400 EL_BUG_LEFT, EL_BUG_RIGHT,
2401 EL_BUG_UP, EL_BUG_DOWN
2405 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2406 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2410 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2411 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2415 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2416 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2420 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2421 EL_PACMAN_UP, EL_PACMAN_DOWN
2431 /* always start with reliable default values (element has no properties) */
2432 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2433 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2434 SET_PROPERTY(i, j, FALSE);
2436 /* set all base element properties from above array definitions */
2437 for (i=0; element_properties[i].elements != NULL; i++)
2438 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2439 SET_PROPERTY((element_properties[i].elements)[j],
2440 element_properties[i].property, TRUE);
2442 /* copy properties to some elements that are only stored in level file */
2443 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2444 for (j=0; copy_properties[j][0] != -1; j++)
2445 if (HAS_PROPERTY(copy_properties[j][0], i))
2446 for (k=1; k<=4; k++)
2447 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2450 void InitElementPropertiesEngine(int engine_version)
2453 static int active_properties[] =
2458 EP_DONT_COLLIDE_WITH,
2462 EP_CAN_PASS_MAGIC_WALL,
2467 EP_CAN_EXPLODE_BY_FIRE,
2480 EP_EM_SLIPPERY_WALL,
2485 static int no_wall_properties[] =
2490 EP_DONT_COLLIDE_WITH,
2493 EP_CAN_SMASH_PLAYER,
2494 EP_CAN_SMASH_ENEMIES,
2495 EP_CAN_SMASH_EVERYTHING,
2502 EP_FOOD_DARK_YAMYAM,
2518 InitElementPropertiesStatic();
2521 /* set all special, combined or engine dependant element properties */
2522 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2525 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2526 SET_PROPERTY(i, j, FALSE);
2529 /* ---------- INACTIVE ------------------------------------------------- */
2530 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2531 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2533 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2534 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2535 IS_WALKABLE_INSIDE(i) ||
2536 IS_WALKABLE_UNDER(i)));
2538 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2539 IS_PASSABLE_INSIDE(i) ||
2540 IS_PASSABLE_UNDER(i)));
2542 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2543 IS_PASSABLE_OVER(i)));
2545 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2546 IS_PASSABLE_INSIDE(i)));
2548 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2549 IS_PASSABLE_UNDER(i)));
2551 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2554 /* ---------- SNAPPABLE ------------------------------------------------ */
2555 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2556 IS_COLLECTIBLE(i) ||
2560 /* ---------- WALL ----------------------------------------------------- */
2561 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2563 for (j=0; no_wall_properties[j] != -1; j++)
2564 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2565 i >= EL_FIRST_RUNTIME_UNREAL)
2566 SET_PROPERTY(i, EP_WALL, FALSE);
2568 if (IS_HISTORIC_WALL(i))
2569 SET_PROPERTY(i, EP_WALL, TRUE);
2571 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2572 if (engine_version < VERSION_IDENT(2,2,0))
2573 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2575 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2577 !IS_COLLECTIBLE(i)));
2579 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2581 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2582 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2584 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2585 IS_INDESTRUCTIBLE(i)));
2587 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2589 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2590 else if (engine_version < VERSION_IDENT(2,2,0))
2591 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2593 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2594 !IS_WALKABLE_OVER(i) &&
2595 !IS_WALKABLE_UNDER(i)));
2597 if (IS_CUSTOM_ELEMENT(i))
2599 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2601 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2602 if (DONT_COLLIDE_WITH(i))
2603 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2605 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2606 if (CAN_SMASH_EVERYTHING(i))
2607 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2608 if (CAN_SMASH_ENEMIES(i))
2609 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2612 /* ---------- CAN_SMASH ------------------------------------------------ */
2613 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2614 CAN_SMASH_ENEMIES(i) ||
2615 CAN_SMASH_EVERYTHING(i)));
2617 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2618 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2619 CAN_EXPLODE_SMASHED(i) ||
2620 CAN_EXPLODE_BY_FIRE(i)));
2624 /* determine inactive elements (used for engine main loop optimization) */
2625 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2627 boolean active = FALSE;
2629 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2631 if (HAS_PROPERTY(i, j))
2637 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2642 /* dynamically adjust element properties according to game engine version */
2644 static int ep_em_slippery_wall[] =
2649 EL_EXPANDABLE_WALL_HORIZONTAL,
2650 EL_EXPANDABLE_WALL_VERTICAL,
2651 EL_EXPANDABLE_WALL_ANY,
2655 /* special EM style gems behaviour */
2656 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2657 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2658 level.em_slippery_gems);
2660 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2661 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2662 (level.em_slippery_gems &&
2663 engine_version > VERSION_IDENT(2,0,1)));
2667 /* dynamically adjust element properties according to game engine version */
2669 if (engine_version < RELEASE_IDENT(2,2,0,7))
2672 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2674 int element = EL_CUSTOM_START + i;
2676 element_info[element].push_delay_fixed = 2;
2677 element_info[element].push_delay_random = 8;
2683 static void InitGlobal()
2685 global.autoplay_leveldir = NULL;
2687 global.frames_per_second = 0;
2688 global.fps_slowdown = FALSE;
2689 global.fps_slowdown_factor = 1;
2692 void Execute_Command(char *command)
2694 if (strcmp(command, "print graphicsinfo.conf") == 0)
2698 printf("# You can configure additional/alternative image files here.\n");
2699 printf("# (The images below are default and therefore commented out.)\n");
2701 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2703 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2706 for (i=0; image_config[i].token != NULL; i++)
2708 getFormattedSetupEntry(image_config[i].token,
2709 image_config[i].value));
2713 else if (strcmp(command, "print soundsinfo.conf") == 0)
2717 printf("# You can configure additional/alternative sound files here.\n");
2718 printf("# (The sounds below are default and therefore commented out.)\n");
2720 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2722 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2725 for (i=0; sound_config[i].token != NULL; i++)
2727 getFormattedSetupEntry(sound_config[i].token,
2728 sound_config[i].value));
2732 else if (strcmp(command, "print musicinfo.conf") == 0)
2734 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2736 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2738 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2742 else if (strncmp(command, "dump level ", 11) == 0)
2744 char *filename = &command[11];
2746 if (access(filename, F_OK) != 0)
2747 Error(ERR_EXIT, "cannot open file '%s'", filename);
2749 LoadLevelFromFilename(filename);
2754 else if (strncmp(command, "dump tape ", 10) == 0)
2756 char *filename = &command[10];
2758 if (access(filename, F_OK) != 0)
2759 Error(ERR_EXIT, "cannot open file '%s'", filename);
2761 LoadTapeFromFilename(filename);
2766 else if (strncmp(command, "autoplay ", 9) == 0)
2768 char *str_copy = getStringCopy(&command[9]);
2769 char *str_ptr = strchr(str_copy, ' ');
2771 global.autoplay_leveldir = str_copy;
2772 global.autoplay_level_nr = -1;
2774 if (str_ptr != NULL)
2776 *str_ptr++ = '\0'; /* terminate leveldir string */
2777 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2782 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2786 static void InitSetup()
2788 LoadSetup(); /* global setup info */
2790 /* set some options from setup file */
2792 if (setup.options.verbose)
2793 options.verbose = TRUE;
2796 static void InitPlayerInfo()
2800 /* choose default local player */
2801 local_player = &stored_player[0];
2803 for (i=0; i<MAX_PLAYERS; i++)
2804 stored_player[i].connected = FALSE;
2806 local_player->connected = TRUE;
2809 static void InitArtworkInfo()
2814 static char *get_string_in_brackets(char *string)
2816 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2818 sprintf(string_in_brackets, "[%s]", string);
2820 return string_in_brackets;
2824 static char *get_element_class_token(int element)
2826 char *element_class_name = element_info[element].class_name;
2827 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2829 sprintf(element_class_token, "[%s]", element_class_name);
2831 return element_class_token;
2834 static char *get_action_class_token(int action)
2836 char *action_class_name = &element_action_info[action].suffix[1];
2837 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2839 sprintf(action_class_token, "[%s]", action_class_name);
2841 return action_class_token;
2845 static void InitArtworkConfig()
2847 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2848 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2849 static char *action_id_suffix[NUM_ACTIONS + 1];
2850 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2851 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2852 static char *dummy[1] = { NULL };
2853 static char *ignore_generic_tokens[] =
2859 static char **ignore_image_tokens, **ignore_sound_tokens;
2860 int num_ignore_generic_tokens;
2861 int num_ignore_image_tokens, num_ignore_sound_tokens;
2864 /* dynamically determine list of generic tokens to be ignored */
2865 num_ignore_generic_tokens = 0;
2866 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2867 num_ignore_generic_tokens++;
2869 /* dynamically determine list of image tokens to be ignored */
2870 num_ignore_image_tokens = num_ignore_generic_tokens;
2871 for (i=0; image_config_vars[i].token != NULL; i++)
2872 num_ignore_image_tokens++;
2873 ignore_image_tokens =
2874 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2875 for (i=0; i < num_ignore_generic_tokens; i++)
2876 ignore_image_tokens[i] = ignore_generic_tokens[i];
2877 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2878 ignore_image_tokens[num_ignore_generic_tokens + i] =
2879 image_config_vars[i].token;
2880 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2882 /* dynamically determine list of sound tokens to be ignored */
2883 num_ignore_sound_tokens = num_ignore_generic_tokens;
2884 ignore_sound_tokens =
2885 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2886 for (i=0; i < num_ignore_generic_tokens; i++)
2887 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2888 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2890 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2891 image_id_prefix[i] = element_info[i].token_name;
2892 for (i=0; i<NUM_FONTS; i++)
2893 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2894 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2896 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2897 sound_id_prefix[i] = element_info[i].token_name;
2898 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2899 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2900 get_string_in_brackets(element_info[i].class_name);
2901 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2903 for (i=0; i<NUM_ACTIONS; i++)
2904 action_id_suffix[i] = element_action_info[i].suffix;
2905 action_id_suffix[NUM_ACTIONS] = NULL;
2907 for (i=0; i<NUM_DIRECTIONS; i++)
2908 direction_id_suffix[i] = element_direction_info[i].suffix;
2909 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2911 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2912 special_id_suffix[i] = special_suffix_info[i].suffix;
2913 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2915 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2916 image_id_prefix, action_id_suffix, direction_id_suffix,
2917 special_id_suffix, ignore_image_tokens);
2918 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2919 sound_id_prefix, action_id_suffix, dummy,
2920 special_id_suffix, ignore_sound_tokens);
2923 static void InitMixer()
2931 char *filename_font_initial = NULL;
2932 Bitmap *bitmap_font_initial = NULL;
2935 /* determine settings for initial font (for displaying startup messages) */
2936 for (i=0; image_config[i].token != NULL; i++)
2938 for (j=0; j < NUM_INITIAL_FONTS; j++)
2940 char font_token[128];
2943 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2944 len_font_token = strlen(font_token);
2946 if (strcmp(image_config[i].token, font_token) == 0)
2947 filename_font_initial = image_config[i].value;
2948 else if (strlen(image_config[i].token) > len_font_token &&
2949 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2951 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2952 font_initial[j].src_x = atoi(image_config[i].value);
2953 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2954 font_initial[j].src_y = atoi(image_config[i].value);
2955 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2956 font_initial[j].width = atoi(image_config[i].value);
2957 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2958 font_initial[j].height = atoi(image_config[i].value);
2963 for (j=0; j < NUM_INITIAL_FONTS; j++)
2965 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2966 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2969 if (filename_font_initial == NULL) /* should not happen */
2970 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2972 /* create additional image buffers for double-buffering */
2973 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2974 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2976 /* initialize screen properties */
2977 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2978 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2980 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2981 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2982 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2984 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2986 for (j=0; j < NUM_INITIAL_FONTS; j++)
2987 font_initial[j].bitmap = bitmap_font_initial;
2989 InitFontGraphicInfo();
2991 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2992 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2994 DrawInitText("Loading graphics:", 120, FC_GREEN);
2996 InitTileClipmasks();
2999 void InitGfxBackground()
3003 drawto = backbuffer;
3004 fieldbuffer = bitmap_db_field;
3005 SetDrawtoField(DRAW_BACKBUFFER);
3007 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3008 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3009 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3010 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3012 for (x=0; x<MAX_BUF_XSIZE; x++)
3013 for (y=0; y<MAX_BUF_YSIZE; y++)
3016 redraw_mask = REDRAW_ALL;
3019 static void InitLevelInfo()
3021 LoadLevelInfo(); /* global level info */
3022 LoadLevelSetup_LastSeries(); /* last played series info */
3023 LoadLevelSetup_SeriesInfo(); /* last played level info */
3026 void InitLevelArtworkInfo()
3028 LoadLevelArtworkInfo();
3031 static void InitImages()
3033 ReloadCustomImages();
3035 LoadCustomElementDescriptions();
3036 LoadSpecialMenuDesignSettings();
3038 ReinitializeGraphics();
3041 static void InitSound()
3043 InitReloadCustomSounds(artwork.snd_current->identifier);
3044 ReinitializeSounds();
3047 static void InitMusic()
3049 InitReloadCustomMusic(artwork.mus_current->identifier);
3050 ReinitializeMusic();
3053 void InitNetworkServer()
3055 #if defined(PLATFORM_UNIX)
3059 if (!options.network)
3062 #if defined(PLATFORM_UNIX)
3063 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3065 if (!ConnectToServer(options.server_host, options.server_port))
3066 Error(ERR_EXIT, "cannot connect to network game server");
3068 SendToServer_PlayerName(setup.player_name);
3069 SendToServer_ProtocolVersion();
3072 SendToServer_NrWanted(nr_wanted);
3076 void ReloadCustomArtwork()
3078 static char *leveldir_current_identifier = NULL;
3079 static boolean last_override_level_graphics = FALSE;
3080 static boolean last_override_level_sounds = FALSE;
3081 static boolean last_override_level_music = FALSE;
3082 /* identifier for new artwork; default: artwork configured in setup */
3083 char *gfx_new_identifier = artwork.gfx_current->identifier;
3084 char *snd_new_identifier = artwork.snd_current->identifier;
3085 char *mus_new_identifier = artwork.mus_current->identifier;
3086 boolean redraw_screen = FALSE;
3088 if (leveldir_current_identifier == NULL)
3089 leveldir_current_identifier = leveldir_current->identifier;
3092 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3093 leveldir_current->graphics_set);
3094 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3095 leveldir_current->identifier);
3099 printf("graphics --> '%s' ('%s')\n",
3100 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3101 printf("sounds --> '%s' ('%s')\n",
3102 artwork.snd_current_identifier, artwork.snd_current->filename);
3103 printf("music --> '%s' ('%s')\n",
3104 artwork.mus_current_identifier, artwork.mus_current->filename);
3107 /* leveldir_current may be invalid (level group, parent link) */
3108 if (!validLevelSeries(leveldir_current))
3111 /* when a new level series was selected, check if there was a change
3112 in custom artwork stored in level series directory */
3113 if (leveldir_current_identifier != leveldir_current->identifier)
3115 char *identifier_old = leveldir_current_identifier;
3116 char *identifier_new = leveldir_current->identifier;
3118 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3119 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3120 gfx_new_identifier = identifier_new;
3121 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3122 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3123 snd_new_identifier = identifier_new;
3124 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3125 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3126 mus_new_identifier = identifier_new;
3128 leveldir_current_identifier = leveldir_current->identifier;
3131 /* custom level artwork configured in level series configuration file
3132 always overrides custom level artwork stored in level series directory
3133 and (level independant) custom artwork configured in setup menue */
3134 if (leveldir_current->graphics_set != NULL)
3135 gfx_new_identifier = leveldir_current->graphics_set;
3136 if (leveldir_current->sounds_set != NULL)
3137 snd_new_identifier = leveldir_current->sounds_set;
3138 if (leveldir_current->music_set != NULL)
3139 mus_new_identifier = leveldir_current->music_set;
3141 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3142 last_override_level_graphics != setup.override_level_graphics)
3145 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3146 artwork.gfx_current_identifier,
3147 artwork.gfx_current->identifier,
3148 gfx_new_identifier);
3151 setLevelArtworkDir(artwork.gfx_first);
3153 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3157 FreeTileClipmasks();
3158 InitTileClipmasks();
3160 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3161 last_override_level_graphics = setup.override_level_graphics;
3163 redraw_screen = TRUE;
3166 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3167 last_override_level_sounds != setup.override_level_sounds)
3170 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3171 artwork.snd_current_identifier,
3172 artwork.snd_current->identifier,
3173 snd_new_identifier);
3176 /* set artwork path to send it to the sound server process */
3177 setLevelArtworkDir(artwork.snd_first);
3179 InitReloadCustomSounds(snd_new_identifier);
3180 ReinitializeSounds();
3182 artwork.snd_current_identifier = artwork.snd_current->identifier;
3183 last_override_level_sounds = setup.override_level_sounds;
3185 redraw_screen = TRUE;
3188 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3189 last_override_level_music != setup.override_level_music)
3191 /* set artwork path to send it to the sound server process */
3192 setLevelArtworkDir(artwork.mus_first);
3194 InitReloadCustomMusic(mus_new_identifier);
3195 ReinitializeMusic();
3197 artwork.mus_current_identifier = artwork.mus_current->identifier;
3198 last_override_level_music = setup.override_level_music;
3200 redraw_screen = TRUE;
3205 InitGfxBackground();
3207 /* force redraw of (open or closed) door graphics */
3208 SetDoorState(DOOR_OPEN_ALL);
3209 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3213 void KeyboardAutoRepeatOffUnlessAutoplay()
3215 if (global.autoplay_leveldir == NULL)
3216 KeyboardAutoRepeatOff();
3220 /* ========================================================================= */
3222 /* ========================================================================= */
3226 InitGlobal(); /* initialize some global variables */
3228 if (options.execute_command)
3229 Execute_Command(options.execute_command);
3231 if (options.serveronly)
3233 #if defined(PLATFORM_UNIX)
3234 NetworkServer(options.server_port, options.serveronly);
3236 Error(ERR_WARN, "networking only supported in Unix version");
3238 exit(0); /* never reached */
3244 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3245 InitArtworkConfig(); /* needed before forking sound child process */
3250 InitRND(NEW_RANDOMIZE);
3251 InitSimpleRND(NEW_RANDOMIZE);
3256 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3259 InitEventFilter(FilterMouseMotionEvents);
3261 InitElementPropertiesStatic();
3266 InitLevelArtworkInfo();
3268 InitImages(); /* needs to know current level directory */
3269 InitSound(); /* needs to know current level directory */
3270 InitMusic(); /* needs to know current level directory */
3272 InitGfxBackground();
3274 if (global.autoplay_leveldir)
3280 game_status = GAME_MODE_MAIN;
3284 InitNetworkServer();
3287 void CloseAllAndExit(int exit_value)
3292 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3295 FreeTileClipmasks();
3297 CloseVideoDisplay();
3298 ClosePlatformDependantStuff();