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_SWITCHGATE_SWITCH_UP,
1278 EL_SWITCHGATE_SWITCH_DOWN,
1281 EL_TIMEGATE_OPENING,
1283 EL_TIMEGATE_CLOSING,
1286 EL_TIMEGATE_SWITCH_ACTIVE,
1291 EL_TUBE_VERTICAL_LEFT,
1292 EL_TUBE_VERTICAL_RIGHT,
1293 EL_TUBE_HORIZONTAL_UP,
1294 EL_TUBE_HORIZONTAL_DOWN,
1302 static int ep_slippery[] =
1316 EL_ROBOT_WHEEL_ACTIVE,
1322 EL_ACID_POOL_TOPLEFT,
1323 EL_ACID_POOL_TOPRIGHT,
1333 EL_STEELWALL_SLANTED,
1339 static int ep_can_change[] =
1344 static int ep_can_move[] =
1366 static int ep_can_fall[] =
1381 EL_BD_MAGIC_WALL_FULL,
1394 static int ep_can_smash_player[] =
1419 static int ep_can_smash_enemies[] =
1427 static int ep_can_smash_everything[] =
1435 static int ep_can_explode_by_fire[] =
1437 /* same elements as in 'ep_can_explode_impact' */
1442 /* same elements as in 'ep_can_explode_smashed' */
1451 EL_DYNABOMB_PLAYER_1_ACTIVE,
1452 EL_DYNABOMB_PLAYER_2_ACTIVE,
1453 EL_DYNABOMB_PLAYER_3_ACTIVE,
1454 EL_DYNABOMB_PLAYER_4_ACTIVE,
1455 EL_DYNABOMB_INCREASE_NUMBER,
1456 EL_DYNABOMB_INCREASE_SIZE,
1457 EL_DYNABOMB_INCREASE_POWER,
1458 EL_SP_DISK_RED_ACTIVE,
1468 static int ep_can_explode_smashed[] =
1470 /* same elements as in 'ep_can_explode_impact' */
1483 static int ep_can_explode_impact[] =
1491 static int ep_walkable_over[] =
1495 EL_SOKOBAN_FIELD_EMPTY,
1509 static int ep_walkable_inside[] =
1514 EL_TUBE_VERTICAL_LEFT,
1515 EL_TUBE_VERTICAL_RIGHT,
1516 EL_TUBE_HORIZONTAL_UP,
1517 EL_TUBE_HORIZONTAL_DOWN,
1525 static int ep_walkable_under[] =
1530 static int ep_passable_over[] =
1545 static int ep_passable_inside[] =
1551 EL_SP_PORT_HORIZONTAL,
1552 EL_SP_PORT_VERTICAL,
1554 EL_SP_GRAVITY_PORT_LEFT,
1555 EL_SP_GRAVITY_PORT_RIGHT,
1556 EL_SP_GRAVITY_PORT_UP,
1557 EL_SP_GRAVITY_PORT_DOWN,
1561 static int ep_passable_under[] =
1566 static int ep_pushable[] =
1578 EL_SOKOBAN_FIELD_FULL,
1585 static int ep_can_be_crumbled[] =
1594 static int ep_player[] =
1603 static int ep_can_pass_magic_wall[] =
1616 static int ep_switchable[] =
1620 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1621 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1622 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1623 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1624 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1625 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1626 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1627 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1628 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1629 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1630 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1631 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1632 EL_SWITCHGATE_SWITCH_UP,
1633 EL_SWITCHGATE_SWITCH_DOWN,
1635 EL_LIGHT_SWITCH_ACTIVE,
1637 EL_BALLOON_SWITCH_LEFT,
1638 EL_BALLOON_SWITCH_RIGHT,
1639 EL_BALLOON_SWITCH_UP,
1640 EL_BALLOON_SWITCH_DOWN,
1641 EL_BALLOON_SWITCH_ANY,
1647 static int ep_bd_element[] =
1676 static int ep_sp_element[] =
1684 EL_SP_HARDWARE_GRAY,
1692 EL_SP_GRAVITY_PORT_RIGHT,
1693 EL_SP_GRAVITY_PORT_DOWN,
1694 EL_SP_GRAVITY_PORT_LEFT,
1695 EL_SP_GRAVITY_PORT_UP,
1700 EL_SP_PORT_VERTICAL,
1701 EL_SP_PORT_HORIZONTAL,
1707 EL_SP_HARDWARE_BASE_1,
1708 EL_SP_HARDWARE_GREEN,
1709 EL_SP_HARDWARE_BLUE,
1711 EL_SP_HARDWARE_YELLOW,
1712 EL_SP_HARDWARE_BASE_2,
1713 EL_SP_HARDWARE_BASE_3,
1714 EL_SP_HARDWARE_BASE_4,
1715 EL_SP_HARDWARE_BASE_5,
1716 EL_SP_HARDWARE_BASE_6,
1719 /* additional elements that appeared in newer Supaplex levels */
1721 /* more than one murphy in a level results in an inactive clone */
1726 static int ep_sb_element[] =
1731 EL_SOKOBAN_FIELD_EMPTY,
1732 EL_SOKOBAN_FIELD_FULL,
1734 EL_INVISIBLE_STEELWALL,
1738 static int ep_gem[] =
1749 static int ep_food_dark_yamyam[] =
1776 static int ep_food_penguin[] =
1789 static int ep_food_pig[] =
1800 static int ep_historic_wall[] =
1825 EL_EXPANDABLE_WALL_HORIZONTAL,
1826 EL_EXPANDABLE_WALL_VERTICAL,
1827 EL_EXPANDABLE_WALL_ANY,
1828 EL_EXPANDABLE_WALL_GROWING,
1835 EL_SP_HARDWARE_GRAY,
1836 EL_SP_HARDWARE_GREEN,
1837 EL_SP_HARDWARE_BLUE,
1839 EL_SP_HARDWARE_YELLOW,
1840 EL_SP_HARDWARE_BASE_1,
1841 EL_SP_HARDWARE_BASE_2,
1842 EL_SP_HARDWARE_BASE_3,
1843 EL_SP_HARDWARE_BASE_4,
1844 EL_SP_HARDWARE_BASE_5,
1845 EL_SP_HARDWARE_BASE_6,
1847 EL_SP_TERMINAL_ACTIVE,
1850 EL_INVISIBLE_STEELWALL,
1851 EL_INVISIBLE_STEELWALL_ACTIVE,
1853 EL_INVISIBLE_WALL_ACTIVE,
1854 EL_STEELWALL_SLANTED,
1870 static int ep_historic_solid[] =
1874 EL_EXPANDABLE_WALL_HORIZONTAL,
1875 EL_EXPANDABLE_WALL_VERTICAL,
1876 EL_EXPANDABLE_WALL_ANY,
1889 EL_QUICKSAND_FILLING,
1890 EL_QUICKSAND_EMPTYING,
1892 EL_MAGIC_WALL_ACTIVE,
1893 EL_MAGIC_WALL_EMPTYING,
1894 EL_MAGIC_WALL_FILLING,
1898 EL_BD_MAGIC_WALL_ACTIVE,
1899 EL_BD_MAGIC_WALL_EMPTYING,
1900 EL_BD_MAGIC_WALL_FULL,
1901 EL_BD_MAGIC_WALL_FILLING,
1902 EL_BD_MAGIC_WALL_DEAD,
1911 EL_SP_TERMINAL_ACTIVE,
1915 EL_INVISIBLE_WALL_ACTIVE,
1916 EL_SWITCHGATE_SWITCH_UP,
1917 EL_SWITCHGATE_SWITCH_DOWN,
1919 EL_TIMEGATE_SWITCH_ACTIVE,
1931 /* the following elements are a direct copy of "indestructible" elements,
1932 except "EL_ACID", which is "indestructible", but not "solid"! */
1937 EL_ACID_POOL_TOPLEFT,
1938 EL_ACID_POOL_TOPRIGHT,
1939 EL_ACID_POOL_BOTTOMLEFT,
1940 EL_ACID_POOL_BOTTOM,
1941 EL_ACID_POOL_BOTTOMRIGHT,
1942 EL_SP_HARDWARE_GRAY,
1943 EL_SP_HARDWARE_GREEN,
1944 EL_SP_HARDWARE_BLUE,
1946 EL_SP_HARDWARE_YELLOW,
1947 EL_SP_HARDWARE_BASE_1,
1948 EL_SP_HARDWARE_BASE_2,
1949 EL_SP_HARDWARE_BASE_3,
1950 EL_SP_HARDWARE_BASE_4,
1951 EL_SP_HARDWARE_BASE_5,
1952 EL_SP_HARDWARE_BASE_6,
1953 EL_INVISIBLE_STEELWALL,
1954 EL_INVISIBLE_STEELWALL_ACTIVE,
1955 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1956 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1957 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1958 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1959 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1960 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1961 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1962 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1963 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1964 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1965 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1966 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1968 EL_LIGHT_SWITCH_ACTIVE,
1969 EL_SIGN_EXCLAMATION,
1970 EL_SIGN_RADIOACTIVITY,
1981 EL_STEELWALL_SLANTED,
2004 EL_SWITCHGATE_OPENING,
2005 EL_SWITCHGATE_CLOSED,
2006 EL_SWITCHGATE_CLOSING,
2008 EL_TIMEGATE_OPENING,
2010 EL_TIMEGATE_CLOSING,
2014 EL_TUBE_VERTICAL_LEFT,
2015 EL_TUBE_VERTICAL_RIGHT,
2016 EL_TUBE_HORIZONTAL_UP,
2017 EL_TUBE_HORIZONTAL_DOWN,
2025 static int ep_classic_enemy[] =
2041 static int ep_belt[] =
2043 EL_CONVEYOR_BELT_1_LEFT,
2044 EL_CONVEYOR_BELT_1_MIDDLE,
2045 EL_CONVEYOR_BELT_1_RIGHT,
2046 EL_CONVEYOR_BELT_2_LEFT,
2047 EL_CONVEYOR_BELT_2_MIDDLE,
2048 EL_CONVEYOR_BELT_2_RIGHT,
2049 EL_CONVEYOR_BELT_3_LEFT,
2050 EL_CONVEYOR_BELT_3_MIDDLE,
2051 EL_CONVEYOR_BELT_3_RIGHT,
2052 EL_CONVEYOR_BELT_4_LEFT,
2053 EL_CONVEYOR_BELT_4_MIDDLE,
2054 EL_CONVEYOR_BELT_4_RIGHT,
2058 static int ep_belt_active[] =
2060 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2061 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2062 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2063 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2064 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2065 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2066 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2067 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2068 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2069 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2070 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2071 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2075 static int ep_belt_switch[] =
2077 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2078 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2079 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2080 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2081 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2082 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2083 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2084 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2085 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2086 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2087 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2088 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2092 static int ep_tube[] =
2099 EL_TUBE_HORIZONTAL_UP,
2100 EL_TUBE_HORIZONTAL_DOWN,
2102 EL_TUBE_VERTICAL_LEFT,
2103 EL_TUBE_VERTICAL_RIGHT,
2108 static int ep_keygate[] =
2129 static int ep_amoeboid[] =
2139 static int ep_amoebalive[] =
2148 static int ep_has_content[] =
2158 static int ep_active_bomb[] =
2161 EL_DYNABOMB_PLAYER_1_ACTIVE,
2162 EL_DYNABOMB_PLAYER_2_ACTIVE,
2163 EL_DYNABOMB_PLAYER_3_ACTIVE,
2164 EL_DYNABOMB_PLAYER_4_ACTIVE,
2165 EL_SP_DISK_RED_ACTIVE,
2169 static int ep_inactive[] =
2206 EL_INVISIBLE_STEELWALL,
2214 EL_WALL_EMERALD_YELLOW,
2215 EL_DYNABOMB_INCREASE_NUMBER,
2216 EL_DYNABOMB_INCREASE_SIZE,
2217 EL_DYNABOMB_INCREASE_POWER,
2219 EL_SOKOBAN_FIELD_EMPTY,
2220 EL_SOKOBAN_FIELD_FULL,
2221 EL_WALL_EMERALD_RED,
2222 EL_WALL_EMERALD_PURPLE,
2223 EL_ACID_POOL_TOPLEFT,
2224 EL_ACID_POOL_TOPRIGHT,
2225 EL_ACID_POOL_BOTTOMLEFT,
2226 EL_ACID_POOL_BOTTOM,
2227 EL_ACID_POOL_BOTTOMRIGHT,
2231 EL_BD_MAGIC_WALL_DEAD,
2232 EL_AMOEBA_TO_DIAMOND,
2240 EL_SP_GRAVITY_PORT_RIGHT,
2241 EL_SP_GRAVITY_PORT_DOWN,
2242 EL_SP_GRAVITY_PORT_LEFT,
2243 EL_SP_GRAVITY_PORT_UP,
2244 EL_SP_PORT_HORIZONTAL,
2245 EL_SP_PORT_VERTICAL,
2254 EL_SP_HARDWARE_GRAY,
2255 EL_SP_HARDWARE_GREEN,
2256 EL_SP_HARDWARE_BLUE,
2258 EL_SP_HARDWARE_YELLOW,
2259 EL_SP_HARDWARE_BASE_1,
2260 EL_SP_HARDWARE_BASE_2,
2261 EL_SP_HARDWARE_BASE_3,
2262 EL_SP_HARDWARE_BASE_4,
2263 EL_SP_HARDWARE_BASE_5,
2264 EL_SP_HARDWARE_BASE_6,
2265 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2266 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2267 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2268 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2269 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2270 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2271 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2272 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2273 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2274 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2275 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2276 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2277 EL_SIGN_EXCLAMATION,
2278 EL_SIGN_RADIOACTIVITY,
2289 EL_STEELWALL_SLANTED,
2309 } element_properties[] =
2311 { ep_diggable, EP_DIGGABLE },
2312 { ep_collectible, EP_COLLECTIBLE },
2313 { ep_dont_run_into, EP_DONT_RUN_INTO },
2314 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2315 { ep_dont_touch, EP_DONT_TOUCH },
2316 { ep_indestructible, EP_INDESTRUCTIBLE },
2317 { ep_slippery, EP_SLIPPERY },
2318 { ep_can_change, EP_CAN_CHANGE },
2319 { ep_can_move, EP_CAN_MOVE },
2320 { ep_can_fall, EP_CAN_FALL },
2321 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2322 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2323 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2324 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2325 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2326 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2327 { ep_walkable_over, EP_WALKABLE_OVER },
2328 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2329 { ep_walkable_under, EP_WALKABLE_UNDER },
2330 { ep_passable_over, EP_PASSABLE_OVER },
2331 { ep_passable_inside, EP_PASSABLE_INSIDE },
2332 { ep_passable_under, EP_PASSABLE_UNDER },
2333 { ep_pushable, EP_PUSHABLE },
2335 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2337 { ep_player, EP_PLAYER },
2338 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2339 { ep_switchable, EP_SWITCHABLE },
2340 { ep_bd_element, EP_BD_ELEMENT },
2341 { ep_sp_element, EP_SP_ELEMENT },
2342 { ep_sb_element, EP_SB_ELEMENT },
2344 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2345 { ep_food_penguin, EP_FOOD_PENGUIN },
2346 { ep_food_pig, EP_FOOD_PIG },
2347 { ep_historic_wall, EP_HISTORIC_WALL },
2348 { ep_historic_solid, EP_HISTORIC_SOLID },
2349 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2350 { ep_belt, EP_BELT },
2351 { ep_belt_active, EP_BELT_ACTIVE },
2352 { ep_belt_switch, EP_BELT_SWITCH },
2353 { ep_tube, EP_TUBE },
2354 { ep_keygate, EP_KEYGATE },
2355 { ep_amoeboid, EP_AMOEBOID },
2356 { ep_amoebalive, EP_AMOEBALIVE },
2357 { ep_has_content, EP_HAS_CONTENT },
2358 { ep_active_bomb, EP_ACTIVE_BOMB },
2359 { ep_inactive, EP_INACTIVE },
2364 static int copy_properties[][5] =
2368 EL_BUG_LEFT, EL_BUG_RIGHT,
2369 EL_BUG_UP, EL_BUG_DOWN
2373 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2374 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2378 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2379 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2383 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2384 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2388 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2389 EL_PACMAN_UP, EL_PACMAN_DOWN
2399 /* always start with reliable default values (element has no properties) */
2400 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2401 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2402 SET_PROPERTY(i, j, FALSE);
2404 /* set all base element properties from above array definitions */
2405 for (i=0; element_properties[i].elements != NULL; i++)
2406 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2407 SET_PROPERTY((element_properties[i].elements)[j],
2408 element_properties[i].property, TRUE);
2410 /* copy properties to some elements that are only stored in level file */
2411 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2412 for (j=0; copy_properties[j][0] != -1; j++)
2413 if (HAS_PROPERTY(copy_properties[j][0], i))
2414 for (k=1; k<=4; k++)
2415 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2418 void InitElementPropertiesEngine(int engine_version)
2421 static int active_properties[] =
2426 EP_DONT_COLLIDE_WITH,
2430 EP_CAN_PASS_MAGIC_WALL,
2435 EP_CAN_EXPLODE_BY_FIRE,
2448 EP_EM_SLIPPERY_WALL,
2453 static int no_wall_properties[] =
2458 EP_DONT_COLLIDE_WITH,
2461 EP_CAN_SMASH_PLAYER,
2462 EP_CAN_SMASH_ENEMIES,
2463 EP_CAN_SMASH_EVERYTHING,
2470 EP_FOOD_DARK_YAMYAM,
2486 InitElementPropertiesStatic();
2489 /* set all special, combined or engine dependant element properties */
2490 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2493 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2494 SET_PROPERTY(i, j, FALSE);
2497 /* ---------- INACTIVE ------------------------------------------------- */
2498 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2499 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2501 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2502 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2503 IS_WALKABLE_INSIDE(i) ||
2504 IS_WALKABLE_UNDER(i)));
2506 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2507 IS_PASSABLE_INSIDE(i) ||
2508 IS_PASSABLE_UNDER(i)));
2510 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2511 IS_PASSABLE_OVER(i)));
2513 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2514 IS_PASSABLE_INSIDE(i)));
2516 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2517 IS_PASSABLE_UNDER(i)));
2519 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2522 /* ---------- SNAPPABLE ------------------------------------------------ */
2523 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2524 IS_COLLECTIBLE(i) ||
2528 /* ---------- WALL ----------------------------------------------------- */
2529 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2531 for (j=0; no_wall_properties[j] != -1; j++)
2532 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2533 i >= EL_FIRST_RUNTIME_UNREAL)
2534 SET_PROPERTY(i, EP_WALL, FALSE);
2536 if (IS_HISTORIC_WALL(i))
2537 SET_PROPERTY(i, EP_WALL, TRUE);
2539 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2540 if (engine_version < VERSION_IDENT(2,2,0))
2541 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2543 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2545 !IS_COLLECTIBLE(i)));
2547 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2549 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2550 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2552 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2553 IS_INDESTRUCTIBLE(i)));
2555 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2557 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2558 else if (engine_version < VERSION_IDENT(2,2,0))
2559 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2561 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2562 !IS_WALKABLE_OVER(i) &&
2563 !IS_WALKABLE_UNDER(i)));
2565 if (IS_CUSTOM_ELEMENT(i))
2567 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2569 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2570 if (DONT_COLLIDE_WITH(i))
2571 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2573 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2574 if (CAN_SMASH_EVERYTHING(i))
2575 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2576 if (CAN_SMASH_ENEMIES(i))
2577 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2580 /* ---------- CAN_SMASH ------------------------------------------------ */
2581 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2582 CAN_SMASH_ENEMIES(i) ||
2583 CAN_SMASH_EVERYTHING(i)));
2585 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2586 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2587 CAN_EXPLODE_SMASHED(i) ||
2588 CAN_EXPLODE_BY_FIRE(i)));
2592 /* determine inactive elements (used for engine main loop optimization) */
2593 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2595 boolean active = FALSE;
2597 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2599 if (HAS_PROPERTY(i, j))
2605 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2610 /* dynamically adjust element properties according to game engine version */
2612 static int ep_em_slippery_wall[] =
2617 EL_EXPANDABLE_WALL_HORIZONTAL,
2618 EL_EXPANDABLE_WALL_VERTICAL,
2619 EL_EXPANDABLE_WALL_ANY,
2623 /* special EM style gems behaviour */
2624 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2625 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2626 level.em_slippery_gems);
2628 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2629 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2630 (level.em_slippery_gems &&
2631 engine_version > VERSION_IDENT(2,0,1)));
2634 /* dynamically adjust element properties according to game engine version */
2636 if (engine_version < RELEASE_IDENT(2,2,0,7))
2639 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2641 int element = EL_CUSTOM_START + i;
2643 element_info[element].push_delay_fixed = 2;
2644 element_info[element].push_delay_random = 8;
2649 static void InitGlobal()
2651 global.autoplay_leveldir = NULL;
2653 global.frames_per_second = 0;
2654 global.fps_slowdown = FALSE;
2655 global.fps_slowdown_factor = 1;
2658 void Execute_Command(char *command)
2660 if (strcmp(command, "print graphicsinfo.conf") == 0)
2664 printf("# You can configure additional/alternative image files here.\n");
2665 printf("# (The images below are default and therefore commented out.)\n");
2667 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2669 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2672 for (i=0; image_config[i].token != NULL; i++)
2674 getFormattedSetupEntry(image_config[i].token,
2675 image_config[i].value));
2679 else if (strcmp(command, "print soundsinfo.conf") == 0)
2683 printf("# You can configure additional/alternative sound files here.\n");
2684 printf("# (The sounds below are default and therefore commented out.)\n");
2686 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2688 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2691 for (i=0; sound_config[i].token != NULL; i++)
2693 getFormattedSetupEntry(sound_config[i].token,
2694 sound_config[i].value));
2698 else if (strcmp(command, "print musicinfo.conf") == 0)
2700 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2702 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2704 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2708 else if (strncmp(command, "dump level ", 11) == 0)
2710 char *filename = &command[11];
2712 if (access(filename, F_OK) != 0)
2713 Error(ERR_EXIT, "cannot open file '%s'", filename);
2715 LoadLevelFromFilename(filename);
2720 else if (strncmp(command, "dump tape ", 10) == 0)
2722 char *filename = &command[10];
2724 if (access(filename, F_OK) != 0)
2725 Error(ERR_EXIT, "cannot open file '%s'", filename);
2727 LoadTapeFromFilename(filename);
2732 else if (strncmp(command, "autoplay ", 9) == 0)
2734 char *str_copy = getStringCopy(&command[9]);
2735 char *str_ptr = strchr(str_copy, ' ');
2737 global.autoplay_leveldir = str_copy;
2738 global.autoplay_level_nr = -1;
2740 if (str_ptr != NULL)
2742 *str_ptr++ = '\0'; /* terminate leveldir string */
2743 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2748 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2752 static void InitSetup()
2754 LoadSetup(); /* global setup info */
2756 /* set some options from setup file */
2758 if (setup.options.verbose)
2759 options.verbose = TRUE;
2762 static void InitPlayerInfo()
2766 /* choose default local player */
2767 local_player = &stored_player[0];
2769 for (i=0; i<MAX_PLAYERS; i++)
2770 stored_player[i].connected = FALSE;
2772 local_player->connected = TRUE;
2775 static void InitArtworkInfo()
2780 static char *get_element_class_token(int element)
2782 char *element_class_name = element_info[element].class_name;
2783 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2785 sprintf(element_class_token, "[%s]", element_class_name);
2787 return element_class_token;
2790 static void InitArtworkConfig()
2792 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2793 static char *sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS + 1];
2794 static char *action_id_suffix[NUM_ACTIONS + 1];
2795 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2796 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2797 static char *dummy[1] = { NULL };
2798 static char *ignore_generic_tokens[] =
2804 static char **ignore_image_tokens, **ignore_sound_tokens;
2805 int num_ignore_generic_tokens;
2806 int num_ignore_image_tokens, num_ignore_sound_tokens;
2809 /* dynamically determine list of generic tokens to be ignored */
2810 num_ignore_generic_tokens = 0;
2811 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2812 num_ignore_generic_tokens++;
2814 /* dynamically determine list of image tokens to be ignored */
2815 num_ignore_image_tokens = num_ignore_generic_tokens;
2816 for (i=0; image_config_vars[i].token != NULL; i++)
2817 num_ignore_image_tokens++;
2818 ignore_image_tokens =
2819 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2820 for (i=0; i < num_ignore_generic_tokens; i++)
2821 ignore_image_tokens[i] = ignore_generic_tokens[i];
2822 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2823 ignore_image_tokens[num_ignore_generic_tokens + i] =
2824 image_config_vars[i].token;
2825 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2827 /* dynamically determine list of sound tokens to be ignored */
2828 num_ignore_sound_tokens = num_ignore_generic_tokens;
2829 ignore_sound_tokens =
2830 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2831 for (i=0; i < num_ignore_generic_tokens; i++)
2832 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2833 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2835 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2836 image_id_prefix[i] = element_info[i].token_name;
2837 for (i=0; i<NUM_FONTS; i++)
2838 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2839 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2841 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2842 sound_id_prefix[i] = element_info[i].token_name;
2843 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2844 sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_element_class_token(i);
2845 sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS] = NULL;
2847 for (i=0; i<NUM_ACTIONS; i++)
2848 action_id_suffix[i] = element_action_info[i].suffix;
2849 action_id_suffix[NUM_ACTIONS] = NULL;
2851 for (i=0; i<NUM_DIRECTIONS; i++)
2852 direction_id_suffix[i] = element_direction_info[i].suffix;
2853 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2855 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2856 special_id_suffix[i] = special_suffix_info[i].suffix;
2857 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2859 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2860 image_id_prefix, action_id_suffix, direction_id_suffix,
2861 special_id_suffix, ignore_image_tokens);
2862 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2863 sound_id_prefix, action_id_suffix, dummy,
2864 special_id_suffix, ignore_sound_tokens);
2867 static void InitMixer()
2875 char *filename_font_initial = NULL;
2876 Bitmap *bitmap_font_initial = NULL;
2879 /* determine settings for initial font (for displaying startup messages) */
2880 for (i=0; image_config[i].token != NULL; i++)
2882 for (j=0; j < NUM_INITIAL_FONTS; j++)
2884 char font_token[128];
2887 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2888 len_font_token = strlen(font_token);
2890 if (strcmp(image_config[i].token, font_token) == 0)
2891 filename_font_initial = image_config[i].value;
2892 else if (strlen(image_config[i].token) > len_font_token &&
2893 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2895 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2896 font_initial[j].src_x = atoi(image_config[i].value);
2897 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2898 font_initial[j].src_y = atoi(image_config[i].value);
2899 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2900 font_initial[j].width = atoi(image_config[i].value);
2901 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2902 font_initial[j].height = atoi(image_config[i].value);
2907 for (j=0; j < NUM_INITIAL_FONTS; j++)
2909 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2910 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2913 if (filename_font_initial == NULL) /* should not happen */
2914 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2916 /* create additional image buffers for double-buffering */
2917 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2918 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2920 /* initialize screen properties */
2921 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2922 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2924 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2925 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2926 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2928 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2930 for (j=0; j < NUM_INITIAL_FONTS; j++)
2931 font_initial[j].bitmap = bitmap_font_initial;
2933 InitFontGraphicInfo();
2935 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2936 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2938 DrawInitText("Loading graphics:", 120, FC_GREEN);
2940 InitTileClipmasks();
2943 void InitGfxBackground()
2947 drawto = backbuffer;
2948 fieldbuffer = bitmap_db_field;
2949 SetDrawtoField(DRAW_BACKBUFFER);
2951 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2952 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2953 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2954 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2956 for (x=0; x<MAX_BUF_XSIZE; x++)
2957 for (y=0; y<MAX_BUF_YSIZE; y++)
2960 redraw_mask = REDRAW_ALL;
2963 static void InitLevelInfo()
2965 LoadLevelInfo(); /* global level info */
2966 LoadLevelSetup_LastSeries(); /* last played series info */
2967 LoadLevelSetup_SeriesInfo(); /* last played level info */
2970 void InitLevelArtworkInfo()
2972 LoadLevelArtworkInfo();
2975 static void InitImages()
2977 ReloadCustomImages();
2979 LoadCustomElementDescriptions();
2980 LoadSpecialMenuDesignSettings();
2982 ReinitializeGraphics();
2985 static void InitSound()
2987 InitReloadCustomSounds(artwork.snd_current->identifier);
2988 ReinitializeSounds();
2991 static void InitMusic()
2993 InitReloadCustomMusic(artwork.mus_current->identifier);
2994 ReinitializeMusic();
2997 void InitNetworkServer()
2999 #if defined(PLATFORM_UNIX)
3003 if (!options.network)
3006 #if defined(PLATFORM_UNIX)
3007 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3009 if (!ConnectToServer(options.server_host, options.server_port))
3010 Error(ERR_EXIT, "cannot connect to network game server");
3012 SendToServer_PlayerName(setup.player_name);
3013 SendToServer_ProtocolVersion();
3016 SendToServer_NrWanted(nr_wanted);
3020 void ReloadCustomArtwork()
3022 static char *leveldir_current_identifier = NULL;
3023 static boolean last_override_level_graphics = FALSE;
3024 static boolean last_override_level_sounds = FALSE;
3025 static boolean last_override_level_music = FALSE;
3026 /* identifier for new artwork; default: artwork configured in setup */
3027 char *gfx_new_identifier = artwork.gfx_current->identifier;
3028 char *snd_new_identifier = artwork.snd_current->identifier;
3029 char *mus_new_identifier = artwork.mus_current->identifier;
3030 boolean redraw_screen = FALSE;
3032 if (leveldir_current_identifier == NULL)
3033 leveldir_current_identifier = leveldir_current->identifier;
3036 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3037 leveldir_current->graphics_set);
3038 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3039 leveldir_current->identifier);
3043 printf("graphics --> '%s' ('%s')\n",
3044 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3045 printf("sounds --> '%s' ('%s')\n",
3046 artwork.snd_current_identifier, artwork.snd_current->filename);
3047 printf("music --> '%s' ('%s')\n",
3048 artwork.mus_current_identifier, artwork.mus_current->filename);
3051 /* leveldir_current may be invalid (level group, parent link) */
3052 if (!validLevelSeries(leveldir_current))
3055 /* when a new level series was selected, check if there was a change
3056 in custom artwork stored in level series directory */
3057 if (leveldir_current_identifier != leveldir_current->identifier)
3059 char *identifier_old = leveldir_current_identifier;
3060 char *identifier_new = leveldir_current->identifier;
3062 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3063 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3064 gfx_new_identifier = identifier_new;
3065 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3066 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3067 snd_new_identifier = identifier_new;
3068 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3069 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3070 mus_new_identifier = identifier_new;
3072 leveldir_current_identifier = leveldir_current->identifier;
3075 /* custom level artwork configured in level series configuration file
3076 always overrides custom level artwork stored in level series directory
3077 and (level independant) custom artwork configured in setup menue */
3078 if (leveldir_current->graphics_set != NULL)
3079 gfx_new_identifier = leveldir_current->graphics_set;
3080 if (leveldir_current->sounds_set != NULL)
3081 snd_new_identifier = leveldir_current->sounds_set;
3082 if (leveldir_current->music_set != NULL)
3083 mus_new_identifier = leveldir_current->music_set;
3085 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3086 last_override_level_graphics != setup.override_level_graphics)
3089 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3090 artwork.gfx_current_identifier,
3091 artwork.gfx_current->identifier,
3092 gfx_new_identifier);
3095 setLevelArtworkDir(artwork.gfx_first);
3097 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3101 FreeTileClipmasks();
3102 InitTileClipmasks();
3104 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3105 last_override_level_graphics = setup.override_level_graphics;
3107 redraw_screen = TRUE;
3110 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3111 last_override_level_sounds != setup.override_level_sounds)
3114 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3115 artwork.snd_current_identifier,
3116 artwork.snd_current->identifier,
3117 snd_new_identifier);
3120 /* set artwork path to send it to the sound server process */
3121 setLevelArtworkDir(artwork.snd_first);
3123 InitReloadCustomSounds(snd_new_identifier);
3124 ReinitializeSounds();
3126 artwork.snd_current_identifier = artwork.snd_current->identifier;
3127 last_override_level_sounds = setup.override_level_sounds;
3129 redraw_screen = TRUE;
3132 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3133 last_override_level_music != setup.override_level_music)
3135 /* set artwork path to send it to the sound server process */
3136 setLevelArtworkDir(artwork.mus_first);
3138 InitReloadCustomMusic(mus_new_identifier);
3139 ReinitializeMusic();
3141 artwork.mus_current_identifier = artwork.mus_current->identifier;
3142 last_override_level_music = setup.override_level_music;
3144 redraw_screen = TRUE;
3149 InitGfxBackground();
3151 /* force redraw of (open or closed) door graphics */
3152 SetDoorState(DOOR_OPEN_ALL);
3153 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3157 void KeyboardAutoRepeatOffUnlessAutoplay()
3159 if (global.autoplay_leveldir == NULL)
3160 KeyboardAutoRepeatOff();
3164 /* ========================================================================= */
3166 /* ========================================================================= */
3170 InitGlobal(); /* initialize some global variables */
3172 if (options.execute_command)
3173 Execute_Command(options.execute_command);
3175 if (options.serveronly)
3177 #if defined(PLATFORM_UNIX)
3178 NetworkServer(options.server_port, options.serveronly);
3180 Error(ERR_WARN, "networking only supported in Unix version");
3182 exit(0); /* never reached */
3188 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3189 InitArtworkConfig(); /* needed before forking sound child process */
3194 InitRND(NEW_RANDOMIZE);
3195 InitSimpleRND(NEW_RANDOMIZE);
3200 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3203 InitEventFilter(FilterMouseMotionEvents);
3205 InitElementPropertiesStatic();
3210 InitLevelArtworkInfo();
3212 InitImages(); /* needs to know current level directory */
3213 InitSound(); /* needs to know current level directory */
3214 InitMusic(); /* needs to know current level directory */
3216 InitGfxBackground();
3218 if (global.autoplay_leveldir)
3224 game_status = GAME_MODE_MAIN;
3228 InitNetworkServer();
3231 void CloseAllAndExit(int exit_value)
3236 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3239 FreeTileClipmasks();
3241 CloseVideoDisplay();
3242 ClosePlatformDependantStuff();