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"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static void InitTileClipmasks()
46 #if defined(TARGET_X11)
47 XGCValues clip_gc_values;
48 unsigned long clip_gc_valuemask;
50 #if defined(TARGET_X11_NATIVE)
60 tile_needs_clipping[] =
62 { GFX_SPIELER1_UP, 4 },
63 { GFX_SPIELER1_DOWN, 4 },
64 { GFX_SPIELER1_LEFT, 4 },
65 { GFX_SPIELER1_RIGHT, 4 },
66 { GFX_SPIELER1_PUSH_LEFT, 4 },
67 { GFX_SPIELER1_PUSH_RIGHT, 4 },
68 { GFX_SPIELER2_UP, 4 },
69 { GFX_SPIELER2_DOWN, 4 },
70 { GFX_SPIELER2_LEFT, 4 },
71 { GFX_SPIELER2_RIGHT, 4 },
72 { GFX_SPIELER2_PUSH_LEFT, 4 },
73 { GFX_SPIELER2_PUSH_RIGHT, 4 },
74 { GFX_SPIELER3_UP, 4 },
75 { GFX_SPIELER3_DOWN, 4 },
76 { GFX_SPIELER3_LEFT, 4 },
77 { GFX_SPIELER3_RIGHT, 4 },
78 { GFX_SPIELER3_PUSH_LEFT, 4 },
79 { GFX_SPIELER3_PUSH_RIGHT, 4 },
80 { GFX_SPIELER4_UP, 4 },
81 { GFX_SPIELER4_DOWN, 4 },
82 { GFX_SPIELER4_LEFT, 4 },
83 { GFX_SPIELER4_RIGHT, 4 },
84 { GFX_SPIELER4_PUSH_LEFT, 4 },
85 { GFX_SPIELER4_PUSH_RIGHT, 4 },
87 { GFX_MURPHY_GO_LEFT, 3 },
88 { GFX_MURPHY_GO_RIGHT, 3 },
89 { GFX_MURPHY_SNAP_UP, 1 },
90 { GFX_MURPHY_SNAP_DOWN, 1 },
91 { GFX_MURPHY_SNAP_RIGHT, 1 },
92 { GFX_MURPHY_SNAP_LEFT, 1 },
93 { GFX_MURPHY_PUSH_RIGHT, 1 },
94 { GFX_MURPHY_PUSH_LEFT, 1 },
99 { GFX_SOKOBAN_OBJEKT, 1 },
100 { GFX_FUNKELN_BLAU, 3 },
101 { GFX_FUNKELN_WEISS, 3 },
102 { GFX2_SHIELD_PASSIVE, 3 },
103 { GFX2_SHIELD_ACTIVE, 3 },
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
113 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114 for (i = 0; i < NUM_TILES; i++)
115 tile_clipmask[i] = None;
117 #if defined(TARGET_X11)
118 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119 often very slow when preparing a masked XCopyArea() for big Pixmaps.
120 To prevent this, create small (tile-sized) mask Pixmaps which will then
121 be set much faster with XSetClipOrigin() and speed things up a lot. */
123 clip_gc_values.graphics_exposures = False;
124 clip_gc_valuemask = GCGraphicsExposures;
125 tile_clip_gc = XCreateGC(display, window->drawable,
126 clip_gc_valuemask, &clip_gc_values);
129 for (i = 0; i < NUM_BITMAPS; i++)
131 if (pix[i]->clip_mask)
133 clip_gc_values.graphics_exposures = False;
134 clip_gc_values.clip_mask = pix[i]->clip_mask;
135 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137 clip_gc_valuemask, &clip_gc_values);
142 #if defined(TARGET_X11_NATIVE)
145 /* create graphic context structures needed for clipping */
146 clip_gc_values.graphics_exposures = False;
147 clip_gc_valuemask = GCGraphicsExposures;
148 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149 clip_gc_valuemask, &clip_gc_values);
151 /* create only those clipping Pixmaps we really need */
152 for (i = 0; tile_needs_clipping[i].start >= 0; i++)
156 for (j = 0; j < tile_needs_clipping[i].count; j++)
158 int tile = tile_needs_clipping[i].start + j;
164 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165 src_pixmap = src_bitmap->clip_mask;
167 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
170 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171 src_x, src_y, TILEX, TILEY, 0, 0);
175 XFreeGC(display, copy_clipmask_gc);
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
183 void FreeTileClipmasks()
186 #if defined(TARGET_X11)
189 for (i = 0; i < NUM_TILES; i++)
191 if (tile_clipmask[i] != None)
193 XFreePixmap(display, tile_clipmask[i]);
194 tile_clipmask[i] = None;
199 XFreeGC(display, tile_clip_gc);
203 for (i = 0; i < NUM_BITMAPS; i++)
205 if (pix[i] != NULL && pix[i]->stored_clip_gc)
207 XFreeGC(display, pix[i]->stored_clip_gc);
208 pix[i]->stored_clip_gc = None;
213 #endif /* TARGET_X11 */
219 FreeLevelEditorGadgets();
228 static boolean gadgets_initialized = FALSE;
230 if (gadgets_initialized)
233 CreateLevelEditorGadgets();
237 CreateScreenGadgets();
239 gadgets_initialized = TRUE;
242 inline void InitElementSmallImagesScaledUp(int graphic)
244 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
247 void InitElementSmallImages()
249 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250 int num_property_mappings = getImageListPropertyMappingSize();
253 /* initialize normal images from static configuration */
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
257 /* initialize special images from static configuration */
258 for (i = 0; element_to_special_graphic[i].element > -1; i++)
259 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 /* initialize images from dynamic configuration */
262 for (i = 0; i < num_property_mappings; i++)
263 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
267 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
268 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
269 InitElementSmallImagesScaledUp(i);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 void SetBitmaps_EM(Bitmap **em_bitmap)
277 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
278 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
282 static int getFontBitmapID(int font_nr)
286 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
287 special = game_status;
288 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
289 special = GFX_SPECIAL_ARG_MAIN;
290 else if (game_status == GAME_MODE_PLAYING)
291 special = GFX_SPECIAL_ARG_DOOR;
294 return font_info[font_nr].special_bitmap_id[special];
299 void InitFontGraphicInfo()
301 static struct FontBitmapInfo *font_bitmap_info = NULL;
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
304 int num_font_bitmaps = NUM_FONTS;
307 if (graphic_info == NULL) /* still at startup phase */
309 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
314 /* ---------- initialize font graphic definitions ---------- */
316 /* always start with reliable default values (normal font graphics) */
318 for (i = 0; i < NUM_FONTS; i++)
319 font_info[i].graphic = IMG_FONT_INITIAL_1;
321 for (i = 0; i < NUM_FONTS; i++)
322 font_info[i].graphic = FONT_INITIAL_1;
325 /* initialize normal font/graphic mapping from static configuration */
326 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
335 font_info[font_nr].graphic = graphic;
338 /* always start with reliable default values (special font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
341 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
343 font_info[i].special_graphic[j] = font_info[i].graphic;
344 font_info[i].special_bitmap_id[j] = i;
348 /* initialize special font/graphic mapping from static configuration */
349 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
351 int font_nr = font_to_graphic[i].font_nr;
352 int special = font_to_graphic[i].special;
353 int graphic = font_to_graphic[i].graphic;
355 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
357 font_info[font_nr].special_graphic[special] = graphic;
358 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
363 /* initialize special element/graphic mapping from dynamic configuration */
364 for (i = 0; i < num_property_mappings; i++)
366 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
367 int special = property_mapping[i].ext3_index;
368 int graphic = property_mapping[i].artwork_index;
373 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
375 font_info[font_nr].special_graphic[special] = graphic;
376 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
381 /* ---------- initialize font bitmap array ---------- */
383 if (font_bitmap_info != NULL)
384 FreeFontInfo(font_bitmap_info);
387 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
389 /* ---------- initialize font bitmap definitions ---------- */
391 for (i = 0; i < NUM_FONTS; i++)
393 if (i < NUM_INITIAL_FONTS)
395 font_bitmap_info[i] = font_initial[i];
399 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
401 int font_bitmap_id = font_info[i].special_bitmap_id[j];
402 int graphic = font_info[i].special_graphic[j];
404 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
405 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
407 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
408 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
411 /* copy font relevant information from graphics information */
412 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
413 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
414 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
415 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
416 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
417 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
418 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
420 font_bitmap_info[font_bitmap_id].num_chars =
421 graphic_info[graphic].anim_frames;
422 font_bitmap_info[font_bitmap_id].num_chars_per_line =
423 graphic_info[graphic].anim_frames_per_line;
427 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
430 void InitElementGraphicInfo()
432 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
433 int num_property_mappings = getImageListPropertyMappingSize();
436 if (graphic_info == NULL) /* still at startup phase */
439 /* set values to -1 to identify later as "uninitialized" values */
440 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
442 for (act = 0; act < NUM_ACTIONS; act++)
444 element_info[i].graphic[act] = -1;
445 element_info[i].crumbled[act] = -1;
447 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
449 element_info[i].direction_graphic[act][dir] = -1;
450 element_info[i].direction_crumbled[act][dir] = -1;
455 /* initialize normal element/graphic mapping from static configuration */
456 for (i = 0; element_to_graphic[i].element > -1; i++)
458 int element = element_to_graphic[i].element;
459 int action = element_to_graphic[i].action;
460 int direction = element_to_graphic[i].direction;
461 boolean crumbled = element_to_graphic[i].crumbled;
462 int graphic = element_to_graphic[i].graphic;
463 int base_graphic = el2baseimg(element);
465 if (graphic_info[graphic].bitmap == NULL)
468 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
471 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
472 boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
474 /* if the base graphic ("emerald", for example) has been redefined,
475 but not the action graphic ("emerald.falling", for example), do not
476 use an existing (in this case considered obsolete) action graphic
477 anymore, but use the automatically determined default graphic */
478 if (base_redefined && !act_dir_redefined)
483 action = ACTION_DEFAULT;
488 element_info[element].direction_crumbled[action][direction] = graphic;
490 element_info[element].crumbled[action] = graphic;
495 element_info[element].direction_graphic[action][direction] = graphic;
497 element_info[element].graphic[action] = graphic;
501 /* initialize normal element/graphic mapping from dynamic configuration */
502 for (i = 0; i < num_property_mappings; i++)
504 int element = property_mapping[i].base_index;
505 int action = property_mapping[i].ext1_index;
506 int direction = property_mapping[i].ext2_index;
507 int special = property_mapping[i].ext3_index;
508 int graphic = property_mapping[i].artwork_index;
509 boolean crumbled = FALSE;
511 if (special == GFX_SPECIAL_ARG_CRUMBLED)
517 if (graphic_info[graphic].bitmap == NULL)
520 if (element >= MAX_NUM_ELEMENTS || special != -1)
524 action = ACTION_DEFAULT;
529 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
530 element_info[element].direction_crumbled[action][dir] = -1;
533 element_info[element].direction_crumbled[action][direction] = graphic;
535 element_info[element].crumbled[action] = graphic;
540 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
541 element_info[element].direction_graphic[action][dir] = -1;
544 element_info[element].direction_graphic[action][direction] = graphic;
546 element_info[element].graphic[action] = graphic;
550 /* now copy all graphics that are defined to be cloned from other graphics */
551 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
553 int graphic = element_info[i].graphic[ACTION_DEFAULT];
554 int crumbled_like, diggable_like;
559 crumbled_like = graphic_info[graphic].crumbled_like;
560 diggable_like = graphic_info[graphic].diggable_like;
562 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
564 for (act = 0; act < NUM_ACTIONS; act++)
565 element_info[i].crumbled[act] =
566 element_info[crumbled_like].crumbled[act];
567 for (act = 0; act < NUM_ACTIONS; act++)
568 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
569 element_info[i].direction_crumbled[act][dir] =
570 element_info[crumbled_like].direction_crumbled[act][dir];
573 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
575 element_info[i].graphic[ACTION_DIGGING] =
576 element_info[diggable_like].graphic[ACTION_DIGGING];
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
579 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
584 /* set hardcoded definitions for some runtime elements without graphic */
585 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
589 /* now set all undefined/invalid graphics to -1 to set to default after it */
590 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
592 for (act = 0; act < NUM_ACTIONS; act++)
596 graphic = element_info[i].graphic[act];
597 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
598 element_info[i].graphic[act] = -1;
600 graphic = element_info[i].crumbled[act];
601 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
602 element_info[i].crumbled[act] = -1;
604 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
606 graphic = element_info[i].direction_graphic[act][dir];
607 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
608 element_info[i].direction_graphic[act][dir] = -1;
610 graphic = element_info[i].direction_crumbled[act][dir];
611 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
612 element_info[i].direction_crumbled[act][dir] = -1;
619 /* adjust graphics with 2nd tile for movement according to direction
620 (do this before correcting '-1' values to minimize calculations) */
621 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
623 for (act = 0; act < NUM_ACTIONS; act++)
625 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
627 int graphic = element_info[i].direction_graphic[act][dir];
628 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
630 if (act == ACTION_FALLING) /* special case */
631 graphic = element_info[i].graphic[act];
633 if (graphic != -1 && graphic_info[graphic].double_movement)
635 struct GraphicInfo *g = &graphic_info[graphic];
636 int src_x_front = g->src_x;
637 int src_y_front = g->src_y;
638 int src_x_back = g->src_x + g->offset2_x;
639 int src_y_back = g->src_y + g->offset2_y;
640 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
642 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
643 src_y_front < src_y_back);
647 printf("::: CHECKING ELEMENT %d ('%s'), ACTION '%s', DIRECTION %d\n",
648 i, element_info[i].token_name,
649 element_action_info[act].suffix, move_dir);
652 /* swap frontside and backside graphic tile coordinates, if needed */
653 if (!frames_are_ordered_diagonally &&
654 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
655 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
656 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
657 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)))
659 /* get current (wrong) backside tile coordinates */
660 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
663 /* set frontside tile coordinates to backside tile coordinates */
664 g->src_x = src_x_back;
665 g->src_y = src_y_back;
667 /* invert tile offset to point to new backside tile coordinates */
672 printf(" CORRECTED\n");
681 /* now set all '-1' values to element specific default values */
682 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
684 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
685 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
686 int default_direction_graphic[NUM_DIRECTIONS];
687 int default_direction_crumbled[NUM_DIRECTIONS];
689 if (default_graphic == -1)
690 default_graphic = IMG_UNKNOWN;
691 if (default_crumbled == -1)
692 default_crumbled = IMG_EMPTY;
694 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
696 default_direction_graphic[dir] =
697 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
698 default_direction_crumbled[dir] =
699 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
701 if (default_direction_graphic[dir] == -1)
702 default_direction_graphic[dir] = default_graphic;
703 if (default_direction_crumbled[dir] == -1)
704 default_direction_crumbled[dir] = default_crumbled;
707 for (act = 0; act < NUM_ACTIONS; act++)
709 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
710 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
711 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
712 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
713 act == ACTION_TURNING_FROM_RIGHT ||
714 act == ACTION_TURNING_FROM_UP ||
715 act == ACTION_TURNING_FROM_DOWN);
717 /* generic default action graphic (defined by "[default]" directive) */
718 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
719 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
721 /* look for special default action graphic (classic game specific) */
722 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
723 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
724 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
725 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
726 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
727 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
729 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
730 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
731 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
732 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
733 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
734 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
737 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
738 /* !!! make this better !!! */
739 if (i == EL_EMPTY_SPACE)
741 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
742 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
746 if (default_action_graphic == -1)
747 default_action_graphic = default_graphic;
748 if (default_action_crumbled == -1)
749 default_action_crumbled = default_crumbled;
751 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
753 int default_action_direction_graphic = element_info[i].graphic[act];
754 int default_action_direction_crumbled = element_info[i].crumbled[act];
756 /* no graphic for current action -- use default direction graphic */
757 /* !!! maybe it's better to use default _action_ graphic here !!! */
758 if (default_action_direction_graphic == -1)
759 default_action_direction_graphic =
760 (act_remove ? IMG_EMPTY :
762 element_info[i].direction_graphic[ACTION_TURNING][dir] :
763 default_direction_graphic[dir]);
764 if (default_action_direction_crumbled == -1)
765 default_action_direction_crumbled =
766 (act_remove ? IMG_EMPTY :
768 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
769 default_direction_crumbled[dir]);
771 if (element_info[i].direction_graphic[act][dir] == -1)
772 element_info[i].direction_graphic[act][dir] =
773 default_action_direction_graphic;
774 if (element_info[i].direction_crumbled[act][dir] == -1)
775 element_info[i].direction_crumbled[act][dir] =
776 default_action_direction_crumbled;
779 /* no graphic for this specific action -- use default action graphic */
780 if (element_info[i].graphic[act] == -1)
781 element_info[i].graphic[act] =
782 (act_remove ? IMG_EMPTY :
783 act_turning ? element_info[i].graphic[ACTION_TURNING] :
784 default_action_graphic);
785 if (element_info[i].crumbled[act] == -1)
786 element_info[i].crumbled[act] =
787 (act_remove ? IMG_EMPTY :
788 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
789 default_action_crumbled);
794 /* set animation mode to "none" for each graphic with only 1 frame */
795 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
797 for (act = 0; act < NUM_ACTIONS; act++)
799 int graphic = element_info[i].graphic[act];
800 int crumbled = element_info[i].crumbled[act];
802 if (graphic_info[graphic].anim_frames == 1)
803 graphic_info[graphic].anim_mode = ANIM_NONE;
804 if (graphic_info[crumbled].anim_frames == 1)
805 graphic_info[crumbled].anim_mode = ANIM_NONE;
807 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
809 graphic = element_info[i].direction_graphic[act][dir];
810 crumbled = element_info[i].direction_crumbled[act][dir];
812 if (graphic_info[graphic].anim_frames == 1)
813 graphic_info[graphic].anim_mode = ANIM_NONE;
814 if (graphic_info[crumbled].anim_frames == 1)
815 graphic_info[crumbled].anim_mode = ANIM_NONE;
825 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
826 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
828 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
829 element_info[i].token_name, i);
835 void InitElementSpecialGraphicInfo()
837 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
838 int num_property_mappings = getImageListPropertyMappingSize();
841 /* always start with reliable default values */
842 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
843 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
844 element_info[i].special_graphic[j] =
845 element_info[i].graphic[ACTION_DEFAULT];
847 /* initialize special element/graphic mapping from static configuration */
848 for (i = 0; element_to_special_graphic[i].element > -1; i++)
850 int element = element_to_special_graphic[i].element;
851 int special = element_to_special_graphic[i].special;
852 int graphic = element_to_special_graphic[i].graphic;
853 int base_graphic = el2baseimg(element);
854 boolean base_redefined = getImageListEntry(base_graphic)->redefined;
855 boolean special_redefined = getImageListEntry(graphic)->redefined;
857 /* if the base graphic ("emerald", for example) has been redefined,
858 but not the special graphic ("emerald.EDITOR", for example), do not
859 use an existing (in this case considered obsolete) special graphic
860 anymore, but use the automatically created (down-scaled) graphic */
861 if (base_redefined && !special_redefined)
864 element_info[element].special_graphic[special] = graphic;
867 /* initialize special element/graphic mapping from dynamic configuration */
868 for (i = 0; i < num_property_mappings; i++)
870 int element = property_mapping[i].base_index;
871 int special = property_mapping[i].ext3_index;
872 int graphic = property_mapping[i].artwork_index;
874 if (element >= MAX_NUM_ELEMENTS)
877 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
878 element_info[element].special_graphic[special] = graphic;
882 /* now set all undefined/invalid graphics to default */
883 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
884 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
885 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
886 element_info[i].special_graphic[j] =
887 element_info[i].graphic[ACTION_DEFAULT];
891 static int get_element_from_token(char *token)
895 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
896 if (strcmp(element_info[i].token_name, token) == 0)
902 static void set_graphic_parameters(int graphic, char **parameter_raw)
904 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
905 int parameter[NUM_GFX_ARGS];
906 int anim_frames_per_row = 1, anim_frames_per_col = 1;
907 int anim_frames_per_line = 1;
910 /* get integer values from string parameters */
911 for (i = 0; i < NUM_GFX_ARGS; i++)
914 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
915 image_config_suffix[i].type);
917 if (image_config_suffix[i].type == TYPE_TOKEN)
918 parameter[i] = get_element_from_token(parameter_raw[i]);
921 graphic_info[graphic].bitmap = src_bitmap;
923 /* start with reliable default values */
924 graphic_info[graphic].src_x = 0;
925 graphic_info[graphic].src_y = 0;
926 graphic_info[graphic].width = TILEX;
927 graphic_info[graphic].height = TILEY;
928 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
929 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
930 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
931 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
932 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
933 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
934 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
935 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
936 graphic_info[graphic].anim_delay_fixed = 0;
937 graphic_info[graphic].anim_delay_random = 0;
938 graphic_info[graphic].post_delay_fixed = 0;
939 graphic_info[graphic].post_delay_random = 0;
941 /* optional x and y tile position of animation frame sequence */
942 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
943 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
944 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
945 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
947 /* optional x and y pixel position of animation frame sequence */
948 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
949 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
950 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
951 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
953 /* optional width and height of each animation frame */
954 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
955 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
956 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
957 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
959 /* optional zoom factor for scaling up the image to a larger size */
960 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
961 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
962 if (graphic_info[graphic].scale_up_factor < 1)
963 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
967 /* bitmap is not scaled at this stage, so calculate final size */
968 int scale_up_factor = graphic_info[graphic].scale_up_factor;
969 int src_bitmap_width = src_bitmap->width * scale_up_factor;
970 int src_bitmap_height = src_bitmap->height * scale_up_factor;
972 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
973 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
976 /* correct x or y offset dependent of vertical or horizontal frame order */
977 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
979 graphic_info[graphic].offset_y =
980 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
981 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
982 anim_frames_per_line = anim_frames_per_col;
984 else /* frames are ordered horizontally */
986 graphic_info[graphic].offset_x =
987 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
988 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
989 anim_frames_per_line = anim_frames_per_row;
992 /* optionally, the x and y offset of frames can be specified directly */
993 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
995 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
996 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
998 /* optionally, moving animations may have separate start and end graphics */
999 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1001 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1002 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1004 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1005 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1006 graphic_info[graphic].offset2_y =
1007 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1008 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1009 else /* frames are ordered horizontally */
1010 graphic_info[graphic].offset2_x =
1011 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1012 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1014 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1015 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1016 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1017 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1018 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1020 /* automatically determine correct number of frames, if not defined */
1021 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1022 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1023 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1024 graphic_info[graphic].anim_frames = anim_frames_per_row;
1025 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1026 graphic_info[graphic].anim_frames = anim_frames_per_col;
1028 graphic_info[graphic].anim_frames = 1;
1030 graphic_info[graphic].anim_frames_per_line =
1031 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1032 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1034 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1035 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1036 graphic_info[graphic].anim_delay = 1;
1038 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1040 if (graphic_info[graphic].anim_frames == 1)
1041 graphic_info[graphic].anim_mode = ANIM_NONE;
1044 /* automatically determine correct start frame, if not defined */
1045 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].anim_start_frame = 0;
1047 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1048 graphic_info[graphic].anim_start_frame =
1049 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1051 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1053 /* animation synchronized with global frame counter, not move position */
1054 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1056 /* optional element for cloning crumble graphics */
1057 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1058 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1060 /* optional element for cloning digging graphics */
1061 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1062 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1064 /* optional border size for "crumbling" diggable graphics */
1065 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1066 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1068 /* this is only used for player "boring" and "sleeping" actions */
1069 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1070 graphic_info[graphic].anim_delay_fixed =
1071 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1072 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].anim_delay_random =
1074 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1075 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1076 graphic_info[graphic].post_delay_fixed =
1077 parameter[GFX_ARG_POST_DELAY_FIXED];
1078 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1079 graphic_info[graphic].post_delay_random =
1080 parameter[GFX_ARG_POST_DELAY_RANDOM];
1082 /* this is only used for toon animations */
1083 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1084 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1086 /* this is only used for drawing font characters */
1087 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1088 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1090 /* this is only used for drawing envelope graphics */
1091 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1094 static void InitGraphicInfo()
1096 int fallback_graphic = IMG_CHAR_EXCLAM;
1097 struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1098 Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1099 int num_images = getImageListSize();
1102 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1103 static boolean clipmasks_initialized = FALSE;
1105 XGCValues clip_gc_values;
1106 unsigned long clip_gc_valuemask;
1107 GC copy_clipmask_gc = None;
1110 checked_free(graphic_info);
1112 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1115 printf("::: graphic_info: %d entries\n", num_images);
1118 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1119 if (clipmasks_initialized)
1121 for (i = 0; i < num_images; i++)
1123 if (graphic_info[i].clip_mask)
1124 XFreePixmap(display, graphic_info[i].clip_mask);
1125 if (graphic_info[i].clip_gc)
1126 XFreeGC(display, graphic_info[i].clip_gc);
1128 graphic_info[i].clip_mask = None;
1129 graphic_info[i].clip_gc = None;
1134 for (i = 0; i < num_images; i++)
1136 struct FileInfo *image = getImageListEntry(i);
1139 int first_frame, last_frame;
1140 int scale_up_factor, src_bitmap_width, src_bitmap_height;
1143 printf("::: image: '%s' [%d]\n", image->token, i);
1147 printf("::: image # %d: '%s' ['%s']\n",
1149 getTokenFromImageID(i));
1152 set_graphic_parameters(i, image->parameter);
1154 /* now check if no animation frames are outside of the loaded image */
1156 if (graphic_info[i].bitmap == NULL)
1157 continue; /* skip check for optional images that are undefined */
1159 /* bitmap is not scaled at this stage, so calculate final size */
1160 scale_up_factor = graphic_info[i].scale_up_factor;
1161 src_bitmap_width = graphic_info[i].bitmap->width * scale_up_factor;
1162 src_bitmap_height = graphic_info[i].bitmap->height * scale_up_factor;
1165 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1166 if (src_x < 0 || src_y < 0 ||
1167 src_x + TILEX > src_bitmap_width ||
1168 src_y + TILEY > src_bitmap_height)
1170 Error(ERR_RETURN_LINE, "-");
1171 Error(ERR_RETURN, "warning: error found in config file:");
1172 Error(ERR_RETURN, "- config file: '%s'",
1173 getImageConfigFilename());
1174 Error(ERR_RETURN, "- config token: '%s'",
1175 getTokenFromImageID(i));
1176 Error(ERR_RETURN, "- image file: '%s'",
1177 src_bitmap->source_filename);
1179 "error: first animation frame out of bounds (%d, %d)",
1181 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1184 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1187 if (i == fallback_graphic)
1188 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1190 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1191 Error(ERR_RETURN_LINE, "-");
1193 set_graphic_parameters(i, fallback_image->default_parameter);
1194 graphic_info[i].bitmap = fallback_bitmap;
1197 last_frame = graphic_info[i].anim_frames - 1;
1198 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1199 if (src_x < 0 || src_y < 0 ||
1200 src_x + TILEX > src_bitmap_width ||
1201 src_y + TILEY > src_bitmap_height)
1203 Error(ERR_RETURN_LINE, "-");
1204 Error(ERR_RETURN, "warning: error found in config file:");
1205 Error(ERR_RETURN, "- config file: '%s'",
1206 getImageConfigFilename());
1207 Error(ERR_RETURN, "- config token: '%s'",
1208 getTokenFromImageID(i));
1209 Error(ERR_RETURN, "- image file: '%s'",
1210 src_bitmap->source_filename);
1212 "error: last animation frame (%d) out of bounds (%d, %d)",
1213 last_frame, src_x, src_y);
1214 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1216 if (i == fallback_graphic)
1217 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1219 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1220 Error(ERR_RETURN_LINE, "-");
1222 set_graphic_parameters(i, fallback_image->default_parameter);
1223 graphic_info[i].bitmap = fallback_bitmap;
1226 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1227 /* currently we need only a tile clip mask from the first frame */
1228 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1230 if (copy_clipmask_gc == None)
1232 clip_gc_values.graphics_exposures = False;
1233 clip_gc_valuemask = GCGraphicsExposures;
1234 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1235 clip_gc_valuemask, &clip_gc_values);
1238 graphic_info[i].clip_mask =
1239 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1241 src_pixmap = src_bitmap->clip_mask;
1242 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1243 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1245 clip_gc_values.graphics_exposures = False;
1246 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1247 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1249 graphic_info[i].clip_gc =
1250 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1254 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1255 if (copy_clipmask_gc)
1256 XFreeGC(display, copy_clipmask_gc);
1258 clipmasks_initialized = TRUE;
1262 static void InitElementSoundInfo()
1264 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1265 int num_property_mappings = getSoundListPropertyMappingSize();
1268 /* set values to -1 to identify later as "uninitialized" values */
1269 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1270 for (act = 0; act < NUM_ACTIONS; act++)
1271 element_info[i].sound[act] = -1;
1273 /* initialize element/sound mapping from static configuration */
1274 for (i = 0; element_to_sound[i].element > -1; i++)
1276 int element = element_to_sound[i].element;
1277 int action = element_to_sound[i].action;
1278 int sound = element_to_sound[i].sound;
1279 boolean is_class = element_to_sound[i].is_class;
1282 action = ACTION_DEFAULT;
1285 element_info[element].sound[action] = sound;
1287 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1288 if (strcmp(element_info[j].class_name,
1289 element_info[element].class_name) == 0)
1290 element_info[j].sound[action] = sound;
1293 /* initialize element class/sound mapping from dynamic configuration */
1294 for (i = 0; i < num_property_mappings; i++)
1296 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1297 int action = property_mapping[i].ext1_index;
1298 int sound = property_mapping[i].artwork_index;
1300 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1304 action = ACTION_DEFAULT;
1306 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1307 if (strcmp(element_info[j].class_name,
1308 element_info[element_class].class_name) == 0)
1309 element_info[j].sound[action] = sound;
1312 /* initialize element/sound mapping from dynamic configuration */
1313 for (i = 0; i < num_property_mappings; i++)
1315 int element = property_mapping[i].base_index;
1316 int action = property_mapping[i].ext1_index;
1317 int sound = property_mapping[i].artwork_index;
1319 if (element >= MAX_NUM_ELEMENTS)
1323 action = ACTION_DEFAULT;
1325 element_info[element].sound[action] = sound;
1328 /* now set all '-1' values to element specific default values */
1329 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1331 for (act = 0; act < NUM_ACTIONS; act++)
1333 /* generic default action sound (defined by "[default]" directive) */
1334 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1336 /* look for special default action sound (classic game specific) */
1337 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1338 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1339 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1340 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1341 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1342 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1344 /* !!! there's no such thing as a "default action sound" !!! */
1346 /* look for element specific default sound (independent from action) */
1347 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1348 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1352 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1353 /* !!! make this better !!! */
1354 if (i == EL_EMPTY_SPACE)
1355 default_action_sound = element_info[EL_DEFAULT].sound[act];
1358 /* no sound for this specific action -- use default action sound */
1359 if (element_info[i].sound[act] == -1)
1360 element_info[i].sound[act] = default_action_sound;
1365 static void InitGameModeSoundInfo()
1369 /* set values to -1 to identify later as "uninitialized" values */
1370 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1373 /* initialize gamemode/sound mapping from static configuration */
1374 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1376 int gamemode = gamemode_to_sound[i].gamemode;
1377 int sound = gamemode_to_sound[i].sound;
1380 gamemode = GAME_MODE_DEFAULT;
1382 menu.sound[gamemode] = sound;
1385 /* now set all '-1' values to levelset specific default values */
1386 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1387 if (menu.sound[i] == -1)
1388 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1392 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1393 if (menu.sound[i] != -1)
1394 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1398 static void set_sound_parameters(int sound, char **parameter_raw)
1400 int parameter[NUM_SND_ARGS];
1403 /* get integer values from string parameters */
1404 for (i = 0; i < NUM_SND_ARGS; i++)
1406 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1407 sound_config_suffix[i].type);
1409 /* explicit loop mode setting in configuration overrides default value */
1410 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1411 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1413 /* sound volume to change the original volume when loading the sound file */
1414 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1416 /* sound priority to give certain sounds a higher or lower priority */
1417 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1420 static void InitSoundInfo()
1423 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1424 int num_property_mappings = getSoundListPropertyMappingSize();
1426 int *sound_effect_properties;
1427 int num_sounds = getSoundListSize();
1430 checked_free(sound_info);
1432 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1433 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1435 /* initialize sound effect for all elements to "no sound" */
1436 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1437 for (j = 0; j < NUM_ACTIONS; j++)
1438 element_info[i].sound[j] = SND_UNDEFINED;
1440 for (i = 0; i < num_sounds; i++)
1442 struct FileInfo *sound = getSoundListEntry(i);
1443 int len_effect_text = strlen(sound->token);
1445 sound_effect_properties[i] = ACTION_OTHER;
1446 sound_info[i].loop = FALSE; /* default: play sound only once */
1449 printf("::: sound %d: '%s'\n", i, sound->token);
1452 /* determine all loop sounds and identify certain sound classes */
1454 for (j = 0; element_action_info[j].suffix; j++)
1456 int len_action_text = strlen(element_action_info[j].suffix);
1458 if (len_action_text < len_effect_text &&
1459 strcmp(&sound->token[len_effect_text - len_action_text],
1460 element_action_info[j].suffix) == 0)
1462 sound_effect_properties[i] = element_action_info[j].value;
1463 sound_info[i].loop = element_action_info[j].is_loop_sound;
1470 if (strcmp(sound->token, "custom_42") == 0)
1471 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1474 /* associate elements and some selected sound actions */
1476 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1478 if (element_info[j].class_name)
1480 int len_class_text = strlen(element_info[j].class_name);
1482 if (len_class_text + 1 < len_effect_text &&
1483 strncmp(sound->token,
1484 element_info[j].class_name, len_class_text) == 0 &&
1485 sound->token[len_class_text] == '.')
1487 int sound_action_value = sound_effect_properties[i];
1489 element_info[j].sound[sound_action_value] = i;
1494 set_sound_parameters(i, sound->parameter);
1497 free(sound_effect_properties);
1500 /* !!! now handled in InitElementSoundInfo() !!! */
1501 /* initialize element/sound mapping from dynamic configuration */
1502 for (i = 0; i < num_property_mappings; i++)
1504 int element = property_mapping[i].base_index;
1505 int action = property_mapping[i].ext1_index;
1506 int sound = property_mapping[i].artwork_index;
1509 action = ACTION_DEFAULT;
1511 printf("::: %d: %d, %d, %d ['%s']\n",
1512 i, element, action, sound, element_info[element].token_name);
1514 element_info[element].sound[action] = sound;
1521 int element = EL_CUSTOM_11;
1524 while (element_action_info[j].suffix)
1526 printf("element %d, sound action '%s' == %d\n",
1527 element, element_action_info[j].suffix,
1528 element_info[element].sound[j]);
1533 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1539 int element = EL_SAND;
1540 int sound_action = ACTION_DIGGING;
1543 while (element_action_info[j].suffix)
1545 if (element_action_info[j].value == sound_action)
1546 printf("element %d, sound action '%s' == %d\n",
1547 element, element_action_info[j].suffix,
1548 element_info[element].sound[sound_action]);
1555 static void InitGameModeMusicInfo()
1557 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1558 int num_property_mappings = getMusicListPropertyMappingSize();
1559 int default_levelset_music = -1;
1562 /* set values to -1 to identify later as "uninitialized" values */
1563 for (i = 0; i < MAX_LEVELS; i++)
1564 levelset.music[i] = -1;
1565 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1568 /* initialize gamemode/music mapping from static configuration */
1569 for (i = 0; gamemode_to_music[i].music > -1; i++)
1571 int gamemode = gamemode_to_music[i].gamemode;
1572 int music = gamemode_to_music[i].music;
1575 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1579 gamemode = GAME_MODE_DEFAULT;
1581 menu.music[gamemode] = music;
1584 /* initialize gamemode/music mapping from dynamic configuration */
1585 for (i = 0; i < num_property_mappings; i++)
1587 int prefix = property_mapping[i].base_index;
1588 int gamemode = property_mapping[i].ext1_index;
1589 int level = property_mapping[i].ext2_index;
1590 int music = property_mapping[i].artwork_index;
1593 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1594 prefix, gamemode, level, music);
1597 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1601 gamemode = GAME_MODE_DEFAULT;
1603 /* level specific music only allowed for in-game music */
1604 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1605 gamemode = GAME_MODE_PLAYING;
1610 default_levelset_music = music;
1613 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1614 levelset.music[level] = music;
1615 if (gamemode != GAME_MODE_PLAYING)
1616 menu.music[gamemode] = music;
1619 /* now set all '-1' values to menu specific default values */
1620 /* (undefined values of "levelset.music[]" might stay at "-1" to
1621 allow dynamic selection of music files from music directory!) */
1622 for (i = 0; i < MAX_LEVELS; i++)
1623 if (levelset.music[i] == -1)
1624 levelset.music[i] = default_levelset_music;
1625 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1626 if (menu.music[i] == -1)
1627 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1631 for (i = 0; i < MAX_LEVELS; i++)
1632 if (levelset.music[i] != -1)
1633 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1634 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1635 if (menu.music[i] != -1)
1636 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1640 static void set_music_parameters(int music, char **parameter_raw)
1642 int parameter[NUM_MUS_ARGS];
1645 /* get integer values from string parameters */
1646 for (i = 0; i < NUM_MUS_ARGS; i++)
1648 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1649 music_config_suffix[i].type);
1651 /* explicit loop mode setting in configuration overrides default value */
1652 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1653 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1656 static void InitMusicInfo()
1658 int num_music = getMusicListSize();
1661 checked_free(music_info);
1663 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1665 for (i = 0; i < num_music; i++)
1667 struct FileInfo *music = getMusicListEntry(i);
1668 int len_music_text = strlen(music->token);
1670 music_info[i].loop = TRUE; /* default: play music in loop mode */
1672 /* determine all loop music */
1674 for (j = 0; music_prefix_info[j].prefix; j++)
1676 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1678 if (len_prefix_text < len_music_text &&
1679 strncmp(music->token,
1680 music_prefix_info[j].prefix, len_prefix_text) == 0)
1682 music_info[i].loop = music_prefix_info[j].is_loop_music;
1688 set_music_parameters(i, music->parameter);
1692 static void ReinitializeGraphics()
1694 InitGraphicInfo(); /* graphic properties mapping */
1695 InitElementGraphicInfo(); /* element game graphic mapping */
1696 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1698 InitElementSmallImages(); /* scale images to all needed sizes */
1699 InitFontGraphicInfo(); /* initialize text drawing functions */
1701 SetMainBackgroundImage(IMG_BACKGROUND);
1702 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1708 static void ReinitializeSounds()
1710 InitSoundInfo(); /* sound properties mapping */
1711 InitElementSoundInfo(); /* element game sound mapping */
1712 InitGameModeSoundInfo(); /* game mode sound mapping */
1714 InitPlayLevelSound(); /* internal game sound settings */
1717 static void ReinitializeMusic()
1719 InitMusicInfo(); /* music properties mapping */
1720 InitGameModeMusicInfo(); /* game mode music mapping */
1723 static int get_special_property_bit(int element, int property_bit_nr)
1725 struct PropertyBitInfo
1731 static struct PropertyBitInfo pb_can_move_into_acid[] =
1733 /* the player may be able fall into acid when gravity is activated */
1738 { EL_SP_MURPHY, 0 },
1739 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1741 /* all element that can move may be able to also move into acid */
1744 { EL_BUG_RIGHT, 1 },
1747 { EL_SPACESHIP, 2 },
1748 { EL_SPACESHIP_LEFT, 2 },
1749 { EL_SPACESHIP_RIGHT, 2 },
1750 { EL_SPACESHIP_UP, 2 },
1751 { EL_SPACESHIP_DOWN, 2 },
1752 { EL_BD_BUTTERFLY, 3 },
1753 { EL_BD_BUTTERFLY_LEFT, 3 },
1754 { EL_BD_BUTTERFLY_RIGHT, 3 },
1755 { EL_BD_BUTTERFLY_UP, 3 },
1756 { EL_BD_BUTTERFLY_DOWN, 3 },
1757 { EL_BD_FIREFLY, 4 },
1758 { EL_BD_FIREFLY_LEFT, 4 },
1759 { EL_BD_FIREFLY_RIGHT, 4 },
1760 { EL_BD_FIREFLY_UP, 4 },
1761 { EL_BD_FIREFLY_DOWN, 4 },
1763 { EL_DARK_YAMYAM, 6 },
1766 { EL_PACMAN_LEFT, 8 },
1767 { EL_PACMAN_RIGHT, 8 },
1768 { EL_PACMAN_UP, 8 },
1769 { EL_PACMAN_DOWN, 8 },
1771 { EL_MOLE_LEFT, 9 },
1772 { EL_MOLE_RIGHT, 9 },
1774 { EL_MOLE_DOWN, 9 },
1778 { EL_SATELLITE, 13 },
1779 { EL_SP_SNIKSNAK, 14 },
1780 { EL_SP_ELECTRON, 15 },
1787 static struct PropertyBitInfo pb_dont_collide_with[] =
1789 { EL_SP_SNIKSNAK, 0 },
1790 { EL_SP_ELECTRON, 1 },
1798 struct PropertyBitInfo *pb_info;
1801 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1802 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1807 struct PropertyBitInfo *pb_info = NULL;
1810 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1811 if (pb_definition[i].bit_nr == property_bit_nr)
1812 pb_info = pb_definition[i].pb_info;
1814 if (pb_info == NULL)
1817 for (i = 0; pb_info[i].element != -1; i++)
1818 if (pb_info[i].element == element)
1819 return pb_info[i].bit_nr;
1825 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1826 boolean property_value)
1828 int bit_nr = get_special_property_bit(element, property_bit_nr);
1833 *bitfield |= (1 << bit_nr);
1835 *bitfield &= ~(1 << bit_nr);
1839 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1841 int bit_nr = get_special_property_bit(element, property_bit_nr);
1844 return ((*bitfield & (1 << bit_nr)) != 0);
1851 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1853 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1857 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1860 level->can_move_into_acid_bits |= (1 << bit_nr);
1864 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1866 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1869 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1875 void InitElementPropertiesStatic()
1877 static int ep_diggable[] =
1882 EL_SP_BUGGY_BASE_ACTIVATING,
1885 EL_INVISIBLE_SAND_ACTIVE,
1888 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1889 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1893 EL_SP_BUGGY_BASE_ACTIVE,
1899 static int ep_collectible_only[] =
1920 EL_DYNABOMB_INCREASE_NUMBER,
1921 EL_DYNABOMB_INCREASE_SIZE,
1922 EL_DYNABOMB_INCREASE_POWER,
1941 static int ep_dont_run_into[] =
1943 /* same elements as in 'ep_dont_touch' */
1949 /* same elements as in 'ep_dont_collide_with' */
1961 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1965 EL_SP_BUGGY_BASE_ACTIVE,
1971 static int ep_dont_collide_with[] =
1973 /* same elements as in 'ep_dont_touch' */
1989 static int ep_dont_touch[] =
1998 static int ep_indestructible[] =
2002 EL_ACID_POOL_TOPLEFT,
2003 EL_ACID_POOL_TOPRIGHT,
2004 EL_ACID_POOL_BOTTOMLEFT,
2005 EL_ACID_POOL_BOTTOM,
2006 EL_ACID_POOL_BOTTOMRIGHT,
2007 EL_SP_HARDWARE_GRAY,
2008 EL_SP_HARDWARE_GREEN,
2009 EL_SP_HARDWARE_BLUE,
2011 EL_SP_HARDWARE_YELLOW,
2012 EL_SP_HARDWARE_BASE_1,
2013 EL_SP_HARDWARE_BASE_2,
2014 EL_SP_HARDWARE_BASE_3,
2015 EL_SP_HARDWARE_BASE_4,
2016 EL_SP_HARDWARE_BASE_5,
2017 EL_SP_HARDWARE_BASE_6,
2018 EL_INVISIBLE_STEELWALL,
2019 EL_INVISIBLE_STEELWALL_ACTIVE,
2020 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2021 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2022 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2023 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2024 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2025 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2026 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2027 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2028 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2029 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2030 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2031 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2033 EL_LIGHT_SWITCH_ACTIVE,
2034 EL_SIGN_EXCLAMATION,
2035 EL_SIGN_RADIOACTIVITY,
2046 EL_STEELWALL_SLIPPERY,
2069 EL_SWITCHGATE_OPENING,
2070 EL_SWITCHGATE_CLOSED,
2071 EL_SWITCHGATE_CLOSING,
2073 EL_SWITCHGATE_SWITCH_UP,
2074 EL_SWITCHGATE_SWITCH_DOWN,
2077 EL_TIMEGATE_OPENING,
2079 EL_TIMEGATE_CLOSING,
2082 EL_TIMEGATE_SWITCH_ACTIVE,
2087 EL_TUBE_VERTICAL_LEFT,
2088 EL_TUBE_VERTICAL_RIGHT,
2089 EL_TUBE_HORIZONTAL_UP,
2090 EL_TUBE_HORIZONTAL_DOWN,
2098 static int ep_slippery[] =
2112 EL_ROBOT_WHEEL_ACTIVE,
2118 EL_ACID_POOL_TOPLEFT,
2119 EL_ACID_POOL_TOPRIGHT,
2129 EL_STEELWALL_SLIPPERY,
2132 EL_EMC_WALL_SLIPPERY_1,
2133 EL_EMC_WALL_SLIPPERY_2,
2134 EL_EMC_WALL_SLIPPERY_3,
2135 EL_EMC_WALL_SLIPPERY_4,
2139 static int ep_can_change[] =
2144 static int ep_can_move[] =
2146 /* same elements as in 'pb_can_move_into_acid' */
2168 static int ep_can_fall[] =
2183 EL_BD_MAGIC_WALL_FULL,
2196 static int ep_can_smash_player[] =
2221 static int ep_can_smash_enemies[] =
2229 static int ep_can_smash_everything[] =
2237 static int ep_explodes_by_fire[] =
2239 /* same elements as in 'ep_explodes_impact' */
2244 /* same elements as in 'ep_explodes_smashed' */
2253 EL_DYNABOMB_PLAYER_1_ACTIVE,
2254 EL_DYNABOMB_PLAYER_2_ACTIVE,
2255 EL_DYNABOMB_PLAYER_3_ACTIVE,
2256 EL_DYNABOMB_PLAYER_4_ACTIVE,
2257 EL_DYNABOMB_INCREASE_NUMBER,
2258 EL_DYNABOMB_INCREASE_SIZE,
2259 EL_DYNABOMB_INCREASE_POWER,
2260 EL_SP_DISK_RED_ACTIVE,
2273 static int ep_explodes_smashed[] =
2275 /* same elements as in 'ep_explodes_impact' */
2288 static int ep_explodes_impact[] =
2296 static int ep_walkable_over[] =
2300 EL_SOKOBAN_FIELD_EMPTY,
2318 static int ep_walkable_inside[] =
2323 EL_TUBE_VERTICAL_LEFT,
2324 EL_TUBE_VERTICAL_RIGHT,
2325 EL_TUBE_HORIZONTAL_UP,
2326 EL_TUBE_HORIZONTAL_DOWN,
2334 static int ep_walkable_under[] =
2339 static int ep_passable_over[] =
2362 static int ep_passable_inside[] =
2368 EL_SP_PORT_HORIZONTAL,
2369 EL_SP_PORT_VERTICAL,
2371 EL_SP_GRAVITY_PORT_LEFT,
2372 EL_SP_GRAVITY_PORT_RIGHT,
2373 EL_SP_GRAVITY_PORT_UP,
2374 EL_SP_GRAVITY_PORT_DOWN,
2375 EL_SP_GRAVITY_ON_PORT_LEFT,
2376 EL_SP_GRAVITY_ON_PORT_RIGHT,
2377 EL_SP_GRAVITY_ON_PORT_UP,
2378 EL_SP_GRAVITY_ON_PORT_DOWN,
2379 EL_SP_GRAVITY_OFF_PORT_LEFT,
2380 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2381 EL_SP_GRAVITY_OFF_PORT_UP,
2382 EL_SP_GRAVITY_OFF_PORT_DOWN,
2386 static int ep_passable_under[] =
2391 static int ep_droppable[] =
2396 static int ep_explodes_1x1_old[] =
2401 static int ep_pushable[] =
2413 EL_SOKOBAN_FIELD_FULL,
2421 static int ep_explodes_cross_old[] =
2426 static int ep_protected[] =
2428 /* same elements as in 'ep_walkable_inside' */
2432 EL_TUBE_VERTICAL_LEFT,
2433 EL_TUBE_VERTICAL_RIGHT,
2434 EL_TUBE_HORIZONTAL_UP,
2435 EL_TUBE_HORIZONTAL_DOWN,
2441 /* same elements as in 'ep_passable_over' */
2461 /* same elements as in 'ep_passable_inside' */
2466 EL_SP_PORT_HORIZONTAL,
2467 EL_SP_PORT_VERTICAL,
2469 EL_SP_GRAVITY_PORT_LEFT,
2470 EL_SP_GRAVITY_PORT_RIGHT,
2471 EL_SP_GRAVITY_PORT_UP,
2472 EL_SP_GRAVITY_PORT_DOWN,
2473 EL_SP_GRAVITY_ON_PORT_LEFT,
2474 EL_SP_GRAVITY_ON_PORT_RIGHT,
2475 EL_SP_GRAVITY_ON_PORT_UP,
2476 EL_SP_GRAVITY_ON_PORT_DOWN,
2477 EL_SP_GRAVITY_OFF_PORT_LEFT,
2478 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2479 EL_SP_GRAVITY_OFF_PORT_UP,
2480 EL_SP_GRAVITY_OFF_PORT_DOWN,
2484 static int ep_throwable[] =
2489 static int ep_can_explode[] =
2491 /* same elements as in 'ep_explodes_impact' */
2496 /* same elements as in 'ep_explodes_smashed' */
2502 /* elements that can explode by explosion or by dragonfire */
2505 EL_DYNABOMB_PLAYER_1_ACTIVE,
2506 EL_DYNABOMB_PLAYER_2_ACTIVE,
2507 EL_DYNABOMB_PLAYER_3_ACTIVE,
2508 EL_DYNABOMB_PLAYER_4_ACTIVE,
2509 EL_DYNABOMB_INCREASE_NUMBER,
2510 EL_DYNABOMB_INCREASE_SIZE,
2511 EL_DYNABOMB_INCREASE_POWER,
2512 EL_SP_DISK_RED_ACTIVE,
2520 /* elements that can explode only by explosion */
2525 static int ep_gravity_reachable[] =
2531 EL_INVISIBLE_SAND_ACTIVE,
2536 EL_SP_PORT_HORIZONTAL,
2537 EL_SP_PORT_VERTICAL,
2539 EL_SP_GRAVITY_PORT_LEFT,
2540 EL_SP_GRAVITY_PORT_RIGHT,
2541 EL_SP_GRAVITY_PORT_UP,
2542 EL_SP_GRAVITY_PORT_DOWN,
2543 EL_SP_GRAVITY_ON_PORT_LEFT,
2544 EL_SP_GRAVITY_ON_PORT_RIGHT,
2545 EL_SP_GRAVITY_ON_PORT_UP,
2546 EL_SP_GRAVITY_ON_PORT_DOWN,
2547 EL_SP_GRAVITY_OFF_PORT_LEFT,
2548 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2549 EL_SP_GRAVITY_OFF_PORT_UP,
2550 EL_SP_GRAVITY_OFF_PORT_DOWN,
2555 static int ep_player[] =
2562 EL_SOKOBAN_FIELD_PLAYER,
2567 static int ep_can_pass_magic_wall[] =
2580 static int ep_switchable[] =
2584 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2585 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2586 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2587 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2588 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2589 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2590 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2591 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2592 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2593 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2594 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2595 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2596 EL_SWITCHGATE_SWITCH_UP,
2597 EL_SWITCHGATE_SWITCH_DOWN,
2599 EL_LIGHT_SWITCH_ACTIVE,
2601 EL_BALLOON_SWITCH_LEFT,
2602 EL_BALLOON_SWITCH_RIGHT,
2603 EL_BALLOON_SWITCH_UP,
2604 EL_BALLOON_SWITCH_DOWN,
2605 EL_BALLOON_SWITCH_ANY,
2608 EL_EMC_MAGIC_BALL_SWITCH,
2612 static int ep_bd_element[] =
2645 static int ep_sp_element[] =
2647 /* should always be valid */
2650 /* standard classic Supaplex elements */
2657 EL_SP_HARDWARE_GRAY,
2665 EL_SP_GRAVITY_PORT_RIGHT,
2666 EL_SP_GRAVITY_PORT_DOWN,
2667 EL_SP_GRAVITY_PORT_LEFT,
2668 EL_SP_GRAVITY_PORT_UP,
2673 EL_SP_PORT_VERTICAL,
2674 EL_SP_PORT_HORIZONTAL,
2680 EL_SP_HARDWARE_BASE_1,
2681 EL_SP_HARDWARE_GREEN,
2682 EL_SP_HARDWARE_BLUE,
2684 EL_SP_HARDWARE_YELLOW,
2685 EL_SP_HARDWARE_BASE_2,
2686 EL_SP_HARDWARE_BASE_3,
2687 EL_SP_HARDWARE_BASE_4,
2688 EL_SP_HARDWARE_BASE_5,
2689 EL_SP_HARDWARE_BASE_6,
2693 /* additional elements that appeared in newer Supaplex levels */
2696 /* additional gravity port elements (not switching, but setting gravity) */
2697 EL_SP_GRAVITY_ON_PORT_LEFT,
2698 EL_SP_GRAVITY_ON_PORT_RIGHT,
2699 EL_SP_GRAVITY_ON_PORT_UP,
2700 EL_SP_GRAVITY_ON_PORT_DOWN,
2701 EL_SP_GRAVITY_OFF_PORT_LEFT,
2702 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2703 EL_SP_GRAVITY_OFF_PORT_UP,
2704 EL_SP_GRAVITY_OFF_PORT_DOWN,
2706 /* more than one Murphy in a level results in an inactive clone */
2709 /* runtime Supaplex elements */
2710 EL_SP_DISK_RED_ACTIVE,
2711 EL_SP_TERMINAL_ACTIVE,
2712 EL_SP_BUGGY_BASE_ACTIVATING,
2713 EL_SP_BUGGY_BASE_ACTIVE,
2719 static int ep_sb_element[] =
2724 EL_SOKOBAN_FIELD_EMPTY,
2725 EL_SOKOBAN_FIELD_FULL,
2726 EL_SOKOBAN_FIELD_PLAYER,
2731 EL_INVISIBLE_STEELWALL,
2735 static int ep_gem[] =
2746 static int ep_food_dark_yamyam[] =
2773 static int ep_food_penguin[] =
2786 static int ep_food_pig[] =
2797 static int ep_historic_wall[] =
2822 EL_EXPANDABLE_WALL_HORIZONTAL,
2823 EL_EXPANDABLE_WALL_VERTICAL,
2824 EL_EXPANDABLE_WALL_ANY,
2825 EL_EXPANDABLE_WALL_GROWING,
2832 EL_SP_HARDWARE_GRAY,
2833 EL_SP_HARDWARE_GREEN,
2834 EL_SP_HARDWARE_BLUE,
2836 EL_SP_HARDWARE_YELLOW,
2837 EL_SP_HARDWARE_BASE_1,
2838 EL_SP_HARDWARE_BASE_2,
2839 EL_SP_HARDWARE_BASE_3,
2840 EL_SP_HARDWARE_BASE_4,
2841 EL_SP_HARDWARE_BASE_5,
2842 EL_SP_HARDWARE_BASE_6,
2844 EL_SP_TERMINAL_ACTIVE,
2847 EL_INVISIBLE_STEELWALL,
2848 EL_INVISIBLE_STEELWALL_ACTIVE,
2850 EL_INVISIBLE_WALL_ACTIVE,
2851 EL_STEELWALL_SLIPPERY,
2867 static int ep_historic_solid[] =
2871 EL_EXPANDABLE_WALL_HORIZONTAL,
2872 EL_EXPANDABLE_WALL_VERTICAL,
2873 EL_EXPANDABLE_WALL_ANY,
2886 EL_QUICKSAND_FILLING,
2887 EL_QUICKSAND_EMPTYING,
2889 EL_MAGIC_WALL_ACTIVE,
2890 EL_MAGIC_WALL_EMPTYING,
2891 EL_MAGIC_WALL_FILLING,
2895 EL_BD_MAGIC_WALL_ACTIVE,
2896 EL_BD_MAGIC_WALL_EMPTYING,
2897 EL_BD_MAGIC_WALL_FULL,
2898 EL_BD_MAGIC_WALL_FILLING,
2899 EL_BD_MAGIC_WALL_DEAD,
2908 EL_SP_TERMINAL_ACTIVE,
2912 EL_INVISIBLE_WALL_ACTIVE,
2913 EL_SWITCHGATE_SWITCH_UP,
2914 EL_SWITCHGATE_SWITCH_DOWN,
2916 EL_TIMEGATE_SWITCH_ACTIVE,
2928 /* the following elements are a direct copy of "indestructible" elements,
2929 except "EL_ACID", which is "indestructible", but not "solid"! */
2934 EL_ACID_POOL_TOPLEFT,
2935 EL_ACID_POOL_TOPRIGHT,
2936 EL_ACID_POOL_BOTTOMLEFT,
2937 EL_ACID_POOL_BOTTOM,
2938 EL_ACID_POOL_BOTTOMRIGHT,
2939 EL_SP_HARDWARE_GRAY,
2940 EL_SP_HARDWARE_GREEN,
2941 EL_SP_HARDWARE_BLUE,
2943 EL_SP_HARDWARE_YELLOW,
2944 EL_SP_HARDWARE_BASE_1,
2945 EL_SP_HARDWARE_BASE_2,
2946 EL_SP_HARDWARE_BASE_3,
2947 EL_SP_HARDWARE_BASE_4,
2948 EL_SP_HARDWARE_BASE_5,
2949 EL_SP_HARDWARE_BASE_6,
2950 EL_INVISIBLE_STEELWALL,
2951 EL_INVISIBLE_STEELWALL_ACTIVE,
2952 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2953 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2954 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2955 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2956 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2957 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2958 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2959 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2960 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2961 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2962 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2963 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2965 EL_LIGHT_SWITCH_ACTIVE,
2966 EL_SIGN_EXCLAMATION,
2967 EL_SIGN_RADIOACTIVITY,
2978 EL_STEELWALL_SLIPPERY,
3001 EL_SWITCHGATE_OPENING,
3002 EL_SWITCHGATE_CLOSED,
3003 EL_SWITCHGATE_CLOSING,
3005 EL_TIMEGATE_OPENING,
3007 EL_TIMEGATE_CLOSING,
3011 EL_TUBE_VERTICAL_LEFT,
3012 EL_TUBE_VERTICAL_RIGHT,
3013 EL_TUBE_HORIZONTAL_UP,
3014 EL_TUBE_HORIZONTAL_DOWN,
3022 static int ep_classic_enemy[] =
3038 static int ep_belt[] =
3040 EL_CONVEYOR_BELT_1_LEFT,
3041 EL_CONVEYOR_BELT_1_MIDDLE,
3042 EL_CONVEYOR_BELT_1_RIGHT,
3043 EL_CONVEYOR_BELT_2_LEFT,
3044 EL_CONVEYOR_BELT_2_MIDDLE,
3045 EL_CONVEYOR_BELT_2_RIGHT,
3046 EL_CONVEYOR_BELT_3_LEFT,
3047 EL_CONVEYOR_BELT_3_MIDDLE,
3048 EL_CONVEYOR_BELT_3_RIGHT,
3049 EL_CONVEYOR_BELT_4_LEFT,
3050 EL_CONVEYOR_BELT_4_MIDDLE,
3051 EL_CONVEYOR_BELT_4_RIGHT,
3055 static int ep_belt_active[] =
3057 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3058 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3059 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3060 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3061 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3062 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3063 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3064 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3065 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3066 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3067 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3068 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3072 static int ep_belt_switch[] =
3074 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3075 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3076 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3077 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3078 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3079 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3080 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3081 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3082 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3083 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3084 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3085 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3089 static int ep_tube[] =
3096 EL_TUBE_HORIZONTAL_UP,
3097 EL_TUBE_HORIZONTAL_DOWN,
3099 EL_TUBE_VERTICAL_LEFT,
3100 EL_TUBE_VERTICAL_RIGHT,
3105 static int ep_keygate[] =
3134 static int ep_amoeboid[] =
3144 static int ep_amoebalive[] =
3153 static int ep_has_content[] =
3163 static int ep_can_turn_each_move[] =
3165 /* !!! do something with this one !!! */
3169 static int ep_can_grow[] =
3181 static int ep_active_bomb[] =
3184 EL_DYNABOMB_PLAYER_1_ACTIVE,
3185 EL_DYNABOMB_PLAYER_2_ACTIVE,
3186 EL_DYNABOMB_PLAYER_3_ACTIVE,
3187 EL_DYNABOMB_PLAYER_4_ACTIVE,
3188 EL_SP_DISK_RED_ACTIVE,
3192 static int ep_inactive[] =
3241 EL_INVISIBLE_STEELWALL,
3249 EL_WALL_EMERALD_YELLOW,
3250 EL_DYNABOMB_INCREASE_NUMBER,
3251 EL_DYNABOMB_INCREASE_SIZE,
3252 EL_DYNABOMB_INCREASE_POWER,
3256 EL_SOKOBAN_FIELD_EMPTY,
3257 EL_SOKOBAN_FIELD_FULL,
3258 EL_WALL_EMERALD_RED,
3259 EL_WALL_EMERALD_PURPLE,
3260 EL_ACID_POOL_TOPLEFT,
3261 EL_ACID_POOL_TOPRIGHT,
3262 EL_ACID_POOL_BOTTOMLEFT,
3263 EL_ACID_POOL_BOTTOM,
3264 EL_ACID_POOL_BOTTOMRIGHT,
3268 EL_BD_MAGIC_WALL_DEAD,
3269 EL_AMOEBA_TO_DIAMOND,
3277 EL_SP_GRAVITY_PORT_RIGHT,
3278 EL_SP_GRAVITY_PORT_DOWN,
3279 EL_SP_GRAVITY_PORT_LEFT,
3280 EL_SP_GRAVITY_PORT_UP,
3281 EL_SP_PORT_HORIZONTAL,
3282 EL_SP_PORT_VERTICAL,
3293 EL_SP_HARDWARE_GRAY,
3294 EL_SP_HARDWARE_GREEN,
3295 EL_SP_HARDWARE_BLUE,
3297 EL_SP_HARDWARE_YELLOW,
3298 EL_SP_HARDWARE_BASE_1,
3299 EL_SP_HARDWARE_BASE_2,
3300 EL_SP_HARDWARE_BASE_3,
3301 EL_SP_HARDWARE_BASE_4,
3302 EL_SP_HARDWARE_BASE_5,
3303 EL_SP_HARDWARE_BASE_6,
3304 EL_SP_GRAVITY_ON_PORT_LEFT,
3305 EL_SP_GRAVITY_ON_PORT_RIGHT,
3306 EL_SP_GRAVITY_ON_PORT_UP,
3307 EL_SP_GRAVITY_ON_PORT_DOWN,
3308 EL_SP_GRAVITY_OFF_PORT_LEFT,
3309 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3310 EL_SP_GRAVITY_OFF_PORT_UP,
3311 EL_SP_GRAVITY_OFF_PORT_DOWN,
3312 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3313 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3314 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3315 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3316 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3317 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3318 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3319 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3320 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3321 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3322 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3323 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3324 EL_SIGN_EXCLAMATION,
3325 EL_SIGN_RADIOACTIVITY,
3336 EL_STEELWALL_SLIPPERY,
3341 EL_EMC_WALL_SLIPPERY_1,
3342 EL_EMC_WALL_SLIPPERY_2,
3343 EL_EMC_WALL_SLIPPERY_3,
3344 EL_EMC_WALL_SLIPPERY_4,
3364 static int ep_em_slippery_wall[] =
3369 static int ep_gfx_crumbled[] =
3382 } element_properties[] =
3384 { ep_diggable, EP_DIGGABLE },
3385 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3386 { ep_dont_run_into, EP_DONT_RUN_INTO },
3387 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3388 { ep_dont_touch, EP_DONT_TOUCH },
3389 { ep_indestructible, EP_INDESTRUCTIBLE },
3390 { ep_slippery, EP_SLIPPERY },
3391 { ep_can_change, EP_CAN_CHANGE },
3392 { ep_can_move, EP_CAN_MOVE },
3393 { ep_can_fall, EP_CAN_FALL },
3394 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3395 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3396 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3397 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3398 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3399 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3400 { ep_walkable_over, EP_WALKABLE_OVER },
3401 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3402 { ep_walkable_under, EP_WALKABLE_UNDER },
3403 { ep_passable_over, EP_PASSABLE_OVER },
3404 { ep_passable_inside, EP_PASSABLE_INSIDE },
3405 { ep_passable_under, EP_PASSABLE_UNDER },
3406 { ep_droppable, EP_DROPPABLE },
3407 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3408 { ep_pushable, EP_PUSHABLE },
3409 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3410 { ep_protected, EP_PROTECTED },
3411 { ep_throwable, EP_THROWABLE },
3412 { ep_can_explode, EP_CAN_EXPLODE },
3413 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3415 { ep_player, EP_PLAYER },
3416 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3417 { ep_switchable, EP_SWITCHABLE },
3418 { ep_bd_element, EP_BD_ELEMENT },
3419 { ep_sp_element, EP_SP_ELEMENT },
3420 { ep_sb_element, EP_SB_ELEMENT },
3422 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3423 { ep_food_penguin, EP_FOOD_PENGUIN },
3424 { ep_food_pig, EP_FOOD_PIG },
3425 { ep_historic_wall, EP_HISTORIC_WALL },
3426 { ep_historic_solid, EP_HISTORIC_SOLID },
3427 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3428 { ep_belt, EP_BELT },
3429 { ep_belt_active, EP_BELT_ACTIVE },
3430 { ep_belt_switch, EP_BELT_SWITCH },
3431 { ep_tube, EP_TUBE },
3432 { ep_keygate, EP_KEYGATE },
3433 { ep_amoeboid, EP_AMOEBOID },
3434 { ep_amoebalive, EP_AMOEBALIVE },
3435 { ep_has_content, EP_HAS_CONTENT },
3436 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3437 { ep_can_grow, EP_CAN_GROW },
3438 { ep_active_bomb, EP_ACTIVE_BOMB },
3439 { ep_inactive, EP_INACTIVE },
3441 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3443 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3448 static int copy_properties[][5] =
3452 EL_BUG_LEFT, EL_BUG_RIGHT,
3453 EL_BUG_UP, EL_BUG_DOWN
3457 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3458 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3462 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3463 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3467 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3468 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3472 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3473 EL_PACMAN_UP, EL_PACMAN_DOWN
3477 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3478 EL_MOLE_UP, EL_MOLE_DOWN
3488 /* always start with reliable default values (element has no properties) */
3489 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3490 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3491 SET_PROPERTY(i, j, FALSE);
3493 /* set all base element properties from above array definitions */
3494 for (i = 0; element_properties[i].elements != NULL; i++)
3495 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3496 SET_PROPERTY((element_properties[i].elements)[j],
3497 element_properties[i].property, TRUE);
3499 /* copy properties to some elements that are only stored in level file */
3500 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3501 for (j = 0; copy_properties[j][0] != -1; j++)
3502 if (HAS_PROPERTY(copy_properties[j][0], i))
3503 for (k = 1; k <= 4; k++)
3504 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3507 void InitElementPropertiesEngine(int engine_version)
3510 static int active_properties[] =
3515 EP_DONT_COLLIDE_WITH,
3519 EP_CAN_PASS_MAGIC_WALL,
3524 EP_EXPLODES_BY_FIRE,
3537 EP_EM_SLIPPERY_WALL,
3541 static int no_wall_properties[] =
3544 EP_COLLECTIBLE_ONLY,
3546 EP_DONT_COLLIDE_WITH,
3549 EP_CAN_SMASH_PLAYER,
3550 EP_CAN_SMASH_ENEMIES,
3551 EP_CAN_SMASH_EVERYTHING,
3556 EP_FOOD_DARK_YAMYAM,
3573 InitElementPropertiesStatic();
3576 /* important: after initialization in InitElementPropertiesStatic(), the
3577 elements are not again initialized to a default value; therefore all
3578 changes have to make sure that they leave the element with a defined
3579 property (which means that conditional property changes must be set to
3580 a reliable default value before) */
3582 /* set all special, combined or engine dependent element properties */
3583 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3586 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3587 SET_PROPERTY(i, j, FALSE);
3590 /* ---------- INACTIVE ------------------------------------------------- */
3591 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3593 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3594 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3595 IS_WALKABLE_INSIDE(i) ||
3596 IS_WALKABLE_UNDER(i)));
3598 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3599 IS_PASSABLE_INSIDE(i) ||
3600 IS_PASSABLE_UNDER(i)));
3602 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3603 IS_PASSABLE_OVER(i)));
3605 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3606 IS_PASSABLE_INSIDE(i)));
3608 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3609 IS_PASSABLE_UNDER(i)));
3611 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3614 /* ---------- COLLECTIBLE ---------------------------------------------- */
3615 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3619 /* ---------- SNAPPABLE ------------------------------------------------ */
3620 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3621 IS_COLLECTIBLE(i) ||
3625 /* ---------- WALL ----------------------------------------------------- */
3626 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3628 for (j = 0; no_wall_properties[j] != -1; j++)
3629 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3630 i >= EL_FIRST_RUNTIME_UNREAL)
3631 SET_PROPERTY(i, EP_WALL, FALSE);
3633 if (IS_HISTORIC_WALL(i))
3634 SET_PROPERTY(i, EP_WALL, TRUE);
3636 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3637 if (engine_version < VERSION_IDENT(2,2,0,0))
3638 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3640 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3642 !IS_COLLECTIBLE(i)));
3645 /* ---------- PROTECTED ------------------------------------------------ */
3646 if (IS_ACCESSIBLE_INSIDE(i))
3647 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3650 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3652 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3653 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3655 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3656 IS_INDESTRUCTIBLE(i)));
3658 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3660 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3661 else if (engine_version < VERSION_IDENT(2,2,0,0))
3662 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3665 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3670 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3671 !IS_WALKABLE_OVER(i) &&
3672 !IS_WALKABLE_UNDER(i)));
3674 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3679 if (IS_CUSTOM_ELEMENT(i))
3681 /* these are additional properties which are initially false when set */
3683 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3685 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3686 if (DONT_COLLIDE_WITH(i))
3687 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3689 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3690 if (CAN_SMASH_EVERYTHING(i))
3691 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3692 if (CAN_SMASH_ENEMIES(i))
3693 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3696 /* ---------- CAN_SMASH ------------------------------------------------ */
3697 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3698 CAN_SMASH_ENEMIES(i) ||
3699 CAN_SMASH_EVERYTHING(i)));
3702 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3703 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3704 CAN_EXPLODE_SMASHED(i) ||
3705 CAN_EXPLODE_IMPACT(i)));
3709 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3711 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3712 !CAN_EXPLODE_CROSS(i)));
3714 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3715 !CAN_EXPLODE_1X1(i) &&
3716 !CAN_EXPLODE_CROSS(i)));
3720 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3721 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3722 EXPLODES_BY_FIRE(i)));
3724 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3725 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3726 EXPLODES_SMASHED(i)));
3728 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3729 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3730 EXPLODES_IMPACT(i)));
3732 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3733 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3735 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3736 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3737 i == EL_BLACK_ORB));
3739 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3740 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3742 IS_CUSTOM_ELEMENT(i)));
3744 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3745 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3746 i == EL_SP_ELECTRON));
3748 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3749 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3750 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3751 getMoveIntoAcidProperty(&level, i));
3753 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3754 if (MAYBE_DONT_COLLIDE_WITH(i))
3755 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3756 getDontCollideWithProperty(&level, i));
3758 /* ---------- SP_PORT -------------------------------------------------- */
3759 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3760 IS_PASSABLE_INSIDE(i)));
3762 /* ---------- CAN_CHANGE ----------------------------------------------- */
3763 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3764 for (j = 0; j < element_info[i].num_change_pages; j++)
3765 if (element_info[i].change_page[j].can_change)
3766 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3768 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3769 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3770 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3774 /* determine inactive elements (used for engine main loop optimization) */
3775 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3777 boolean active = FALSE;
3779 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3781 if (HAS_PROPERTY(i, j))
3787 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3792 /* dynamically adjust element properties according to game engine version */
3794 static int ep_em_slippery_wall[] =
3799 EL_EXPANDABLE_WALL_HORIZONTAL,
3800 EL_EXPANDABLE_WALL_VERTICAL,
3801 EL_EXPANDABLE_WALL_ANY,
3805 /* special EM style gems behaviour */
3806 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3807 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3808 level.em_slippery_gems);
3810 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3811 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3812 (level.em_slippery_gems &&
3813 engine_version > VERSION_IDENT(2,0,1,0)));
3817 /* set default push delay values (corrected since version 3.0.7-1) */
3818 if (engine_version < VERSION_IDENT(3,0,7,1))
3820 game.default_push_delay_fixed = 2;
3821 game.default_push_delay_random = 8;
3825 game.default_push_delay_fixed = 8;
3826 game.default_push_delay_random = 8;
3829 /* set uninitialized push delay values of custom elements in older levels */
3830 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3832 int element = EL_CUSTOM_START + i;
3834 if (element_info[element].push_delay_fixed == -1)
3835 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3836 if (element_info[element].push_delay_random == -1)
3837 element_info[element].push_delay_random = game.default_push_delay_random;
3840 /* set some other uninitialized values of custom elements in older levels */
3841 if (engine_version < VERSION_IDENT(3,1,0,0))
3843 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3845 int element = EL_CUSTOM_START + i;
3847 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3849 element_info[element].explosion_delay = 17;
3850 element_info[element].ignition_delay = 8;
3855 /* set element properties that were handled incorrectly in older levels */
3856 if (engine_version < VERSION_IDENT(3,1,0,0))
3858 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3859 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3865 /* this is needed because some graphics depend on element properties */
3866 if (game_status == GAME_MODE_PLAYING)
3867 InitElementGraphicInfo();
3870 static void InitGlobal()
3874 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3876 /* check if element_name_info entry defined for each element in "main.h" */
3877 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3878 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3880 element_info[i].token_name = element_name_info[i].token_name;
3881 element_info[i].class_name = element_name_info[i].class_name;
3882 element_info[i].editor_description=element_name_info[i].editor_description;
3885 global.autoplay_leveldir = NULL;
3886 global.convert_leveldir = NULL;
3888 global.frames_per_second = 0;
3889 global.fps_slowdown = FALSE;
3890 global.fps_slowdown_factor = 1;
3893 void Execute_Command(char *command)
3897 if (strcmp(command, "print graphicsinfo.conf") == 0)
3899 printf("# You can configure additional/alternative image files here.\n");
3900 printf("# (The entries below are default and therefore commented out.)\n");
3902 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3904 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3907 for (i = 0; image_config[i].token != NULL; i++)
3908 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3909 image_config[i].value));
3913 else if (strcmp(command, "print soundsinfo.conf") == 0)
3915 printf("# You can configure additional/alternative sound files here.\n");
3916 printf("# (The entries below are default and therefore commented out.)\n");
3918 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3920 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3923 for (i = 0; sound_config[i].token != NULL; i++)
3924 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3925 sound_config[i].value));
3929 else if (strcmp(command, "print musicinfo.conf") == 0)
3931 printf("# You can configure additional/alternative music files here.\n");
3932 printf("# (The entries below are default and therefore commented out.)\n");
3934 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3936 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3939 for (i = 0; music_config[i].token != NULL; i++)
3940 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3941 music_config[i].value));
3945 else if (strcmp(command, "print editorsetup.conf") == 0)
3947 printf("# You can configure your personal editor element list here.\n");
3948 printf("# (The entries below are default and therefore commented out.)\n");
3951 PrintEditorElementList();
3955 else if (strcmp(command, "print helpanim.conf") == 0)
3957 printf("# You can configure different element help animations here.\n");
3958 printf("# (The entries below are default and therefore commented out.)\n");
3961 for (i = 0; helpanim_config[i].token != NULL; i++)
3963 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3964 helpanim_config[i].value));
3966 if (strcmp(helpanim_config[i].token, "end") == 0)
3972 else if (strcmp(command, "print helptext.conf") == 0)
3974 printf("# You can configure different element help text here.\n");
3975 printf("# (The entries below are default and therefore commented out.)\n");
3978 for (i = 0; helptext_config[i].token != NULL; i++)
3979 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3980 helptext_config[i].value));
3984 else if (strncmp(command, "dump level ", 11) == 0)
3986 char *filename = &command[11];
3988 if (access(filename, F_OK) != 0)
3989 Error(ERR_EXIT, "cannot open file '%s'", filename);
3991 LoadLevelFromFilename(&level, filename);
3996 else if (strncmp(command, "dump tape ", 10) == 0)
3998 char *filename = &command[10];
4000 if (access(filename, F_OK) != 0)
4001 Error(ERR_EXIT, "cannot open file '%s'", filename);
4003 LoadTapeFromFilename(filename);
4008 else if (strncmp(command, "autoplay ", 9) == 0)
4010 char *str_copy = getStringCopy(&command[9]);
4011 char *str_ptr = strchr(str_copy, ' ');
4013 global.autoplay_leveldir = str_copy;
4014 global.autoplay_level_nr = -1;
4016 if (str_ptr != NULL)
4018 *str_ptr++ = '\0'; /* terminate leveldir string */
4019 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4022 else if (strncmp(command, "convert ", 8) == 0)
4024 char *str_copy = getStringCopy(&command[8]);
4025 char *str_ptr = strchr(str_copy, ' ');
4027 global.convert_leveldir = str_copy;
4028 global.convert_level_nr = -1;
4030 if (str_ptr != NULL)
4032 *str_ptr++ = '\0'; /* terminate leveldir string */
4033 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4038 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4042 static void InitSetup()
4044 LoadSetup(); /* global setup info */
4046 /* set some options from setup file */
4048 if (setup.options.verbose)
4049 options.verbose = TRUE;
4052 static void InitPlayerInfo()
4056 /* choose default local player */
4057 local_player = &stored_player[0];
4059 for (i = 0; i < MAX_PLAYERS; i++)
4060 stored_player[i].connected = FALSE;
4062 local_player->connected = TRUE;
4065 static void InitArtworkInfo()
4070 static char *get_string_in_brackets(char *string)
4072 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4074 sprintf(string_in_brackets, "[%s]", string);
4076 return string_in_brackets;
4079 static char *get_level_id_suffix(int id_nr)
4081 char *id_suffix = checked_malloc(1 + 3 + 1);
4083 if (id_nr < 0 || id_nr > 999)
4086 sprintf(id_suffix, ".%03d", id_nr);
4092 static char *get_element_class_token(int element)
4094 char *element_class_name = element_info[element].class_name;
4095 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4097 sprintf(element_class_token, "[%s]", element_class_name);
4099 return element_class_token;
4102 static char *get_action_class_token(int action)
4104 char *action_class_name = &element_action_info[action].suffix[1];
4105 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4107 sprintf(action_class_token, "[%s]", action_class_name);
4109 return action_class_token;
4113 static void InitArtworkConfig()
4115 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4116 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4117 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4118 static char *action_id_suffix[NUM_ACTIONS + 1];
4119 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4120 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4121 static char *level_id_suffix[MAX_LEVELS + 1];
4122 static char *dummy[1] = { NULL };
4123 static char *ignore_generic_tokens[] =
4129 static char **ignore_image_tokens;
4130 static char **ignore_sound_tokens;
4131 static char **ignore_music_tokens;
4132 int num_ignore_generic_tokens;
4133 int num_ignore_image_tokens;
4134 int num_ignore_sound_tokens;
4135 int num_ignore_music_tokens;
4138 /* dynamically determine list of generic tokens to be ignored */
4139 num_ignore_generic_tokens = 0;
4140 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4141 num_ignore_generic_tokens++;
4143 /* dynamically determine list of image tokens to be ignored */
4144 num_ignore_image_tokens = num_ignore_generic_tokens;
4145 for (i = 0; image_config_vars[i].token != NULL; i++)
4146 num_ignore_image_tokens++;
4147 ignore_image_tokens =
4148 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4149 for (i = 0; i < num_ignore_generic_tokens; i++)
4150 ignore_image_tokens[i] = ignore_generic_tokens[i];
4151 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4152 ignore_image_tokens[num_ignore_generic_tokens + i] =
4153 image_config_vars[i].token;
4154 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4156 /* dynamically determine list of sound tokens to be ignored */
4157 num_ignore_sound_tokens = num_ignore_generic_tokens;
4158 ignore_sound_tokens =
4159 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4160 for (i = 0; i < num_ignore_generic_tokens; i++)
4161 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4162 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4164 /* dynamically determine list of music tokens to be ignored */
4165 num_ignore_music_tokens = num_ignore_generic_tokens;
4166 ignore_music_tokens =
4167 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4168 for (i = 0; i < num_ignore_generic_tokens; i++)
4169 ignore_music_tokens[i] = ignore_generic_tokens[i];
4170 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4172 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4173 image_id_prefix[i] = element_info[i].token_name;
4174 for (i = 0; i < NUM_FONTS; i++)
4175 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4176 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4178 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4179 sound_id_prefix[i] = element_info[i].token_name;
4180 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4181 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4182 get_string_in_brackets(element_info[i].class_name);
4183 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4185 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4186 music_id_prefix[i] = music_prefix_info[i].prefix;
4187 music_id_prefix[MAX_LEVELS] = NULL;
4189 for (i = 0; i < NUM_ACTIONS; i++)
4190 action_id_suffix[i] = element_action_info[i].suffix;
4191 action_id_suffix[NUM_ACTIONS] = NULL;
4193 for (i = 0; i < NUM_DIRECTIONS; i++)
4194 direction_id_suffix[i] = element_direction_info[i].suffix;
4195 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4197 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4198 special_id_suffix[i] = special_suffix_info[i].suffix;
4199 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4201 for (i = 0; i < MAX_LEVELS; i++)
4202 level_id_suffix[i] = get_level_id_suffix(i);
4203 level_id_suffix[MAX_LEVELS] = NULL;
4205 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4206 image_id_prefix, action_id_suffix, direction_id_suffix,
4207 special_id_suffix, ignore_image_tokens);
4208 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4209 sound_id_prefix, action_id_suffix, dummy,
4210 special_id_suffix, ignore_sound_tokens);
4211 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4212 music_id_prefix, special_id_suffix, level_id_suffix,
4213 dummy, ignore_music_tokens);
4216 static void InitMixer()
4224 char *filename_font_initial = NULL;
4225 Bitmap *bitmap_font_initial = NULL;
4228 /* determine settings for initial font (for displaying startup messages) */
4229 for (i = 0; image_config[i].token != NULL; i++)
4231 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4233 char font_token[128];
4236 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4237 len_font_token = strlen(font_token);
4239 if (strcmp(image_config[i].token, font_token) == 0)
4240 filename_font_initial = image_config[i].value;
4241 else if (strlen(image_config[i].token) > len_font_token &&
4242 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4244 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4245 font_initial[j].src_x = atoi(image_config[i].value);
4246 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4247 font_initial[j].src_y = atoi(image_config[i].value);
4248 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4249 font_initial[j].width = atoi(image_config[i].value);
4250 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4251 font_initial[j].height = atoi(image_config[i].value);
4256 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4258 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4259 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4262 if (filename_font_initial == NULL) /* should not happen */
4263 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4265 /* create additional image buffers for double-buffering */
4266 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4267 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4269 /* initialize screen properties */
4270 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4271 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4273 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4274 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4275 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4277 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4279 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4280 font_initial[j].bitmap = bitmap_font_initial;
4282 InitFontGraphicInfo();
4284 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4285 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4287 DrawInitText("Loading graphics:", 120, FC_GREEN);
4289 InitTileClipmasks();
4292 void InitGfxBackground()
4296 drawto = backbuffer;
4297 fieldbuffer = bitmap_db_field;
4298 SetDrawtoField(DRAW_BACKBUFFER);
4300 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4301 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4302 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4303 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4305 for (x = 0; x < MAX_BUF_XSIZE; x++)
4306 for (y = 0; y < MAX_BUF_YSIZE; y++)
4309 redraw_mask = REDRAW_ALL;
4312 static void InitLevelInfo()
4314 LoadLevelInfo(); /* global level info */
4315 LoadLevelSetup_LastSeries(); /* last played series info */
4316 LoadLevelSetup_SeriesInfo(); /* last played level info */
4319 void InitLevelArtworkInfo()
4321 LoadLevelArtworkInfo();
4324 static void InitImages()
4327 setLevelArtworkDir(artwork.gfx_first);
4331 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4332 leveldir_current->identifier,
4333 artwork.gfx_current_identifier,
4334 artwork.gfx_current->identifier,
4335 leveldir_current->graphics_set,
4336 leveldir_current->graphics_path);
4339 ReloadCustomImages();
4341 LoadCustomElementDescriptions();
4342 LoadSpecialMenuDesignSettings();
4344 ReinitializeGraphics();
4347 static void InitSound(char *identifier)
4349 if (identifier == NULL)
4350 identifier = artwork.snd_current->identifier;
4353 /* set artwork path to send it to the sound server process */
4354 setLevelArtworkDir(artwork.snd_first);
4357 InitReloadCustomSounds(identifier);
4358 ReinitializeSounds();
4361 static void InitMusic(char *identifier)
4363 if (identifier == NULL)
4364 identifier = artwork.mus_current->identifier;
4367 /* set artwork path to send it to the sound server process */
4368 setLevelArtworkDir(artwork.mus_first);
4371 InitReloadCustomMusic(identifier);
4372 ReinitializeMusic();
4375 void InitNetworkServer()
4377 #if defined(NETWORK_AVALIABLE)
4381 if (!options.network)
4384 #if defined(NETWORK_AVALIABLE)
4385 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4387 if (!ConnectToServer(options.server_host, options.server_port))
4388 Error(ERR_EXIT, "cannot connect to network game server");
4390 SendToServer_PlayerName(setup.player_name);
4391 SendToServer_ProtocolVersion();
4394 SendToServer_NrWanted(nr_wanted);
4398 static char *getNewArtworkIdentifier(int type)
4400 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4401 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4402 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4403 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4404 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4405 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4406 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4407 char *leveldir_identifier = leveldir_current->identifier;
4409 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4410 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4412 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4414 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4415 char *artwork_current_identifier;
4416 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4418 /* leveldir_current may be invalid (level group, parent link) */
4419 if (!validLevelSeries(leveldir_current))
4422 /* 1st step: determine artwork set to be activated in descending order:
4423 --------------------------------------------------------------------
4424 1. setup artwork (when configured to override everything else)
4425 2. artwork set configured in "levelinfo.conf" of current level set
4426 (artwork in level directory will have priority when loading later)
4427 3. artwork in level directory (stored in artwork sub-directory)
4428 4. setup artwork (currently configured in setup menu) */
4430 if (setup_override_artwork)
4431 artwork_current_identifier = setup_artwork_set;
4432 else if (leveldir_artwork_set != NULL)
4433 artwork_current_identifier = leveldir_artwork_set;
4434 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4435 artwork_current_identifier = leveldir_identifier;
4437 artwork_current_identifier = setup_artwork_set;
4440 /* 2nd step: check if it is really needed to reload artwork set
4441 ------------------------------------------------------------ */
4444 if (type == ARTWORK_TYPE_GRAPHICS)
4445 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4446 artwork_new_identifier,
4447 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4448 artwork_current_identifier,
4449 leveldir_current->graphics_set,
4450 leveldir_current->identifier);
4453 /* ---------- reload if level set and also artwork set has changed ------- */
4454 if (leveldir_current_identifier[type] != leveldir_identifier &&
4455 (last_has_level_artwork_set[type] || has_level_artwork_set))
4456 artwork_new_identifier = artwork_current_identifier;
4458 leveldir_current_identifier[type] = leveldir_identifier;
4459 last_has_level_artwork_set[type] = has_level_artwork_set;
4462 if (type == ARTWORK_TYPE_GRAPHICS)
4463 printf("::: 1: '%s'\n", artwork_new_identifier);
4466 /* ---------- reload if "override artwork" setting has changed ----------- */
4467 if (last_override_level_artwork[type] != setup_override_artwork)
4468 artwork_new_identifier = artwork_current_identifier;
4470 last_override_level_artwork[type] = setup_override_artwork;
4473 if (type == ARTWORK_TYPE_GRAPHICS)
4474 printf("::: 2: '%s'\n", artwork_new_identifier);
4477 /* ---------- reload if current artwork identifier has changed ----------- */
4478 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4479 artwork_current_identifier) != 0)
4480 artwork_new_identifier = artwork_current_identifier;
4482 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4485 if (type == ARTWORK_TYPE_GRAPHICS)
4486 printf("::: 3: '%s'\n", artwork_new_identifier);
4489 /* ---------- do not reload directly after starting ---------------------- */
4490 if (!initialized[type])
4491 artwork_new_identifier = NULL;
4493 initialized[type] = TRUE;
4496 if (type == ARTWORK_TYPE_GRAPHICS)
4497 printf("::: 4: '%s'\n", artwork_new_identifier);
4501 if (type == ARTWORK_TYPE_GRAPHICS)
4502 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4503 artwork.gfx_current_identifier, artwork_current_identifier,
4504 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4505 artwork_new_identifier);
4508 return artwork_new_identifier;
4511 void ReloadCustomArtwork(int force_reload)
4513 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4514 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4515 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4516 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4517 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4518 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4519 boolean redraw_screen = FALSE;
4521 if (gfx_new_identifier != NULL || force_reload_gfx)
4524 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4525 artwork.gfx_current_identifier,
4527 artwork.gfx_current->identifier,
4528 leveldir_current->graphics_set);
4531 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4536 printf("... '%s'\n",
4537 leveldir_current->graphics_set);
4540 FreeTileClipmasks();
4541 InitTileClipmasks();
4543 redraw_screen = TRUE;
4546 if (snd_new_identifier != NULL || force_reload_snd)
4548 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4550 InitSound(snd_new_identifier);
4552 redraw_screen = TRUE;
4555 if (mus_new_identifier != NULL || force_reload_mus)
4557 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4559 InitMusic(mus_new_identifier);
4561 redraw_screen = TRUE;
4566 InitGfxBackground();
4568 /* force redraw of (open or closed) door graphics */
4569 SetDoorState(DOOR_OPEN_ALL);
4570 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4574 void KeyboardAutoRepeatOffUnlessAutoplay()
4576 if (global.autoplay_leveldir == NULL)
4577 KeyboardAutoRepeatOff();
4581 /* ========================================================================= */
4583 /* ========================================================================= */
4587 InitGlobal(); /* initialize some global variables */
4589 if (options.execute_command)
4590 Execute_Command(options.execute_command);
4592 if (options.serveronly)
4594 #if defined(PLATFORM_UNIX)
4595 NetworkServer(options.server_port, options.serveronly);
4597 Error(ERR_WARN, "networking only supported in Unix version");
4599 exit(0); /* never reached */
4605 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4606 InitArtworkConfig(); /* needed before forking sound child process */
4611 InitRND(NEW_RANDOMIZE);
4612 InitSimpleRND(NEW_RANDOMIZE);
4617 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4620 InitEventFilter(FilterMouseMotionEvents);
4622 InitElementPropertiesStatic();
4623 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4628 InitLevelArtworkInfo();
4630 InitImages(); /* needs to know current level directory */
4631 InitSound(NULL); /* needs to know current level directory */
4632 InitMusic(NULL); /* needs to know current level directory */
4634 InitGfxBackground();
4636 if (global.autoplay_leveldir)
4641 else if (global.convert_leveldir)
4647 game_status = GAME_MODE_MAIN;
4655 InitNetworkServer();
4658 void CloseAllAndExit(int exit_value)
4663 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4670 FreeTileClipmasks();
4672 #if defined(TARGET_SDL)
4673 if (network_server) /* terminate network server */
4674 SDL_KillThread(server_thread);
4677 CloseVideoDisplay();
4678 ClosePlatformDependentStuff();