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_action_graphic = element_info[i].graphic[ACTION_DEFAULT];
485 int default_action_direction_graphic[NUM_DIRECTIONS];
487 if (default_action_graphic == -1)
488 default_action_graphic = IMG_CHAR_QUESTION;
490 for (dir=0; dir<NUM_DIRECTIONS; dir++)
492 default_action_direction_graphic[dir] =
493 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
495 if (default_action_direction_graphic[dir] == -1)
496 default_action_direction_graphic[dir] = default_action_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 for (dir=0; dir<NUM_DIRECTIONS; dir++)
507 int default_direction_graphic = element_info[i].graphic[act];
509 /* no graphic for current action -- use default direction graphic */
510 if (default_direction_graphic == -1)
511 default_direction_graphic =
512 (act_remove ? IMG_EMPTY : default_action_direction_graphic[dir]);
514 if (element_info[i].direction_graphic[act][dir] == -1)
515 element_info[i].direction_graphic[act][dir] =
516 default_direction_graphic;
519 /* no graphic for this specific action -- use default action graphic */
520 if (element_info[i].graphic[act] == -1)
521 element_info[i].graphic[act] =
522 (act_remove ? IMG_EMPTY : default_action_graphic);
530 for (i=0; i<MAX_NUM_ELEMENTS; i++)
531 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
532 i != EL_CHAR_QUESTION)
533 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
534 element_info[i].token_name, i);
540 void InitElementSpecialGraphicInfo()
542 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
543 int num_property_mappings = getImageListPropertyMappingSize();
546 /* always start with reliable default values */
547 for (i=0; i < MAX_NUM_ELEMENTS; i++)
548 for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
549 element_info[i].special_graphic[j] =
550 element_info[i].graphic[ACTION_DEFAULT];
552 /* initialize special element/graphic mapping from static configuration */
553 for (i=0; element_to_special_graphic[i].element > -1; i++)
555 int element = element_to_special_graphic[i].element;
556 int special = element_to_special_graphic[i].special;
557 int graphic = element_to_special_graphic[i].graphic;
558 boolean base_redefined = getImageListEntry(el2img(element))->redefined;
559 boolean special_redefined = getImageListEntry(graphic)->redefined;
561 /* if the base graphic ("emerald", for example) has been redefined,
562 but not the special graphic ("emerald.EDITOR", for example), do not
563 use an existing (in this case considered obsolete) special graphic
564 anymore, but use the automatically created (down-scaled) graphic */
565 if (base_redefined && !special_redefined)
568 element_info[element].special_graphic[special] = graphic;
571 /* initialize special element/graphic mapping from dynamic configuration */
572 for (i=0; i < num_property_mappings; i++)
574 int element = property_mapping[i].base_index;
575 int special = property_mapping[i].ext3_index;
576 int graphic = property_mapping[i].artwork_index;
578 if (element >= MAX_NUM_ELEMENTS)
581 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
582 element_info[element].special_graphic[special] = graphic;
586 static void set_graphic_parameters(int graphic, char **parameter_raw)
588 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
589 int parameter[NUM_GFX_ARGS];
590 int anim_frames_per_row = 1, anim_frames_per_col = 1;
591 int anim_frames_per_line = 1;
594 /* get integer values from string parameters */
595 for (i=0; i < NUM_GFX_ARGS; i++)
597 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
598 image_config_suffix[i].type);
600 graphic_info[graphic].bitmap = src_bitmap;
602 /* start with reliable default values */
603 graphic_info[graphic].src_x = 0;
604 graphic_info[graphic].src_y = 0;
605 graphic_info[graphic].width = TILEX;
606 graphic_info[graphic].height = TILEY;
607 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
608 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
610 /* optional x and y tile position of animation frame sequence */
611 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
612 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
613 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
614 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
616 /* optional x and y pixel position of animation frame sequence */
617 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
618 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
619 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
620 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
622 /* optional width and height of each animation frame */
623 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
624 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
625 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
626 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
630 anim_frames_per_row = src_bitmap->width / graphic_info[graphic].width;
631 anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
634 /* correct x or y offset dependant of vertical or horizontal frame order */
635 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
637 graphic_info[graphic].offset_y =
638 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
639 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
640 anim_frames_per_line = anim_frames_per_col;
642 else /* frames are ordered horizontally */
644 graphic_info[graphic].offset_x =
645 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
646 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
647 anim_frames_per_line = anim_frames_per_row;
650 /* optionally, the x and y offset of frames can be specified directly */
651 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
652 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
653 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
654 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
656 /* automatically determine correct number of frames, if not defined */
657 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
658 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
659 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
660 graphic_info[graphic].anim_frames = anim_frames_per_row;
661 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
662 graphic_info[graphic].anim_frames = anim_frames_per_col;
664 graphic_info[graphic].anim_frames = 1;
666 graphic_info[graphic].anim_frames_per_line =
667 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
668 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
670 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
671 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
672 graphic_info[graphic].anim_delay = 1;
674 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
675 if (graphic_info[graphic].anim_frames == 1)
676 graphic_info[graphic].anim_mode = ANIM_NONE;
678 /* automatically determine correct start frame, if not defined */
679 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
680 graphic_info[graphic].anim_start_frame = 0;
681 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
682 graphic_info[graphic].anim_start_frame =
683 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
685 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
687 /* animation synchronized with global frame counter, not move position */
688 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
690 /* this is only used for toon animations */
691 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
692 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
694 /* this is only used for drawing font characters */
695 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
696 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
699 static void InitGraphicInfo()
701 int fallback_graphic = IMG_CHAR_EXCLAM;
702 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
703 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
704 int num_images = getImageListSize();
707 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
708 static boolean clipmasks_initialized = FALSE;
710 XGCValues clip_gc_values;
711 unsigned long clip_gc_valuemask;
712 GC copy_clipmask_gc = None;
715 if (graphic_info != NULL)
718 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
720 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
721 if (clipmasks_initialized)
723 for (i=0; i<num_images; i++)
725 if (graphic_info[i].clip_mask)
726 XFreePixmap(display, graphic_info[i].clip_mask);
727 if (graphic_info[i].clip_gc)
728 XFreeGC(display, graphic_info[i].clip_gc);
730 graphic_info[i].clip_mask = None;
731 graphic_info[i].clip_gc = None;
736 for (i=0; i<num_images; i++)
738 struct FileInfo *image = getImageListEntry(i);
741 int first_frame, last_frame;
743 set_graphic_parameters(i, image->parameter);
745 /* now check if no animation frames are outside of the loaded image */
747 if (graphic_info[i].bitmap == NULL)
748 continue; /* skip check for optional images that are undefined */
751 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
752 if (src_x < 0 || src_y < 0 ||
753 src_x + TILEX > src_bitmap->width ||
754 src_y + TILEY > src_bitmap->height)
756 Error(ERR_RETURN_LINE, "-");
757 Error(ERR_RETURN, "warning: error found in config file:");
758 Error(ERR_RETURN, "- config file: '%s'",
759 getImageConfigFilename());
760 Error(ERR_RETURN, "- config token: '%s'",
761 getTokenFromImageID(i));
762 Error(ERR_RETURN, "- image file: '%s'",
763 src_bitmap->source_filename);
765 "error: first animation frame out of bounds (%d, %d)",
767 Error(ERR_RETURN, "custom graphic rejected for this element/action");
769 if (i == fallback_graphic)
770 Error(ERR_EXIT, "fatal error: no fallback graphic available");
772 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
773 Error(ERR_RETURN_LINE, "-");
775 set_graphic_parameters(i, fallback_image->default_parameter);
776 graphic_info[i].bitmap = fallback_bitmap;
779 last_frame = graphic_info[i].anim_frames - 1;
780 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
781 if (src_x < 0 || src_y < 0 ||
782 src_x + TILEX > src_bitmap->width ||
783 src_y + TILEY > src_bitmap->height)
785 Error(ERR_RETURN_LINE, "-");
786 Error(ERR_RETURN, "warning: error found in config file:");
787 Error(ERR_RETURN, "- config file: '%s'",
788 getImageConfigFilename());
789 Error(ERR_RETURN, "- config token: '%s'",
790 getTokenFromImageID(i));
791 Error(ERR_RETURN, "- image file: '%s'",
792 src_bitmap->source_filename);
794 "error: last animation frame (%d) out of bounds (%d, %d)",
795 last_frame, src_x, src_y);
796 Error(ERR_RETURN, "custom graphic rejected for this element/action");
798 if (i == fallback_graphic)
799 Error(ERR_EXIT, "fatal error: no fallback graphic available");
801 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
802 Error(ERR_RETURN_LINE, "-");
804 set_graphic_parameters(i, fallback_image->default_parameter);
805 graphic_info[i].bitmap = fallback_bitmap;
808 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
809 /* currently we need only a tile clip mask from the first frame */
810 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
812 if (copy_clipmask_gc == None)
814 clip_gc_values.graphics_exposures = False;
815 clip_gc_valuemask = GCGraphicsExposures;
816 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
817 clip_gc_valuemask, &clip_gc_values);
820 graphic_info[i].clip_mask =
821 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
823 src_pixmap = src_bitmap->clip_mask;
824 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
825 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
827 clip_gc_values.graphics_exposures = False;
828 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
829 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
831 graphic_info[i].clip_gc =
832 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
836 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
837 if (copy_clipmask_gc)
838 XFreeGC(display, copy_clipmask_gc);
840 clipmasks_initialized = TRUE;
844 static void InitElementSoundInfo()
846 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
847 int num_property_mappings = getSoundListPropertyMappingSize();
850 /* set values to -1 to identify later as "uninitialized" values */
851 for (i=0; i < MAX_NUM_ELEMENTS; i++)
852 for (act=0; act < NUM_ACTIONS; act++)
853 element_info[i].sound[act] = -1;
855 /* initialize element/sound mapping from static configuration */
856 for (i=0; element_to_sound[i].element > -1; i++)
858 int element = element_to_sound[i].element;
859 int action = element_to_sound[i].action;
860 int sound = element_to_sound[i].sound;
861 boolean is_class = element_to_sound[i].is_class;
864 action = ACTION_DEFAULT;
867 element_info[element].sound[action] = sound;
869 for (j=0; j < MAX_NUM_ELEMENTS; j++)
870 if (strcmp(element_info[j].class_name,
871 element_info[element].class_name) == 0)
872 element_info[j].sound[action] = sound;
875 /* initialize element/sound mapping from dynamic configuration */
876 for (i=0; i < num_property_mappings; i++)
878 int element = property_mapping[i].base_index;
879 int action = property_mapping[i].ext1_index;
880 int sound = property_mapping[i].artwork_index;
882 if (element >= MAX_NUM_ELEMENTS)
886 action = ACTION_DEFAULT;
888 element_info[element].sound[action] = sound;
891 /* initialize element class/sound mapping from dynamic configuration */
892 for (i=0; i < num_property_mappings; i++)
894 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
895 int action = property_mapping[i].ext1_index;
896 int sound = property_mapping[i].artwork_index;
898 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
902 action = ACTION_DEFAULT;
904 for (j=0; j < MAX_NUM_ELEMENTS; j++)
905 if (strcmp(element_info[j].class_name,
906 element_info[element_class].class_name) == 0)
907 element_info[j].sound[action] = sound;
910 /* now set all '-1' values to element specific default values */
911 for (i=0; i<MAX_NUM_ELEMENTS; i++)
913 int default_action_sound = element_info[i].sound[ACTION_DEFAULT];
915 for (act=0; act < NUM_ACTIONS; act++)
917 /* no sound for this specific action -- use default action sound */
918 if (element_info[i].sound[act] == -1)
919 element_info[i].sound[act] = default_action_sound;
924 static void set_sound_parameters(int sound, char **parameter_raw)
926 int parameter[NUM_SND_ARGS];
929 /* get integer values from string parameters */
930 for (i=0; i < NUM_SND_ARGS; i++)
932 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
933 sound_config_suffix[i].type);
935 /* explicit loop mode setting in configuration overrides default value */
936 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
937 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
940 static void InitSoundInfo()
942 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
943 int num_property_mappings = getSoundListPropertyMappingSize();
944 int *sound_effect_properties;
945 int num_sounds = getSoundListSize();
948 if (sound_info != NULL)
951 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
952 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
954 /* initialize sound effect for all elements to "no sound" */
955 for (i=0; i<MAX_NUM_ELEMENTS; i++)
956 for (j=0; j<NUM_ACTIONS; j++)
957 element_info[i].sound[j] = SND_UNDEFINED;
959 for (i=0; i<num_sounds; i++)
961 struct FileInfo *sound = getSoundListEntry(i);
962 int len_effect_text = strlen(sound->token);
964 sound_effect_properties[i] = ACTION_OTHER;
965 sound_info[i].loop = FALSE;
967 /* determine all loop sounds and identify certain sound classes */
969 for (j=0; element_action_info[j].suffix; j++)
971 int len_action_text = strlen(element_action_info[j].suffix);
973 if (len_action_text < len_effect_text &&
974 strcmp(&sound->token[len_effect_text - len_action_text],
975 element_action_info[j].suffix) == 0)
977 sound_effect_properties[i] = element_action_info[j].value;
979 if (element_action_info[j].is_loop_sound)
980 sound_info[i].loop = TRUE;
984 /* associate elements and some selected sound actions */
986 for (j=0; j<MAX_NUM_ELEMENTS; j++)
988 if (element_info[j].class_name)
990 int len_class_text = strlen(element_info[j].class_name);
992 if (len_class_text + 1 < len_effect_text &&
993 strncmp(sound->token,
994 element_info[j].class_name, len_class_text) == 0 &&
995 sound->token[len_class_text] == '.')
997 int sound_action_value = sound_effect_properties[i];
999 element_info[j].sound[sound_action_value] = i;
1004 set_sound_parameters(i, sound->parameter);
1007 free(sound_effect_properties);
1009 /* initialize element/sound mapping from dynamic configuration */
1010 for (i=0; i < num_property_mappings; i++)
1012 int element = property_mapping[i].base_index;
1013 int action = property_mapping[i].ext1_index;
1014 int sound = property_mapping[i].artwork_index;
1017 action = ACTION_DEFAULT;
1019 element_info[element].sound[action] = sound;
1025 int element = EL_CUSTOM_11;
1028 while (element_action_info[j].suffix)
1030 printf("element %d, sound action '%s' == %d\n",
1031 element, element_action_info[j].suffix,
1032 element_info[element].sound[j]);
1037 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1043 int element = EL_SAND;
1044 int sound_action = ACTION_DIGGING;
1047 while (element_action_info[j].suffix)
1049 if (element_action_info[j].value == sound_action)
1050 printf("element %d, sound action '%s' == %d\n",
1051 element, element_action_info[j].suffix,
1052 element_info[element].sound[sound_action]);
1059 static void ReinitializeGraphics()
1061 InitGraphicInfo(); /* graphic properties mapping */
1062 InitElementGraphicInfo(); /* element game graphic mapping */
1063 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1065 InitElementSmallImages(); /* create editor and preview images */
1066 InitFontGraphicInfo(); /* initialize text drawing functions */
1068 SetMainBackgroundImage(IMG_BACKGROUND);
1069 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1075 static void ReinitializeSounds()
1077 InitSoundInfo(); /* sound properties mapping */
1078 InitElementSoundInfo(); /* element game sound mapping */
1081 InitElementSoundInfo(); /* element game sound mapping */
1084 InitPlaySoundLevel(); /* internal game sound settings */
1087 static void ReinitializeMusic()
1089 /* currently nothing to do */
1092 void InitElementPropertiesStatic()
1094 static int ep_diggable[] =
1099 EL_SP_BUGGY_BASE_ACTIVATING,
1102 EL_INVISIBLE_SAND_ACTIVE,
1104 /* !!! currently not diggable, but handled by 'ep_dont_go_to' !!! */
1108 EL_SP_BUGGY_BASE_ACTIVE,
1113 static int ep_collectible[] =
1130 EL_DYNABOMB_INCREASE_NUMBER,
1131 EL_DYNABOMB_INCREASE_SIZE,
1132 EL_DYNABOMB_INCREASE_POWER,
1146 static int ep_indestructible[] =
1150 EL_ACID_POOL_TOPLEFT,
1151 EL_ACID_POOL_TOPRIGHT,
1152 EL_ACID_POOL_BOTTOMLEFT,
1153 EL_ACID_POOL_BOTTOM,
1154 EL_ACID_POOL_BOTTOMRIGHT,
1155 EL_SP_HARDWARE_GRAY,
1156 EL_SP_HARDWARE_GREEN,
1157 EL_SP_HARDWARE_BLUE,
1159 EL_SP_HARDWARE_YELLOW,
1160 EL_SP_HARDWARE_BASE_1,
1161 EL_SP_HARDWARE_BASE_2,
1162 EL_SP_HARDWARE_BASE_3,
1163 EL_SP_HARDWARE_BASE_4,
1164 EL_SP_HARDWARE_BASE_5,
1165 EL_SP_HARDWARE_BASE_6,
1166 EL_INVISIBLE_STEELWALL,
1167 EL_INVISIBLE_STEELWALL_ACTIVE,
1168 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1169 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1170 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1171 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1172 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1173 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1174 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1175 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1176 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1177 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1178 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1179 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1181 EL_LIGHT_SWITCH_ACTIVE,
1182 EL_SIGN_EXCLAMATION,
1183 EL_SIGN_RADIOACTIVITY,
1194 EL_STEELWALL_SLANTED,
1217 EL_SWITCHGATE_OPENING,
1218 EL_SWITCHGATE_CLOSED,
1219 EL_SWITCHGATE_CLOSING,
1221 EL_TIMEGATE_OPENING,
1223 EL_TIMEGATE_CLOSING,
1227 EL_TUBE_VERTICAL_LEFT,
1228 EL_TUBE_VERTICAL_RIGHT,
1229 EL_TUBE_HORIZONTAL_UP,
1230 EL_TUBE_HORIZONTAL_DOWN,
1238 static int ep_slippery[] =
1252 EL_ROBOT_WHEEL_ACTIVE,
1258 EL_ACID_POOL_TOPLEFT,
1259 EL_ACID_POOL_TOPRIGHT,
1269 EL_STEELWALL_SLANTED,
1275 static int ep_can_explode[] =
1280 EL_DYNABOMB_PLAYER_1_ACTIVE,
1281 EL_DYNABOMB_PLAYER_2_ACTIVE,
1282 EL_DYNABOMB_PLAYER_3_ACTIVE,
1283 EL_DYNABOMB_PLAYER_4_ACTIVE,
1284 EL_DYNABOMB_INCREASE_NUMBER,
1285 EL_DYNABOMB_INCREASE_SIZE,
1286 EL_DYNABOMB_INCREASE_POWER,
1287 EL_SP_DISK_RED_ACTIVE,
1303 static int ep_can_move[] =
1305 /* only stored in level file */
1314 EL_BD_BUTTERFLY_RIGHT,
1316 EL_BD_BUTTERFLY_LEFT,
1317 EL_BD_BUTTERFLY_DOWN,
1318 EL_BD_FIREFLY_RIGHT,
1327 /* level file and runtime elements */
1348 static int ep_can_fall[] =
1363 EL_BD_MAGIC_WALL_FULL,
1376 static int ep_can_smash[] =
1401 static int ep_walkable_over[] =
1405 EL_SOKOBAN_FIELD_EMPTY,
1419 static int ep_walkable_inside[] =
1424 EL_TUBE_VERTICAL_LEFT,
1425 EL_TUBE_VERTICAL_RIGHT,
1426 EL_TUBE_HORIZONTAL_UP,
1427 EL_TUBE_HORIZONTAL_DOWN,
1435 static int ep_walkable_under[] =
1440 static int ep_passable_over[] =
1455 static int ep_passable_inside[] =
1461 EL_SP_PORT_HORIZONTAL,
1462 EL_SP_PORT_VERTICAL,
1464 EL_SP_GRAVITY_PORT_LEFT,
1465 EL_SP_GRAVITY_PORT_RIGHT,
1466 EL_SP_GRAVITY_PORT_UP,
1467 EL_SP_GRAVITY_PORT_DOWN,
1471 static int ep_passable_under[] =
1476 static int ep_pushable[] =
1488 EL_SOKOBAN_FIELD_FULL,
1495 static int ep_can_be_crumbled[] =
1504 static int ep_player[] =
1513 static int ep_can_pass_magic_wall[] =
1526 static int ep_switchable[] =
1530 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1531 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1532 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1533 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1534 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1535 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1536 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1537 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1538 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1539 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1540 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1541 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1542 EL_SWITCHGATE_SWITCH_UP,
1543 EL_SWITCHGATE_SWITCH_DOWN,
1545 EL_LIGHT_SWITCH_ACTIVE,
1547 EL_BALLOON_SWITCH_LEFT,
1548 EL_BALLOON_SWITCH_RIGHT,
1549 EL_BALLOON_SWITCH_UP,
1550 EL_BALLOON_SWITCH_DOWN,
1551 EL_BALLOON_SWITCH_ANY,
1557 static int ep_dont_touch[] =
1566 static int ep_enemy[] =
1582 static int ep_dont_go_to[] =
1599 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1601 EL_SP_BUGGY_BASE_ACTIVE,
1608 static int ep_bd_element[] =
1637 static int ep_sp_element[] =
1645 EL_SP_HARDWARE_GRAY,
1653 EL_SP_GRAVITY_PORT_RIGHT,
1654 EL_SP_GRAVITY_PORT_DOWN,
1655 EL_SP_GRAVITY_PORT_LEFT,
1656 EL_SP_GRAVITY_PORT_UP,
1661 EL_SP_PORT_VERTICAL,
1662 EL_SP_PORT_HORIZONTAL,
1668 EL_SP_HARDWARE_BASE_1,
1669 EL_SP_HARDWARE_GREEN,
1670 EL_SP_HARDWARE_BLUE,
1672 EL_SP_HARDWARE_YELLOW,
1673 EL_SP_HARDWARE_BASE_2,
1674 EL_SP_HARDWARE_BASE_3,
1675 EL_SP_HARDWARE_BASE_4,
1676 EL_SP_HARDWARE_BASE_5,
1677 EL_SP_HARDWARE_BASE_6,
1680 /* additional elements that appeared in newer Supaplex levels */
1682 /* more than one murphy in a level results in an inactive clone */
1687 static int ep_sb_element[] =
1692 EL_SOKOBAN_FIELD_EMPTY,
1693 EL_SOKOBAN_FIELD_FULL,
1695 EL_INVISIBLE_STEELWALL,
1699 static int ep_gem[] =
1710 static int ep_food_dark_yamyam[] =
1737 static int ep_food_penguin[] =
1750 static int ep_food_pig[] =
1761 static int ep_historic_wall[] =
1786 EL_EXPANDABLE_WALL_HORIZONTAL,
1787 EL_EXPANDABLE_WALL_VERTICAL,
1788 EL_EXPANDABLE_WALL_ANY,
1789 EL_EXPANDABLE_WALL_GROWING,
1796 EL_SP_HARDWARE_GRAY,
1797 EL_SP_HARDWARE_GREEN,
1798 EL_SP_HARDWARE_BLUE,
1800 EL_SP_HARDWARE_YELLOW,
1801 EL_SP_HARDWARE_BASE_1,
1802 EL_SP_HARDWARE_BASE_2,
1803 EL_SP_HARDWARE_BASE_3,
1804 EL_SP_HARDWARE_BASE_4,
1805 EL_SP_HARDWARE_BASE_5,
1806 EL_SP_HARDWARE_BASE_6,
1808 EL_SP_TERMINAL_ACTIVE,
1811 EL_INVISIBLE_STEELWALL,
1812 EL_INVISIBLE_STEELWALL_ACTIVE,
1814 EL_INVISIBLE_WALL_ACTIVE,
1815 EL_STEELWALL_SLANTED,
1831 static int ep_historic_solid[] =
1835 EL_EXPANDABLE_WALL_HORIZONTAL,
1836 EL_EXPANDABLE_WALL_VERTICAL,
1837 EL_EXPANDABLE_WALL_ANY,
1850 EL_QUICKSAND_FILLING,
1851 EL_QUICKSAND_EMPTYING,
1853 EL_MAGIC_WALL_ACTIVE,
1854 EL_MAGIC_WALL_EMPTYING,
1855 EL_MAGIC_WALL_FILLING,
1859 EL_BD_MAGIC_WALL_ACTIVE,
1860 EL_BD_MAGIC_WALL_EMPTYING,
1861 EL_BD_MAGIC_WALL_FULL,
1862 EL_BD_MAGIC_WALL_FILLING,
1863 EL_BD_MAGIC_WALL_DEAD,
1872 EL_SP_TERMINAL_ACTIVE,
1876 EL_INVISIBLE_WALL_ACTIVE,
1877 EL_SWITCHGATE_SWITCH_UP,
1878 EL_SWITCHGATE_SWITCH_DOWN,
1880 EL_TIMEGATE_SWITCH_ACTIVE,
1892 /* the following elements are a direct copy of "indestructible" elements,
1893 except "EL_ACID", which is "indestructible", but not "solid"! */
1898 EL_ACID_POOL_TOPLEFT,
1899 EL_ACID_POOL_TOPRIGHT,
1900 EL_ACID_POOL_BOTTOMLEFT,
1901 EL_ACID_POOL_BOTTOM,
1902 EL_ACID_POOL_BOTTOMRIGHT,
1903 EL_SP_HARDWARE_GRAY,
1904 EL_SP_HARDWARE_GREEN,
1905 EL_SP_HARDWARE_BLUE,
1907 EL_SP_HARDWARE_YELLOW,
1908 EL_SP_HARDWARE_BASE_1,
1909 EL_SP_HARDWARE_BASE_2,
1910 EL_SP_HARDWARE_BASE_3,
1911 EL_SP_HARDWARE_BASE_4,
1912 EL_SP_HARDWARE_BASE_5,
1913 EL_SP_HARDWARE_BASE_6,
1914 EL_INVISIBLE_STEELWALL,
1915 EL_INVISIBLE_STEELWALL_ACTIVE,
1916 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1917 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1918 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1919 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1920 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1921 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1922 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1923 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1924 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1925 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1926 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1927 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1929 EL_LIGHT_SWITCH_ACTIVE,
1930 EL_SIGN_EXCLAMATION,
1931 EL_SIGN_RADIOACTIVITY,
1942 EL_STEELWALL_SLANTED,
1965 EL_SWITCHGATE_OPENING,
1966 EL_SWITCHGATE_CLOSED,
1967 EL_SWITCHGATE_CLOSING,
1969 EL_TIMEGATE_OPENING,
1971 EL_TIMEGATE_CLOSING,
1975 EL_TUBE_VERTICAL_LEFT,
1976 EL_TUBE_VERTICAL_RIGHT,
1977 EL_TUBE_HORIZONTAL_UP,
1978 EL_TUBE_HORIZONTAL_DOWN,
1986 static int ep_belt[] =
1988 EL_CONVEYOR_BELT_1_LEFT,
1989 EL_CONVEYOR_BELT_1_MIDDLE,
1990 EL_CONVEYOR_BELT_1_RIGHT,
1991 EL_CONVEYOR_BELT_2_LEFT,
1992 EL_CONVEYOR_BELT_2_MIDDLE,
1993 EL_CONVEYOR_BELT_2_RIGHT,
1994 EL_CONVEYOR_BELT_3_LEFT,
1995 EL_CONVEYOR_BELT_3_MIDDLE,
1996 EL_CONVEYOR_BELT_3_RIGHT,
1997 EL_CONVEYOR_BELT_4_LEFT,
1998 EL_CONVEYOR_BELT_4_MIDDLE,
1999 EL_CONVEYOR_BELT_4_RIGHT,
2003 static int ep_belt_active[] =
2005 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2006 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2007 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2008 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2009 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2010 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2011 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2012 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2013 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2014 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2015 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2016 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2020 static int ep_belt_switch[] =
2022 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2023 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2024 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2025 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2026 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2027 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2028 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2029 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2030 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2031 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2032 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2033 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2037 static int ep_tube[] =
2044 EL_TUBE_HORIZONTAL_UP,
2045 EL_TUBE_HORIZONTAL_DOWN,
2047 EL_TUBE_VERTICAL_LEFT,
2048 EL_TUBE_VERTICAL_RIGHT,
2053 static int ep_keygate[] =
2074 static int ep_amoeboid[] =
2084 static int ep_amoebalive[] =
2093 static int ep_has_content[] =
2103 static int ep_active_bomb[] =
2106 EL_DYNABOMB_PLAYER_1_ACTIVE,
2107 EL_DYNABOMB_PLAYER_2_ACTIVE,
2108 EL_DYNABOMB_PLAYER_3_ACTIVE,
2109 EL_DYNABOMB_PLAYER_4_ACTIVE,
2110 EL_SP_DISK_RED_ACTIVE,
2114 static int ep_inactive[] =
2151 EL_INVISIBLE_STEELWALL,
2159 EL_WALL_EMERALD_YELLOW,
2160 EL_DYNABOMB_INCREASE_NUMBER,
2161 EL_DYNABOMB_INCREASE_SIZE,
2162 EL_DYNABOMB_INCREASE_POWER,
2164 EL_SOKOBAN_FIELD_EMPTY,
2165 EL_SOKOBAN_FIELD_FULL,
2166 EL_WALL_EMERALD_RED,
2167 EL_WALL_EMERALD_PURPLE,
2168 EL_ACID_POOL_TOPLEFT,
2169 EL_ACID_POOL_TOPRIGHT,
2170 EL_ACID_POOL_BOTTOMLEFT,
2171 EL_ACID_POOL_BOTTOM,
2172 EL_ACID_POOL_BOTTOMRIGHT,
2176 EL_BD_MAGIC_WALL_DEAD,
2177 EL_AMOEBA_TO_DIAMOND,
2185 EL_SP_GRAVITY_PORT_RIGHT,
2186 EL_SP_GRAVITY_PORT_DOWN,
2187 EL_SP_GRAVITY_PORT_LEFT,
2188 EL_SP_GRAVITY_PORT_UP,
2189 EL_SP_PORT_HORIZONTAL,
2190 EL_SP_PORT_VERTICAL,
2199 EL_SP_HARDWARE_GRAY,
2200 EL_SP_HARDWARE_GREEN,
2201 EL_SP_HARDWARE_BLUE,
2203 EL_SP_HARDWARE_YELLOW,
2204 EL_SP_HARDWARE_BASE_1,
2205 EL_SP_HARDWARE_BASE_2,
2206 EL_SP_HARDWARE_BASE_3,
2207 EL_SP_HARDWARE_BASE_4,
2208 EL_SP_HARDWARE_BASE_5,
2209 EL_SP_HARDWARE_BASE_6,
2210 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2211 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2212 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2213 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2214 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2215 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2216 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2217 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2218 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2219 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2220 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2221 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2222 EL_SIGN_EXCLAMATION,
2223 EL_SIGN_RADIOACTIVITY,
2234 EL_STEELWALL_SLANTED,
2254 } element_properties[] =
2256 { ep_diggable, EP_DIGGABLE },
2257 { ep_collectible, EP_COLLECTIBLE },
2258 { ep_indestructible, EP_INDESTRUCTIBLE },
2259 { ep_slippery, EP_SLIPPERY },
2260 { ep_can_fall, EP_CAN_FALL },
2261 { ep_can_smash, EP_CAN_SMASH },
2262 { ep_walkable_over, EP_WALKABLE_OVER },
2263 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2264 { ep_walkable_under, EP_WALKABLE_UNDER },
2265 { ep_passable_over, EP_PASSABLE_OVER },
2266 { ep_passable_inside, EP_PASSABLE_INSIDE },
2267 { ep_passable_under, EP_PASSABLE_UNDER },
2268 { ep_pushable, EP_PUSHABLE },
2270 { ep_player, EP_PLAYER },
2271 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2272 { ep_can_move, EP_CAN_MOVE },
2273 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2274 { ep_switchable, EP_SWITCHABLE },
2275 { ep_dont_touch, EP_DONT_TOUCH },
2276 { ep_enemy, EP_ENEMY },
2277 { ep_dont_go_to, EP_DONT_GO_TO },
2278 { ep_can_explode, EP_CAN_EXPLODE },
2279 { ep_bd_element, EP_BD_ELEMENT },
2280 { ep_sp_element, EP_SP_ELEMENT },
2281 { ep_sb_element, EP_SB_ELEMENT },
2283 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2284 { ep_food_penguin, EP_FOOD_PENGUIN },
2285 { ep_food_pig, EP_FOOD_PIG },
2286 { ep_historic_wall, EP_HISTORIC_WALL },
2287 { ep_historic_solid, EP_HISTORIC_SOLID },
2288 { ep_belt, EP_BELT },
2289 { ep_belt_active, EP_BELT_ACTIVE },
2290 { ep_belt_switch, EP_BELT_SWITCH },
2291 { ep_tube, EP_TUBE },
2292 { ep_keygate, EP_KEYGATE },
2293 { ep_amoeboid, EP_AMOEBOID },
2294 { ep_amoebalive, EP_AMOEBALIVE },
2295 { ep_has_content, EP_HAS_CONTENT },
2296 { ep_active_bomb, EP_ACTIVE_BOMB },
2297 { ep_inactive, EP_INACTIVE },
2304 /* always start with reliable default values (element has no properties) */
2305 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2306 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2307 SET_PROPERTY(i, j, FALSE);
2309 /* set all base element properties from above array definitions */
2310 for (i=0; element_properties[i].elements != NULL; i++)
2311 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2312 SET_PROPERTY((element_properties[i].elements)[j],
2313 element_properties[i].property, TRUE);
2316 void InitElementPropertiesEngine(int engine_version)
2319 static int active_properties[] =
2328 EP_CAN_PASS_MAGIC_WALL,
2346 EP_EM_SLIPPERY_WALL,
2351 static int no_wall_properties[] =
2361 EP_FOOD_DARK_YAMYAM,
2379 InitElementPropertiesStatic();
2382 /* set all special, combined or engine dependant element properties */
2383 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2386 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2387 SET_PROPERTY(i, j, FALSE);
2390 /* ---------- INACTIVE ------------------------------------------------- */
2391 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2392 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2394 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2395 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2396 IS_WALKABLE_INSIDE(i) ||
2397 IS_WALKABLE_UNDER(i)));
2399 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2400 IS_PASSABLE_INSIDE(i) ||
2401 IS_PASSABLE_UNDER(i)));
2403 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2404 IS_PASSABLE_OVER(i)));
2406 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2407 IS_PASSABLE_INSIDE(i)));
2409 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2410 IS_PASSABLE_UNDER(i)));
2412 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2415 /* ---------- SNAPPABLE ------------------------------------------------ */
2416 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2417 IS_COLLECTIBLE(i) ||
2421 /* ---------- WALL ----------------------------------------------------- */
2422 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2424 for (j=0; no_wall_properties[j] != -1; j++)
2425 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2426 i >= EL_FIRST_RUNTIME_UNREAL)
2427 SET_PROPERTY(i, EP_WALL, FALSE);
2429 if (IS_HISTORIC_WALL(i))
2430 SET_PROPERTY(i, EP_WALL, TRUE);
2432 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2433 if (engine_version < VERSION_IDENT(2,2,0))
2434 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2436 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2438 !IS_COLLECTIBLE(i)));
2440 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2442 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2443 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2445 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2446 IS_INDESTRUCTIBLE(i)));
2448 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2450 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2451 else if (engine_version < VERSION_IDENT(2,2,0))
2452 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2454 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2455 !IS_WALKABLE_OVER(i) &&
2456 !IS_WALKABLE_UNDER(i)));
2458 /* ---------- ENEMY ---------------------------------------------------- */
2460 SET_PROPERTY(i, EP_ENEMY, TRUE);
2462 /* ---------- DONT_GO_TO ----------------------------------------------- */
2464 SET_PROPERTY(i, EP_DONT_GO_TO, TRUE);
2468 /* determine inactive elements (used for engine main loop optimization) */
2469 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2471 boolean active = FALSE;
2473 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2475 if (HAS_PROPERTY(i, j))
2481 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2486 /* dynamically adjust element properties according to game engine version */
2488 static int ep_em_slippery_wall[] =
2493 EL_EXPANDABLE_WALL_HORIZONTAL,
2494 EL_EXPANDABLE_WALL_VERTICAL,
2495 EL_EXPANDABLE_WALL_ANY,
2499 /* special EM style gems behaviour */
2500 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2501 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2502 level.em_slippery_gems);
2504 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2505 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2506 (level.em_slippery_gems &&
2507 engine_version > VERSION_IDENT(2,0,1)));
2510 /* dynamically adjust element properties according to game engine version */
2512 if (engine_version < RELEASE_IDENT(2,2,0,7))
2515 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2517 int element = EL_CUSTOM_START + i;
2519 element_info[element].push_delay_fixed = 2;
2520 element_info[element].push_delay_random = 8;
2525 static void InitGlobal()
2527 global.autoplay_leveldir = NULL;
2529 global.frames_per_second = 0;
2530 global.fps_slowdown = FALSE;
2531 global.fps_slowdown_factor = 1;
2534 void Execute_Command(char *command)
2536 if (strcmp(command, "print graphicsinfo.conf") == 0)
2540 printf("# You can configure additional/alternative image files here.\n");
2541 printf("# (The images below are default and therefore commented out.)\n");
2543 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2545 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2548 for (i=0; image_config[i].token != NULL; i++)
2550 getFormattedSetupEntry(image_config[i].token,
2551 image_config[i].value));
2555 else if (strcmp(command, "print soundsinfo.conf") == 0)
2559 printf("# You can configure additional/alternative sound files here.\n");
2560 printf("# (The sounds below are default and therefore commented out.)\n");
2562 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2564 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2567 for (i=0; sound_config[i].token != NULL; i++)
2569 getFormattedSetupEntry(sound_config[i].token,
2570 sound_config[i].value));
2574 else if (strcmp(command, "print musicinfo.conf") == 0)
2576 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2578 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2580 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2584 else if (strncmp(command, "dump level ", 11) == 0)
2586 char *filename = &command[11];
2588 if (access(filename, F_OK) != 0)
2589 Error(ERR_EXIT, "cannot open file '%s'", filename);
2591 LoadLevelFromFilename(filename);
2596 else if (strncmp(command, "dump tape ", 10) == 0)
2598 char *filename = &command[10];
2600 if (access(filename, F_OK) != 0)
2601 Error(ERR_EXIT, "cannot open file '%s'", filename);
2603 LoadTapeFromFilename(filename);
2608 else if (strncmp(command, "autoplay ", 9) == 0)
2610 char *str_copy = getStringCopy(&command[9]);
2611 char *str_ptr = strchr(str_copy, ' ');
2613 global.autoplay_leveldir = str_copy;
2614 global.autoplay_level_nr = -1;
2616 if (str_ptr != NULL)
2618 *str_ptr++ = '\0'; /* terminate leveldir string */
2619 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2624 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2628 static void InitSetup()
2630 LoadSetup(); /* global setup info */
2632 /* set some options from setup file */
2634 if (setup.options.verbose)
2635 options.verbose = TRUE;
2638 static void InitPlayerInfo()
2642 /* choose default local player */
2643 local_player = &stored_player[0];
2645 for (i=0; i<MAX_PLAYERS; i++)
2646 stored_player[i].connected = FALSE;
2648 local_player->connected = TRUE;
2651 static void InitArtworkInfo()
2656 static char *get_element_class_token(int element)
2658 char *element_class_name = element_info[element].class_name;
2659 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2661 sprintf(element_class_token, "[%s]", element_class_name);
2663 return element_class_token;
2666 static void InitArtworkConfig()
2668 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2669 static char *sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS + 1];
2670 static char *action_id_suffix[NUM_ACTIONS + 1];
2671 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2672 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2673 static char *dummy[1] = { NULL };
2674 static char *ignore_generic_tokens[] =
2680 static char **ignore_image_tokens, **ignore_sound_tokens;
2681 int num_ignore_generic_tokens;
2682 int num_ignore_image_tokens, num_ignore_sound_tokens;
2685 /* dynamically determine list of generic tokens to be ignored */
2686 num_ignore_generic_tokens = 0;
2687 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2688 num_ignore_generic_tokens++;
2690 /* dynamically determine list of image tokens to be ignored */
2691 num_ignore_image_tokens = num_ignore_generic_tokens;
2692 for (i=0; image_config_vars[i].token != NULL; i++)
2693 num_ignore_image_tokens++;
2694 ignore_image_tokens =
2695 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2696 for (i=0; i < num_ignore_generic_tokens; i++)
2697 ignore_image_tokens[i] = ignore_generic_tokens[i];
2698 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2699 ignore_image_tokens[num_ignore_generic_tokens + i] =
2700 image_config_vars[i].token;
2701 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2703 /* dynamically determine list of sound tokens to be ignored */
2704 num_ignore_sound_tokens = num_ignore_generic_tokens;
2705 ignore_sound_tokens =
2706 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2707 for (i=0; i < num_ignore_generic_tokens; i++)
2708 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2709 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2711 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2712 image_id_prefix[i] = element_info[i].token_name;
2713 for (i=0; i<NUM_FONTS; i++)
2714 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2715 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2717 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2718 sound_id_prefix[i] = element_info[i].token_name;
2719 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2720 sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_element_class_token(i);
2721 sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS] = NULL;
2723 for (i=0; i<NUM_ACTIONS; i++)
2724 action_id_suffix[i] = element_action_info[i].suffix;
2725 action_id_suffix[NUM_ACTIONS] = NULL;
2727 for (i=0; i<NUM_DIRECTIONS; i++)
2728 direction_id_suffix[i] = element_direction_info[i].suffix;
2729 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2731 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2732 special_id_suffix[i] = special_suffix_info[i].suffix;
2733 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2735 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2736 image_id_prefix, action_id_suffix, direction_id_suffix,
2737 special_id_suffix, ignore_image_tokens);
2738 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2739 sound_id_prefix, action_id_suffix, dummy,
2740 special_id_suffix, ignore_sound_tokens);
2743 static void InitMixer()
2751 char *filename_font_initial = NULL;
2752 Bitmap *bitmap_font_initial = NULL;
2755 /* determine settings for initial font (for displaying startup messages) */
2756 for (i=0; image_config[i].token != NULL; i++)
2758 for (j=0; j < NUM_INITIAL_FONTS; j++)
2760 char font_token[128];
2763 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2764 len_font_token = strlen(font_token);
2766 if (strcmp(image_config[i].token, font_token) == 0)
2767 filename_font_initial = image_config[i].value;
2768 else if (strlen(image_config[i].token) > len_font_token &&
2769 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2771 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2772 font_initial[j].src_x = atoi(image_config[i].value);
2773 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2774 font_initial[j].src_y = atoi(image_config[i].value);
2775 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2776 font_initial[j].width = atoi(image_config[i].value);
2777 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2778 font_initial[j].height = atoi(image_config[i].value);
2783 for (j=0; j < NUM_INITIAL_FONTS; j++)
2785 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2786 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2789 if (filename_font_initial == NULL) /* should not happen */
2790 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2792 /* create additional image buffers for double-buffering */
2793 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2794 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2796 /* initialize screen properties */
2797 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2798 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2800 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2801 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2802 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2804 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2806 for (j=0; j < NUM_INITIAL_FONTS; j++)
2807 font_initial[j].bitmap = bitmap_font_initial;
2809 InitFontGraphicInfo();
2811 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2812 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2814 DrawInitText("Loading graphics:", 120, FC_GREEN);
2816 InitTileClipmasks();
2819 void InitGfxBackground()
2823 drawto = backbuffer;
2824 fieldbuffer = bitmap_db_field;
2825 SetDrawtoField(DRAW_BACKBUFFER);
2827 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2828 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2829 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2830 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2832 for (x=0; x<MAX_BUF_XSIZE; x++)
2833 for (y=0; y<MAX_BUF_YSIZE; y++)
2836 redraw_mask = REDRAW_ALL;
2839 static void InitLevelInfo()
2841 LoadLevelInfo(); /* global level info */
2842 LoadLevelSetup_LastSeries(); /* last played series info */
2843 LoadLevelSetup_SeriesInfo(); /* last played level info */
2846 void InitLevelArtworkInfo()
2848 LoadLevelArtworkInfo();
2851 static void InitImages()
2853 ReloadCustomImages();
2855 LoadCustomElementDescriptions();
2856 LoadSpecialMenuDesignSettings();
2858 ReinitializeGraphics();
2861 static void InitSound()
2863 InitReloadCustomSounds(artwork.snd_current->identifier);
2864 ReinitializeSounds();
2867 static void InitMusic()
2869 InitReloadCustomMusic(artwork.mus_current->identifier);
2870 ReinitializeMusic();
2873 void InitNetworkServer()
2875 #if defined(PLATFORM_UNIX)
2879 if (!options.network)
2882 #if defined(PLATFORM_UNIX)
2883 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
2885 if (!ConnectToServer(options.server_host, options.server_port))
2886 Error(ERR_EXIT, "cannot connect to network game server");
2888 SendToServer_PlayerName(setup.player_name);
2889 SendToServer_ProtocolVersion();
2892 SendToServer_NrWanted(nr_wanted);
2896 void ReloadCustomArtwork()
2898 static char *leveldir_current_identifier = NULL;
2899 static boolean last_override_level_graphics = FALSE;
2900 static boolean last_override_level_sounds = FALSE;
2901 static boolean last_override_level_music = FALSE;
2902 /* identifier for new artwork; default: artwork configured in setup */
2903 char *gfx_new_identifier = artwork.gfx_current->identifier;
2904 char *snd_new_identifier = artwork.snd_current->identifier;
2905 char *mus_new_identifier = artwork.mus_current->identifier;
2906 boolean redraw_screen = FALSE;
2908 if (leveldir_current_identifier == NULL)
2909 leveldir_current_identifier = leveldir_current->identifier;
2912 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
2913 leveldir_current->graphics_set);
2914 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
2915 leveldir_current->identifier);
2919 printf("graphics --> '%s' ('%s')\n",
2920 artwork.gfx_current_identifier, artwork.gfx_current->filename);
2921 printf("sounds --> '%s' ('%s')\n",
2922 artwork.snd_current_identifier, artwork.snd_current->filename);
2923 printf("music --> '%s' ('%s')\n",
2924 artwork.mus_current_identifier, artwork.mus_current->filename);
2927 /* leveldir_current may be invalid (level group, parent link) */
2928 if (!validLevelSeries(leveldir_current))
2931 /* when a new level series was selected, check if there was a change
2932 in custom artwork stored in level series directory */
2933 if (leveldir_current_identifier != leveldir_current->identifier)
2935 char *identifier_old = leveldir_current_identifier;
2936 char *identifier_new = leveldir_current->identifier;
2938 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
2939 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
2940 gfx_new_identifier = identifier_new;
2941 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
2942 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
2943 snd_new_identifier = identifier_new;
2944 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
2945 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
2946 mus_new_identifier = identifier_new;
2948 leveldir_current_identifier = leveldir_current->identifier;
2951 /* custom level artwork configured in level series configuration file
2952 always overrides custom level artwork stored in level series directory
2953 and (level independant) custom artwork configured in setup menue */
2954 if (leveldir_current->graphics_set != NULL)
2955 gfx_new_identifier = leveldir_current->graphics_set;
2956 if (leveldir_current->sounds_set != NULL)
2957 snd_new_identifier = leveldir_current->sounds_set;
2958 if (leveldir_current->music_set != NULL)
2959 mus_new_identifier = leveldir_current->music_set;
2961 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
2962 last_override_level_graphics != setup.override_level_graphics)
2965 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
2966 artwork.gfx_current_identifier,
2967 artwork.gfx_current->identifier,
2968 gfx_new_identifier);
2971 setLevelArtworkDir(artwork.gfx_first);
2973 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
2977 FreeTileClipmasks();
2978 InitTileClipmasks();
2980 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
2981 last_override_level_graphics = setup.override_level_graphics;
2983 redraw_screen = TRUE;
2986 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
2987 last_override_level_sounds != setup.override_level_sounds)
2990 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
2991 artwork.snd_current_identifier,
2992 artwork.snd_current->identifier,
2993 snd_new_identifier);
2996 /* set artwork path to send it to the sound server process */
2997 setLevelArtworkDir(artwork.snd_first);
2999 InitReloadCustomSounds(snd_new_identifier);
3000 ReinitializeSounds();
3002 artwork.snd_current_identifier = artwork.snd_current->identifier;
3003 last_override_level_sounds = setup.override_level_sounds;
3005 redraw_screen = TRUE;
3008 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3009 last_override_level_music != setup.override_level_music)
3011 /* set artwork path to send it to the sound server process */
3012 setLevelArtworkDir(artwork.mus_first);
3014 InitReloadCustomMusic(mus_new_identifier);
3015 ReinitializeMusic();
3017 artwork.mus_current_identifier = artwork.mus_current->identifier;
3018 last_override_level_music = setup.override_level_music;
3020 redraw_screen = TRUE;
3025 InitGfxBackground();
3027 /* force redraw of (open or closed) door graphics */
3028 SetDoorState(DOOR_OPEN_ALL);
3029 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3033 void KeyboardAutoRepeatOffUnlessAutoplay()
3035 if (global.autoplay_leveldir == NULL)
3036 KeyboardAutoRepeatOff();
3040 /* ========================================================================= */
3042 /* ========================================================================= */
3046 InitGlobal(); /* initialize some global variables */
3048 if (options.execute_command)
3049 Execute_Command(options.execute_command);
3051 if (options.serveronly)
3053 #if defined(PLATFORM_UNIX)
3054 NetworkServer(options.server_port, options.serveronly);
3056 Error(ERR_WARN, "networking only supported in Unix version");
3058 exit(0); /* never reached */
3064 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3065 InitArtworkConfig(); /* needed before forking sound child process */
3070 InitRND(NEW_RANDOMIZE);
3071 InitSimpleRND(NEW_RANDOMIZE);
3076 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3079 InitEventFilter(FilterMouseMotionEvents);
3081 InitElementPropertiesStatic();
3086 InitLevelArtworkInfo();
3088 InitImages(); /* needs to know current level directory */
3089 InitSound(); /* needs to know current level directory */
3090 InitMusic(); /* needs to know current level directory */
3092 InitGfxBackground();
3094 if (global.autoplay_leveldir)
3100 game_status = GAME_MODE_MAIN;
3104 InitNetworkServer();
3107 void CloseAllAndExit(int exit_value)
3112 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3115 FreeTileClipmasks();
3117 CloseVideoDisplay();
3118 ClosePlatformDependantStuff();