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_run_into' !!! */
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_by_fire[] =
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[] =
1325 static int ep_can_fall[] =
1340 EL_BD_MAGIC_WALL_FULL,
1353 static int ep_can_smash[] =
1378 static int ep_walkable_over[] =
1382 EL_SOKOBAN_FIELD_EMPTY,
1396 static int ep_walkable_inside[] =
1401 EL_TUBE_VERTICAL_LEFT,
1402 EL_TUBE_VERTICAL_RIGHT,
1403 EL_TUBE_HORIZONTAL_UP,
1404 EL_TUBE_HORIZONTAL_DOWN,
1412 static int ep_walkable_under[] =
1417 static int ep_passable_over[] =
1432 static int ep_passable_inside[] =
1438 EL_SP_PORT_HORIZONTAL,
1439 EL_SP_PORT_VERTICAL,
1441 EL_SP_GRAVITY_PORT_LEFT,
1442 EL_SP_GRAVITY_PORT_RIGHT,
1443 EL_SP_GRAVITY_PORT_UP,
1444 EL_SP_GRAVITY_PORT_DOWN,
1448 static int ep_passable_under[] =
1453 static int ep_pushable[] =
1465 EL_SOKOBAN_FIELD_FULL,
1472 static int ep_can_be_crumbled[] =
1481 static int ep_player[] =
1490 static int ep_can_pass_magic_wall[] =
1503 static int ep_switchable[] =
1507 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1508 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1509 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1510 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1511 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1512 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1513 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1514 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1515 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1516 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1517 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1518 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1519 EL_SWITCHGATE_SWITCH_UP,
1520 EL_SWITCHGATE_SWITCH_DOWN,
1522 EL_LIGHT_SWITCH_ACTIVE,
1524 EL_BALLOON_SWITCH_LEFT,
1525 EL_BALLOON_SWITCH_RIGHT,
1526 EL_BALLOON_SWITCH_UP,
1527 EL_BALLOON_SWITCH_DOWN,
1528 EL_BALLOON_SWITCH_ANY,
1534 static int ep_dont_touch[] =
1543 static int ep_dont_collide_with[] =
1559 static int ep_dont_run_into[] =
1576 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1578 EL_SP_BUGGY_BASE_ACTIVE,
1585 static int ep_bd_element[] =
1614 static int ep_sp_element[] =
1622 EL_SP_HARDWARE_GRAY,
1630 EL_SP_GRAVITY_PORT_RIGHT,
1631 EL_SP_GRAVITY_PORT_DOWN,
1632 EL_SP_GRAVITY_PORT_LEFT,
1633 EL_SP_GRAVITY_PORT_UP,
1638 EL_SP_PORT_VERTICAL,
1639 EL_SP_PORT_HORIZONTAL,
1645 EL_SP_HARDWARE_BASE_1,
1646 EL_SP_HARDWARE_GREEN,
1647 EL_SP_HARDWARE_BLUE,
1649 EL_SP_HARDWARE_YELLOW,
1650 EL_SP_HARDWARE_BASE_2,
1651 EL_SP_HARDWARE_BASE_3,
1652 EL_SP_HARDWARE_BASE_4,
1653 EL_SP_HARDWARE_BASE_5,
1654 EL_SP_HARDWARE_BASE_6,
1657 /* additional elements that appeared in newer Supaplex levels */
1659 /* more than one murphy in a level results in an inactive clone */
1664 static int ep_sb_element[] =
1669 EL_SOKOBAN_FIELD_EMPTY,
1670 EL_SOKOBAN_FIELD_FULL,
1672 EL_INVISIBLE_STEELWALL,
1676 static int ep_gem[] =
1687 static int ep_food_dark_yamyam[] =
1714 static int ep_food_penguin[] =
1727 static int ep_food_pig[] =
1738 static int ep_historic_wall[] =
1763 EL_EXPANDABLE_WALL_HORIZONTAL,
1764 EL_EXPANDABLE_WALL_VERTICAL,
1765 EL_EXPANDABLE_WALL_ANY,
1766 EL_EXPANDABLE_WALL_GROWING,
1773 EL_SP_HARDWARE_GRAY,
1774 EL_SP_HARDWARE_GREEN,
1775 EL_SP_HARDWARE_BLUE,
1777 EL_SP_HARDWARE_YELLOW,
1778 EL_SP_HARDWARE_BASE_1,
1779 EL_SP_HARDWARE_BASE_2,
1780 EL_SP_HARDWARE_BASE_3,
1781 EL_SP_HARDWARE_BASE_4,
1782 EL_SP_HARDWARE_BASE_5,
1783 EL_SP_HARDWARE_BASE_6,
1785 EL_SP_TERMINAL_ACTIVE,
1788 EL_INVISIBLE_STEELWALL,
1789 EL_INVISIBLE_STEELWALL_ACTIVE,
1791 EL_INVISIBLE_WALL_ACTIVE,
1792 EL_STEELWALL_SLANTED,
1808 static int ep_historic_solid[] =
1812 EL_EXPANDABLE_WALL_HORIZONTAL,
1813 EL_EXPANDABLE_WALL_VERTICAL,
1814 EL_EXPANDABLE_WALL_ANY,
1827 EL_QUICKSAND_FILLING,
1828 EL_QUICKSAND_EMPTYING,
1830 EL_MAGIC_WALL_ACTIVE,
1831 EL_MAGIC_WALL_EMPTYING,
1832 EL_MAGIC_WALL_FILLING,
1836 EL_BD_MAGIC_WALL_ACTIVE,
1837 EL_BD_MAGIC_WALL_EMPTYING,
1838 EL_BD_MAGIC_WALL_FULL,
1839 EL_BD_MAGIC_WALL_FILLING,
1840 EL_BD_MAGIC_WALL_DEAD,
1849 EL_SP_TERMINAL_ACTIVE,
1853 EL_INVISIBLE_WALL_ACTIVE,
1854 EL_SWITCHGATE_SWITCH_UP,
1855 EL_SWITCHGATE_SWITCH_DOWN,
1857 EL_TIMEGATE_SWITCH_ACTIVE,
1869 /* the following elements are a direct copy of "indestructible" elements,
1870 except "EL_ACID", which is "indestructible", but not "solid"! */
1875 EL_ACID_POOL_TOPLEFT,
1876 EL_ACID_POOL_TOPRIGHT,
1877 EL_ACID_POOL_BOTTOMLEFT,
1878 EL_ACID_POOL_BOTTOM,
1879 EL_ACID_POOL_BOTTOMRIGHT,
1880 EL_SP_HARDWARE_GRAY,
1881 EL_SP_HARDWARE_GREEN,
1882 EL_SP_HARDWARE_BLUE,
1884 EL_SP_HARDWARE_YELLOW,
1885 EL_SP_HARDWARE_BASE_1,
1886 EL_SP_HARDWARE_BASE_2,
1887 EL_SP_HARDWARE_BASE_3,
1888 EL_SP_HARDWARE_BASE_4,
1889 EL_SP_HARDWARE_BASE_5,
1890 EL_SP_HARDWARE_BASE_6,
1891 EL_INVISIBLE_STEELWALL,
1892 EL_INVISIBLE_STEELWALL_ACTIVE,
1893 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1894 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1895 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1896 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1897 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1898 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1899 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1900 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1901 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1902 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1903 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1904 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1906 EL_LIGHT_SWITCH_ACTIVE,
1907 EL_SIGN_EXCLAMATION,
1908 EL_SIGN_RADIOACTIVITY,
1919 EL_STEELWALL_SLANTED,
1942 EL_SWITCHGATE_OPENING,
1943 EL_SWITCHGATE_CLOSED,
1944 EL_SWITCHGATE_CLOSING,
1946 EL_TIMEGATE_OPENING,
1948 EL_TIMEGATE_CLOSING,
1952 EL_TUBE_VERTICAL_LEFT,
1953 EL_TUBE_VERTICAL_RIGHT,
1954 EL_TUBE_HORIZONTAL_UP,
1955 EL_TUBE_HORIZONTAL_DOWN,
1963 static int ep_classic_enemy[] =
1979 static int ep_belt[] =
1981 EL_CONVEYOR_BELT_1_LEFT,
1982 EL_CONVEYOR_BELT_1_MIDDLE,
1983 EL_CONVEYOR_BELT_1_RIGHT,
1984 EL_CONVEYOR_BELT_2_LEFT,
1985 EL_CONVEYOR_BELT_2_MIDDLE,
1986 EL_CONVEYOR_BELT_2_RIGHT,
1987 EL_CONVEYOR_BELT_3_LEFT,
1988 EL_CONVEYOR_BELT_3_MIDDLE,
1989 EL_CONVEYOR_BELT_3_RIGHT,
1990 EL_CONVEYOR_BELT_4_LEFT,
1991 EL_CONVEYOR_BELT_4_MIDDLE,
1992 EL_CONVEYOR_BELT_4_RIGHT,
1996 static int ep_belt_active[] =
1998 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
1999 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2000 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2001 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2002 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2003 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2004 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2005 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2006 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2007 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2008 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2009 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2013 static int ep_belt_switch[] =
2015 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2016 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2017 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2018 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2019 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2020 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2021 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2022 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2023 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2024 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2025 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2026 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2030 static int ep_tube[] =
2037 EL_TUBE_HORIZONTAL_UP,
2038 EL_TUBE_HORIZONTAL_DOWN,
2040 EL_TUBE_VERTICAL_LEFT,
2041 EL_TUBE_VERTICAL_RIGHT,
2046 static int ep_keygate[] =
2067 static int ep_amoeboid[] =
2077 static int ep_amoebalive[] =
2086 static int ep_has_content[] =
2096 static int ep_active_bomb[] =
2099 EL_DYNABOMB_PLAYER_1_ACTIVE,
2100 EL_DYNABOMB_PLAYER_2_ACTIVE,
2101 EL_DYNABOMB_PLAYER_3_ACTIVE,
2102 EL_DYNABOMB_PLAYER_4_ACTIVE,
2103 EL_SP_DISK_RED_ACTIVE,
2107 static int ep_inactive[] =
2144 EL_INVISIBLE_STEELWALL,
2152 EL_WALL_EMERALD_YELLOW,
2153 EL_DYNABOMB_INCREASE_NUMBER,
2154 EL_DYNABOMB_INCREASE_SIZE,
2155 EL_DYNABOMB_INCREASE_POWER,
2157 EL_SOKOBAN_FIELD_EMPTY,
2158 EL_SOKOBAN_FIELD_FULL,
2159 EL_WALL_EMERALD_RED,
2160 EL_WALL_EMERALD_PURPLE,
2161 EL_ACID_POOL_TOPLEFT,
2162 EL_ACID_POOL_TOPRIGHT,
2163 EL_ACID_POOL_BOTTOMLEFT,
2164 EL_ACID_POOL_BOTTOM,
2165 EL_ACID_POOL_BOTTOMRIGHT,
2169 EL_BD_MAGIC_WALL_DEAD,
2170 EL_AMOEBA_TO_DIAMOND,
2178 EL_SP_GRAVITY_PORT_RIGHT,
2179 EL_SP_GRAVITY_PORT_DOWN,
2180 EL_SP_GRAVITY_PORT_LEFT,
2181 EL_SP_GRAVITY_PORT_UP,
2182 EL_SP_PORT_HORIZONTAL,
2183 EL_SP_PORT_VERTICAL,
2192 EL_SP_HARDWARE_GRAY,
2193 EL_SP_HARDWARE_GREEN,
2194 EL_SP_HARDWARE_BLUE,
2196 EL_SP_HARDWARE_YELLOW,
2197 EL_SP_HARDWARE_BASE_1,
2198 EL_SP_HARDWARE_BASE_2,
2199 EL_SP_HARDWARE_BASE_3,
2200 EL_SP_HARDWARE_BASE_4,
2201 EL_SP_HARDWARE_BASE_5,
2202 EL_SP_HARDWARE_BASE_6,
2203 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2204 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2205 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2206 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2207 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2208 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2209 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2210 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2211 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2212 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2213 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2214 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2215 EL_SIGN_EXCLAMATION,
2216 EL_SIGN_RADIOACTIVITY,
2227 EL_STEELWALL_SLANTED,
2247 } element_properties[] =
2249 { ep_diggable, EP_DIGGABLE },
2250 { ep_collectible, EP_COLLECTIBLE },
2251 { ep_indestructible, EP_INDESTRUCTIBLE },
2252 { ep_slippery, EP_SLIPPERY },
2253 { ep_can_fall, EP_CAN_FALL },
2254 { ep_can_smash, EP_CAN_SMASH },
2255 { ep_walkable_over, EP_WALKABLE_OVER },
2256 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2257 { ep_walkable_under, EP_WALKABLE_UNDER },
2258 { ep_passable_over, EP_PASSABLE_OVER },
2259 { ep_passable_inside, EP_PASSABLE_INSIDE },
2260 { ep_passable_under, EP_PASSABLE_UNDER },
2261 { ep_pushable, EP_PUSHABLE },
2263 { ep_player, EP_PLAYER },
2264 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2265 { ep_can_move, EP_CAN_MOVE },
2266 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2267 { ep_switchable, EP_SWITCHABLE },
2268 { ep_dont_touch, EP_DONT_TOUCH },
2269 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2270 { ep_dont_run_into, EP_DONT_RUN_INTO },
2271 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2272 { ep_bd_element, EP_BD_ELEMENT },
2273 { ep_sp_element, EP_SP_ELEMENT },
2274 { ep_sb_element, EP_SB_ELEMENT },
2276 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2277 { ep_food_penguin, EP_FOOD_PENGUIN },
2278 { ep_food_pig, EP_FOOD_PIG },
2279 { ep_historic_wall, EP_HISTORIC_WALL },
2280 { ep_historic_solid, EP_HISTORIC_SOLID },
2281 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2282 { ep_belt, EP_BELT },
2283 { ep_belt_active, EP_BELT_ACTIVE },
2284 { ep_belt_switch, EP_BELT_SWITCH },
2285 { ep_tube, EP_TUBE },
2286 { ep_keygate, EP_KEYGATE },
2287 { ep_amoeboid, EP_AMOEBOID },
2288 { ep_amoebalive, EP_AMOEBALIVE },
2289 { ep_has_content, EP_HAS_CONTENT },
2290 { ep_active_bomb, EP_ACTIVE_BOMB },
2291 { ep_inactive, EP_INACTIVE },
2296 static int copy_properties[][5] =
2300 EL_BUG_LEFT, EL_BUG_RIGHT,
2301 EL_BUG_UP, EL_BUG_DOWN
2305 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2306 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2310 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2311 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2315 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2316 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2320 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2321 EL_PACMAN_UP, EL_PACMAN_DOWN
2331 /* always start with reliable default values (element has no properties) */
2332 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2333 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2334 SET_PROPERTY(i, j, FALSE);
2336 /* set all base element properties from above array definitions */
2337 for (i=0; element_properties[i].elements != NULL; i++)
2338 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2339 SET_PROPERTY((element_properties[i].elements)[j],
2340 element_properties[i].property, TRUE);
2342 /* copy properties to some elements that are only stored in level file */
2343 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2344 for (j=0; copy_properties[j][0] != -1; j++)
2345 if (HAS_PROPERTY(copy_properties[j][0], i))
2346 for (k=1; k<=4; k++)
2347 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2350 void InitElementPropertiesEngine(int engine_version)
2353 static int active_properties[] =
2358 EP_DONT_COLLIDE_WITH,
2362 EP_CAN_PASS_MAGIC_WALL,
2367 EP_CAN_EXPLODE_BY_FIRE,
2380 EP_EM_SLIPPERY_WALL,
2385 static int no_wall_properties[] =
2390 EP_DONT_COLLIDE_WITH,
2395 EP_FOOD_DARK_YAMYAM,
2413 InitElementPropertiesStatic();
2416 /* set all special, combined or engine dependant element properties */
2417 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2420 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2421 SET_PROPERTY(i, j, FALSE);
2424 /* ---------- INACTIVE ------------------------------------------------- */
2425 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2426 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2428 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2429 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2430 IS_WALKABLE_INSIDE(i) ||
2431 IS_WALKABLE_UNDER(i)));
2433 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2434 IS_PASSABLE_INSIDE(i) ||
2435 IS_PASSABLE_UNDER(i)));
2437 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2438 IS_PASSABLE_OVER(i)));
2440 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2441 IS_PASSABLE_INSIDE(i)));
2443 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2444 IS_PASSABLE_UNDER(i)));
2446 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2449 /* ---------- SNAPPABLE ------------------------------------------------ */
2450 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2451 IS_COLLECTIBLE(i) ||
2455 /* ---------- WALL ----------------------------------------------------- */
2456 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2458 for (j=0; no_wall_properties[j] != -1; j++)
2459 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2460 i >= EL_FIRST_RUNTIME_UNREAL)
2461 SET_PROPERTY(i, EP_WALL, FALSE);
2463 if (IS_HISTORIC_WALL(i))
2464 SET_PROPERTY(i, EP_WALL, TRUE);
2466 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2467 if (engine_version < VERSION_IDENT(2,2,0))
2468 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2470 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2472 !IS_COLLECTIBLE(i)));
2474 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2476 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2477 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2479 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2480 IS_INDESTRUCTIBLE(i)));
2482 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2484 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2485 else if (engine_version < VERSION_IDENT(2,2,0))
2486 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2488 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2489 !IS_WALKABLE_OVER(i) &&
2490 !IS_WALKABLE_UNDER(i)));
2492 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
2493 if (DONT_TOUCH(i)) /* dont_touch => dont_collide_with */
2494 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2496 /* ---------- DONT_RUN_INTO -------------------------------------------- */
2497 if (DONT_COLLIDE_WITH(i)) /* dont_collide_with => dont_run_into */
2498 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2502 /* determine inactive elements (used for engine main loop optimization) */
2503 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2505 boolean active = FALSE;
2507 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2509 if (HAS_PROPERTY(i, j))
2515 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2520 /* dynamically adjust element properties according to game engine version */
2522 static int ep_em_slippery_wall[] =
2527 EL_EXPANDABLE_WALL_HORIZONTAL,
2528 EL_EXPANDABLE_WALL_VERTICAL,
2529 EL_EXPANDABLE_WALL_ANY,
2533 /* special EM style gems behaviour */
2534 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2535 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2536 level.em_slippery_gems);
2538 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2539 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2540 (level.em_slippery_gems &&
2541 engine_version > VERSION_IDENT(2,0,1)));
2544 /* dynamically adjust element properties according to game engine version */
2546 if (engine_version < RELEASE_IDENT(2,2,0,7))
2549 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2551 int element = EL_CUSTOM_START + i;
2553 element_info[element].push_delay_fixed = 2;
2554 element_info[element].push_delay_random = 8;
2559 static void InitGlobal()
2561 global.autoplay_leveldir = NULL;
2563 global.frames_per_second = 0;
2564 global.fps_slowdown = FALSE;
2565 global.fps_slowdown_factor = 1;
2568 void Execute_Command(char *command)
2570 if (strcmp(command, "print graphicsinfo.conf") == 0)
2574 printf("# You can configure additional/alternative image files here.\n");
2575 printf("# (The images below are default and therefore commented out.)\n");
2577 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2579 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2582 for (i=0; image_config[i].token != NULL; i++)
2584 getFormattedSetupEntry(image_config[i].token,
2585 image_config[i].value));
2589 else if (strcmp(command, "print soundsinfo.conf") == 0)
2593 printf("# You can configure additional/alternative sound files here.\n");
2594 printf("# (The sounds below are default and therefore commented out.)\n");
2596 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2598 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2601 for (i=0; sound_config[i].token != NULL; i++)
2603 getFormattedSetupEntry(sound_config[i].token,
2604 sound_config[i].value));
2608 else if (strcmp(command, "print musicinfo.conf") == 0)
2610 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2612 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2614 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2618 else if (strncmp(command, "dump level ", 11) == 0)
2620 char *filename = &command[11];
2622 if (access(filename, F_OK) != 0)
2623 Error(ERR_EXIT, "cannot open file '%s'", filename);
2625 LoadLevelFromFilename(filename);
2630 else if (strncmp(command, "dump tape ", 10) == 0)
2632 char *filename = &command[10];
2634 if (access(filename, F_OK) != 0)
2635 Error(ERR_EXIT, "cannot open file '%s'", filename);
2637 LoadTapeFromFilename(filename);
2642 else if (strncmp(command, "autoplay ", 9) == 0)
2644 char *str_copy = getStringCopy(&command[9]);
2645 char *str_ptr = strchr(str_copy, ' ');
2647 global.autoplay_leveldir = str_copy;
2648 global.autoplay_level_nr = -1;
2650 if (str_ptr != NULL)
2652 *str_ptr++ = '\0'; /* terminate leveldir string */
2653 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2658 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2662 static void InitSetup()
2664 LoadSetup(); /* global setup info */
2666 /* set some options from setup file */
2668 if (setup.options.verbose)
2669 options.verbose = TRUE;
2672 static void InitPlayerInfo()
2676 /* choose default local player */
2677 local_player = &stored_player[0];
2679 for (i=0; i<MAX_PLAYERS; i++)
2680 stored_player[i].connected = FALSE;
2682 local_player->connected = TRUE;
2685 static void InitArtworkInfo()
2690 static char *get_element_class_token(int element)
2692 char *element_class_name = element_info[element].class_name;
2693 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2695 sprintf(element_class_token, "[%s]", element_class_name);
2697 return element_class_token;
2700 static void InitArtworkConfig()
2702 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2703 static char *sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS + 1];
2704 static char *action_id_suffix[NUM_ACTIONS + 1];
2705 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2706 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2707 static char *dummy[1] = { NULL };
2708 static char *ignore_generic_tokens[] =
2714 static char **ignore_image_tokens, **ignore_sound_tokens;
2715 int num_ignore_generic_tokens;
2716 int num_ignore_image_tokens, num_ignore_sound_tokens;
2719 /* dynamically determine list of generic tokens to be ignored */
2720 num_ignore_generic_tokens = 0;
2721 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2722 num_ignore_generic_tokens++;
2724 /* dynamically determine list of image tokens to be ignored */
2725 num_ignore_image_tokens = num_ignore_generic_tokens;
2726 for (i=0; image_config_vars[i].token != NULL; i++)
2727 num_ignore_image_tokens++;
2728 ignore_image_tokens =
2729 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2730 for (i=0; i < num_ignore_generic_tokens; i++)
2731 ignore_image_tokens[i] = ignore_generic_tokens[i];
2732 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2733 ignore_image_tokens[num_ignore_generic_tokens + i] =
2734 image_config_vars[i].token;
2735 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2737 /* dynamically determine list of sound tokens to be ignored */
2738 num_ignore_sound_tokens = num_ignore_generic_tokens;
2739 ignore_sound_tokens =
2740 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2741 for (i=0; i < num_ignore_generic_tokens; i++)
2742 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2743 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2745 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2746 image_id_prefix[i] = element_info[i].token_name;
2747 for (i=0; i<NUM_FONTS; i++)
2748 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2749 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2751 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2752 sound_id_prefix[i] = element_info[i].token_name;
2753 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2754 sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_element_class_token(i);
2755 sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS] = NULL;
2757 for (i=0; i<NUM_ACTIONS; i++)
2758 action_id_suffix[i] = element_action_info[i].suffix;
2759 action_id_suffix[NUM_ACTIONS] = NULL;
2761 for (i=0; i<NUM_DIRECTIONS; i++)
2762 direction_id_suffix[i] = element_direction_info[i].suffix;
2763 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2765 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2766 special_id_suffix[i] = special_suffix_info[i].suffix;
2767 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2769 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2770 image_id_prefix, action_id_suffix, direction_id_suffix,
2771 special_id_suffix, ignore_image_tokens);
2772 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2773 sound_id_prefix, action_id_suffix, dummy,
2774 special_id_suffix, ignore_sound_tokens);
2777 static void InitMixer()
2785 char *filename_font_initial = NULL;
2786 Bitmap *bitmap_font_initial = NULL;
2789 /* determine settings for initial font (for displaying startup messages) */
2790 for (i=0; image_config[i].token != NULL; i++)
2792 for (j=0; j < NUM_INITIAL_FONTS; j++)
2794 char font_token[128];
2797 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2798 len_font_token = strlen(font_token);
2800 if (strcmp(image_config[i].token, font_token) == 0)
2801 filename_font_initial = image_config[i].value;
2802 else if (strlen(image_config[i].token) > len_font_token &&
2803 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2805 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2806 font_initial[j].src_x = atoi(image_config[i].value);
2807 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2808 font_initial[j].src_y = atoi(image_config[i].value);
2809 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2810 font_initial[j].width = atoi(image_config[i].value);
2811 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2812 font_initial[j].height = atoi(image_config[i].value);
2817 for (j=0; j < NUM_INITIAL_FONTS; j++)
2819 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2820 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2823 if (filename_font_initial == NULL) /* should not happen */
2824 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2826 /* create additional image buffers for double-buffering */
2827 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2828 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2830 /* initialize screen properties */
2831 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2832 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2834 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2835 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2836 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2838 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2840 for (j=0; j < NUM_INITIAL_FONTS; j++)
2841 font_initial[j].bitmap = bitmap_font_initial;
2843 InitFontGraphicInfo();
2845 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2846 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2848 DrawInitText("Loading graphics:", 120, FC_GREEN);
2850 InitTileClipmasks();
2853 void InitGfxBackground()
2857 drawto = backbuffer;
2858 fieldbuffer = bitmap_db_field;
2859 SetDrawtoField(DRAW_BACKBUFFER);
2861 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2862 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2863 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2864 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2866 for (x=0; x<MAX_BUF_XSIZE; x++)
2867 for (y=0; y<MAX_BUF_YSIZE; y++)
2870 redraw_mask = REDRAW_ALL;
2873 static void InitLevelInfo()
2875 LoadLevelInfo(); /* global level info */
2876 LoadLevelSetup_LastSeries(); /* last played series info */
2877 LoadLevelSetup_SeriesInfo(); /* last played level info */
2880 void InitLevelArtworkInfo()
2882 LoadLevelArtworkInfo();
2885 static void InitImages()
2887 ReloadCustomImages();
2889 LoadCustomElementDescriptions();
2890 LoadSpecialMenuDesignSettings();
2892 ReinitializeGraphics();
2895 static void InitSound()
2897 InitReloadCustomSounds(artwork.snd_current->identifier);
2898 ReinitializeSounds();
2901 static void InitMusic()
2903 InitReloadCustomMusic(artwork.mus_current->identifier);
2904 ReinitializeMusic();
2907 void InitNetworkServer()
2909 #if defined(PLATFORM_UNIX)
2913 if (!options.network)
2916 #if defined(PLATFORM_UNIX)
2917 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
2919 if (!ConnectToServer(options.server_host, options.server_port))
2920 Error(ERR_EXIT, "cannot connect to network game server");
2922 SendToServer_PlayerName(setup.player_name);
2923 SendToServer_ProtocolVersion();
2926 SendToServer_NrWanted(nr_wanted);
2930 void ReloadCustomArtwork()
2932 static char *leveldir_current_identifier = NULL;
2933 static boolean last_override_level_graphics = FALSE;
2934 static boolean last_override_level_sounds = FALSE;
2935 static boolean last_override_level_music = FALSE;
2936 /* identifier for new artwork; default: artwork configured in setup */
2937 char *gfx_new_identifier = artwork.gfx_current->identifier;
2938 char *snd_new_identifier = artwork.snd_current->identifier;
2939 char *mus_new_identifier = artwork.mus_current->identifier;
2940 boolean redraw_screen = FALSE;
2942 if (leveldir_current_identifier == NULL)
2943 leveldir_current_identifier = leveldir_current->identifier;
2946 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
2947 leveldir_current->graphics_set);
2948 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
2949 leveldir_current->identifier);
2953 printf("graphics --> '%s' ('%s')\n",
2954 artwork.gfx_current_identifier, artwork.gfx_current->filename);
2955 printf("sounds --> '%s' ('%s')\n",
2956 artwork.snd_current_identifier, artwork.snd_current->filename);
2957 printf("music --> '%s' ('%s')\n",
2958 artwork.mus_current_identifier, artwork.mus_current->filename);
2961 /* leveldir_current may be invalid (level group, parent link) */
2962 if (!validLevelSeries(leveldir_current))
2965 /* when a new level series was selected, check if there was a change
2966 in custom artwork stored in level series directory */
2967 if (leveldir_current_identifier != leveldir_current->identifier)
2969 char *identifier_old = leveldir_current_identifier;
2970 char *identifier_new = leveldir_current->identifier;
2972 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
2973 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
2974 gfx_new_identifier = identifier_new;
2975 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
2976 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
2977 snd_new_identifier = identifier_new;
2978 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
2979 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
2980 mus_new_identifier = identifier_new;
2982 leveldir_current_identifier = leveldir_current->identifier;
2985 /* custom level artwork configured in level series configuration file
2986 always overrides custom level artwork stored in level series directory
2987 and (level independant) custom artwork configured in setup menue */
2988 if (leveldir_current->graphics_set != NULL)
2989 gfx_new_identifier = leveldir_current->graphics_set;
2990 if (leveldir_current->sounds_set != NULL)
2991 snd_new_identifier = leveldir_current->sounds_set;
2992 if (leveldir_current->music_set != NULL)
2993 mus_new_identifier = leveldir_current->music_set;
2995 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
2996 last_override_level_graphics != setup.override_level_graphics)
2999 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3000 artwork.gfx_current_identifier,
3001 artwork.gfx_current->identifier,
3002 gfx_new_identifier);
3005 setLevelArtworkDir(artwork.gfx_first);
3007 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3011 FreeTileClipmasks();
3012 InitTileClipmasks();
3014 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3015 last_override_level_graphics = setup.override_level_graphics;
3017 redraw_screen = TRUE;
3020 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3021 last_override_level_sounds != setup.override_level_sounds)
3024 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3025 artwork.snd_current_identifier,
3026 artwork.snd_current->identifier,
3027 snd_new_identifier);
3030 /* set artwork path to send it to the sound server process */
3031 setLevelArtworkDir(artwork.snd_first);
3033 InitReloadCustomSounds(snd_new_identifier);
3034 ReinitializeSounds();
3036 artwork.snd_current_identifier = artwork.snd_current->identifier;
3037 last_override_level_sounds = setup.override_level_sounds;
3039 redraw_screen = TRUE;
3042 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3043 last_override_level_music != setup.override_level_music)
3045 /* set artwork path to send it to the sound server process */
3046 setLevelArtworkDir(artwork.mus_first);
3048 InitReloadCustomMusic(mus_new_identifier);
3049 ReinitializeMusic();
3051 artwork.mus_current_identifier = artwork.mus_current->identifier;
3052 last_override_level_music = setup.override_level_music;
3054 redraw_screen = TRUE;
3059 InitGfxBackground();
3061 /* force redraw of (open or closed) door graphics */
3062 SetDoorState(DOOR_OPEN_ALL);
3063 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3067 void KeyboardAutoRepeatOffUnlessAutoplay()
3069 if (global.autoplay_leveldir == NULL)
3070 KeyboardAutoRepeatOff();
3074 /* ========================================================================= */
3076 /* ========================================================================= */
3080 InitGlobal(); /* initialize some global variables */
3082 if (options.execute_command)
3083 Execute_Command(options.execute_command);
3085 if (options.serveronly)
3087 #if defined(PLATFORM_UNIX)
3088 NetworkServer(options.server_port, options.serveronly);
3090 Error(ERR_WARN, "networking only supported in Unix version");
3092 exit(0); /* never reached */
3098 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3099 InitArtworkConfig(); /* needed before forking sound child process */
3104 InitRND(NEW_RANDOMIZE);
3105 InitSimpleRND(NEW_RANDOMIZE);
3110 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3113 InitEventFilter(FilterMouseMotionEvents);
3115 InitElementPropertiesStatic();
3120 InitLevelArtworkInfo();
3122 InitImages(); /* needs to know current level directory */
3123 InitSound(); /* needs to know current level directory */
3124 InitMusic(); /* needs to know current level directory */
3126 InitGfxBackground();
3128 if (global.autoplay_leveldir)
3134 game_status = GAME_MODE_MAIN;
3138 InitNetworkServer();
3141 void CloseAllAndExit(int exit_value)
3146 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3149 FreeTileClipmasks();
3151 CloseVideoDisplay();
3152 ClosePlatformDependantStuff();