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 class/sound mapping from dynamic configuration */
876 for (i=0; i < num_property_mappings; i++)
878 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
879 int action = property_mapping[i].ext1_index;
880 int sound = property_mapping[i].artwork_index;
882 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
886 action = ACTION_DEFAULT;
888 for (j=0; j < MAX_NUM_ELEMENTS; j++)
889 if (strcmp(element_info[j].class_name,
890 element_info[element_class].class_name) == 0)
891 element_info[j].sound[action] = sound;
894 /* initialize element/sound mapping from dynamic configuration */
895 for (i=0; i < num_property_mappings; i++)
897 int element = property_mapping[i].base_index;
898 int action = property_mapping[i].ext1_index;
899 int sound = property_mapping[i].artwork_index;
901 if (element >= MAX_NUM_ELEMENTS)
905 action = ACTION_DEFAULT;
907 element_info[element].sound[action] = sound;
910 /* now set all '-1' values to element specific default values */
911 for (i=0; i<MAX_NUM_ELEMENTS; i++)
913 for (act=0; act < NUM_ACTIONS; act++)
915 /* no sound for this specific action -- use default action sound */
916 if (element_info[i].sound[act] == -1)
917 element_info[i].sound[act] =
918 (element_info[i].sound[ACTION_DEFAULT] != -1 ?
919 element_info[i].sound[ACTION_DEFAULT] :
920 element_info[EL_INTERNAL_DEFAULT_ELEMENT].sound[act]);
925 static void set_sound_parameters(int sound, char **parameter_raw)
927 int parameter[NUM_SND_ARGS];
930 /* get integer values from string parameters */
931 for (i=0; i < NUM_SND_ARGS; i++)
933 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
934 sound_config_suffix[i].type);
936 /* explicit loop mode setting in configuration overrides default value */
937 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
938 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
941 static void InitSoundInfo()
943 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
944 int num_property_mappings = getSoundListPropertyMappingSize();
945 int *sound_effect_properties;
946 int num_sounds = getSoundListSize();
949 if (sound_info != NULL)
952 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
953 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
955 /* initialize sound effect for all elements to "no sound" */
956 for (i=0; i<MAX_NUM_ELEMENTS; i++)
957 for (j=0; j<NUM_ACTIONS; j++)
958 element_info[i].sound[j] = SND_UNDEFINED;
960 for (i=0; i<num_sounds; i++)
962 struct FileInfo *sound = getSoundListEntry(i);
963 int len_effect_text = strlen(sound->token);
965 sound_effect_properties[i] = ACTION_OTHER;
966 sound_info[i].loop = FALSE;
968 /* determine all loop sounds and identify certain sound classes */
970 for (j=0; element_action_info[j].suffix; j++)
972 int len_action_text = strlen(element_action_info[j].suffix);
974 if (len_action_text < len_effect_text &&
975 strcmp(&sound->token[len_effect_text - len_action_text],
976 element_action_info[j].suffix) == 0)
978 sound_effect_properties[i] = element_action_info[j].value;
980 if (element_action_info[j].is_loop_sound)
981 sound_info[i].loop = TRUE;
985 /* associate elements and some selected sound actions */
987 for (j=0; j<MAX_NUM_ELEMENTS; j++)
989 if (element_info[j].class_name)
991 int len_class_text = strlen(element_info[j].class_name);
993 if (len_class_text + 1 < len_effect_text &&
994 strncmp(sound->token,
995 element_info[j].class_name, len_class_text) == 0 &&
996 sound->token[len_class_text] == '.')
998 int sound_action_value = sound_effect_properties[i];
1000 element_info[j].sound[sound_action_value] = i;
1005 set_sound_parameters(i, sound->parameter);
1008 free(sound_effect_properties);
1010 /* initialize element/sound mapping from dynamic configuration */
1011 for (i=0; i < num_property_mappings; i++)
1013 int element = property_mapping[i].base_index;
1014 int action = property_mapping[i].ext1_index;
1015 int sound = property_mapping[i].artwork_index;
1018 action = ACTION_DEFAULT;
1020 element_info[element].sound[action] = sound;
1026 int element = EL_CUSTOM_11;
1029 while (element_action_info[j].suffix)
1031 printf("element %d, sound action '%s' == %d\n",
1032 element, element_action_info[j].suffix,
1033 element_info[element].sound[j]);
1038 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1044 int element = EL_SAND;
1045 int sound_action = ACTION_DIGGING;
1048 while (element_action_info[j].suffix)
1050 if (element_action_info[j].value == sound_action)
1051 printf("element %d, sound action '%s' == %d\n",
1052 element, element_action_info[j].suffix,
1053 element_info[element].sound[sound_action]);
1060 static void ReinitializeGraphics()
1062 InitGraphicInfo(); /* graphic properties mapping */
1063 InitElementGraphicInfo(); /* element game graphic mapping */
1064 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1066 InitElementSmallImages(); /* create editor and preview images */
1067 InitFontGraphicInfo(); /* initialize text drawing functions */
1069 SetMainBackgroundImage(IMG_BACKGROUND);
1070 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1076 static void ReinitializeSounds()
1078 InitSoundInfo(); /* sound properties mapping */
1079 InitElementSoundInfo(); /* element game sound mapping */
1081 InitPlaySoundLevel(); /* internal game sound settings */
1084 static void ReinitializeMusic()
1086 /* currently nothing to do */
1089 void InitElementPropertiesStatic()
1091 static int ep_diggable[] =
1096 EL_SP_BUGGY_BASE_ACTIVATING,
1099 EL_INVISIBLE_SAND_ACTIVE,
1101 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1105 EL_SP_BUGGY_BASE_ACTIVE,
1110 static int ep_collectible[] =
1127 EL_DYNABOMB_INCREASE_NUMBER,
1128 EL_DYNABOMB_INCREASE_SIZE,
1129 EL_DYNABOMB_INCREASE_POWER,
1143 static int ep_dont_run_into[] =
1145 /* same elements as in 'ep_dont_touch' */
1151 /* same elements as in 'ep_dont_collide_with' */
1163 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1165 EL_SP_BUGGY_BASE_ACTIVE,
1172 static int ep_dont_collide_with[] =
1174 /* same elements as in 'ep_dont_touch' */
1190 static int ep_dont_touch[] =
1199 static int ep_indestructible[] =
1203 EL_ACID_POOL_TOPLEFT,
1204 EL_ACID_POOL_TOPRIGHT,
1205 EL_ACID_POOL_BOTTOMLEFT,
1206 EL_ACID_POOL_BOTTOM,
1207 EL_ACID_POOL_BOTTOMRIGHT,
1208 EL_SP_HARDWARE_GRAY,
1209 EL_SP_HARDWARE_GREEN,
1210 EL_SP_HARDWARE_BLUE,
1212 EL_SP_HARDWARE_YELLOW,
1213 EL_SP_HARDWARE_BASE_1,
1214 EL_SP_HARDWARE_BASE_2,
1215 EL_SP_HARDWARE_BASE_3,
1216 EL_SP_HARDWARE_BASE_4,
1217 EL_SP_HARDWARE_BASE_5,
1218 EL_SP_HARDWARE_BASE_6,
1219 EL_INVISIBLE_STEELWALL,
1220 EL_INVISIBLE_STEELWALL_ACTIVE,
1221 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1222 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1223 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1224 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1225 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1226 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1227 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1228 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1229 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1230 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1231 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1232 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1234 EL_LIGHT_SWITCH_ACTIVE,
1235 EL_SIGN_EXCLAMATION,
1236 EL_SIGN_RADIOACTIVITY,
1247 EL_STEELWALL_SLANTED,
1270 EL_SWITCHGATE_OPENING,
1271 EL_SWITCHGATE_CLOSED,
1272 EL_SWITCHGATE_CLOSING,
1274 EL_SWITCHGATE_SWITCH_UP,
1275 EL_SWITCHGATE_SWITCH_DOWN,
1278 EL_TIMEGATE_OPENING,
1280 EL_TIMEGATE_CLOSING,
1283 EL_TIMEGATE_SWITCH_ACTIVE,
1288 EL_TUBE_VERTICAL_LEFT,
1289 EL_TUBE_VERTICAL_RIGHT,
1290 EL_TUBE_HORIZONTAL_UP,
1291 EL_TUBE_HORIZONTAL_DOWN,
1299 static int ep_slippery[] =
1313 EL_ROBOT_WHEEL_ACTIVE,
1319 EL_ACID_POOL_TOPLEFT,
1320 EL_ACID_POOL_TOPRIGHT,
1330 EL_STEELWALL_SLANTED,
1336 static int ep_can_change[] =
1341 static int ep_can_move[] =
1363 static int ep_can_fall[] =
1378 EL_BD_MAGIC_WALL_FULL,
1391 static int ep_can_smash_player[] =
1416 static int ep_can_smash_enemies[] =
1424 static int ep_can_smash_everything[] =
1432 static int ep_can_explode_by_fire[] =
1434 /* same elements as in 'ep_can_explode_impact' */
1439 /* same elements as in 'ep_can_explode_smashed' */
1448 EL_DYNABOMB_PLAYER_1_ACTIVE,
1449 EL_DYNABOMB_PLAYER_2_ACTIVE,
1450 EL_DYNABOMB_PLAYER_3_ACTIVE,
1451 EL_DYNABOMB_PLAYER_4_ACTIVE,
1452 EL_DYNABOMB_INCREASE_NUMBER,
1453 EL_DYNABOMB_INCREASE_SIZE,
1454 EL_DYNABOMB_INCREASE_POWER,
1455 EL_SP_DISK_RED_ACTIVE,
1465 static int ep_can_explode_smashed[] =
1467 /* same elements as in 'ep_can_explode_impact' */
1480 static int ep_can_explode_impact[] =
1488 static int ep_walkable_over[] =
1492 EL_SOKOBAN_FIELD_EMPTY,
1506 static int ep_walkable_inside[] =
1511 EL_TUBE_VERTICAL_LEFT,
1512 EL_TUBE_VERTICAL_RIGHT,
1513 EL_TUBE_HORIZONTAL_UP,
1514 EL_TUBE_HORIZONTAL_DOWN,
1522 static int ep_walkable_under[] =
1527 static int ep_passable_over[] =
1542 static int ep_passable_inside[] =
1548 EL_SP_PORT_HORIZONTAL,
1549 EL_SP_PORT_VERTICAL,
1551 EL_SP_GRAVITY_PORT_LEFT,
1552 EL_SP_GRAVITY_PORT_RIGHT,
1553 EL_SP_GRAVITY_PORT_UP,
1554 EL_SP_GRAVITY_PORT_DOWN,
1558 static int ep_passable_under[] =
1563 static int ep_pushable[] =
1575 EL_SOKOBAN_FIELD_FULL,
1582 static int ep_can_be_crumbled[] =
1591 static int ep_player[] =
1600 static int ep_can_pass_magic_wall[] =
1613 static int ep_switchable[] =
1617 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1618 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1619 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1620 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1621 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1622 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1623 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1624 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1625 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1626 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1627 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1628 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1629 EL_SWITCHGATE_SWITCH_UP,
1630 EL_SWITCHGATE_SWITCH_DOWN,
1632 EL_LIGHT_SWITCH_ACTIVE,
1634 EL_BALLOON_SWITCH_LEFT,
1635 EL_BALLOON_SWITCH_RIGHT,
1636 EL_BALLOON_SWITCH_UP,
1637 EL_BALLOON_SWITCH_DOWN,
1638 EL_BALLOON_SWITCH_ANY,
1644 static int ep_bd_element[] =
1673 static int ep_sp_element[] =
1681 EL_SP_HARDWARE_GRAY,
1689 EL_SP_GRAVITY_PORT_RIGHT,
1690 EL_SP_GRAVITY_PORT_DOWN,
1691 EL_SP_GRAVITY_PORT_LEFT,
1692 EL_SP_GRAVITY_PORT_UP,
1697 EL_SP_PORT_VERTICAL,
1698 EL_SP_PORT_HORIZONTAL,
1704 EL_SP_HARDWARE_BASE_1,
1705 EL_SP_HARDWARE_GREEN,
1706 EL_SP_HARDWARE_BLUE,
1708 EL_SP_HARDWARE_YELLOW,
1709 EL_SP_HARDWARE_BASE_2,
1710 EL_SP_HARDWARE_BASE_3,
1711 EL_SP_HARDWARE_BASE_4,
1712 EL_SP_HARDWARE_BASE_5,
1713 EL_SP_HARDWARE_BASE_6,
1716 /* additional elements that appeared in newer Supaplex levels */
1718 /* more than one murphy in a level results in an inactive clone */
1723 static int ep_sb_element[] =
1728 EL_SOKOBAN_FIELD_EMPTY,
1729 EL_SOKOBAN_FIELD_FULL,
1731 EL_INVISIBLE_STEELWALL,
1735 static int ep_gem[] =
1746 static int ep_food_dark_yamyam[] =
1773 static int ep_food_penguin[] =
1786 static int ep_food_pig[] =
1797 static int ep_historic_wall[] =
1822 EL_EXPANDABLE_WALL_HORIZONTAL,
1823 EL_EXPANDABLE_WALL_VERTICAL,
1824 EL_EXPANDABLE_WALL_ANY,
1825 EL_EXPANDABLE_WALL_GROWING,
1832 EL_SP_HARDWARE_GRAY,
1833 EL_SP_HARDWARE_GREEN,
1834 EL_SP_HARDWARE_BLUE,
1836 EL_SP_HARDWARE_YELLOW,
1837 EL_SP_HARDWARE_BASE_1,
1838 EL_SP_HARDWARE_BASE_2,
1839 EL_SP_HARDWARE_BASE_3,
1840 EL_SP_HARDWARE_BASE_4,
1841 EL_SP_HARDWARE_BASE_5,
1842 EL_SP_HARDWARE_BASE_6,
1844 EL_SP_TERMINAL_ACTIVE,
1847 EL_INVISIBLE_STEELWALL,
1848 EL_INVISIBLE_STEELWALL_ACTIVE,
1850 EL_INVISIBLE_WALL_ACTIVE,
1851 EL_STEELWALL_SLANTED,
1867 static int ep_historic_solid[] =
1871 EL_EXPANDABLE_WALL_HORIZONTAL,
1872 EL_EXPANDABLE_WALL_VERTICAL,
1873 EL_EXPANDABLE_WALL_ANY,
1886 EL_QUICKSAND_FILLING,
1887 EL_QUICKSAND_EMPTYING,
1889 EL_MAGIC_WALL_ACTIVE,
1890 EL_MAGIC_WALL_EMPTYING,
1891 EL_MAGIC_WALL_FILLING,
1895 EL_BD_MAGIC_WALL_ACTIVE,
1896 EL_BD_MAGIC_WALL_EMPTYING,
1897 EL_BD_MAGIC_WALL_FULL,
1898 EL_BD_MAGIC_WALL_FILLING,
1899 EL_BD_MAGIC_WALL_DEAD,
1908 EL_SP_TERMINAL_ACTIVE,
1912 EL_INVISIBLE_WALL_ACTIVE,
1913 EL_SWITCHGATE_SWITCH_UP,
1914 EL_SWITCHGATE_SWITCH_DOWN,
1916 EL_TIMEGATE_SWITCH_ACTIVE,
1928 /* the following elements are a direct copy of "indestructible" elements,
1929 except "EL_ACID", which is "indestructible", but not "solid"! */
1934 EL_ACID_POOL_TOPLEFT,
1935 EL_ACID_POOL_TOPRIGHT,
1936 EL_ACID_POOL_BOTTOMLEFT,
1937 EL_ACID_POOL_BOTTOM,
1938 EL_ACID_POOL_BOTTOMRIGHT,
1939 EL_SP_HARDWARE_GRAY,
1940 EL_SP_HARDWARE_GREEN,
1941 EL_SP_HARDWARE_BLUE,
1943 EL_SP_HARDWARE_YELLOW,
1944 EL_SP_HARDWARE_BASE_1,
1945 EL_SP_HARDWARE_BASE_2,
1946 EL_SP_HARDWARE_BASE_3,
1947 EL_SP_HARDWARE_BASE_4,
1948 EL_SP_HARDWARE_BASE_5,
1949 EL_SP_HARDWARE_BASE_6,
1950 EL_INVISIBLE_STEELWALL,
1951 EL_INVISIBLE_STEELWALL_ACTIVE,
1952 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1953 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1954 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1955 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1956 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1957 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1958 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1959 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1960 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1961 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1962 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1963 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1965 EL_LIGHT_SWITCH_ACTIVE,
1966 EL_SIGN_EXCLAMATION,
1967 EL_SIGN_RADIOACTIVITY,
1978 EL_STEELWALL_SLANTED,
2001 EL_SWITCHGATE_OPENING,
2002 EL_SWITCHGATE_CLOSED,
2003 EL_SWITCHGATE_CLOSING,
2005 EL_TIMEGATE_OPENING,
2007 EL_TIMEGATE_CLOSING,
2011 EL_TUBE_VERTICAL_LEFT,
2012 EL_TUBE_VERTICAL_RIGHT,
2013 EL_TUBE_HORIZONTAL_UP,
2014 EL_TUBE_HORIZONTAL_DOWN,
2022 static int ep_classic_enemy[] =
2038 static int ep_belt[] =
2040 EL_CONVEYOR_BELT_1_LEFT,
2041 EL_CONVEYOR_BELT_1_MIDDLE,
2042 EL_CONVEYOR_BELT_1_RIGHT,
2043 EL_CONVEYOR_BELT_2_LEFT,
2044 EL_CONVEYOR_BELT_2_MIDDLE,
2045 EL_CONVEYOR_BELT_2_RIGHT,
2046 EL_CONVEYOR_BELT_3_LEFT,
2047 EL_CONVEYOR_BELT_3_MIDDLE,
2048 EL_CONVEYOR_BELT_3_RIGHT,
2049 EL_CONVEYOR_BELT_4_LEFT,
2050 EL_CONVEYOR_BELT_4_MIDDLE,
2051 EL_CONVEYOR_BELT_4_RIGHT,
2055 static int ep_belt_active[] =
2057 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2058 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2059 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2060 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2061 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2062 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2063 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2064 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2065 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2066 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2067 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2068 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2072 static int ep_belt_switch[] =
2074 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2075 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2076 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2077 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2078 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2079 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2080 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2081 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2082 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2083 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2084 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2085 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2089 static int ep_tube[] =
2096 EL_TUBE_HORIZONTAL_UP,
2097 EL_TUBE_HORIZONTAL_DOWN,
2099 EL_TUBE_VERTICAL_LEFT,
2100 EL_TUBE_VERTICAL_RIGHT,
2105 static int ep_keygate[] =
2126 static int ep_amoeboid[] =
2136 static int ep_amoebalive[] =
2145 static int ep_has_content[] =
2155 static int ep_active_bomb[] =
2158 EL_DYNABOMB_PLAYER_1_ACTIVE,
2159 EL_DYNABOMB_PLAYER_2_ACTIVE,
2160 EL_DYNABOMB_PLAYER_3_ACTIVE,
2161 EL_DYNABOMB_PLAYER_4_ACTIVE,
2162 EL_SP_DISK_RED_ACTIVE,
2166 static int ep_inactive[] =
2203 EL_INVISIBLE_STEELWALL,
2211 EL_WALL_EMERALD_YELLOW,
2212 EL_DYNABOMB_INCREASE_NUMBER,
2213 EL_DYNABOMB_INCREASE_SIZE,
2214 EL_DYNABOMB_INCREASE_POWER,
2216 EL_SOKOBAN_FIELD_EMPTY,
2217 EL_SOKOBAN_FIELD_FULL,
2218 EL_WALL_EMERALD_RED,
2219 EL_WALL_EMERALD_PURPLE,
2220 EL_ACID_POOL_TOPLEFT,
2221 EL_ACID_POOL_TOPRIGHT,
2222 EL_ACID_POOL_BOTTOMLEFT,
2223 EL_ACID_POOL_BOTTOM,
2224 EL_ACID_POOL_BOTTOMRIGHT,
2228 EL_BD_MAGIC_WALL_DEAD,
2229 EL_AMOEBA_TO_DIAMOND,
2237 EL_SP_GRAVITY_PORT_RIGHT,
2238 EL_SP_GRAVITY_PORT_DOWN,
2239 EL_SP_GRAVITY_PORT_LEFT,
2240 EL_SP_GRAVITY_PORT_UP,
2241 EL_SP_PORT_HORIZONTAL,
2242 EL_SP_PORT_VERTICAL,
2251 EL_SP_HARDWARE_GRAY,
2252 EL_SP_HARDWARE_GREEN,
2253 EL_SP_HARDWARE_BLUE,
2255 EL_SP_HARDWARE_YELLOW,
2256 EL_SP_HARDWARE_BASE_1,
2257 EL_SP_HARDWARE_BASE_2,
2258 EL_SP_HARDWARE_BASE_3,
2259 EL_SP_HARDWARE_BASE_4,
2260 EL_SP_HARDWARE_BASE_5,
2261 EL_SP_HARDWARE_BASE_6,
2262 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2263 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2264 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2265 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2266 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2267 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2268 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2269 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2270 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2271 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2272 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2273 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2274 EL_SIGN_EXCLAMATION,
2275 EL_SIGN_RADIOACTIVITY,
2286 EL_STEELWALL_SLANTED,
2306 } element_properties[] =
2308 { ep_diggable, EP_DIGGABLE },
2309 { ep_collectible, EP_COLLECTIBLE },
2310 { ep_dont_run_into, EP_DONT_RUN_INTO },
2311 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
2312 { ep_dont_touch, EP_DONT_TOUCH },
2313 { ep_indestructible, EP_INDESTRUCTIBLE },
2314 { ep_slippery, EP_SLIPPERY },
2315 { ep_can_change, EP_CAN_CHANGE },
2316 { ep_can_move, EP_CAN_MOVE },
2317 { ep_can_fall, EP_CAN_FALL },
2318 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
2319 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
2320 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
2321 { ep_can_explode_by_fire, EP_CAN_EXPLODE_BY_FIRE },
2322 { ep_can_explode_smashed, EP_CAN_EXPLODE_SMASHED },
2323 { ep_can_explode_impact, EP_CAN_EXPLODE_IMPACT },
2324 { ep_walkable_over, EP_WALKABLE_OVER },
2325 { ep_walkable_inside, EP_WALKABLE_INSIDE },
2326 { ep_walkable_under, EP_WALKABLE_UNDER },
2327 { ep_passable_over, EP_PASSABLE_OVER },
2328 { ep_passable_inside, EP_PASSABLE_INSIDE },
2329 { ep_passable_under, EP_PASSABLE_UNDER },
2330 { ep_pushable, EP_PUSHABLE },
2332 { ep_can_be_crumbled, EP_CAN_BE_CRUMBLED },
2334 { ep_player, EP_PLAYER },
2335 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
2336 { ep_switchable, EP_SWITCHABLE },
2337 { ep_bd_element, EP_BD_ELEMENT },
2338 { ep_sp_element, EP_SP_ELEMENT },
2339 { ep_sb_element, EP_SB_ELEMENT },
2341 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
2342 { ep_food_penguin, EP_FOOD_PENGUIN },
2343 { ep_food_pig, EP_FOOD_PIG },
2344 { ep_historic_wall, EP_HISTORIC_WALL },
2345 { ep_historic_solid, EP_HISTORIC_SOLID },
2346 { ep_classic_enemy, EP_CLASSIC_ENEMY },
2347 { ep_belt, EP_BELT },
2348 { ep_belt_active, EP_BELT_ACTIVE },
2349 { ep_belt_switch, EP_BELT_SWITCH },
2350 { ep_tube, EP_TUBE },
2351 { ep_keygate, EP_KEYGATE },
2352 { ep_amoeboid, EP_AMOEBOID },
2353 { ep_amoebalive, EP_AMOEBALIVE },
2354 { ep_has_content, EP_HAS_CONTENT },
2355 { ep_active_bomb, EP_ACTIVE_BOMB },
2356 { ep_inactive, EP_INACTIVE },
2361 static int copy_properties[][5] =
2365 EL_BUG_LEFT, EL_BUG_RIGHT,
2366 EL_BUG_UP, EL_BUG_DOWN
2370 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
2371 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
2375 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
2376 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
2380 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
2381 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
2385 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
2386 EL_PACMAN_UP, EL_PACMAN_DOWN
2396 /* always start with reliable default values (element has no properties) */
2397 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2398 for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2399 SET_PROPERTY(i, j, FALSE);
2401 /* set all base element properties from above array definitions */
2402 for (i=0; element_properties[i].elements != NULL; i++)
2403 for (j=0; (element_properties[i].elements)[j] != -1; j++)
2404 SET_PROPERTY((element_properties[i].elements)[j],
2405 element_properties[i].property, TRUE);
2407 /* copy properties to some elements that are only stored in level file */
2408 for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2409 for (j=0; copy_properties[j][0] != -1; j++)
2410 if (HAS_PROPERTY(copy_properties[j][0], i))
2411 for (k=1; k<=4; k++)
2412 SET_PROPERTY(copy_properties[j][k], i, TRUE);
2415 void InitElementPropertiesEngine(int engine_version)
2418 static int active_properties[] =
2423 EP_DONT_COLLIDE_WITH,
2427 EP_CAN_PASS_MAGIC_WALL,
2432 EP_CAN_EXPLODE_BY_FIRE,
2445 EP_EM_SLIPPERY_WALL,
2450 static int no_wall_properties[] =
2455 EP_DONT_COLLIDE_WITH,
2458 EP_CAN_SMASH_PLAYER,
2459 EP_CAN_SMASH_ENEMIES,
2460 EP_CAN_SMASH_EVERYTHING,
2467 EP_FOOD_DARK_YAMYAM,
2483 InitElementPropertiesStatic();
2486 /* set all special, combined or engine dependant element properties */
2487 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2490 for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2491 SET_PROPERTY(i, j, FALSE);
2494 /* ---------- INACTIVE ------------------------------------------------- */
2495 if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2496 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2498 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2499 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2500 IS_WALKABLE_INSIDE(i) ||
2501 IS_WALKABLE_UNDER(i)));
2503 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2504 IS_PASSABLE_INSIDE(i) ||
2505 IS_PASSABLE_UNDER(i)));
2507 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2508 IS_PASSABLE_OVER(i)));
2510 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2511 IS_PASSABLE_INSIDE(i)));
2513 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2514 IS_PASSABLE_UNDER(i)));
2516 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2519 /* ---------- SNAPPABLE ------------------------------------------------ */
2520 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2521 IS_COLLECTIBLE(i) ||
2525 /* ---------- WALL ----------------------------------------------------- */
2526 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
2528 for (j=0; no_wall_properties[j] != -1; j++)
2529 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2530 i >= EL_FIRST_RUNTIME_UNREAL)
2531 SET_PROPERTY(i, EP_WALL, FALSE);
2533 if (IS_HISTORIC_WALL(i))
2534 SET_PROPERTY(i, EP_WALL, TRUE);
2536 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2537 if (engine_version < VERSION_IDENT(2,2,0))
2538 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2540 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2542 !IS_COLLECTIBLE(i)));
2544 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2546 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2547 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2549 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2550 IS_INDESTRUCTIBLE(i)));
2552 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2554 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2555 else if (engine_version < VERSION_IDENT(2,2,0))
2556 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2558 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2559 !IS_WALKABLE_OVER(i) &&
2560 !IS_WALKABLE_UNDER(i)));
2562 if (IS_CUSTOM_ELEMENT(i))
2564 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2566 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2567 if (DONT_COLLIDE_WITH(i))
2568 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2570 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2571 if (CAN_SMASH_EVERYTHING(i))
2572 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2573 if (CAN_SMASH_ENEMIES(i))
2574 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2577 /* ---------- CAN_SMASH ------------------------------------------------ */
2578 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2579 CAN_SMASH_ENEMIES(i) ||
2580 CAN_SMASH_EVERYTHING(i)));
2582 /* ---------- CAN_EXPLODE ---------------------------------------------- */
2583 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2584 CAN_EXPLODE_SMASHED(i) ||
2585 CAN_EXPLODE_BY_FIRE(i)));
2589 /* determine inactive elements (used for engine main loop optimization) */
2590 for (i=0; i < MAX_NUM_ELEMENTS; i++)
2592 boolean active = FALSE;
2594 for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2596 if (HAS_PROPERTY(i, j))
2602 SET_PROPERTY(i, EP_INACTIVE, TRUE);
2607 /* dynamically adjust element properties according to game engine version */
2609 static int ep_em_slippery_wall[] =
2614 EL_EXPANDABLE_WALL_HORIZONTAL,
2615 EL_EXPANDABLE_WALL_VERTICAL,
2616 EL_EXPANDABLE_WALL_ANY,
2620 /* special EM style gems behaviour */
2621 for (i=0; ep_em_slippery_wall[i] != -1; i++)
2622 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2623 level.em_slippery_gems);
2625 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2626 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2627 (level.em_slippery_gems &&
2628 engine_version > VERSION_IDENT(2,0,1)));
2631 /* dynamically adjust element properties according to game engine version */
2633 if (engine_version < RELEASE_IDENT(2,2,0,7))
2636 for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2638 int element = EL_CUSTOM_START + i;
2640 element_info[element].push_delay_fixed = 2;
2641 element_info[element].push_delay_random = 8;
2646 static void InitGlobal()
2648 global.autoplay_leveldir = NULL;
2650 global.frames_per_second = 0;
2651 global.fps_slowdown = FALSE;
2652 global.fps_slowdown_factor = 1;
2655 void Execute_Command(char *command)
2657 if (strcmp(command, "print graphicsinfo.conf") == 0)
2661 printf("# You can configure additional/alternative image files here.\n");
2662 printf("# (The images below are default and therefore commented out.)\n");
2664 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2666 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2669 for (i=0; image_config[i].token != NULL; i++)
2671 getFormattedSetupEntry(image_config[i].token,
2672 image_config[i].value));
2676 else if (strcmp(command, "print soundsinfo.conf") == 0)
2680 printf("# You can configure additional/alternative sound files here.\n");
2681 printf("# (The sounds below are default and therefore commented out.)\n");
2683 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2685 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2688 for (i=0; sound_config[i].token != NULL; i++)
2690 getFormattedSetupEntry(sound_config[i].token,
2691 sound_config[i].value));
2695 else if (strcmp(command, "print musicinfo.conf") == 0)
2697 printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2699 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2701 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2705 else if (strncmp(command, "dump level ", 11) == 0)
2707 char *filename = &command[11];
2709 if (access(filename, F_OK) != 0)
2710 Error(ERR_EXIT, "cannot open file '%s'", filename);
2712 LoadLevelFromFilename(filename);
2717 else if (strncmp(command, "dump tape ", 10) == 0)
2719 char *filename = &command[10];
2721 if (access(filename, F_OK) != 0)
2722 Error(ERR_EXIT, "cannot open file '%s'", filename);
2724 LoadTapeFromFilename(filename);
2729 else if (strncmp(command, "autoplay ", 9) == 0)
2731 char *str_copy = getStringCopy(&command[9]);
2732 char *str_ptr = strchr(str_copy, ' ');
2734 global.autoplay_leveldir = str_copy;
2735 global.autoplay_level_nr = -1;
2737 if (str_ptr != NULL)
2739 *str_ptr++ = '\0'; /* terminate leveldir string */
2740 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2745 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2749 static void InitSetup()
2751 LoadSetup(); /* global setup info */
2753 /* set some options from setup file */
2755 if (setup.options.verbose)
2756 options.verbose = TRUE;
2759 static void InitPlayerInfo()
2763 /* choose default local player */
2764 local_player = &stored_player[0];
2766 for (i=0; i<MAX_PLAYERS; i++)
2767 stored_player[i].connected = FALSE;
2769 local_player->connected = TRUE;
2772 static void InitArtworkInfo()
2777 static char *get_string_in_brackets(char *string)
2779 char *string_in_brackets = checked_malloc(strlen(string) + 3);
2781 sprintf(string_in_brackets, "[%s]", string);
2783 return string_in_brackets;
2787 static char *get_element_class_token(int element)
2789 char *element_class_name = element_info[element].class_name;
2790 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2792 sprintf(element_class_token, "[%s]", element_class_name);
2794 return element_class_token;
2797 static char *get_action_class_token(int action)
2799 char *action_class_name = &element_action_info[action].suffix[1];
2800 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2802 sprintf(action_class_token, "[%s]", action_class_name);
2804 return action_class_token;
2808 static void InitArtworkConfig()
2810 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2811 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2812 static char *action_id_suffix[NUM_ACTIONS + 1];
2813 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2814 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2815 static char *dummy[1] = { NULL };
2816 static char *ignore_generic_tokens[] =
2822 static char **ignore_image_tokens, **ignore_sound_tokens;
2823 int num_ignore_generic_tokens;
2824 int num_ignore_image_tokens, num_ignore_sound_tokens;
2827 /* dynamically determine list of generic tokens to be ignored */
2828 num_ignore_generic_tokens = 0;
2829 for (i=0; ignore_generic_tokens[i] != NULL; i++)
2830 num_ignore_generic_tokens++;
2832 /* dynamically determine list of image tokens to be ignored */
2833 num_ignore_image_tokens = num_ignore_generic_tokens;
2834 for (i=0; image_config_vars[i].token != NULL; i++)
2835 num_ignore_image_tokens++;
2836 ignore_image_tokens =
2837 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2838 for (i=0; i < num_ignore_generic_tokens; i++)
2839 ignore_image_tokens[i] = ignore_generic_tokens[i];
2840 for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2841 ignore_image_tokens[num_ignore_generic_tokens + i] =
2842 image_config_vars[i].token;
2843 ignore_image_tokens[num_ignore_image_tokens] = NULL;
2845 /* dynamically determine list of sound tokens to be ignored */
2846 num_ignore_sound_tokens = num_ignore_generic_tokens;
2847 ignore_sound_tokens =
2848 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2849 for (i=0; i < num_ignore_generic_tokens; i++)
2850 ignore_sound_tokens[i] = ignore_generic_tokens[i];
2851 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2853 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2854 image_id_prefix[i] = element_info[i].token_name;
2855 for (i=0; i<NUM_FONTS; i++)
2856 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2857 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2859 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2860 sound_id_prefix[i] = element_info[i].token_name;
2861 for (i=0; i<MAX_NUM_ELEMENTS; i++)
2862 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2863 get_string_in_brackets(element_info[i].class_name);
2864 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2866 for (i=0; i<NUM_ACTIONS; i++)
2867 action_id_suffix[i] = element_action_info[i].suffix;
2868 action_id_suffix[NUM_ACTIONS] = NULL;
2870 for (i=0; i<NUM_DIRECTIONS; i++)
2871 direction_id_suffix[i] = element_direction_info[i].suffix;
2872 direction_id_suffix[NUM_DIRECTIONS] = NULL;
2874 for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2875 special_id_suffix[i] = special_suffix_info[i].suffix;
2876 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2878 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2879 image_id_prefix, action_id_suffix, direction_id_suffix,
2880 special_id_suffix, ignore_image_tokens);
2881 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2882 sound_id_prefix, action_id_suffix, dummy,
2883 special_id_suffix, ignore_sound_tokens);
2886 static void InitMixer()
2894 char *filename_font_initial = NULL;
2895 Bitmap *bitmap_font_initial = NULL;
2898 /* determine settings for initial font (for displaying startup messages) */
2899 for (i=0; image_config[i].token != NULL; i++)
2901 for (j=0; j < NUM_INITIAL_FONTS; j++)
2903 char font_token[128];
2906 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2907 len_font_token = strlen(font_token);
2909 if (strcmp(image_config[i].token, font_token) == 0)
2910 filename_font_initial = image_config[i].value;
2911 else if (strlen(image_config[i].token) > len_font_token &&
2912 strncmp(image_config[i].token, font_token, len_font_token) == 0)
2914 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2915 font_initial[j].src_x = atoi(image_config[i].value);
2916 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2917 font_initial[j].src_y = atoi(image_config[i].value);
2918 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2919 font_initial[j].width = atoi(image_config[i].value);
2920 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2921 font_initial[j].height = atoi(image_config[i].value);
2926 for (j=0; j < NUM_INITIAL_FONTS; j++)
2928 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2929 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2932 if (filename_font_initial == NULL) /* should not happen */
2933 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2935 /* create additional image buffers for double-buffering */
2936 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2937 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2939 /* initialize screen properties */
2940 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2941 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2943 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2944 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2945 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2947 bitmap_font_initial = LoadCustomImage(filename_font_initial);
2949 for (j=0; j < NUM_INITIAL_FONTS; j++)
2950 font_initial[j].bitmap = bitmap_font_initial;
2952 InitFontGraphicInfo();
2954 DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2955 DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2957 DrawInitText("Loading graphics:", 120, FC_GREEN);
2959 InitTileClipmasks();
2962 void InitGfxBackground()
2966 drawto = backbuffer;
2967 fieldbuffer = bitmap_db_field;
2968 SetDrawtoField(DRAW_BACKBUFFER);
2970 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2971 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2972 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2973 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2975 for (x=0; x<MAX_BUF_XSIZE; x++)
2976 for (y=0; y<MAX_BUF_YSIZE; y++)
2979 redraw_mask = REDRAW_ALL;
2982 static void InitLevelInfo()
2984 LoadLevelInfo(); /* global level info */
2985 LoadLevelSetup_LastSeries(); /* last played series info */
2986 LoadLevelSetup_SeriesInfo(); /* last played level info */
2989 void InitLevelArtworkInfo()
2991 LoadLevelArtworkInfo();
2994 static void InitImages()
2996 ReloadCustomImages();
2998 LoadCustomElementDescriptions();
2999 LoadSpecialMenuDesignSettings();
3001 ReinitializeGraphics();
3004 static void InitSound()
3006 InitReloadCustomSounds(artwork.snd_current->identifier);
3007 ReinitializeSounds();
3010 static void InitMusic()
3012 InitReloadCustomMusic(artwork.mus_current->identifier);
3013 ReinitializeMusic();
3016 void InitNetworkServer()
3018 #if defined(PLATFORM_UNIX)
3022 if (!options.network)
3025 #if defined(PLATFORM_UNIX)
3026 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3028 if (!ConnectToServer(options.server_host, options.server_port))
3029 Error(ERR_EXIT, "cannot connect to network game server");
3031 SendToServer_PlayerName(setup.player_name);
3032 SendToServer_ProtocolVersion();
3035 SendToServer_NrWanted(nr_wanted);
3039 void ReloadCustomArtwork()
3041 static char *leveldir_current_identifier = NULL;
3042 static boolean last_override_level_graphics = FALSE;
3043 static boolean last_override_level_sounds = FALSE;
3044 static boolean last_override_level_music = FALSE;
3045 /* identifier for new artwork; default: artwork configured in setup */
3046 char *gfx_new_identifier = artwork.gfx_current->identifier;
3047 char *snd_new_identifier = artwork.snd_current->identifier;
3048 char *mus_new_identifier = artwork.mus_current->identifier;
3049 boolean redraw_screen = FALSE;
3051 if (leveldir_current_identifier == NULL)
3052 leveldir_current_identifier = leveldir_current->identifier;
3055 printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3056 leveldir_current->graphics_set);
3057 printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3058 leveldir_current->identifier);
3062 printf("graphics --> '%s' ('%s')\n",
3063 artwork.gfx_current_identifier, artwork.gfx_current->filename);
3064 printf("sounds --> '%s' ('%s')\n",
3065 artwork.snd_current_identifier, artwork.snd_current->filename);
3066 printf("music --> '%s' ('%s')\n",
3067 artwork.mus_current_identifier, artwork.mus_current->filename);
3070 /* leveldir_current may be invalid (level group, parent link) */
3071 if (!validLevelSeries(leveldir_current))
3074 /* when a new level series was selected, check if there was a change
3075 in custom artwork stored in level series directory */
3076 if (leveldir_current_identifier != leveldir_current->identifier)
3078 char *identifier_old = leveldir_current_identifier;
3079 char *identifier_new = leveldir_current->identifier;
3081 if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3082 getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3083 gfx_new_identifier = identifier_new;
3084 if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3085 getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3086 snd_new_identifier = identifier_new;
3087 if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3088 getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3089 mus_new_identifier = identifier_new;
3091 leveldir_current_identifier = leveldir_current->identifier;
3094 /* custom level artwork configured in level series configuration file
3095 always overrides custom level artwork stored in level series directory
3096 and (level independant) custom artwork configured in setup menue */
3097 if (leveldir_current->graphics_set != NULL)
3098 gfx_new_identifier = leveldir_current->graphics_set;
3099 if (leveldir_current->sounds_set != NULL)
3100 snd_new_identifier = leveldir_current->sounds_set;
3101 if (leveldir_current->music_set != NULL)
3102 mus_new_identifier = leveldir_current->music_set;
3104 if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3105 last_override_level_graphics != setup.override_level_graphics)
3108 printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3109 artwork.gfx_current_identifier,
3110 artwork.gfx_current->identifier,
3111 gfx_new_identifier);
3114 setLevelArtworkDir(artwork.gfx_first);
3116 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3120 FreeTileClipmasks();
3121 InitTileClipmasks();
3123 artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3124 last_override_level_graphics = setup.override_level_graphics;
3126 redraw_screen = TRUE;
3129 if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3130 last_override_level_sounds != setup.override_level_sounds)
3133 printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3134 artwork.snd_current_identifier,
3135 artwork.snd_current->identifier,
3136 snd_new_identifier);
3139 /* set artwork path to send it to the sound server process */
3140 setLevelArtworkDir(artwork.snd_first);
3142 InitReloadCustomSounds(snd_new_identifier);
3143 ReinitializeSounds();
3145 artwork.snd_current_identifier = artwork.snd_current->identifier;
3146 last_override_level_sounds = setup.override_level_sounds;
3148 redraw_screen = TRUE;
3151 if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3152 last_override_level_music != setup.override_level_music)
3154 /* set artwork path to send it to the sound server process */
3155 setLevelArtworkDir(artwork.mus_first);
3157 InitReloadCustomMusic(mus_new_identifier);
3158 ReinitializeMusic();
3160 artwork.mus_current_identifier = artwork.mus_current->identifier;
3161 last_override_level_music = setup.override_level_music;
3163 redraw_screen = TRUE;
3168 InitGfxBackground();
3170 /* force redraw of (open or closed) door graphics */
3171 SetDoorState(DOOR_OPEN_ALL);
3172 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3176 void KeyboardAutoRepeatOffUnlessAutoplay()
3178 if (global.autoplay_leveldir == NULL)
3179 KeyboardAutoRepeatOff();
3183 /* ========================================================================= */
3185 /* ========================================================================= */
3189 InitGlobal(); /* initialize some global variables */
3191 if (options.execute_command)
3192 Execute_Command(options.execute_command);
3194 if (options.serveronly)
3196 #if defined(PLATFORM_UNIX)
3197 NetworkServer(options.server_port, options.serveronly);
3199 Error(ERR_WARN, "networking only supported in Unix version");
3201 exit(0); /* never reached */
3207 InitArtworkInfo(); /* needed before loading gfx, sound & music */
3208 InitArtworkConfig(); /* needed before forking sound child process */
3213 InitRND(NEW_RANDOMIZE);
3214 InitSimpleRND(NEW_RANDOMIZE);
3219 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3222 InitEventFilter(FilterMouseMotionEvents);
3224 InitElementPropertiesStatic();
3229 InitLevelArtworkInfo();
3231 InitImages(); /* needs to know current level directory */
3232 InitSound(); /* needs to know current level directory */
3233 InitMusic(); /* needs to know current level directory */
3235 InitGfxBackground();
3237 if (global.autoplay_leveldir)
3243 game_status = GAME_MODE_MAIN;
3247 InitNetworkServer();
3250 void CloseAllAndExit(int exit_value)
3255 CloseAudio(); /* called after freeing sounds (needed for SDL) */
3258 FreeTileClipmasks();
3260 CloseVideoDisplay();
3261 ClosePlatformDependantStuff();