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_dont_run_into[] =
1148 /* same elements as in 'ep_dont_touch' */
1154 /* same elements as in 'ep_dont_collide_with' */
1166 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1168 EL_SP_BUGGY_BASE_ACTIVE,
1175 static int ep_dont_collide_with[] =
1177 /* same elements as in 'ep_dont_touch' */
1193 static int ep_dont_touch[] =
1202 static int ep_indestructible[] =
1206 EL_ACID_POOL_TOPLEFT,
1207 EL_ACID_POOL_TOPRIGHT,
1208 EL_ACID_POOL_BOTTOMLEFT,
1209 EL_ACID_POOL_BOTTOM,
1210 EL_ACID_POOL_BOTTOMRIGHT,
1211 EL_SP_HARDWARE_GRAY,
1212 EL_SP_HARDWARE_GREEN,
1213 EL_SP_HARDWARE_BLUE,
1215 EL_SP_HARDWARE_YELLOW,
1216 EL_SP_HARDWARE_BASE_1,
1217 EL_SP_HARDWARE_BASE_2,
1218 EL_SP_HARDWARE_BASE_3,
1219 EL_SP_HARDWARE_BASE_4,
1220 EL_SP_HARDWARE_BASE_5,
1221 EL_SP_HARDWARE_BASE_6,
1222 EL_INVISIBLE_STEELWALL,
1223 EL_INVISIBLE_STEELWALL_ACTIVE,
1224 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1225 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1226 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1227 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1228 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1229 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1230 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1231 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1232 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1233 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1234 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1235 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1237 EL_LIGHT_SWITCH_ACTIVE,
1238 EL_SIGN_EXCLAMATION,
1239 EL_SIGN_RADIOACTIVITY,
1250 EL_STEELWALL_SLANTED,
1273 EL_SWITCHGATE_OPENING,
1274 EL_SWITCHGATE_CLOSED,
1275 EL_SWITCHGATE_CLOSING,
1277 EL_TIMEGATE_OPENING,
1279 EL_TIMEGATE_CLOSING,
1283 EL_TUBE_VERTICAL_LEFT,
1284 EL_TUBE_VERTICAL_RIGHT,
1285 EL_TUBE_HORIZONTAL_UP,
1286 EL_TUBE_HORIZONTAL_DOWN,
1294 static int ep_slippery[] =
1308 EL_ROBOT_WHEEL_ACTIVE,
1314 EL_ACID_POOL_TOPLEFT,
1315 EL_ACID_POOL_TOPRIGHT,
1325 EL_STEELWALL_SLANTED,
1331 static int ep_can_change[] =
1336 static int ep_can_move[] =
1358 static int ep_can_fall[] =
1373 EL_BD_MAGIC_WALL_FULL,
1386 static int ep_can_smash_friends[] =
1411 static int ep_can_smash_enemies[] =
1419 static int ep_can_smash_explosives[] =
1427 static int ep_can_explode_by_fire[] =
1429 /* same elements as in 'ep_can_explode_impact' */
1434 /* same elements as in 'ep_can_explode_smashed' */
1443 EL_DYNABOMB_PLAYER_1_ACTIVE,
1444 EL_DYNABOMB_PLAYER_2_ACTIVE,
1445 EL_DYNABOMB_PLAYER_3_ACTIVE,
1446 EL_DYNABOMB_PLAYER_4_ACTIVE,
1447 EL_DYNABOMB_INCREASE_NUMBER,
1448 EL_DYNABOMB_INCREASE_SIZE,
1449 EL_DYNABOMB_INCREASE_POWER,
1450 EL_SP_DISK_RED_ACTIVE,
1460 static int ep_can_explode_smashed[] =
1462 /* same elements as in 'ep_can_explode_impact' */
1475 static int ep_can_explode_impact[] =
1483 static int ep_walkable_over[] =
1487 EL_SOKOBAN_FIELD_EMPTY,
1501 static int ep_walkable_inside[] =
1506 EL_TUBE_VERTICAL_LEFT,
1507 EL_TUBE_VERTICAL_RIGHT,
1508 EL_TUBE_HORIZONTAL_UP,
1509 EL_TUBE_HORIZONTAL_DOWN,
1517 static int ep_walkable_under[] =
1522 static int ep_passable_over[] =
1537 static int ep_passable_inside[] =
1543 EL_SP_PORT_HORIZONTAL,
1544 EL_SP_PORT_VERTICAL,
1546 EL_SP_GRAVITY_PORT_LEFT,
1547 EL_SP_GRAVITY_PORT_RIGHT,
1548 EL_SP_GRAVITY_PORT_UP,
1549 EL_SP_GRAVITY_PORT_DOWN,
1553 static int ep_passable_under[] =
1558 static int ep_pushable[] =
1570 EL_SOKOBAN_FIELD_FULL,
1577 static int ep_can_be_crumbled[] =
1586 static int ep_player[] =
1595 static int ep_can_pass_magic_wall[] =
1608 static int ep_switchable[] =
1612 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1613 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1614 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1615 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1616 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1617 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1618 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1619 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1620 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1621 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1622 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1623 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1624 EL_SWITCHGATE_SWITCH_UP,
1625 EL_SWITCHGATE_SWITCH_DOWN,
1627 EL_LIGHT_SWITCH_ACTIVE,
1629 EL_BALLOON_SWITCH_LEFT,
1630 EL_BALLOON_SWITCH_RIGHT,
1631 EL_BALLOON_SWITCH_UP,
1632 EL_BALLOON_SWITCH_DOWN,
1633 EL_BALLOON_SWITCH_ANY,
1639 static int ep_bd_element[] =
1668 static int ep_sp_element[] =
1676 EL_SP_HARDWARE_GRAY,
1684 EL_SP_GRAVITY_PORT_RIGHT,
1685 EL_SP_GRAVITY_PORT_DOWN,
1686 EL_SP_GRAVITY_PORT_LEFT,
1687 EL_SP_GRAVITY_PORT_UP,
1692 EL_SP_PORT_VERTICAL,
1693 EL_SP_PORT_HORIZONTAL,
1699 EL_SP_HARDWARE_BASE_1,
1700 EL_SP_HARDWARE_GREEN,
1701 EL_SP_HARDWARE_BLUE,
1703 EL_SP_HARDWARE_YELLOW,
1704 EL_SP_HARDWARE_BASE_2,
1705 EL_SP_HARDWARE_BASE_3,
1706 EL_SP_HARDWARE_BASE_4,
1707 EL_SP_HARDWARE_BASE_5,
1708 EL_SP_HARDWARE_BASE_6,
1711 /* additional elements that appeared in newer Supaplex levels */
1713 /* more than one murphy in a level results in an inactive clone */
1718 static int ep_sb_element[] =
1723 EL_SOKOBAN_FIELD_EMPTY,
1724 EL_SOKOBAN_FIELD_FULL,
1726 EL_INVISIBLE_STEELWALL,
1730 static int ep_gem[] =
1741 static int ep_food_dark_yamyam[] =
1768 static int ep_food_penguin[] =
1781 static int ep_food_pig[] =
1792 static int ep_historic_wall[] =
1817 EL_EXPANDABLE_WALL_HORIZONTAL,
1818 EL_EXPANDABLE_WALL_VERTICAL,
1819 EL_EXPANDABLE_WALL_ANY,
1820 EL_EXPANDABLE_WALL_GROWING,
1827 EL_SP_HARDWARE_GRAY,
1828 EL_SP_HARDWARE_GREEN,
1829 EL_SP_HARDWARE_BLUE,
1831 EL_SP_HARDWARE_YELLOW,
1832 EL_SP_HARDWARE_BASE_1,
1833 EL_SP_HARDWARE_BASE_2,
1834 EL_SP_HARDWARE_BASE_3,
1835 EL_SP_HARDWARE_BASE_4,
1836 EL_SP_HARDWARE_BASE_5,
1837 EL_SP_HARDWARE_BASE_6,
1839 EL_SP_TERMINAL_ACTIVE,
1842 EL_INVISIBLE_STEELWALL,
1843 EL_INVISIBLE_STEELWALL_ACTIVE,
1845 EL_INVISIBLE_WALL_ACTIVE,
1846 EL_STEELWALL_SLANTED,
1862 static int ep_historic_solid[] =
1866 EL_EXPANDABLE_WALL_HORIZONTAL,
1867 EL_EXPANDABLE_WALL_VERTICAL,
1868 EL_EXPANDABLE_WALL_ANY,
1881 EL_QUICKSAND_FILLING,
1882 EL_QUICKSAND_EMPTYING,
1884 EL_MAGIC_WALL_ACTIVE,
1885 EL_MAGIC_WALL_EMPTYING,
1886 EL_MAGIC_WALL_FILLING,
1890 EL_BD_MAGIC_WALL_ACTIVE,
1891 EL_BD_MAGIC_WALL_EMPTYING,
1892 EL_BD_MAGIC_WALL_FULL,
1893 EL_BD_MAGIC_WALL_FILLING,
1894 EL_BD_MAGIC_WALL_DEAD,
1903 EL_SP_TERMINAL_ACTIVE,
1907 EL_INVISIBLE_WALL_ACTIVE,
1908 EL_SWITCHGATE_SWITCH_UP,
1909 EL_SWITCHGATE_SWITCH_DOWN,
1911 EL_TIMEGATE_SWITCH_ACTIVE,
1923 /* the following elements are a direct copy of "indestructible" elements,
1924 except "EL_ACID", which is "indestructible", but not "solid"! */
1929 EL_ACID_POOL_TOPLEFT,
1930 EL_ACID_POOL_TOPRIGHT,
1931 EL_ACID_POOL_BOTTOMLEFT,
1932 EL_ACID_POOL_BOTTOM,
1933 EL_ACID_POOL_BOTTOMRIGHT,
1934 EL_SP_HARDWARE_GRAY,
1935 EL_SP_HARDWARE_GREEN,
1936 EL_SP_HARDWARE_BLUE,
1938 EL_SP_HARDWARE_YELLOW,
1939 EL_SP_HARDWARE_BASE_1,
1940 EL_SP_HARDWARE_BASE_2,
1941 EL_SP_HARDWARE_BASE_3,
1942 EL_SP_HARDWARE_BASE_4,
1943 EL_SP_HARDWARE_BASE_5,
1944 EL_SP_HARDWARE_BASE_6,
1945 EL_INVISIBLE_STEELWALL,
1946 EL_INVISIBLE_STEELWALL_ACTIVE,
1947 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1948 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1949 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1950 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1951 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1952 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1953 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1954 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1955 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1956 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1957 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1958 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1960 EL_LIGHT_SWITCH_ACTIVE,
1961 EL_SIGN_EXCLAMATION,
1962 EL_SIGN_RADIOACTIVITY,
1973 EL_STEELWALL_SLANTED,
1996 EL_SWITCHGATE_OPENING,
1997 EL_SWITCHGATE_CLOSED,
1998 EL_SWITCHGATE_CLOSING,
2000 EL_TIMEGATE_OPENING,
2002 EL_TIMEGATE_CLOSING,
2006 EL_TUBE_VERTICAL_LEFT,
2007 EL_TUBE_VERTICAL_RIGHT,
2008 EL_TUBE_HORIZONTAL_UP,
2009 EL_TUBE_HORIZONTAL_DOWN,
2017 static int ep_classic_enemy[] =
2033 static int ep_belt[] =
2035 EL_CONVEYOR_BELT_1_LEFT,
2036 EL_CONVEYOR_BELT_1_MIDDLE,
2037 EL_CONVEYOR_BELT_1_RIGHT,
2038 EL_CONVEYOR_BELT_2_LEFT,
2039 EL_CONVEYOR_BELT_2_MIDDLE,
2040 EL_CONVEYOR_BELT_2_RIGHT,
2041 EL_CONVEYOR_BELT_3_LEFT,
2042 EL_CONVEYOR_BELT_3_MIDDLE,
2043 EL_CONVEYOR_BELT_3_RIGHT,
2044 EL_CONVEYOR_BELT_4_LEFT,
2045 EL_CONVEYOR_BELT_4_MIDDLE,
2046 EL_CONVEYOR_BELT_4_RIGHT,
2050 static int ep_belt_active[] =
2052 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2053 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2054 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2055 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2056 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2057 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2058 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2059 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2060 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2061 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2062 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2063 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2067 static int ep_belt_switch[] =
2069 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2070 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2071 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2072 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2073 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2074 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2075 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2076 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2077 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2078 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2079 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2080 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2084 static int ep_tube[] =
2091 EL_TUBE_HORIZONTAL_UP,
2092 EL_TUBE_HORIZONTAL_DOWN,
2094 EL_TUBE_VERTICAL_LEFT,
2095 EL_TUBE_VERTICAL_RIGHT,
2100 static int ep_keygate[] =
2121 static int ep_amoeboid[] =
2131 static int ep_amoebalive[] =
2140 static int ep_has_content[] =
2150 static int ep_active_bomb[] =
2153 EL_DYNABOMB_PLAYER_1_ACTIVE,
2154 EL_DYNABOMB_PLAYER_2_ACTIVE,
2155 EL_DYNABOMB_PLAYER_3_ACTIVE,
2156 EL_DYNABOMB_PLAYER_4_ACTIVE,
2157 EL_SP_DISK_RED_ACTIVE,
2161 static int ep_inactive[] =
2198 EL_INVISIBLE_STEELWALL,
2206 EL_WALL_EMERALD_YELLOW,
2207 EL_DYNABOMB_INCREASE_NUMBER,
2208 EL_DYNABOMB_INCREASE_SIZE,
2209 EL_DYNABOMB_INCREASE_POWER,
2211 EL_SOKOBAN_FIELD_EMPTY,
2212 EL_SOKOBAN_FIELD_FULL,
2213 EL_WALL_EMERALD_RED,
2214 EL_WALL_EMERALD_PURPLE,
2215 EL_ACID_POOL_TOPLEFT,
2216 EL_ACID_POOL_TOPRIGHT,
2217 EL_ACID_POOL_BOTTOMLEFT,
2218 EL_ACID_POOL_BOTTOM,
2219 EL_ACID_POOL_BOTTOMRIGHT,
2223 EL_BD_MAGIC_WALL_DEAD,
2224 EL_AMOEBA_TO_DIAMOND,
2232 EL_SP_GRAVITY_PORT_RIGHT,
2233 EL_SP_GRAVITY_PORT_DOWN,
2234 EL_SP_GRAVITY_PORT_LEFT,
2235 EL_SP_GRAVITY_PORT_UP,
2236 EL_SP_PORT_HORIZONTAL,
2237 EL_SP_PORT_VERTICAL,
2246 EL_SP_HARDWARE_GRAY,
2247 EL_SP_HARDWARE_GREEN,
2248 EL_SP_HARDWARE_BLUE,
2250 EL_SP_HARDWARE_YELLOW,
2251 EL_SP_HARDWARE_BASE_1,
2252 EL_SP_HARDWARE_BASE_2,
2253 EL_SP_HARDWARE_BASE_3,
2254 EL_SP_HARDWARE_BASE_4,
2255 EL_SP_HARDWARE_BASE_5,
2256 EL_SP_HARDWARE_BASE_6,
2257 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2258 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2259 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2260 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2261 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2262 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2263 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2264 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2265 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2266 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2267 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2268 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2269 EL_SIGN_EXCLAMATION,
2270 EL_SIGN_RADIOACTIVITY,
2281 EL_STEELWALL_SLANTED,
2301 } element_properties[] =
2303 { ep_diggable, EP_DIGGABLE },
2304 { ep_collectible, EP_COLLECTIBLE },
2305 { ep_dont_run_into, EP_DONT_RUN_INTO },
2306 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2307 { ep_dont_touch, EP_DONT_TOUCH },
2308 { ep_indestructible, EP_INDESTRUCTIBLE },
2309 { ep_slippery, EP_SLIPPERY },
2310 { ep_can_change, EP_CAN_CHANGE },
2311 { ep_can_move, EP_CAN_MOVE },
2312 { ep_can_fall, EP_CAN_FALL },
2313 { ep_can_smash_friends, EP_CAN_SMASH_FRIENDS },
2314 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2315 { ep_can_smash_explosives, EP_CAN_SMASH_EXPLOSIVES },
2316 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2317 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2318 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2319 { ep_walkable_over, EP_WALKABLE_OVER },
2320 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2321 { ep_walkable_under, EP_WALKABLE_UNDER },
2322 { ep_passable_over, EP_PASSABLE_OVER },
2323 { ep_passable_inside, EP_PASSABLE_INSIDE },
2324 { ep_passable_under, EP_PASSABLE_UNDER },
2325 { ep_pushable, EP_PUSHABLE },
2327 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2329 { ep_player, EP_PLAYER },
2330 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2331 { ep_switchable, EP_SWITCHABLE },
2332 { ep_bd_element, EP_BD_ELEMENT },
2333 { ep_sp_element, EP_SP_ELEMENT },
2334 { ep_sb_element, EP_SB_ELEMENT },
2336 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2337 { ep_food_penguin, EP_FOOD_PENGUIN },
2338 { ep_food_pig, EP_FOOD_PIG },
2339 { ep_historic_wall, EP_HISTORIC_WALL },
2340 { ep_historic_solid, EP_HISTORIC_SOLID },
2341 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2342 { ep_belt, EP_BELT },
2343 { ep_belt_active, EP_BELT_ACTIVE },
2344 { ep_belt_switch, EP_BELT_SWITCH },
2345 { ep_tube, EP_TUBE },
2346 { ep_keygate, EP_KEYGATE },
2347 { ep_amoeboid, EP_AMOEBOID },
2348 { ep_amoebalive, EP_AMOEBALIVE },
2349 { ep_has_content, EP_HAS_CONTENT },
2350 { ep_active_bomb, EP_ACTIVE_BOMB },
2351 { ep_inactive, EP_INACTIVE },
2356 static int copy_properties[][5] =
2360 EL_BUG_LEFT, EL_BUG_RIGHT,
2361 EL_BUG_UP, EL_BUG_DOWN
2365 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2366 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2370 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2371 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2375 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2376 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2380 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2381 EL_PACMAN_UP, EL_PACMAN_DOWN
2391 /* always start with reliable default values (element has no properties) */
2392 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2393 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2394 SET_PROPERTY(i, j, FALSE);
2396 /* set all base element properties from above array definitions */
2397 for (i=0; element_properties[i].elements != NULL; i++)
2398 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2399 SET_PROPERTY((element_properties[i].elements)[j],
2400 element_properties[i].property, TRUE);
2402 /* copy properties to some elements that are only stored in level file */
2403 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2404 for (j=0; copy_properties[j][0] != -1; j++)
2405 if (HAS_PROPERTY(copy_properties[j][0], i))
2406 for (k=1; k<=4; k++)
2407 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2410 void InitElementPropertiesEngine(int engine_version)
2413 static int active_properties[] =
2418 EP_DONT_COLLIDE_WITH,
2422 EP_CAN_PASS_MAGIC_WALL,
2427 EP_CAN_EXPLODE_BY_FIRE,
2440 EP_EM_SLIPPERY_WALL,
2445 static int no_wall_properties[] =
2450 EP_DONT_COLLIDE_WITH,
2453 EP_CAN_SMASH_FRIENDS,
2454 EP_CAN_SMASH_ENEMIES,
2455 EP_CAN_SMASH_EXPLOSIVES,
2462 EP_FOOD_DARK_YAMYAM,
2478 InitElementPropertiesStatic();
2481 /* set all special, combined or engine dependant element properties */
2482 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2485 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2486 SET_PROPERTY(i, j, FALSE);
2489 /* ---------- INACTIVE ------------------------------------------------- */
2490 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2491 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2493 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2494 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2495 IS_WALKABLE_INSIDE(i) ||
2496 IS_WALKABLE_UNDER(i)));
2498 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2499 IS_PASSABLE_INSIDE(i) ||
2500 IS_PASSABLE_UNDER(i)));
2502 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2503 IS_PASSABLE_OVER(i)));
2505 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2506 IS_PASSABLE_INSIDE(i)));
2508 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2509 IS_PASSABLE_UNDER(i)));
2511 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2514 /* ---------- SNAPPABLE ------------------------------------------------ */
2515 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2516 IS_COLLECTIBLE(i) ||
2520 /* ---------- WALL ----------------------------------------------------- */
2521 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2523 for (j=0; no_wall_properties[j] != -1; j++)
2524 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2525 i >= EL_FIRST_RUNTIME_UNREAL)
2526 SET_PROPERTY(i, EP_WALL, FALSE);
2528 if (IS_HISTORIC_WALL(i))
2529 SET_PROPERTY(i, EP_WALL, TRUE);
2531 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2532 if (engine_version < VERSION_IDENT(2,2,0))
2533 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2535 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2537 !IS_COLLECTIBLE(i)));
2539 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2541 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2542 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2544 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2545 IS_INDESTRUCTIBLE(i)));
2547 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2549 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2550 else if (engine_version < VERSION_IDENT(2,2,0))
2551 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2553 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2554 !IS_WALKABLE_OVER(i) &&
2555 !IS_WALKABLE_UNDER(i)));
2557 if (IS_CUSTOM_ELEMENT(i))
2559 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2561 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2562 if (DONT_COLLIDE_WITH(i))
2563 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2565 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_FRIENDS ------------------ */
2566 if (CAN_SMASH_EXPLOSIVES(i))
2567 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2568 if (CAN_SMASH_ENEMIES(i))
2569 SET_PROPERTY(i, EP_CAN_SMASH_FRIENDS, TRUE);
2572 /* ---------- CAN_SMASH ------------------------------------------------ */
2573 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_FRIENDS(i) ||
2574 CAN_SMASH_ENEMIES(i) ||
2575 CAN_SMASH_EXPLOSIVES(i)));
2577 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2578 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2579 CAN_EXPLODE_SMASHED(i) ||
2580 CAN_EXPLODE_BY_FIRE(i)));
2584 /* determine inactive elements (used for engine main loop optimization) */
2585 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2587 boolean active = FALSE;
2589 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2591 if (HAS_PROPERTY(i, j))
2597 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2602 /* dynamically adjust element properties according to game engine version */
2604 static int ep_em_slippery_wall[] =
2609 EL_EXPANDABLE_WALL_HORIZONTAL,
2610 EL_EXPANDABLE_WALL_VERTICAL,
2611 EL_EXPANDABLE_WALL_ANY,
2615 /* special EM style gems behaviour */
2616 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2617 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2618 level.em_slippery_gems);
2620 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2621 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2622 (level.em_slippery_gems &&
2623 engine_version > VERSION_IDENT(2,0,1)));
2626 /* dynamically adjust element properties according to game engine version */
2628 if (engine_version < RELEASE_IDENT(2,2,0,7))
2631 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2633 int element = EL_CUSTOM_START + i;
2635 element_info[element].push_delay_fixed = 2;
2636 element_info[element].push_delay_random = 8;
2641 static void InitGlobal()
2643 global.autoplay_leveldir = NULL;
2645 global.frames_per_second = 0;
2646 global.fps_slowdown = FALSE;
2647 global.fps_slowdown_factor = 1;
2650 void Execute_Command(char *command)
2652 if (strcmp(command, "print graphicsinfo.conf") == 0)
2656 printf("# You can configure additional/alternative image files here.\n");
2657 printf("# (The images below are default and therefore commented out.)\n");
2659 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2661 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2664 for (i=0; image_config[i].token != NULL; i++)
2666 getFormattedSetupEntry(image_config[i].token,
2667 image_config[i].value));
2671 else if (strcmp(command, "print soundsinfo.conf") == 0)
2675 printf("# You can configure additional/alternative sound files here.\n");
2676 printf("# (The sounds below are default and therefore commented out.)\n");
2678 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2680 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2683 for (i=0; sound_config[i].token != NULL; i++)
2685 getFormattedSetupEntry(sound_config[i].token,
2686 sound_config[i].value));
2690 else if (strcmp(command, "print musicinfo.conf") == 0)
2692 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2694 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2696 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2700 else if (strncmp(command, "dump level ", 11) == 0)
2702 char *filename = &command[11];
2704 if (access(filename, F_OK) != 0)
2705 Error(ERR_EXIT, "cannot open file '%s'", filename);
2707 LoadLevelFromFilename(filename);
2712 else if (strncmp(command, "dump tape ", 10) == 0)
2714 char *filename = &command[10];
2716 if (access(filename, F_OK) != 0)
2717 Error(ERR_EXIT, "cannot open file '%s'", filename);
2719 LoadTapeFromFilename(filename);
2724 else if (strncmp(command, "autoplay ", 9) == 0)
2726 char *str_copy = getStringCopy(&command[9]);
2727 char *str_ptr = strchr(str_copy, ' ');
2729 global.autoplay_leveldir = str_copy;
2730 global.autoplay_level_nr = -1;
2732 if (str_ptr != NULL)
2734 *str_ptr++ = '\0'; /* terminate leveldir string */
2735 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2740 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2744 static void InitSetup()
2746 LoadSetup(); /* global setup info */
2748 /* set some options from setup file */
2750 if (setup.options.verbose)
2751 options.verbose = TRUE;
2754 static void InitPlayerInfo()
2758 /* choose default local player */
2759 local_player = &stored_player[0];
2761 for (i=0; i<MAX_PLAYERS; i++)
2762 stored_player[i].connected = FALSE;
2764 local_player->connected = TRUE;
2767 static void InitArtworkInfo()
2772 static char *get_element_class_token(int element)
2774 char *element_class_name = element_info[element].class_name;
2775 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2777 sprintf(element_class_token, "[%s]", element_class_name);
2779 return element_class_token;
2782 static void InitArtworkConfig()
2784 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2785 static char *sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS + 1];
2786 static char *action_id_suffix[NUM_ACTIONS + 1];
2787 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2788 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2789 static char *dummy[1] = { NULL };
2790 static char *ignore_generic_tokens[] =
2796 static char **ignore_image_tokens, **ignore_sound_tokens;
2797 int num_ignore_generic_tokens;
2798 int num_ignore_image_tokens, num_ignore_sound_tokens;
2801 /* dynamically determine list of generic tokens to be ignored */
2802 num_ignore_generic_tokens = 0;
2803 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2804 num_ignore_generic_tokens++;
2806 /* dynamically determine list of image tokens to be ignored */
2807 num_ignore_image_tokens = num_ignore_generic_tokens;
2808 for (i=0; image_config_vars[i].token != NULL; i++)
2809 num_ignore_image_tokens++;
2810 ignore_image_tokens =
2811 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2812 for (i=0; i < num_ignore_generic_tokens; i++)
2813 ignore_image_tokens[i] = ignore_generic_tokens[i];
2814 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2815 ignore_image_tokens[num_ignore_generic_tokens + i] =
2816 image_config_vars[i].token;
2817 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2819 /* dynamically determine list of sound tokens to be ignored */
2820 num_ignore_sound_tokens = num_ignore_generic_tokens;
2821 ignore_sound_tokens =
2822 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2823 for (i=0; i < num_ignore_generic_tokens; i++)
2824 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2825 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2827 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2828 image_id_prefix[i] = element_info[i].token_name;
2829 for (i=0; i<NUM_FONTS; i++)
2830 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2831 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2833 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2834 sound_id_prefix[i] = element_info[i].token_name;
2835 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2836 sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_element_class_token(i);
2837 sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS] = NULL;
2839 for (i=0; i<NUM_ACTIONS; i++)
2840 action_id_suffix[i] = element_action_info[i].suffix;
2841 action_id_suffix[NUM_ACTIONS] = NULL;
2843 for (i=0; i<NUM_DIRECTIONS; i++)
2844 direction_id_suffix[i] = element_direction_info[i].suffix;
2845 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2847 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2848 special_id_suffix[i] = special_suffix_info[i].suffix;
2849 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2851 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2852 image_id_prefix, action_id_suffix, direction_id_suffix,
2853 special_id_suffix, ignore_image_tokens);
2854 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2855 sound_id_prefix, action_id_suffix, dummy,
2856 special_id_suffix, ignore_sound_tokens);
2859 static void InitMixer()
2867 char *filename_font_initial = NULL;
2868 Bitmap *bitmap_font_initial = NULL;
2871 /* determine settings for initial font (for displaying startup messages) */
2872 for (i=0; image_config[i].token != NULL; i++)
2874 for (j=0; j < NUM_INITIAL_FONTS; j++)
2876 char font_token[128];
2879 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2880 len_font_token = strlen(font_token);
2882 if (strcmp(image_config[i].token, font_token) == 0)
2883 filename_font_initial = image_config[i].value;
2884 else if (strlen(image_config[i].token) > len_font_token &&
2885 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2887 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2888 font_initial[j].src_x = atoi(image_config[i].value);
2889 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2890 font_initial[j].src_y = atoi(image_config[i].value);
2891 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2892 font_initial[j].width = atoi(image_config[i].value);
2893 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2894 font_initial[j].height = atoi(image_config[i].value);
2899 for (j=0; j < NUM_INITIAL_FONTS; j++)
2901 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2902 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2905 if (filename_font_initial == NULL) /* should not happen */
2906 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2908 /* create additional image buffers for double-buffering */
2909 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2910 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2912 /* initialize screen properties */
2913 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2914 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2916 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2917 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2918 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2920 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2922 for (j=0; j < NUM_INITIAL_FONTS; j++)
2923 font_initial[j].bitmap = bitmap_font_initial;
2925 InitFontGraphicInfo();
2927 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2928 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2930 DrawInitText("Loading graphics:", 120, FC_GREEN);
2932 InitTileClipmasks();
2935 void InitGfxBackground()
2939 drawto = backbuffer;
2940 fieldbuffer = bitmap_db_field;
2941 SetDrawtoField(DRAW_BACKBUFFER);
2943 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2944 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2945 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2946 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2948 for (x=0; x<MAX_BUF_XSIZE; x++)
2949 for (y=0; y<MAX_BUF_YSIZE; y++)
2952 redraw_mask = REDRAW_ALL;
2955 static void InitLevelInfo()
2957 LoadLevelInfo(); /* global level info */
2958 LoadLevelSetup_LastSeries(); /* last played series info */
2959 LoadLevelSetup_SeriesInfo(); /* last played level info */
2962 void InitLevelArtworkInfo()
2964 LoadLevelArtworkInfo();
2967 static void InitImages()
2969 ReloadCustomImages();
2971 LoadCustomElementDescriptions();
2972 LoadSpecialMenuDesignSettings();
2974 ReinitializeGraphics();
2977 static void InitSound()
2979 InitReloadCustomSounds(artwork.snd_current->identifier);
2980 ReinitializeSounds();
2983 static void InitMusic()
2985 InitReloadCustomMusic(artwork.mus_current->identifier);
2986 ReinitializeMusic();
2989 void InitNetworkServer()
2991 #if defined(PLATFORM_UNIX)
2995 if (!options.network)
2998 #if defined(PLATFORM_UNIX)
2999 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3001 if (!ConnectToServer(options.server_host, options.server_port))
3002 Error(ERR_EXIT, "cannot connect to network game server");
3004 SendToServer_PlayerName(setup.player_name);
3005 SendToServer_ProtocolVersion();
3008 SendToServer_NrWanted(nr_wanted);
3012 void ReloadCustomArtwork()
3014 static char *leveldir_current_identifier = NULL;
3015 static boolean last_override_level_graphics = FALSE;
3016 static boolean last_override_level_sounds = FALSE;
3017 static boolean last_override_level_music = FALSE;
3018 /* identifier for new artwork; default: artwork configured in setup */
3019 char *gfx_new_identifier = artwork.gfx_current->identifier;
3020 char *snd_new_identifier = artwork.snd_current->identifier;
3021 char *mus_new_identifier = artwork.mus_current->identifier;
3022 boolean redraw_screen = FALSE;
3024 if (leveldir_current_identifier == NULL)
3025 leveldir_current_identifier = leveldir_current->identifier;
3028 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3029 leveldir_current->graphics_set);
3030 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3031 leveldir_current->identifier);
3035 printf("graphics --> '%s' ('%s')\n",
3036 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3037 printf("sounds --> '%s' ('%s')\n",
3038 artwork.snd_current_identifier, artwork.snd_current->filename);
3039 printf("music --> '%s' ('%s')\n",
3040 artwork.mus_current_identifier, artwork.mus_current->filename);
3043 /* leveldir_current may be invalid (level group, parent link) */
3044 if (!validLevelSeries(leveldir_current))
3047 /* when a new level series was selected, check if there was a change
3048 in custom artwork stored in level series directory */
3049 if (leveldir_current_identifier != leveldir_current->identifier)
3051 char *identifier_old = leveldir_current_identifier;
3052 char *identifier_new = leveldir_current->identifier;
3054 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3055 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3056 gfx_new_identifier = identifier_new;
3057 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3058 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3059 snd_new_identifier = identifier_new;
3060 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3061 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3062 mus_new_identifier = identifier_new;
3064 leveldir_current_identifier = leveldir_current->identifier;
3067 /* custom level artwork configured in level series configuration file
3068 always overrides custom level artwork stored in level series directory
3069 and (level independant) custom artwork configured in setup menue */
3070 if (leveldir_current->graphics_set != NULL)
3071 gfx_new_identifier = leveldir_current->graphics_set;
3072 if (leveldir_current->sounds_set != NULL)
3073 snd_new_identifier = leveldir_current->sounds_set;
3074 if (leveldir_current->music_set != NULL)
3075 mus_new_identifier = leveldir_current->music_set;
3077 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3078 last_override_level_graphics != setup.override_level_graphics)
3081 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3082 artwork.gfx_current_identifier,
3083 artwork.gfx_current->identifier,
3084 gfx_new_identifier);
3087 setLevelArtworkDir(artwork.gfx_first);
3089 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3093 FreeTileClipmasks();
3094 InitTileClipmasks();
3096 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3097 last_override_level_graphics = setup.override_level_graphics;
3099 redraw_screen = TRUE;
3102 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3103 last_override_level_sounds != setup.override_level_sounds)
3106 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3107 artwork.snd_current_identifier,
3108 artwork.snd_current->identifier,
3109 snd_new_identifier);
3112 /* set artwork path to send it to the sound server process */
3113 setLevelArtworkDir(artwork.snd_first);
3115 InitReloadCustomSounds(snd_new_identifier);
3116 ReinitializeSounds();
3118 artwork.snd_current_identifier = artwork.snd_current->identifier;
3119 last_override_level_sounds = setup.override_level_sounds;
3121 redraw_screen = TRUE;
3124 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3125 last_override_level_music != setup.override_level_music)
3127 /* set artwork path to send it to the sound server process */
3128 setLevelArtworkDir(artwork.mus_first);
3130 InitReloadCustomMusic(mus_new_identifier);
3131 ReinitializeMusic();
3133 artwork.mus_current_identifier = artwork.mus_current->identifier;
3134 last_override_level_music = setup.override_level_music;
3136 redraw_screen = TRUE;
3141 InitGfxBackground();
3143 /* force redraw of (open or closed) door graphics */
3144 SetDoorState(DOOR_OPEN_ALL);
3145 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3149 void KeyboardAutoRepeatOffUnlessAutoplay()
3151 if (global.autoplay_leveldir == NULL)
3152 KeyboardAutoRepeatOff();
3156 /* ========================================================================= */
3158 /* ========================================================================= */
3162 InitGlobal(); /* initialize some global variables */
3164 if (options.execute_command)
3165 Execute_Command(options.execute_command);
3167 if (options.serveronly)
3169 #if defined(PLATFORM_UNIX)
3170 NetworkServer(options.server_port, options.serveronly);
3172 Error(ERR_WARN, "networking only supported in Unix version");
3174 exit(0); /* never reached */
3180 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3181 InitArtworkConfig(); /* needed before forking sound child process */
3186 InitRND(NEW_RANDOMIZE);
3187 InitSimpleRND(NEW_RANDOMIZE);
3192 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3195 InitEventFilter(FilterMouseMotionEvents);
3197 InitElementPropertiesStatic();
3202 InitLevelArtworkInfo();
3204 InitImages(); /* needs to know current level directory */
3205 InitSound(); /* needs to know current level directory */
3206 InitMusic(); /* needs to know current level directory */
3208 InitGfxBackground();
3210 if (global.autoplay_leveldir)
3216 game_status = GAME_MODE_MAIN;
3220 InitNetworkServer();
3223 void CloseAllAndExit(int exit_value)
3228 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3231 FreeTileClipmasks();
3233 CloseVideoDisplay();
3234 ClosePlatformDependantStuff();