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,
2247 EL_SOKOBAN_FIELD_EMPTY,
2248 EL_SOKOBAN_FIELD_FULL,
2249 EL_WALL_EMERALD_RED,
2250 EL_WALL_EMERALD_PURPLE,
2251 EL_ACID_POOL_TOPLEFT,
2252 EL_ACID_POOL_TOPRIGHT,
2253 EL_ACID_POOL_BOTTOMLEFT,
2254 EL_ACID_POOL_BOTTOM,
2255 EL_ACID_POOL_BOTTOMRIGHT,
2259 EL_BD_MAGIC_WALL_DEAD,
2260 EL_AMOEBA_TO_DIAMOND,
2268 EL_SP_GRAVITY_PORT_RIGHT,
2269 EL_SP_GRAVITY_PORT_DOWN,
2270 EL_SP_GRAVITY_PORT_LEFT,
2271 EL_SP_GRAVITY_PORT_UP,
2272 EL_SP_PORT_HORIZONTAL,
2273 EL_SP_PORT_VERTICAL,
2282 EL_SP_HARDWARE_GRAY,
2283 EL_SP_HARDWARE_GREEN,
2284 EL_SP_HARDWARE_BLUE,
2286 EL_SP_HARDWARE_YELLOW,
2287 EL_SP_HARDWARE_BASE_1,
2288 EL_SP_HARDWARE_BASE_2,
2289 EL_SP_HARDWARE_BASE_3,
2290 EL_SP_HARDWARE_BASE_4,
2291 EL_SP_HARDWARE_BASE_5,
2292 EL_SP_HARDWARE_BASE_6,
2293 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2294 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2295 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2296 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2297 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2298 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2299 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2300 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2301 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2302 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2303 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2304 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2305 EL_SIGN_EXCLAMATION,
2306 EL_SIGN_RADIOACTIVITY,
2317 EL_STEELWALL_SLANTED,
2337 } element_properties[] =
2339 { ep_diggable, EP_DIGGABLE },
2340 { ep_collectible, EP_COLLECTIBLE },
2341 { ep_dont_run_into, EP_DONT_RUN_INTO },
2342 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2343 { ep_dont_touch, EP_DONT_TOUCH },
2344 { ep_indestructible, EP_INDESTRUCTIBLE },
2345 { ep_slippery, EP_SLIPPERY },
2346 { ep_can_change, EP_CAN_CHANGE },
2347 { ep_can_move, EP_CAN_MOVE },
2348 { ep_can_fall, EP_CAN_FALL },
2349 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2350 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2351 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2352 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2353 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2354 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2355 { ep_walkable_over, EP_WALKABLE_OVER },
2356 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2357 { ep_walkable_under, EP_WALKABLE_UNDER },
2358 { ep_passable_over, EP_PASSABLE_OVER },
2359 { ep_passable_inside, EP_PASSABLE_INSIDE },
2360 { ep_passable_under, EP_PASSABLE_UNDER },
2361 { ep_pushable, EP_PUSHABLE },
2363 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2365 { ep_player, EP_PLAYER },
2366 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2367 { ep_switchable, EP_SWITCHABLE },
2368 { ep_bd_element, EP_BD_ELEMENT },
2369 { ep_sp_element, EP_SP_ELEMENT },
2370 { ep_sb_element, EP_SB_ELEMENT },
2372 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2373 { ep_food_penguin, EP_FOOD_PENGUIN },
2374 { ep_food_pig, EP_FOOD_PIG },
2375 { ep_historic_wall, EP_HISTORIC_WALL },
2376 { ep_historic_solid, EP_HISTORIC_SOLID },
2377 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2378 { ep_belt, EP_BELT },
2379 { ep_belt_active, EP_BELT_ACTIVE },
2380 { ep_belt_switch, EP_BELT_SWITCH },
2381 { ep_tube, EP_TUBE },
2382 { ep_keygate, EP_KEYGATE },
2383 { ep_amoeboid, EP_AMOEBOID },
2384 { ep_amoebalive, EP_AMOEBALIVE },
2385 { ep_has_content, EP_HAS_CONTENT },
2386 { ep_active_bomb, EP_ACTIVE_BOMB },
2387 { ep_inactive, EP_INACTIVE },
2392 static int copy_properties[][5] =
2396 EL_BUG_LEFT, EL_BUG_RIGHT,
2397 EL_BUG_UP, EL_BUG_DOWN
2401 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2402 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2406 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2407 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2411 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2412 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2416 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2417 EL_PACMAN_UP, EL_PACMAN_DOWN
2427 /* always start with reliable default values (element has no properties) */
2428 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2429 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2430 SET_PROPERTY(i, j, FALSE);
2432 /* set all base element properties from above array definitions */
2433 for (i=0; element_properties[i].elements != NULL; i++)
2434 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2435 SET_PROPERTY((element_properties[i].elements)[j],
2436 element_properties[i].property, TRUE);
2438 /* copy properties to some elements that are only stored in level file */
2439 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2440 for (j=0; copy_properties[j][0] != -1; j++)
2441 if (HAS_PROPERTY(copy_properties[j][0], i))
2442 for (k=1; k<=4; k++)
2443 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2446 void InitElementPropertiesEngine(int engine_version)
2449 static int active_properties[] =
2454 EP_DONT_COLLIDE_WITH,
2458 EP_CAN_PASS_MAGIC_WALL,
2463 EP_CAN_EXPLODE_BY_FIRE,
2476 EP_EM_SLIPPERY_WALL,
2481 static int no_wall_properties[] =
2486 EP_DONT_COLLIDE_WITH,
2489 EP_CAN_SMASH_PLAYER,
2490 EP_CAN_SMASH_ENEMIES,
2491 EP_CAN_SMASH_EVERYTHING,
2498 EP_FOOD_DARK_YAMYAM,
2514 InitElementPropertiesStatic();
2517 /* set all special, combined or engine dependant element properties */
2518 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2521 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2522 SET_PROPERTY(i, j, FALSE);
2525 /* ---------- INACTIVE ------------------------------------------------- */
2526 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2527 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2529 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2530 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2531 IS_WALKABLE_INSIDE(i) ||
2532 IS_WALKABLE_UNDER(i)));
2534 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2535 IS_PASSABLE_INSIDE(i) ||
2536 IS_PASSABLE_UNDER(i)));
2538 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2539 IS_PASSABLE_OVER(i)));
2541 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2542 IS_PASSABLE_INSIDE(i)));
2544 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2545 IS_PASSABLE_UNDER(i)));
2547 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2550 /* ---------- SNAPPABLE ------------------------------------------------ */
2551 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2552 IS_COLLECTIBLE(i) ||
2556 /* ---------- WALL ----------------------------------------------------- */
2557 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2559 for (j=0; no_wall_properties[j] != -1; j++)
2560 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2561 i >= EL_FIRST_RUNTIME_UNREAL)
2562 SET_PROPERTY(i, EP_WALL, FALSE);
2564 if (IS_HISTORIC_WALL(i))
2565 SET_PROPERTY(i, EP_WALL, TRUE);
2567 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2568 if (engine_version < VERSION_IDENT(2,2,0))
2569 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2571 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2573 !IS_COLLECTIBLE(i)));
2575 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2577 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2578 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2580 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2581 IS_INDESTRUCTIBLE(i)));
2583 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2585 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2586 else if (engine_version < VERSION_IDENT(2,2,0))
2587 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2589 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2590 !IS_WALKABLE_OVER(i) &&
2591 !IS_WALKABLE_UNDER(i)));
2593 if (IS_CUSTOM_ELEMENT(i))
2595 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2597 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2598 if (DONT_COLLIDE_WITH(i))
2599 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2601 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2602 if (CAN_SMASH_EVERYTHING(i))
2603 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2604 if (CAN_SMASH_ENEMIES(i))
2605 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2608 /* ---------- CAN_SMASH ------------------------------------------------ */
2609 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2610 CAN_SMASH_ENEMIES(i) ||
2611 CAN_SMASH_EVERYTHING(i)));
2613 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2614 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2615 CAN_EXPLODE_SMASHED(i) ||
2616 CAN_EXPLODE_BY_FIRE(i)));
2620 /* determine inactive elements (used for engine main loop optimization) */
2621 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2623 boolean active = FALSE;
2625 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2627 if (HAS_PROPERTY(i, j))
2633 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2638 /* dynamically adjust element properties according to game engine version */
2640 static int ep_em_slippery_wall[] =
2645 EL_EXPANDABLE_WALL_HORIZONTAL,
2646 EL_EXPANDABLE_WALL_VERTICAL,
2647 EL_EXPANDABLE_WALL_ANY,
2651 /* special EM style gems behaviour */
2652 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2653 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2654 level.em_slippery_gems);
2656 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2657 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2658 (level.em_slippery_gems &&
2659 engine_version > VERSION_IDENT(2,0,1)));
2662 /* dynamically adjust element properties according to game engine version */
2664 if (engine_version < RELEASE_IDENT(2,2,0,7))
2667 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2669 int element = EL_CUSTOM_START + i;
2671 element_info[element].push_delay_fixed = 2;
2672 element_info[element].push_delay_random = 8;
2677 static void InitGlobal()
2679 global.autoplay_leveldir = NULL;
2681 global.frames_per_second = 0;
2682 global.fps_slowdown = FALSE;
2683 global.fps_slowdown_factor = 1;
2686 void Execute_Command(char *command)
2688 if (strcmp(command, "print graphicsinfo.conf") == 0)
2692 printf("# You can configure additional/alternative image files here.\n");
2693 printf("# (The images below are default and therefore commented out.)\n");
2695 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2697 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2700 for (i=0; image_config[i].token != NULL; i++)
2702 getFormattedSetupEntry(image_config[i].token,
2703 image_config[i].value));
2707 else if (strcmp(command, "print soundsinfo.conf") == 0)
2711 printf("# You can configure additional/alternative sound files here.\n");
2712 printf("# (The sounds below are default and therefore commented out.)\n");
2714 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2716 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2719 for (i=0; sound_config[i].token != NULL; i++)
2721 getFormattedSetupEntry(sound_config[i].token,
2722 sound_config[i].value));
2726 else if (strcmp(command, "print musicinfo.conf") == 0)
2728 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2730 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2732 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2736 else if (strncmp(command, "dump level ", 11) == 0)
2738 char *filename = &command[11];
2740 if (access(filename, F_OK) != 0)
2741 Error(ERR_EXIT, "cannot open file '%s'", filename);
2743 LoadLevelFromFilename(filename);
2748 else if (strncmp(command, "dump tape ", 10) == 0)
2750 char *filename = &command[10];
2752 if (access(filename, F_OK) != 0)
2753 Error(ERR_EXIT, "cannot open file '%s'", filename);
2755 LoadTapeFromFilename(filename);
2760 else if (strncmp(command, "autoplay ", 9) == 0)
2762 char *str_copy = getStringCopy(&command[9]);
2763 char *str_ptr = strchr(str_copy, ' ');
2765 global.autoplay_leveldir = str_copy;
2766 global.autoplay_level_nr = -1;
2768 if (str_ptr != NULL)
2770 *str_ptr++ = '\0'; /* terminate leveldir string */
2771 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2776 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2780 static void InitSetup()
2782 LoadSetup(); /* global setup info */
2784 /* set some options from setup file */
2786 if (setup.options.verbose)
2787 options.verbose = TRUE;
2790 static void InitPlayerInfo()
2794 /* choose default local player */
2795 local_player = &stored_player[0];
2797 for (i=0; i<MAX_PLAYERS; i++)
2798 stored_player[i].connected = FALSE;
2800 local_player->connected = TRUE;
2803 static void InitArtworkInfo()
2808 static char *get_string_in_brackets(char *string)
2810 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2812 sprintf(string_in_brackets, "[%s]", string);
2814 return string_in_brackets;
2818 static char *get_element_class_token(int element)
2820 char *element_class_name = element_info[element].class_name;
2821 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2823 sprintf(element_class_token, "[%s]", element_class_name);
2825 return element_class_token;
2828 static char *get_action_class_token(int action)
2830 char *action_class_name = &element_action_info[action].suffix[1];
2831 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2833 sprintf(action_class_token, "[%s]", action_class_name);
2835 return action_class_token;
2839 static void InitArtworkConfig()
2841 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2842 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2843 static char *action_id_suffix[NUM_ACTIONS + 1];
2844 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2845 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2846 static char *dummy[1] = { NULL };
2847 static char *ignore_generic_tokens[] =
2853 static char **ignore_image_tokens, **ignore_sound_tokens;
2854 int num_ignore_generic_tokens;
2855 int num_ignore_image_tokens, num_ignore_sound_tokens;
2858 /* dynamically determine list of generic tokens to be ignored */
2859 num_ignore_generic_tokens = 0;
2860 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2861 num_ignore_generic_tokens++;
2863 /* dynamically determine list of image tokens to be ignored */
2864 num_ignore_image_tokens = num_ignore_generic_tokens;
2865 for (i=0; image_config_vars[i].token != NULL; i++)
2866 num_ignore_image_tokens++;
2867 ignore_image_tokens =
2868 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2869 for (i=0; i < num_ignore_generic_tokens; i++)
2870 ignore_image_tokens[i] = ignore_generic_tokens[i];
2871 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2872 ignore_image_tokens[num_ignore_generic_tokens + i] =
2873 image_config_vars[i].token;
2874 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2876 /* dynamically determine list of sound tokens to be ignored */
2877 num_ignore_sound_tokens = num_ignore_generic_tokens;
2878 ignore_sound_tokens =
2879 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2880 for (i=0; i < num_ignore_generic_tokens; i++)
2881 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2882 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2884 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2885 image_id_prefix[i] = element_info[i].token_name;
2886 for (i=0; i<NUM_FONTS; i++)
2887 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2888 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2890 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2891 sound_id_prefix[i] = element_info[i].token_name;
2892 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2893 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2894 get_string_in_brackets(element_info[i].class_name);
2895 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2897 for (i=0; i<NUM_ACTIONS; i++)
2898 action_id_suffix[i] = element_action_info[i].suffix;
2899 action_id_suffix[NUM_ACTIONS] = NULL;
2901 for (i=0; i<NUM_DIRECTIONS; i++)
2902 direction_id_suffix[i] = element_direction_info[i].suffix;
2903 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2905 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2906 special_id_suffix[i] = special_suffix_info[i].suffix;
2907 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2909 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2910 image_id_prefix, action_id_suffix, direction_id_suffix,
2911 special_id_suffix, ignore_image_tokens);
2912 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2913 sound_id_prefix, action_id_suffix, dummy,
2914 special_id_suffix, ignore_sound_tokens);
2917 static void InitMixer()
2925 char *filename_font_initial = NULL;
2926 Bitmap *bitmap_font_initial = NULL;
2929 /* determine settings for initial font (for displaying startup messages) */
2930 for (i=0; image_config[i].token != NULL; i++)
2932 for (j=0; j < NUM_INITIAL_FONTS; j++)
2934 char font_token[128];
2937 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2938 len_font_token = strlen(font_token);
2940 if (strcmp(image_config[i].token, font_token) == 0)
2941 filename_font_initial = image_config[i].value;
2942 else if (strlen(image_config[i].token) > len_font_token &&
2943 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2945 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2946 font_initial[j].src_x = atoi(image_config[i].value);
2947 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2948 font_initial[j].src_y = atoi(image_config[i].value);
2949 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2950 font_initial[j].width = atoi(image_config[i].value);
2951 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2952 font_initial[j].height = atoi(image_config[i].value);
2957 for (j=0; j < NUM_INITIAL_FONTS; j++)
2959 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2960 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2963 if (filename_font_initial == NULL) /* should not happen */
2964 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2966 /* create additional image buffers for double-buffering */
2967 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2968 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2970 /* initialize screen properties */
2971 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2972 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2974 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2975 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2976 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2978 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2980 for (j=0; j < NUM_INITIAL_FONTS; j++)
2981 font_initial[j].bitmap = bitmap_font_initial;
2983 InitFontGraphicInfo();
2985 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2986 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2988 DrawInitText("Loading graphics:", 120, FC_GREEN);
2990 InitTileClipmasks();
2993 void InitGfxBackground()
2997 drawto = backbuffer;
2998 fieldbuffer = bitmap_db_field;
2999 SetDrawtoField(DRAW_BACKBUFFER);
3001 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3002 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3003 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3004 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3006 for (x=0; x<MAX_BUF_XSIZE; x++)
3007 for (y=0; y<MAX_BUF_YSIZE; y++)
3010 redraw_mask = REDRAW_ALL;
3013 static void InitLevelInfo()
3015 LoadLevelInfo(); /* global level info */
3016 LoadLevelSetup_LastSeries(); /* last played series info */
3017 LoadLevelSetup_SeriesInfo(); /* last played level info */
3020 void InitLevelArtworkInfo()
3022 LoadLevelArtworkInfo();
3025 static void InitImages()
3027 ReloadCustomImages();
3029 LoadCustomElementDescriptions();
3030 LoadSpecialMenuDesignSettings();
3032 ReinitializeGraphics();
3035 static void InitSound()
3037 InitReloadCustomSounds(artwork.snd_current->identifier);
3038 ReinitializeSounds();
3041 static void InitMusic()
3043 InitReloadCustomMusic(artwork.mus_current->identifier);
3044 ReinitializeMusic();
3047 void InitNetworkServer()
3049 #if defined(PLATFORM_UNIX)
3053 if (!options.network)
3056 #if defined(PLATFORM_UNIX)
3057 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3059 if (!ConnectToServer(options.server_host, options.server_port))
3060 Error(ERR_EXIT, "cannot connect to network game server");
3062 SendToServer_PlayerName(setup.player_name);
3063 SendToServer_ProtocolVersion();
3066 SendToServer_NrWanted(nr_wanted);
3070 void ReloadCustomArtwork()
3072 static char *leveldir_current_identifier = NULL;
3073 static boolean last_override_level_graphics = FALSE;
3074 static boolean last_override_level_sounds = FALSE;
3075 static boolean last_override_level_music = FALSE;
3076 /* identifier for new artwork; default: artwork configured in setup */
3077 char *gfx_new_identifier = artwork.gfx_current->identifier;
3078 char *snd_new_identifier = artwork.snd_current->identifier;
3079 char *mus_new_identifier = artwork.mus_current->identifier;
3080 boolean redraw_screen = FALSE;
3082 if (leveldir_current_identifier == NULL)
3083 leveldir_current_identifier = leveldir_current->identifier;
3086 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3087 leveldir_current->graphics_set);
3088 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3089 leveldir_current->identifier);
3093 printf("graphics --> '%s' ('%s')\n",
3094 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3095 printf("sounds --> '%s' ('%s')\n",
3096 artwork.snd_current_identifier, artwork.snd_current->filename);
3097 printf("music --> '%s' ('%s')\n",
3098 artwork.mus_current_identifier, artwork.mus_current->filename);
3101 /* leveldir_current may be invalid (level group, parent link) */
3102 if (!validLevelSeries(leveldir_current))
3105 /* when a new level series was selected, check if there was a change
3106 in custom artwork stored in level series directory */
3107 if (leveldir_current_identifier != leveldir_current->identifier)
3109 char *identifier_old = leveldir_current_identifier;
3110 char *identifier_new = leveldir_current->identifier;
3112 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3113 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3114 gfx_new_identifier = identifier_new;
3115 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3116 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3117 snd_new_identifier = identifier_new;
3118 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3119 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3120 mus_new_identifier = identifier_new;
3122 leveldir_current_identifier = leveldir_current->identifier;
3125 /* custom level artwork configured in level series configuration file
3126 always overrides custom level artwork stored in level series directory
3127 and (level independant) custom artwork configured in setup menue */
3128 if (leveldir_current->graphics_set != NULL)
3129 gfx_new_identifier = leveldir_current->graphics_set;
3130 if (leveldir_current->sounds_set != NULL)
3131 snd_new_identifier = leveldir_current->sounds_set;
3132 if (leveldir_current->music_set != NULL)
3133 mus_new_identifier = leveldir_current->music_set;
3135 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3136 last_override_level_graphics != setup.override_level_graphics)
3139 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3140 artwork.gfx_current_identifier,
3141 artwork.gfx_current->identifier,
3142 gfx_new_identifier);
3145 setLevelArtworkDir(artwork.gfx_first);
3147 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3151 FreeTileClipmasks();
3152 InitTileClipmasks();
3154 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3155 last_override_level_graphics = setup.override_level_graphics;
3157 redraw_screen = TRUE;
3160 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3161 last_override_level_sounds != setup.override_level_sounds)
3164 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3165 artwork.snd_current_identifier,
3166 artwork.snd_current->identifier,
3167 snd_new_identifier);
3170 /* set artwork path to send it to the sound server process */
3171 setLevelArtworkDir(artwork.snd_first);
3173 InitReloadCustomSounds(snd_new_identifier);
3174 ReinitializeSounds();
3176 artwork.snd_current_identifier = artwork.snd_current->identifier;
3177 last_override_level_sounds = setup.override_level_sounds;
3179 redraw_screen = TRUE;
3182 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3183 last_override_level_music != setup.override_level_music)
3185 /* set artwork path to send it to the sound server process */
3186 setLevelArtworkDir(artwork.mus_first);
3188 InitReloadCustomMusic(mus_new_identifier);
3189 ReinitializeMusic();
3191 artwork.mus_current_identifier = artwork.mus_current->identifier;
3192 last_override_level_music = setup.override_level_music;
3194 redraw_screen = TRUE;
3199 InitGfxBackground();
3201 /* force redraw of (open or closed) door graphics */
3202 SetDoorState(DOOR_OPEN_ALL);
3203 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3207 void KeyboardAutoRepeatOffUnlessAutoplay()
3209 if (global.autoplay_leveldir == NULL)
3210 KeyboardAutoRepeatOff();
3214 /* ========================================================================= */
3216 /* ========================================================================= */
3220 InitGlobal(); /* initialize some global variables */
3222 if (options.execute_command)
3223 Execute_Command(options.execute_command);
3225 if (options.serveronly)
3227 #if defined(PLATFORM_UNIX)
3228 NetworkServer(options.server_port, options.serveronly);
3230 Error(ERR_WARN, "networking only supported in Unix version");
3232 exit(0); /* never reached */
3238 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3239 InitArtworkConfig(); /* needed before forking sound child process */
3244 InitRND(NEW_RANDOMIZE);
3245 InitSimpleRND(NEW_RANDOMIZE);
3250 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3253 InitEventFilter(FilterMouseMotionEvents);
3255 InitElementPropertiesStatic();
3260 InitLevelArtworkInfo();
3262 InitImages(); /* needs to know current level directory */
3263 InitSound(); /* needs to know current level directory */
3264 InitMusic(); /* needs to know current level directory */
3266 InitGfxBackground();
3268 if (global.autoplay_leveldir)
3274 game_status = GAME_MODE_MAIN;
3278 InitNetworkServer();
3281 void CloseAllAndExit(int exit_value)
3286 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3289 FreeTileClipmasks();
3291 CloseVideoDisplay();
3292 ClosePlatformDependantStuff();