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 (may be elements or other) */
263 for (i = 0; i < num_property_mappings; i++)
264 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
266 /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
267 /* !!! ALSO, non-element graphics might need scaling-up !!! */
268 for (i = 0; i < num_property_mappings; i++)
269 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
270 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
276 InitElementSmallImagesScaledUp(i);
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_EM(Bitmap **em_bitmap)
284 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
285 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
289 static int getFontBitmapID(int font_nr)
293 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
297 else if (game_status == GAME_MODE_PLAYING)
298 special = GFX_SPECIAL_ARG_DOOR;
301 return font_info[font_nr].special_bitmap_id[special];
306 void InitFontGraphicInfo()
308 static struct FontBitmapInfo *font_bitmap_info = NULL;
309 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
310 int num_property_mappings = getImageListPropertyMappingSize();
311 int num_font_bitmaps = NUM_FONTS;
314 if (graphic_info == NULL) /* still at startup phase */
316 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
321 /* ---------- initialize font graphic definitions ---------- */
323 /* always start with reliable default values (normal font graphics) */
325 for (i = 0; i < NUM_FONTS; i++)
326 font_info[i].graphic = IMG_FONT_INITIAL_1;
328 for (i = 0; i < NUM_FONTS; i++)
329 font_info[i].graphic = FONT_INITIAL_1;
332 /* initialize normal font/graphic mapping from static configuration */
333 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
335 int font_nr = font_to_graphic[i].font_nr;
336 int special = font_to_graphic[i].special;
337 int graphic = font_to_graphic[i].graphic;
342 font_info[font_nr].graphic = graphic;
345 /* always start with reliable default values (special font graphics) */
346 for (i = 0; i < NUM_FONTS; i++)
348 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
350 font_info[i].special_graphic[j] = font_info[i].graphic;
351 font_info[i].special_bitmap_id[j] = i;
355 /* initialize special font/graphic mapping from static configuration */
356 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
358 int font_nr = font_to_graphic[i].font_nr;
359 int special = font_to_graphic[i].special;
360 int graphic = font_to_graphic[i].graphic;
362 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
364 font_info[font_nr].special_graphic[special] = graphic;
365 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
370 /* initialize special element/graphic mapping from dynamic configuration */
371 for (i = 0; i < num_property_mappings; i++)
373 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
374 int special = property_mapping[i].ext3_index;
375 int graphic = property_mapping[i].artwork_index;
380 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
382 font_info[font_nr].special_graphic[special] = graphic;
383 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
388 /* ---------- initialize font bitmap array ---------- */
390 if (font_bitmap_info != NULL)
391 FreeFontInfo(font_bitmap_info);
394 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
396 /* ---------- initialize font bitmap definitions ---------- */
398 for (i = 0; i < NUM_FONTS; i++)
400 if (i < NUM_INITIAL_FONTS)
402 font_bitmap_info[i] = font_initial[i];
406 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
408 int font_bitmap_id = font_info[i].special_bitmap_id[j];
409 int graphic = font_info[i].special_graphic[j];
411 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
412 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
414 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
415 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
418 /* copy font relevant information from graphics information */
419 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
420 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
421 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
422 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
423 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
424 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
425 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
427 font_bitmap_info[font_bitmap_id].num_chars =
428 graphic_info[graphic].anim_frames;
429 font_bitmap_info[font_bitmap_id].num_chars_per_line =
430 graphic_info[graphic].anim_frames_per_line;
434 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
437 void InitElementGraphicInfo()
439 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
440 int num_property_mappings = getImageListPropertyMappingSize();
443 if (graphic_info == NULL) /* still at startup phase */
446 /* set values to -1 to identify later as "uninitialized" values */
447 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
449 for (act = 0; act < NUM_ACTIONS; act++)
451 element_info[i].graphic[act] = -1;
452 element_info[i].crumbled[act] = -1;
454 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
456 element_info[i].direction_graphic[act][dir] = -1;
457 element_info[i].direction_crumbled[act][dir] = -1;
462 /* initialize normal element/graphic mapping from static configuration */
463 for (i = 0; element_to_graphic[i].element > -1; i++)
465 int element = element_to_graphic[i].element;
466 int action = element_to_graphic[i].action;
467 int direction = element_to_graphic[i].direction;
468 boolean crumbled = element_to_graphic[i].crumbled;
469 int graphic = element_to_graphic[i].graphic;
470 int base_graphic = el2baseimg(element);
472 if (graphic_info[graphic].bitmap == NULL)
475 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
478 boolean base_redefined =
479 getImageListEntryFromImageID(base_graphic)->redefined;
480 boolean act_dir_redefined =
481 getImageListEntryFromImageID(graphic)->redefined;
483 /* if the base graphic ("emerald", for example) has been redefined,
484 but not the action graphic ("emerald.falling", for example), do not
485 use an existing (in this case considered obsolete) action graphic
486 anymore, but use the automatically determined default graphic */
487 if (base_redefined && !act_dir_redefined)
492 action = ACTION_DEFAULT;
497 element_info[element].direction_crumbled[action][direction] = graphic;
499 element_info[element].crumbled[action] = graphic;
504 element_info[element].direction_graphic[action][direction] = graphic;
506 element_info[element].graphic[action] = graphic;
510 /* initialize normal element/graphic mapping from dynamic configuration */
511 for (i = 0; i < num_property_mappings; i++)
513 int element = property_mapping[i].base_index;
514 int action = property_mapping[i].ext1_index;
515 int direction = property_mapping[i].ext2_index;
516 int special = property_mapping[i].ext3_index;
517 int graphic = property_mapping[i].artwork_index;
518 boolean crumbled = FALSE;
520 if (special == GFX_SPECIAL_ARG_CRUMBLED)
526 if (graphic_info[graphic].bitmap == NULL)
529 if (element >= MAX_NUM_ELEMENTS || special != -1)
533 action = ACTION_DEFAULT;
538 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
539 element_info[element].direction_crumbled[action][dir] = -1;
542 element_info[element].direction_crumbled[action][direction] = graphic;
544 element_info[element].crumbled[action] = graphic;
549 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
550 element_info[element].direction_graphic[action][dir] = -1;
553 element_info[element].direction_graphic[action][direction] = graphic;
555 element_info[element].graphic[action] = graphic;
559 /* now copy all graphics that are defined to be cloned from other graphics */
560 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
562 int graphic = element_info[i].graphic[ACTION_DEFAULT];
563 int crumbled_like, diggable_like;
568 crumbled_like = graphic_info[graphic].crumbled_like;
569 diggable_like = graphic_info[graphic].diggable_like;
571 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
573 for (act = 0; act < NUM_ACTIONS; act++)
574 element_info[i].crumbled[act] =
575 element_info[crumbled_like].crumbled[act];
576 for (act = 0; act < NUM_ACTIONS; act++)
577 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578 element_info[i].direction_crumbled[act][dir] =
579 element_info[crumbled_like].direction_crumbled[act][dir];
582 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
584 element_info[i].graphic[ACTION_DIGGING] =
585 element_info[diggable_like].graphic[ACTION_DIGGING];
586 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
587 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
588 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
593 /* set hardcoded definitions for some runtime elements without graphic */
594 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
598 /* now set all undefined/invalid graphics to -1 to set to default after it */
599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601 for (act = 0; act < NUM_ACTIONS; act++)
605 graphic = element_info[i].graphic[act];
606 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
607 element_info[i].graphic[act] = -1;
609 graphic = element_info[i].crumbled[act];
610 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
611 element_info[i].crumbled[act] = -1;
613 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
615 graphic = element_info[i].direction_graphic[act][dir];
616 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
617 element_info[i].direction_graphic[act][dir] = -1;
619 graphic = element_info[i].direction_crumbled[act][dir];
620 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
621 element_info[i].direction_crumbled[act][dir] = -1;
628 /* adjust graphics with 2nd tile for movement according to direction
629 (do this before correcting '-1' values to minimize calculations) */
630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
632 for (act = 0; act < NUM_ACTIONS; act++)
634 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
636 int graphic = element_info[i].direction_graphic[act][dir];
637 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
639 if (act == ACTION_FALLING) /* special case */
640 graphic = element_info[i].graphic[act];
642 if (graphic != -1 && graphic_info[graphic].double_movement)
644 struct GraphicInfo *g = &graphic_info[graphic];
645 int src_x_front = g->src_x;
646 int src_y_front = g->src_y;
647 int src_x_back = g->src_x + g->offset2_x;
648 int src_y_back = g->src_y + g->offset2_y;
649 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
651 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
652 src_y_front < src_y_back);
656 printf("::: CHECKING ELEMENT %d ('%s'), ACTION '%s', DIRECTION %d\n",
657 i, element_info[i].token_name,
658 element_action_info[act].suffix, move_dir);
661 /* swap frontside and backside graphic tile coordinates, if needed */
662 if (!frames_are_ordered_diagonally &&
663 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
664 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
665 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
666 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)))
668 /* get current (wrong) backside tile coordinates */
669 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
672 /* set frontside tile coordinates to backside tile coordinates */
673 g->src_x = src_x_back;
674 g->src_y = src_y_back;
676 /* invert tile offset to point to new backside tile coordinates */
681 printf(" CORRECTED\n");
690 /* now set all '-1' values to element specific default values */
691 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
693 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
694 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
695 int default_direction_graphic[NUM_DIRECTIONS];
696 int default_direction_crumbled[NUM_DIRECTIONS];
698 if (default_graphic == -1)
699 default_graphic = IMG_UNKNOWN;
700 if (default_crumbled == -1)
701 default_crumbled = IMG_EMPTY;
703 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
705 default_direction_graphic[dir] =
706 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
707 default_direction_crumbled[dir] =
708 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
710 if (default_direction_graphic[dir] == -1)
711 default_direction_graphic[dir] = default_graphic;
712 if (default_direction_crumbled[dir] == -1)
713 default_direction_crumbled[dir] = default_crumbled;
716 for (act = 0; act < NUM_ACTIONS; act++)
718 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
719 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
720 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
721 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
722 act == ACTION_TURNING_FROM_RIGHT ||
723 act == ACTION_TURNING_FROM_UP ||
724 act == ACTION_TURNING_FROM_DOWN);
726 /* generic default action graphic (defined by "[default]" directive) */
727 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
728 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
729 int default_remove_graphic = IMG_EMPTY;
731 if (act_remove && default_action_graphic != -1)
732 default_remove_graphic = default_action_graphic;
734 /* look for special default action graphic (classic game specific) */
735 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
736 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
737 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
738 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
739 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
740 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
742 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
743 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
744 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
745 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
746 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
747 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
750 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
751 /* !!! make this better !!! */
752 if (i == EL_EMPTY_SPACE)
754 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
755 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
759 if (default_action_graphic == -1)
760 default_action_graphic = default_graphic;
761 if (default_action_crumbled == -1)
762 default_action_crumbled = default_crumbled;
764 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
766 int default_action_direction_graphic = element_info[i].graphic[act];
767 int default_action_direction_crumbled = element_info[i].crumbled[act];
769 /* no graphic for current action -- use default direction graphic */
770 /* !!! maybe it's better to use default _action_ graphic here !!! */
771 if (default_action_direction_graphic == -1)
772 default_action_direction_graphic =
773 (act_remove ? default_remove_graphic :
775 element_info[i].direction_graphic[ACTION_TURNING][dir] :
776 default_direction_graphic[dir]);
777 if (default_action_direction_crumbled == -1)
778 default_action_direction_crumbled =
779 (act_remove ? default_remove_graphic :
781 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
782 default_direction_crumbled[dir]);
784 if (element_info[i].direction_graphic[act][dir] == -1)
785 element_info[i].direction_graphic[act][dir] =
786 default_action_direction_graphic;
787 if (element_info[i].direction_crumbled[act][dir] == -1)
788 element_info[i].direction_crumbled[act][dir] =
789 default_action_direction_crumbled;
792 /* no graphic for this specific action -- use default action graphic */
793 if (element_info[i].graphic[act] == -1)
794 element_info[i].graphic[act] =
795 (act_remove ? default_remove_graphic :
796 act_turning ? element_info[i].graphic[ACTION_TURNING] :
797 default_action_graphic);
798 if (element_info[i].crumbled[act] == -1)
799 element_info[i].crumbled[act] =
800 (act_remove ? default_remove_graphic :
801 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
802 default_action_crumbled);
807 /* set animation mode to "none" for each graphic with only 1 frame */
808 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
810 for (act = 0; act < NUM_ACTIONS; act++)
812 int graphic = element_info[i].graphic[act];
813 int crumbled = element_info[i].crumbled[act];
815 if (graphic_info[graphic].anim_frames == 1)
816 graphic_info[graphic].anim_mode = ANIM_NONE;
817 if (graphic_info[crumbled].anim_frames == 1)
818 graphic_info[crumbled].anim_mode = ANIM_NONE;
820 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
822 graphic = element_info[i].direction_graphic[act][dir];
823 crumbled = element_info[i].direction_crumbled[act][dir];
825 if (graphic_info[graphic].anim_frames == 1)
826 graphic_info[graphic].anim_mode = ANIM_NONE;
827 if (graphic_info[crumbled].anim_frames == 1)
828 graphic_info[crumbled].anim_mode = ANIM_NONE;
838 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
839 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
841 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
842 element_info[i].token_name, i);
848 void InitElementSpecialGraphicInfo()
850 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
851 int num_property_mappings = getImageListPropertyMappingSize();
854 /* always start with reliable default values */
855 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
856 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
857 element_info[i].special_graphic[j] =
858 element_info[i].graphic[ACTION_DEFAULT];
860 /* initialize special element/graphic mapping from static configuration */
861 for (i = 0; element_to_special_graphic[i].element > -1; i++)
863 int element = element_to_special_graphic[i].element;
864 int special = element_to_special_graphic[i].special;
865 int graphic = element_to_special_graphic[i].graphic;
866 int base_graphic = el2baseimg(element);
867 boolean base_redefined =
868 getImageListEntryFromImageID(base_graphic)->redefined;
869 boolean special_redefined =
870 getImageListEntryFromImageID(graphic)->redefined;
872 /* if the base graphic ("emerald", for example) has been redefined,
873 but not the special graphic ("emerald.EDITOR", for example), do not
874 use an existing (in this case considered obsolete) special graphic
875 anymore, but use the automatically created (down-scaled) graphic */
876 if (base_redefined && !special_redefined)
879 element_info[element].special_graphic[special] = graphic;
882 /* initialize special element/graphic mapping from dynamic configuration */
883 for (i = 0; i < num_property_mappings; i++)
885 int element = property_mapping[i].base_index;
886 int special = property_mapping[i].ext3_index;
887 int graphic = property_mapping[i].artwork_index;
889 if (element >= MAX_NUM_ELEMENTS)
892 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
893 element_info[element].special_graphic[special] = graphic;
897 /* now set all undefined/invalid graphics to default */
898 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
899 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
900 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
901 element_info[i].special_graphic[j] =
902 element_info[i].graphic[ACTION_DEFAULT];
906 static int get_element_from_token(char *token)
910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
911 if (strcmp(element_info[i].token_name, token) == 0)
917 static int get_scaled_graphic_width(int graphic)
919 int original_width = getOriginalImageWidthFromImageID(graphic);
920 int scale_up_factor = graphic_info[graphic].scale_up_factor;
922 return original_width * scale_up_factor;
925 static int get_scaled_graphic_height(int graphic)
927 int original_height = getOriginalImageHeightFromImageID(graphic);
928 int scale_up_factor = graphic_info[graphic].scale_up_factor;
930 return original_height * scale_up_factor;
933 static void set_graphic_parameters(int graphic, int graphic_copy_from)
935 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
936 char **parameter_raw = image->parameter;
937 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
938 int parameter[NUM_GFX_ARGS];
939 int anim_frames_per_row = 1, anim_frames_per_col = 1;
940 int anim_frames_per_line = 1;
943 /* get integer values from string parameters */
944 for (i = 0; i < NUM_GFX_ARGS; i++)
947 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
948 image_config_suffix[i].type);
950 if (image_config_suffix[i].type == TYPE_TOKEN)
951 parameter[i] = get_element_from_token(parameter_raw[i]);
954 graphic_info[graphic].bitmap = src_bitmap;
956 /* start with reliable default values */
957 graphic_info[graphic].src_x = 0;
958 graphic_info[graphic].src_y = 0;
959 graphic_info[graphic].width = TILEX;
960 graphic_info[graphic].height = TILEY;
961 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
962 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
963 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
964 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
965 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
966 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
967 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
968 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
969 graphic_info[graphic].anim_delay_fixed = 0;
970 graphic_info[graphic].anim_delay_random = 0;
971 graphic_info[graphic].post_delay_fixed = 0;
972 graphic_info[graphic].post_delay_random = 0;
974 /* optional x and y tile position of animation frame sequence */
975 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
976 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
977 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
980 /* optional x and y pixel position of animation frame sequence */
981 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
983 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
984 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
986 /* optional width and height of each animation frame */
987 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
989 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
992 /* optional zoom factor for scaling up the image to a larger size */
993 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
995 if (graphic_info[graphic].scale_up_factor < 1)
996 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1000 /* get final bitmap size (with scaling, but without small images) */
1001 int src_bitmap_width = get_scaled_graphic_width(graphic);
1002 int src_bitmap_height = get_scaled_graphic_height(graphic);
1004 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1005 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1008 /* correct x or y offset dependent of vertical or horizontal frame order */
1009 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1011 graphic_info[graphic].offset_y =
1012 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1013 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1014 anim_frames_per_line = anim_frames_per_col;
1016 else /* frames are ordered horizontally */
1018 graphic_info[graphic].offset_x =
1019 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1020 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1021 anim_frames_per_line = anim_frames_per_row;
1024 /* optionally, the x and y offset of frames can be specified directly */
1025 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1026 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1027 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1028 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1030 /* optionally, moving animations may have separate start and end graphics */
1031 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1033 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1034 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1036 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1037 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1038 graphic_info[graphic].offset2_y =
1039 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1040 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1041 else /* frames are ordered horizontally */
1042 graphic_info[graphic].offset2_x =
1043 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1044 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1046 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1047 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1048 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1049 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1050 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1052 /* automatically determine correct number of frames, if not defined */
1053 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1055 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1056 graphic_info[graphic].anim_frames = anim_frames_per_row;
1057 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1058 graphic_info[graphic].anim_frames = anim_frames_per_col;
1060 graphic_info[graphic].anim_frames = 1;
1062 graphic_info[graphic].anim_frames_per_line =
1063 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1064 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1066 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1067 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1068 graphic_info[graphic].anim_delay = 1;
1070 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1072 if (graphic_info[graphic].anim_frames == 1)
1073 graphic_info[graphic].anim_mode = ANIM_NONE;
1076 /* automatically determine correct start frame, if not defined */
1077 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1078 graphic_info[graphic].anim_start_frame = 0;
1079 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1080 graphic_info[graphic].anim_start_frame =
1081 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1083 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1085 /* animation synchronized with global frame counter, not move position */
1086 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1088 /* optional element for cloning crumble graphics */
1089 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1090 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1092 /* optional element for cloning digging graphics */
1093 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1094 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1096 /* optional border size for "crumbling" diggable graphics */
1097 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1098 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1100 /* this is only used for player "boring" and "sleeping" actions */
1101 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1102 graphic_info[graphic].anim_delay_fixed =
1103 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1104 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1105 graphic_info[graphic].anim_delay_random =
1106 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1107 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1108 graphic_info[graphic].post_delay_fixed =
1109 parameter[GFX_ARG_POST_DELAY_FIXED];
1110 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1111 graphic_info[graphic].post_delay_random =
1112 parameter[GFX_ARG_POST_DELAY_RANDOM];
1114 /* this is only used for toon animations */
1115 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1116 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1118 /* this is only used for drawing font characters */
1119 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1120 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1122 /* this is only used for drawing envelope graphics */
1123 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1126 static void InitGraphicInfo()
1128 int fallback_graphic = IMG_CHAR_EXCLAM;
1129 int num_images = getImageListSize();
1132 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1133 static boolean clipmasks_initialized = FALSE;
1135 XGCValues clip_gc_values;
1136 unsigned long clip_gc_valuemask;
1137 GC copy_clipmask_gc = None;
1140 checked_free(graphic_info);
1142 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1145 printf("::: graphic_info: %d entries\n", num_images);
1148 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1149 if (clipmasks_initialized)
1151 for (i = 0; i < num_images; i++)
1153 if (graphic_info[i].clip_mask)
1154 XFreePixmap(display, graphic_info[i].clip_mask);
1155 if (graphic_info[i].clip_gc)
1156 XFreeGC(display, graphic_info[i].clip_gc);
1158 graphic_info[i].clip_mask = None;
1159 graphic_info[i].clip_gc = None;
1164 for (i = 0; i < num_images; i++)
1168 int first_frame, last_frame;
1169 int src_bitmap_width, src_bitmap_height;
1172 printf("::: image: '%s' [%d]\n", image->token, i);
1176 printf("::: image # %d: '%s' ['%s']\n",
1178 getTokenFromImageID(i));
1181 set_graphic_parameters(i, i);
1183 /* now check if no animation frames are outside of the loaded image */
1185 if (graphic_info[i].bitmap == NULL)
1186 continue; /* skip check for optional images that are undefined */
1188 /* get final bitmap size (with scaling, but without small images) */
1189 src_bitmap_width = get_scaled_graphic_width(i);
1190 src_bitmap_height = get_scaled_graphic_height(i);
1193 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1194 if (src_x < 0 || src_y < 0 ||
1195 src_x + TILEX > src_bitmap_width ||
1196 src_y + TILEY > src_bitmap_height)
1198 Error(ERR_RETURN_LINE, "-");
1199 Error(ERR_RETURN, "warning: error found in config file:");
1200 Error(ERR_RETURN, "- config file: '%s'",
1201 getImageConfigFilename());
1202 Error(ERR_RETURN, "- config token: '%s'",
1203 getTokenFromImageID(i));
1204 Error(ERR_RETURN, "- image file: '%s'",
1205 src_bitmap->source_filename);
1207 "error: first animation frame out of bounds (%d, %d)",
1209 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1212 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1215 if (i == fallback_graphic)
1216 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1218 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1219 Error(ERR_RETURN_LINE, "-");
1221 set_graphic_parameters(i, fallback_graphic);
1224 last_frame = graphic_info[i].anim_frames - 1;
1225 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1226 if (src_x < 0 || src_y < 0 ||
1227 src_x + TILEX > src_bitmap_width ||
1228 src_y + TILEY > src_bitmap_height)
1230 Error(ERR_RETURN_LINE, "-");
1231 Error(ERR_RETURN, "warning: error found in config file:");
1232 Error(ERR_RETURN, "- config file: '%s'",
1233 getImageConfigFilename());
1234 Error(ERR_RETURN, "- config token: '%s'",
1235 getTokenFromImageID(i));
1236 Error(ERR_RETURN, "- image file: '%s'",
1237 src_bitmap->source_filename);
1239 "error: last animation frame (%d) out of bounds (%d, %d)",
1240 last_frame, src_x, src_y);
1241 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1243 if (i == fallback_graphic)
1244 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1246 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1247 Error(ERR_RETURN_LINE, "-");
1249 set_graphic_parameters(i, fallback_graphic);
1252 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1253 /* currently we only need a tile clip mask from the first frame */
1254 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1256 if (copy_clipmask_gc == None)
1258 clip_gc_values.graphics_exposures = False;
1259 clip_gc_valuemask = GCGraphicsExposures;
1260 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1261 clip_gc_valuemask, &clip_gc_values);
1264 graphic_info[i].clip_mask =
1265 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1267 src_pixmap = src_bitmap->clip_mask;
1268 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1269 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1271 clip_gc_values.graphics_exposures = False;
1272 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1273 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1275 graphic_info[i].clip_gc =
1276 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1280 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1281 if (copy_clipmask_gc)
1282 XFreeGC(display, copy_clipmask_gc);
1284 clipmasks_initialized = TRUE;
1288 static void InitElementSoundInfo()
1290 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1291 int num_property_mappings = getSoundListPropertyMappingSize();
1294 /* set values to -1 to identify later as "uninitialized" values */
1295 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1296 for (act = 0; act < NUM_ACTIONS; act++)
1297 element_info[i].sound[act] = -1;
1299 /* initialize element/sound mapping from static configuration */
1300 for (i = 0; element_to_sound[i].element > -1; i++)
1302 int element = element_to_sound[i].element;
1303 int action = element_to_sound[i].action;
1304 int sound = element_to_sound[i].sound;
1305 boolean is_class = element_to_sound[i].is_class;
1308 action = ACTION_DEFAULT;
1311 element_info[element].sound[action] = sound;
1313 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1314 if (strcmp(element_info[j].class_name,
1315 element_info[element].class_name) == 0)
1316 element_info[j].sound[action] = sound;
1319 /* initialize element class/sound mapping from dynamic configuration */
1320 for (i = 0; i < num_property_mappings; i++)
1322 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1323 int action = property_mapping[i].ext1_index;
1324 int sound = property_mapping[i].artwork_index;
1326 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1330 action = ACTION_DEFAULT;
1332 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1333 if (strcmp(element_info[j].class_name,
1334 element_info[element_class].class_name) == 0)
1335 element_info[j].sound[action] = sound;
1338 /* initialize element/sound mapping from dynamic configuration */
1339 for (i = 0; i < num_property_mappings; i++)
1341 int element = property_mapping[i].base_index;
1342 int action = property_mapping[i].ext1_index;
1343 int sound = property_mapping[i].artwork_index;
1345 if (element >= MAX_NUM_ELEMENTS)
1349 action = ACTION_DEFAULT;
1351 element_info[element].sound[action] = sound;
1354 /* now set all '-1' values to element specific default values */
1355 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1357 for (act = 0; act < NUM_ACTIONS; act++)
1359 /* generic default action sound (defined by "[default]" directive) */
1360 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1362 /* look for special default action sound (classic game specific) */
1363 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1364 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1365 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1366 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1367 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1368 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1370 /* !!! there's no such thing as a "default action sound" !!! */
1372 /* look for element specific default sound (independent from action) */
1373 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1374 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1378 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1379 /* !!! make this better !!! */
1380 if (i == EL_EMPTY_SPACE)
1381 default_action_sound = element_info[EL_DEFAULT].sound[act];
1384 /* no sound for this specific action -- use default action sound */
1385 if (element_info[i].sound[act] == -1)
1386 element_info[i].sound[act] = default_action_sound;
1391 static void InitGameModeSoundInfo()
1395 /* set values to -1 to identify later as "uninitialized" values */
1396 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1399 /* initialize gamemode/sound mapping from static configuration */
1400 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1402 int gamemode = gamemode_to_sound[i].gamemode;
1403 int sound = gamemode_to_sound[i].sound;
1406 gamemode = GAME_MODE_DEFAULT;
1408 menu.sound[gamemode] = sound;
1411 /* now set all '-1' values to levelset specific default values */
1412 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1413 if (menu.sound[i] == -1)
1414 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1418 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1419 if (menu.sound[i] != -1)
1420 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1424 static void set_sound_parameters(int sound, char **parameter_raw)
1426 int parameter[NUM_SND_ARGS];
1429 /* get integer values from string parameters */
1430 for (i = 0; i < NUM_SND_ARGS; i++)
1432 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1433 sound_config_suffix[i].type);
1435 /* explicit loop mode setting in configuration overrides default value */
1436 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1437 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1439 /* sound volume to change the original volume when loading the sound file */
1440 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1442 /* sound priority to give certain sounds a higher or lower priority */
1443 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1446 static void InitSoundInfo()
1449 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1450 int num_property_mappings = getSoundListPropertyMappingSize();
1452 int *sound_effect_properties;
1453 int num_sounds = getSoundListSize();
1456 checked_free(sound_info);
1458 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1459 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1461 /* initialize sound effect for all elements to "no sound" */
1462 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1463 for (j = 0; j < NUM_ACTIONS; j++)
1464 element_info[i].sound[j] = SND_UNDEFINED;
1466 for (i = 0; i < num_sounds; i++)
1468 struct FileInfo *sound = getSoundListEntry(i);
1469 int len_effect_text = strlen(sound->token);
1471 sound_effect_properties[i] = ACTION_OTHER;
1472 sound_info[i].loop = FALSE; /* default: play sound only once */
1475 printf("::: sound %d: '%s'\n", i, sound->token);
1478 /* determine all loop sounds and identify certain sound classes */
1480 for (j = 0; element_action_info[j].suffix; j++)
1482 int len_action_text = strlen(element_action_info[j].suffix);
1484 if (len_action_text < len_effect_text &&
1485 strcmp(&sound->token[len_effect_text - len_action_text],
1486 element_action_info[j].suffix) == 0)
1488 sound_effect_properties[i] = element_action_info[j].value;
1489 sound_info[i].loop = element_action_info[j].is_loop_sound;
1496 if (strcmp(sound->token, "custom_42") == 0)
1497 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1500 /* associate elements and some selected sound actions */
1502 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1504 if (element_info[j].class_name)
1506 int len_class_text = strlen(element_info[j].class_name);
1508 if (len_class_text + 1 < len_effect_text &&
1509 strncmp(sound->token,
1510 element_info[j].class_name, len_class_text) == 0 &&
1511 sound->token[len_class_text] == '.')
1513 int sound_action_value = sound_effect_properties[i];
1515 element_info[j].sound[sound_action_value] = i;
1520 set_sound_parameters(i, sound->parameter);
1523 free(sound_effect_properties);
1526 /* !!! now handled in InitElementSoundInfo() !!! */
1527 /* initialize element/sound mapping from dynamic configuration */
1528 for (i = 0; i < num_property_mappings; i++)
1530 int element = property_mapping[i].base_index;
1531 int action = property_mapping[i].ext1_index;
1532 int sound = property_mapping[i].artwork_index;
1535 action = ACTION_DEFAULT;
1537 printf("::: %d: %d, %d, %d ['%s']\n",
1538 i, element, action, sound, element_info[element].token_name);
1540 element_info[element].sound[action] = sound;
1547 int element = EL_CUSTOM_11;
1550 while (element_action_info[j].suffix)
1552 printf("element %d, sound action '%s' == %d\n",
1553 element, element_action_info[j].suffix,
1554 element_info[element].sound[j]);
1559 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1565 int element = EL_SAND;
1566 int sound_action = ACTION_DIGGING;
1569 while (element_action_info[j].suffix)
1571 if (element_action_info[j].value == sound_action)
1572 printf("element %d, sound action '%s' == %d\n",
1573 element, element_action_info[j].suffix,
1574 element_info[element].sound[sound_action]);
1581 static void InitGameModeMusicInfo()
1583 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1584 int num_property_mappings = getMusicListPropertyMappingSize();
1585 int default_levelset_music = -1;
1588 /* set values to -1 to identify later as "uninitialized" values */
1589 for (i = 0; i < MAX_LEVELS; i++)
1590 levelset.music[i] = -1;
1591 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1594 /* initialize gamemode/music mapping from static configuration */
1595 for (i = 0; gamemode_to_music[i].music > -1; i++)
1597 int gamemode = gamemode_to_music[i].gamemode;
1598 int music = gamemode_to_music[i].music;
1601 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1605 gamemode = GAME_MODE_DEFAULT;
1607 menu.music[gamemode] = music;
1610 /* initialize gamemode/music mapping from dynamic configuration */
1611 for (i = 0; i < num_property_mappings; i++)
1613 int prefix = property_mapping[i].base_index;
1614 int gamemode = property_mapping[i].ext1_index;
1615 int level = property_mapping[i].ext2_index;
1616 int music = property_mapping[i].artwork_index;
1619 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1620 prefix, gamemode, level, music);
1623 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1627 gamemode = GAME_MODE_DEFAULT;
1629 /* level specific music only allowed for in-game music */
1630 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1631 gamemode = GAME_MODE_PLAYING;
1636 default_levelset_music = music;
1639 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1640 levelset.music[level] = music;
1641 if (gamemode != GAME_MODE_PLAYING)
1642 menu.music[gamemode] = music;
1645 /* now set all '-1' values to menu specific default values */
1646 /* (undefined values of "levelset.music[]" might stay at "-1" to
1647 allow dynamic selection of music files from music directory!) */
1648 for (i = 0; i < MAX_LEVELS; i++)
1649 if (levelset.music[i] == -1)
1650 levelset.music[i] = default_levelset_music;
1651 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1652 if (menu.music[i] == -1)
1653 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1657 for (i = 0; i < MAX_LEVELS; i++)
1658 if (levelset.music[i] != -1)
1659 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1660 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1661 if (menu.music[i] != -1)
1662 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1666 static void set_music_parameters(int music, char **parameter_raw)
1668 int parameter[NUM_MUS_ARGS];
1671 /* get integer values from string parameters */
1672 for (i = 0; i < NUM_MUS_ARGS; i++)
1674 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1675 music_config_suffix[i].type);
1677 /* explicit loop mode setting in configuration overrides default value */
1678 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1679 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1682 static void InitMusicInfo()
1684 int num_music = getMusicListSize();
1687 checked_free(music_info);
1689 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1691 for (i = 0; i < num_music; i++)
1693 struct FileInfo *music = getMusicListEntry(i);
1694 int len_music_text = strlen(music->token);
1696 music_info[i].loop = TRUE; /* default: play music in loop mode */
1698 /* determine all loop music */
1700 for (j = 0; music_prefix_info[j].prefix; j++)
1702 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1704 if (len_prefix_text < len_music_text &&
1705 strncmp(music->token,
1706 music_prefix_info[j].prefix, len_prefix_text) == 0)
1708 music_info[i].loop = music_prefix_info[j].is_loop_music;
1714 set_music_parameters(i, music->parameter);
1718 static void ReinitializeGraphics()
1720 InitGraphicInfo(); /* graphic properties mapping */
1721 InitElementGraphicInfo(); /* element game graphic mapping */
1722 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1724 InitElementSmallImages(); /* scale images to all needed sizes */
1725 InitFontGraphicInfo(); /* initialize text drawing functions */
1727 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1729 SetMainBackgroundImage(IMG_BACKGROUND);
1730 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1736 static void ReinitializeSounds()
1738 InitSoundInfo(); /* sound properties mapping */
1739 InitElementSoundInfo(); /* element game sound mapping */
1740 InitGameModeSoundInfo(); /* game mode sound mapping */
1742 InitPlayLevelSound(); /* internal game sound settings */
1745 static void ReinitializeMusic()
1747 InitMusicInfo(); /* music properties mapping */
1748 InitGameModeMusicInfo(); /* game mode music mapping */
1751 static int get_special_property_bit(int element, int property_bit_nr)
1753 struct PropertyBitInfo
1759 static struct PropertyBitInfo pb_can_move_into_acid[] =
1761 /* the player may be able fall into acid when gravity is activated */
1766 { EL_SP_MURPHY, 0 },
1767 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1769 /* all element that can move may be able to also move into acid */
1772 { EL_BUG_RIGHT, 1 },
1775 { EL_SPACESHIP, 2 },
1776 { EL_SPACESHIP_LEFT, 2 },
1777 { EL_SPACESHIP_RIGHT, 2 },
1778 { EL_SPACESHIP_UP, 2 },
1779 { EL_SPACESHIP_DOWN, 2 },
1780 { EL_BD_BUTTERFLY, 3 },
1781 { EL_BD_BUTTERFLY_LEFT, 3 },
1782 { EL_BD_BUTTERFLY_RIGHT, 3 },
1783 { EL_BD_BUTTERFLY_UP, 3 },
1784 { EL_BD_BUTTERFLY_DOWN, 3 },
1785 { EL_BD_FIREFLY, 4 },
1786 { EL_BD_FIREFLY_LEFT, 4 },
1787 { EL_BD_FIREFLY_RIGHT, 4 },
1788 { EL_BD_FIREFLY_UP, 4 },
1789 { EL_BD_FIREFLY_DOWN, 4 },
1791 { EL_DARK_YAMYAM, 6 },
1794 { EL_PACMAN_LEFT, 8 },
1795 { EL_PACMAN_RIGHT, 8 },
1796 { EL_PACMAN_UP, 8 },
1797 { EL_PACMAN_DOWN, 8 },
1799 { EL_MOLE_LEFT, 9 },
1800 { EL_MOLE_RIGHT, 9 },
1802 { EL_MOLE_DOWN, 9 },
1806 { EL_SATELLITE, 13 },
1807 { EL_SP_SNIKSNAK, 14 },
1808 { EL_SP_ELECTRON, 15 },
1815 static struct PropertyBitInfo pb_dont_collide_with[] =
1817 { EL_SP_SNIKSNAK, 0 },
1818 { EL_SP_ELECTRON, 1 },
1826 struct PropertyBitInfo *pb_info;
1829 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1830 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1835 struct PropertyBitInfo *pb_info = NULL;
1838 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1839 if (pb_definition[i].bit_nr == property_bit_nr)
1840 pb_info = pb_definition[i].pb_info;
1842 if (pb_info == NULL)
1845 for (i = 0; pb_info[i].element != -1; i++)
1846 if (pb_info[i].element == element)
1847 return pb_info[i].bit_nr;
1853 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1854 boolean property_value)
1856 int bit_nr = get_special_property_bit(element, property_bit_nr);
1861 *bitfield |= (1 << bit_nr);
1863 *bitfield &= ~(1 << bit_nr);
1867 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1869 int bit_nr = get_special_property_bit(element, property_bit_nr);
1872 return ((*bitfield & (1 << bit_nr)) != 0);
1879 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1881 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1885 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1888 level->can_move_into_acid_bits |= (1 << bit_nr);
1892 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1894 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1897 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1903 void InitElementPropertiesStatic()
1905 static int ep_diggable[] =
1910 EL_SP_BUGGY_BASE_ACTIVATING,
1913 EL_INVISIBLE_SAND_ACTIVE,
1916 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1917 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1921 EL_SP_BUGGY_BASE_ACTIVE,
1927 static int ep_collectible_only[] =
1948 EL_DYNABOMB_INCREASE_NUMBER,
1949 EL_DYNABOMB_INCREASE_SIZE,
1950 EL_DYNABOMB_INCREASE_POWER,
1969 static int ep_dont_run_into[] =
1971 /* same elements as in 'ep_dont_touch' */
1977 /* same elements as in 'ep_dont_collide_with' */
1989 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1993 EL_SP_BUGGY_BASE_ACTIVE,
1999 static int ep_dont_collide_with[] =
2001 /* same elements as in 'ep_dont_touch' */
2017 static int ep_dont_touch[] =
2026 static int ep_indestructible[] =
2030 EL_ACID_POOL_TOPLEFT,
2031 EL_ACID_POOL_TOPRIGHT,
2032 EL_ACID_POOL_BOTTOMLEFT,
2033 EL_ACID_POOL_BOTTOM,
2034 EL_ACID_POOL_BOTTOMRIGHT,
2035 EL_SP_HARDWARE_GRAY,
2036 EL_SP_HARDWARE_GREEN,
2037 EL_SP_HARDWARE_BLUE,
2039 EL_SP_HARDWARE_YELLOW,
2040 EL_SP_HARDWARE_BASE_1,
2041 EL_SP_HARDWARE_BASE_2,
2042 EL_SP_HARDWARE_BASE_3,
2043 EL_SP_HARDWARE_BASE_4,
2044 EL_SP_HARDWARE_BASE_5,
2045 EL_SP_HARDWARE_BASE_6,
2046 EL_INVISIBLE_STEELWALL,
2047 EL_INVISIBLE_STEELWALL_ACTIVE,
2048 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2049 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2050 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2051 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2052 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2053 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2054 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2055 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2056 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2057 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2058 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2059 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2061 EL_LIGHT_SWITCH_ACTIVE,
2062 EL_SIGN_EXCLAMATION,
2063 EL_SIGN_RADIOACTIVITY,
2074 EL_STEELWALL_SLIPPERY,
2097 EL_SWITCHGATE_OPENING,
2098 EL_SWITCHGATE_CLOSED,
2099 EL_SWITCHGATE_CLOSING,
2101 EL_SWITCHGATE_SWITCH_UP,
2102 EL_SWITCHGATE_SWITCH_DOWN,
2105 EL_TIMEGATE_OPENING,
2107 EL_TIMEGATE_CLOSING,
2110 EL_TIMEGATE_SWITCH_ACTIVE,
2115 EL_TUBE_VERTICAL_LEFT,
2116 EL_TUBE_VERTICAL_RIGHT,
2117 EL_TUBE_HORIZONTAL_UP,
2118 EL_TUBE_HORIZONTAL_DOWN,
2126 static int ep_slippery[] =
2140 EL_ROBOT_WHEEL_ACTIVE,
2146 EL_ACID_POOL_TOPLEFT,
2147 EL_ACID_POOL_TOPRIGHT,
2157 EL_STEELWALL_SLIPPERY,
2160 EL_EMC_WALL_SLIPPERY_1,
2161 EL_EMC_WALL_SLIPPERY_2,
2162 EL_EMC_WALL_SLIPPERY_3,
2163 EL_EMC_WALL_SLIPPERY_4,
2167 static int ep_can_change[] =
2172 static int ep_can_move[] =
2174 /* same elements as in 'pb_can_move_into_acid' */
2196 static int ep_can_fall[] =
2211 EL_BD_MAGIC_WALL_FULL,
2224 static int ep_can_smash_player[] =
2249 static int ep_can_smash_enemies[] =
2257 static int ep_can_smash_everything[] =
2265 static int ep_explodes_by_fire[] =
2267 /* same elements as in 'ep_explodes_impact' */
2272 /* same elements as in 'ep_explodes_smashed' */
2281 EL_DYNABOMB_PLAYER_1_ACTIVE,
2282 EL_DYNABOMB_PLAYER_2_ACTIVE,
2283 EL_DYNABOMB_PLAYER_3_ACTIVE,
2284 EL_DYNABOMB_PLAYER_4_ACTIVE,
2285 EL_DYNABOMB_INCREASE_NUMBER,
2286 EL_DYNABOMB_INCREASE_SIZE,
2287 EL_DYNABOMB_INCREASE_POWER,
2288 EL_SP_DISK_RED_ACTIVE,
2301 static int ep_explodes_smashed[] =
2303 /* same elements as in 'ep_explodes_impact' */
2316 static int ep_explodes_impact[] =
2324 static int ep_walkable_over[] =
2328 EL_SOKOBAN_FIELD_EMPTY,
2346 static int ep_walkable_inside[] =
2351 EL_TUBE_VERTICAL_LEFT,
2352 EL_TUBE_VERTICAL_RIGHT,
2353 EL_TUBE_HORIZONTAL_UP,
2354 EL_TUBE_HORIZONTAL_DOWN,
2362 static int ep_walkable_under[] =
2367 static int ep_passable_over[] =
2390 static int ep_passable_inside[] =
2396 EL_SP_PORT_HORIZONTAL,
2397 EL_SP_PORT_VERTICAL,
2399 EL_SP_GRAVITY_PORT_LEFT,
2400 EL_SP_GRAVITY_PORT_RIGHT,
2401 EL_SP_GRAVITY_PORT_UP,
2402 EL_SP_GRAVITY_PORT_DOWN,
2403 EL_SP_GRAVITY_ON_PORT_LEFT,
2404 EL_SP_GRAVITY_ON_PORT_RIGHT,
2405 EL_SP_GRAVITY_ON_PORT_UP,
2406 EL_SP_GRAVITY_ON_PORT_DOWN,
2407 EL_SP_GRAVITY_OFF_PORT_LEFT,
2408 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2409 EL_SP_GRAVITY_OFF_PORT_UP,
2410 EL_SP_GRAVITY_OFF_PORT_DOWN,
2414 static int ep_passable_under[] =
2419 static int ep_droppable[] =
2424 static int ep_explodes_1x1_old[] =
2429 static int ep_pushable[] =
2441 EL_SOKOBAN_FIELD_FULL,
2449 static int ep_explodes_cross_old[] =
2454 static int ep_protected[] =
2456 /* same elements as in 'ep_walkable_inside' */
2460 EL_TUBE_VERTICAL_LEFT,
2461 EL_TUBE_VERTICAL_RIGHT,
2462 EL_TUBE_HORIZONTAL_UP,
2463 EL_TUBE_HORIZONTAL_DOWN,
2469 /* same elements as in 'ep_passable_over' */
2489 /* same elements as in 'ep_passable_inside' */
2494 EL_SP_PORT_HORIZONTAL,
2495 EL_SP_PORT_VERTICAL,
2497 EL_SP_GRAVITY_PORT_LEFT,
2498 EL_SP_GRAVITY_PORT_RIGHT,
2499 EL_SP_GRAVITY_PORT_UP,
2500 EL_SP_GRAVITY_PORT_DOWN,
2501 EL_SP_GRAVITY_ON_PORT_LEFT,
2502 EL_SP_GRAVITY_ON_PORT_RIGHT,
2503 EL_SP_GRAVITY_ON_PORT_UP,
2504 EL_SP_GRAVITY_ON_PORT_DOWN,
2505 EL_SP_GRAVITY_OFF_PORT_LEFT,
2506 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2507 EL_SP_GRAVITY_OFF_PORT_UP,
2508 EL_SP_GRAVITY_OFF_PORT_DOWN,
2512 static int ep_throwable[] =
2517 static int ep_can_explode[] =
2519 /* same elements as in 'ep_explodes_impact' */
2524 /* same elements as in 'ep_explodes_smashed' */
2530 /* elements that can explode by explosion or by dragonfire */
2533 EL_DYNABOMB_PLAYER_1_ACTIVE,
2534 EL_DYNABOMB_PLAYER_2_ACTIVE,
2535 EL_DYNABOMB_PLAYER_3_ACTIVE,
2536 EL_DYNABOMB_PLAYER_4_ACTIVE,
2537 EL_DYNABOMB_INCREASE_NUMBER,
2538 EL_DYNABOMB_INCREASE_SIZE,
2539 EL_DYNABOMB_INCREASE_POWER,
2540 EL_SP_DISK_RED_ACTIVE,
2548 /* elements that can explode only by explosion */
2553 static int ep_gravity_reachable[] =
2559 EL_INVISIBLE_SAND_ACTIVE,
2564 EL_SP_PORT_HORIZONTAL,
2565 EL_SP_PORT_VERTICAL,
2567 EL_SP_GRAVITY_PORT_LEFT,
2568 EL_SP_GRAVITY_PORT_RIGHT,
2569 EL_SP_GRAVITY_PORT_UP,
2570 EL_SP_GRAVITY_PORT_DOWN,
2571 EL_SP_GRAVITY_ON_PORT_LEFT,
2572 EL_SP_GRAVITY_ON_PORT_RIGHT,
2573 EL_SP_GRAVITY_ON_PORT_UP,
2574 EL_SP_GRAVITY_ON_PORT_DOWN,
2575 EL_SP_GRAVITY_OFF_PORT_LEFT,
2576 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2577 EL_SP_GRAVITY_OFF_PORT_UP,
2578 EL_SP_GRAVITY_OFF_PORT_DOWN,
2583 static int ep_player[] =
2590 EL_SOKOBAN_FIELD_PLAYER,
2595 static int ep_can_pass_magic_wall[] =
2608 static int ep_switchable[] =
2612 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2613 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2614 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2615 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2616 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2617 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2618 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2619 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2620 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2621 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2622 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2623 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2624 EL_SWITCHGATE_SWITCH_UP,
2625 EL_SWITCHGATE_SWITCH_DOWN,
2627 EL_LIGHT_SWITCH_ACTIVE,
2629 EL_BALLOON_SWITCH_LEFT,
2630 EL_BALLOON_SWITCH_RIGHT,
2631 EL_BALLOON_SWITCH_UP,
2632 EL_BALLOON_SWITCH_DOWN,
2633 EL_BALLOON_SWITCH_ANY,
2636 EL_EMC_MAGIC_BALL_SWITCH,
2640 static int ep_bd_element[] =
2673 static int ep_sp_element[] =
2675 /* should always be valid */
2678 /* standard classic Supaplex elements */
2685 EL_SP_HARDWARE_GRAY,
2693 EL_SP_GRAVITY_PORT_RIGHT,
2694 EL_SP_GRAVITY_PORT_DOWN,
2695 EL_SP_GRAVITY_PORT_LEFT,
2696 EL_SP_GRAVITY_PORT_UP,
2701 EL_SP_PORT_VERTICAL,
2702 EL_SP_PORT_HORIZONTAL,
2708 EL_SP_HARDWARE_BASE_1,
2709 EL_SP_HARDWARE_GREEN,
2710 EL_SP_HARDWARE_BLUE,
2712 EL_SP_HARDWARE_YELLOW,
2713 EL_SP_HARDWARE_BASE_2,
2714 EL_SP_HARDWARE_BASE_3,
2715 EL_SP_HARDWARE_BASE_4,
2716 EL_SP_HARDWARE_BASE_5,
2717 EL_SP_HARDWARE_BASE_6,
2721 /* additional elements that appeared in newer Supaplex levels */
2724 /* additional gravity port elements (not switching, but setting gravity) */
2725 EL_SP_GRAVITY_ON_PORT_LEFT,
2726 EL_SP_GRAVITY_ON_PORT_RIGHT,
2727 EL_SP_GRAVITY_ON_PORT_UP,
2728 EL_SP_GRAVITY_ON_PORT_DOWN,
2729 EL_SP_GRAVITY_OFF_PORT_LEFT,
2730 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2731 EL_SP_GRAVITY_OFF_PORT_UP,
2732 EL_SP_GRAVITY_OFF_PORT_DOWN,
2734 /* more than one Murphy in a level results in an inactive clone */
2737 /* runtime Supaplex elements */
2738 EL_SP_DISK_RED_ACTIVE,
2739 EL_SP_TERMINAL_ACTIVE,
2740 EL_SP_BUGGY_BASE_ACTIVATING,
2741 EL_SP_BUGGY_BASE_ACTIVE,
2747 static int ep_sb_element[] =
2752 EL_SOKOBAN_FIELD_EMPTY,
2753 EL_SOKOBAN_FIELD_FULL,
2754 EL_SOKOBAN_FIELD_PLAYER,
2759 EL_INVISIBLE_STEELWALL,
2763 static int ep_gem[] =
2774 static int ep_food_dark_yamyam[] =
2801 static int ep_food_penguin[] =
2814 static int ep_food_pig[] =
2825 static int ep_historic_wall[] =
2850 EL_EXPANDABLE_WALL_HORIZONTAL,
2851 EL_EXPANDABLE_WALL_VERTICAL,
2852 EL_EXPANDABLE_WALL_ANY,
2853 EL_EXPANDABLE_WALL_GROWING,
2860 EL_SP_HARDWARE_GRAY,
2861 EL_SP_HARDWARE_GREEN,
2862 EL_SP_HARDWARE_BLUE,
2864 EL_SP_HARDWARE_YELLOW,
2865 EL_SP_HARDWARE_BASE_1,
2866 EL_SP_HARDWARE_BASE_2,
2867 EL_SP_HARDWARE_BASE_3,
2868 EL_SP_HARDWARE_BASE_4,
2869 EL_SP_HARDWARE_BASE_5,
2870 EL_SP_HARDWARE_BASE_6,
2872 EL_SP_TERMINAL_ACTIVE,
2875 EL_INVISIBLE_STEELWALL,
2876 EL_INVISIBLE_STEELWALL_ACTIVE,
2878 EL_INVISIBLE_WALL_ACTIVE,
2879 EL_STEELWALL_SLIPPERY,
2895 static int ep_historic_solid[] =
2899 EL_EXPANDABLE_WALL_HORIZONTAL,
2900 EL_EXPANDABLE_WALL_VERTICAL,
2901 EL_EXPANDABLE_WALL_ANY,
2914 EL_QUICKSAND_FILLING,
2915 EL_QUICKSAND_EMPTYING,
2917 EL_MAGIC_WALL_ACTIVE,
2918 EL_MAGIC_WALL_EMPTYING,
2919 EL_MAGIC_WALL_FILLING,
2923 EL_BD_MAGIC_WALL_ACTIVE,
2924 EL_BD_MAGIC_WALL_EMPTYING,
2925 EL_BD_MAGIC_WALL_FULL,
2926 EL_BD_MAGIC_WALL_FILLING,
2927 EL_BD_MAGIC_WALL_DEAD,
2936 EL_SP_TERMINAL_ACTIVE,
2940 EL_INVISIBLE_WALL_ACTIVE,
2941 EL_SWITCHGATE_SWITCH_UP,
2942 EL_SWITCHGATE_SWITCH_DOWN,
2944 EL_TIMEGATE_SWITCH_ACTIVE,
2956 /* the following elements are a direct copy of "indestructible" elements,
2957 except "EL_ACID", which is "indestructible", but not "solid"! */
2962 EL_ACID_POOL_TOPLEFT,
2963 EL_ACID_POOL_TOPRIGHT,
2964 EL_ACID_POOL_BOTTOMLEFT,
2965 EL_ACID_POOL_BOTTOM,
2966 EL_ACID_POOL_BOTTOMRIGHT,
2967 EL_SP_HARDWARE_GRAY,
2968 EL_SP_HARDWARE_GREEN,
2969 EL_SP_HARDWARE_BLUE,
2971 EL_SP_HARDWARE_YELLOW,
2972 EL_SP_HARDWARE_BASE_1,
2973 EL_SP_HARDWARE_BASE_2,
2974 EL_SP_HARDWARE_BASE_3,
2975 EL_SP_HARDWARE_BASE_4,
2976 EL_SP_HARDWARE_BASE_5,
2977 EL_SP_HARDWARE_BASE_6,
2978 EL_INVISIBLE_STEELWALL,
2979 EL_INVISIBLE_STEELWALL_ACTIVE,
2980 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2981 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2982 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2983 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2984 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2985 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2986 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2987 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2988 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2989 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2990 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2991 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2993 EL_LIGHT_SWITCH_ACTIVE,
2994 EL_SIGN_EXCLAMATION,
2995 EL_SIGN_RADIOACTIVITY,
3006 EL_STEELWALL_SLIPPERY,
3029 EL_SWITCHGATE_OPENING,
3030 EL_SWITCHGATE_CLOSED,
3031 EL_SWITCHGATE_CLOSING,
3033 EL_TIMEGATE_OPENING,
3035 EL_TIMEGATE_CLOSING,
3039 EL_TUBE_VERTICAL_LEFT,
3040 EL_TUBE_VERTICAL_RIGHT,
3041 EL_TUBE_HORIZONTAL_UP,
3042 EL_TUBE_HORIZONTAL_DOWN,
3050 static int ep_classic_enemy[] =
3066 static int ep_belt[] =
3068 EL_CONVEYOR_BELT_1_LEFT,
3069 EL_CONVEYOR_BELT_1_MIDDLE,
3070 EL_CONVEYOR_BELT_1_RIGHT,
3071 EL_CONVEYOR_BELT_2_LEFT,
3072 EL_CONVEYOR_BELT_2_MIDDLE,
3073 EL_CONVEYOR_BELT_2_RIGHT,
3074 EL_CONVEYOR_BELT_3_LEFT,
3075 EL_CONVEYOR_BELT_3_MIDDLE,
3076 EL_CONVEYOR_BELT_3_RIGHT,
3077 EL_CONVEYOR_BELT_4_LEFT,
3078 EL_CONVEYOR_BELT_4_MIDDLE,
3079 EL_CONVEYOR_BELT_4_RIGHT,
3083 static int ep_belt_active[] =
3085 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3086 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3087 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3088 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3089 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3090 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3091 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3092 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3093 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3094 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3095 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3096 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3100 static int ep_belt_switch[] =
3102 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3103 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3104 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3105 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3106 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3107 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3108 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3109 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3110 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3111 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3112 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3113 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3117 static int ep_tube[] =
3124 EL_TUBE_HORIZONTAL_UP,
3125 EL_TUBE_HORIZONTAL_DOWN,
3127 EL_TUBE_VERTICAL_LEFT,
3128 EL_TUBE_VERTICAL_RIGHT,
3133 static int ep_keygate[] =
3162 static int ep_amoeboid[] =
3172 static int ep_amoebalive[] =
3181 static int ep_has_content[] =
3191 static int ep_can_turn_each_move[] =
3193 /* !!! do something with this one !!! */
3197 static int ep_can_grow[] =
3209 static int ep_active_bomb[] =
3212 EL_DYNABOMB_PLAYER_1_ACTIVE,
3213 EL_DYNABOMB_PLAYER_2_ACTIVE,
3214 EL_DYNABOMB_PLAYER_3_ACTIVE,
3215 EL_DYNABOMB_PLAYER_4_ACTIVE,
3216 EL_SP_DISK_RED_ACTIVE,
3220 static int ep_inactive[] =
3269 EL_INVISIBLE_STEELWALL,
3277 EL_WALL_EMERALD_YELLOW,
3278 EL_DYNABOMB_INCREASE_NUMBER,
3279 EL_DYNABOMB_INCREASE_SIZE,
3280 EL_DYNABOMB_INCREASE_POWER,
3284 EL_SOKOBAN_FIELD_EMPTY,
3285 EL_SOKOBAN_FIELD_FULL,
3286 EL_WALL_EMERALD_RED,
3287 EL_WALL_EMERALD_PURPLE,
3288 EL_ACID_POOL_TOPLEFT,
3289 EL_ACID_POOL_TOPRIGHT,
3290 EL_ACID_POOL_BOTTOMLEFT,
3291 EL_ACID_POOL_BOTTOM,
3292 EL_ACID_POOL_BOTTOMRIGHT,
3296 EL_BD_MAGIC_WALL_DEAD,
3297 EL_AMOEBA_TO_DIAMOND,
3305 EL_SP_GRAVITY_PORT_RIGHT,
3306 EL_SP_GRAVITY_PORT_DOWN,
3307 EL_SP_GRAVITY_PORT_LEFT,
3308 EL_SP_GRAVITY_PORT_UP,
3309 EL_SP_PORT_HORIZONTAL,
3310 EL_SP_PORT_VERTICAL,
3321 EL_SP_HARDWARE_GRAY,
3322 EL_SP_HARDWARE_GREEN,
3323 EL_SP_HARDWARE_BLUE,
3325 EL_SP_HARDWARE_YELLOW,
3326 EL_SP_HARDWARE_BASE_1,
3327 EL_SP_HARDWARE_BASE_2,
3328 EL_SP_HARDWARE_BASE_3,
3329 EL_SP_HARDWARE_BASE_4,
3330 EL_SP_HARDWARE_BASE_5,
3331 EL_SP_HARDWARE_BASE_6,
3332 EL_SP_GRAVITY_ON_PORT_LEFT,
3333 EL_SP_GRAVITY_ON_PORT_RIGHT,
3334 EL_SP_GRAVITY_ON_PORT_UP,
3335 EL_SP_GRAVITY_ON_PORT_DOWN,
3336 EL_SP_GRAVITY_OFF_PORT_LEFT,
3337 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3338 EL_SP_GRAVITY_OFF_PORT_UP,
3339 EL_SP_GRAVITY_OFF_PORT_DOWN,
3340 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3341 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3342 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3343 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3344 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3345 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3346 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3347 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3348 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3349 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3350 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3351 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3352 EL_SIGN_EXCLAMATION,
3353 EL_SIGN_RADIOACTIVITY,
3364 EL_STEELWALL_SLIPPERY,
3369 EL_EMC_WALL_SLIPPERY_1,
3370 EL_EMC_WALL_SLIPPERY_2,
3371 EL_EMC_WALL_SLIPPERY_3,
3372 EL_EMC_WALL_SLIPPERY_4,
3392 static int ep_em_slippery_wall[] =
3397 static int ep_gfx_crumbled[] =
3410 } element_properties[] =
3412 { ep_diggable, EP_DIGGABLE },
3413 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3414 { ep_dont_run_into, EP_DONT_RUN_INTO },
3415 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3416 { ep_dont_touch, EP_DONT_TOUCH },
3417 { ep_indestructible, EP_INDESTRUCTIBLE },
3418 { ep_slippery, EP_SLIPPERY },
3419 { ep_can_change, EP_CAN_CHANGE },
3420 { ep_can_move, EP_CAN_MOVE },
3421 { ep_can_fall, EP_CAN_FALL },
3422 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3423 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3424 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3425 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3426 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3427 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3428 { ep_walkable_over, EP_WALKABLE_OVER },
3429 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3430 { ep_walkable_under, EP_WALKABLE_UNDER },
3431 { ep_passable_over, EP_PASSABLE_OVER },
3432 { ep_passable_inside, EP_PASSABLE_INSIDE },
3433 { ep_passable_under, EP_PASSABLE_UNDER },
3434 { ep_droppable, EP_DROPPABLE },
3435 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3436 { ep_pushable, EP_PUSHABLE },
3437 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3438 { ep_protected, EP_PROTECTED },
3439 { ep_throwable, EP_THROWABLE },
3440 { ep_can_explode, EP_CAN_EXPLODE },
3441 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3443 { ep_player, EP_PLAYER },
3444 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3445 { ep_switchable, EP_SWITCHABLE },
3446 { ep_bd_element, EP_BD_ELEMENT },
3447 { ep_sp_element, EP_SP_ELEMENT },
3448 { ep_sb_element, EP_SB_ELEMENT },
3450 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3451 { ep_food_penguin, EP_FOOD_PENGUIN },
3452 { ep_food_pig, EP_FOOD_PIG },
3453 { ep_historic_wall, EP_HISTORIC_WALL },
3454 { ep_historic_solid, EP_HISTORIC_SOLID },
3455 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3456 { ep_belt, EP_BELT },
3457 { ep_belt_active, EP_BELT_ACTIVE },
3458 { ep_belt_switch, EP_BELT_SWITCH },
3459 { ep_tube, EP_TUBE },
3460 { ep_keygate, EP_KEYGATE },
3461 { ep_amoeboid, EP_AMOEBOID },
3462 { ep_amoebalive, EP_AMOEBALIVE },
3463 { ep_has_content, EP_HAS_CONTENT },
3464 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3465 { ep_can_grow, EP_CAN_GROW },
3466 { ep_active_bomb, EP_ACTIVE_BOMB },
3467 { ep_inactive, EP_INACTIVE },
3469 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3471 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3476 static int copy_properties[][5] =
3480 EL_BUG_LEFT, EL_BUG_RIGHT,
3481 EL_BUG_UP, EL_BUG_DOWN
3485 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3486 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3490 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3491 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3495 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3496 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3500 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3501 EL_PACMAN_UP, EL_PACMAN_DOWN
3505 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3506 EL_MOLE_UP, EL_MOLE_DOWN
3516 /* always start with reliable default values (element has no properties) */
3517 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3518 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3519 SET_PROPERTY(i, j, FALSE);
3521 /* set all base element properties from above array definitions */
3522 for (i = 0; element_properties[i].elements != NULL; i++)
3523 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3524 SET_PROPERTY((element_properties[i].elements)[j],
3525 element_properties[i].property, TRUE);
3527 /* copy properties to some elements that are only stored in level file */
3528 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3529 for (j = 0; copy_properties[j][0] != -1; j++)
3530 if (HAS_PROPERTY(copy_properties[j][0], i))
3531 for (k = 1; k <= 4; k++)
3532 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3535 void InitElementPropertiesEngine(int engine_version)
3538 static int active_properties[] =
3543 EP_DONT_COLLIDE_WITH,
3547 EP_CAN_PASS_MAGIC_WALL,
3552 EP_EXPLODES_BY_FIRE,
3565 EP_EM_SLIPPERY_WALL,
3569 static int no_wall_properties[] =
3572 EP_COLLECTIBLE_ONLY,
3574 EP_DONT_COLLIDE_WITH,
3577 EP_CAN_SMASH_PLAYER,
3578 EP_CAN_SMASH_ENEMIES,
3579 EP_CAN_SMASH_EVERYTHING,
3584 EP_FOOD_DARK_YAMYAM,
3601 InitElementPropertiesStatic();
3604 /* important: after initialization in InitElementPropertiesStatic(), the
3605 elements are not again initialized to a default value; therefore all
3606 changes have to make sure that they leave the element with a defined
3607 property (which means that conditional property changes must be set to
3608 a reliable default value before) */
3610 /* set all special, combined or engine dependent element properties */
3611 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3614 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3615 SET_PROPERTY(i, j, FALSE);
3618 /* ---------- INACTIVE ------------------------------------------------- */
3619 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3621 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3622 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3623 IS_WALKABLE_INSIDE(i) ||
3624 IS_WALKABLE_UNDER(i)));
3626 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3627 IS_PASSABLE_INSIDE(i) ||
3628 IS_PASSABLE_UNDER(i)));
3630 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3631 IS_PASSABLE_OVER(i)));
3633 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3634 IS_PASSABLE_INSIDE(i)));
3636 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3637 IS_PASSABLE_UNDER(i)));
3639 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3642 /* ---------- COLLECTIBLE ---------------------------------------------- */
3643 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3647 /* ---------- SNAPPABLE ------------------------------------------------ */
3648 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3649 IS_COLLECTIBLE(i) ||
3653 /* ---------- WALL ----------------------------------------------------- */
3654 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3656 for (j = 0; no_wall_properties[j] != -1; j++)
3657 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3658 i >= EL_FIRST_RUNTIME_UNREAL)
3659 SET_PROPERTY(i, EP_WALL, FALSE);
3661 if (IS_HISTORIC_WALL(i))
3662 SET_PROPERTY(i, EP_WALL, TRUE);
3664 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3665 if (engine_version < VERSION_IDENT(2,2,0,0))
3666 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3668 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3670 !IS_COLLECTIBLE(i)));
3673 /* ---------- PROTECTED ------------------------------------------------ */
3674 if (IS_ACCESSIBLE_INSIDE(i))
3675 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3678 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3680 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3681 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3683 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3684 IS_INDESTRUCTIBLE(i)));
3686 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3688 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3689 else if (engine_version < VERSION_IDENT(2,2,0,0))
3690 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3693 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3698 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3699 !IS_WALKABLE_OVER(i) &&
3700 !IS_WALKABLE_UNDER(i)));
3702 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3707 if (IS_CUSTOM_ELEMENT(i))
3709 /* these are additional properties which are initially false when set */
3711 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3713 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3714 if (DONT_COLLIDE_WITH(i))
3715 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3717 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3718 if (CAN_SMASH_EVERYTHING(i))
3719 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3720 if (CAN_SMASH_ENEMIES(i))
3721 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3724 /* ---------- CAN_SMASH ------------------------------------------------ */
3725 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3726 CAN_SMASH_ENEMIES(i) ||
3727 CAN_SMASH_EVERYTHING(i)));
3730 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3731 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3732 CAN_EXPLODE_SMASHED(i) ||
3733 CAN_EXPLODE_IMPACT(i)));
3737 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3739 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3740 !CAN_EXPLODE_CROSS(i)));
3742 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3743 !CAN_EXPLODE_1X1(i) &&
3744 !CAN_EXPLODE_CROSS(i)));
3748 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3749 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3750 EXPLODES_BY_FIRE(i)));
3752 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3753 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3754 EXPLODES_SMASHED(i)));
3756 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3757 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3758 EXPLODES_IMPACT(i)));
3760 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3761 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3763 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3764 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3765 i == EL_BLACK_ORB));
3767 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3768 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3770 IS_CUSTOM_ELEMENT(i)));
3772 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3773 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3774 i == EL_SP_ELECTRON));
3776 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3777 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3778 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3779 getMoveIntoAcidProperty(&level, i));
3781 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3782 if (MAYBE_DONT_COLLIDE_WITH(i))
3783 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3784 getDontCollideWithProperty(&level, i));
3786 /* ---------- SP_PORT -------------------------------------------------- */
3787 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3788 IS_PASSABLE_INSIDE(i)));
3790 /* ---------- CAN_CHANGE ----------------------------------------------- */
3791 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3792 for (j = 0; j < element_info[i].num_change_pages; j++)
3793 if (element_info[i].change_page[j].can_change)
3794 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3796 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3797 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3798 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3802 /* determine inactive elements (used for engine main loop optimization) */
3803 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3805 boolean active = FALSE;
3807 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3809 if (HAS_PROPERTY(i, j))
3815 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3820 /* dynamically adjust element properties according to game engine version */
3822 static int ep_em_slippery_wall[] =
3827 EL_EXPANDABLE_WALL_HORIZONTAL,
3828 EL_EXPANDABLE_WALL_VERTICAL,
3829 EL_EXPANDABLE_WALL_ANY,
3833 /* special EM style gems behaviour */
3834 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3835 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3836 level.em_slippery_gems);
3838 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3839 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3840 (level.em_slippery_gems &&
3841 engine_version > VERSION_IDENT(2,0,1,0)));
3845 /* set default push delay values (corrected since version 3.0.7-1) */
3846 if (engine_version < VERSION_IDENT(3,0,7,1))
3848 game.default_push_delay_fixed = 2;
3849 game.default_push_delay_random = 8;
3853 game.default_push_delay_fixed = 8;
3854 game.default_push_delay_random = 8;
3857 /* set uninitialized push delay values of custom elements in older levels */
3858 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3860 int element = EL_CUSTOM_START + i;
3862 if (element_info[element].push_delay_fixed == -1)
3863 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3864 if (element_info[element].push_delay_random == -1)
3865 element_info[element].push_delay_random = game.default_push_delay_random;
3868 /* set some other uninitialized values of custom elements in older levels */
3869 if (engine_version < VERSION_IDENT(3,1,0,0))
3871 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3873 int element = EL_CUSTOM_START + i;
3875 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3877 element_info[element].explosion_delay = 17;
3878 element_info[element].ignition_delay = 8;
3883 /* set element properties that were handled incorrectly in older levels */
3884 if (engine_version < VERSION_IDENT(3,1,0,0))
3886 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3887 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3893 /* this is needed because some graphics depend on element properties */
3894 if (game_status == GAME_MODE_PLAYING)
3895 InitElementGraphicInfo();
3898 static void InitGlobal()
3902 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3904 /* check if element_name_info entry defined for each element in "main.h" */
3905 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3906 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3908 element_info[i].token_name = element_name_info[i].token_name;
3909 element_info[i].class_name = element_name_info[i].class_name;
3910 element_info[i].editor_description=element_name_info[i].editor_description;
3913 global.autoplay_leveldir = NULL;
3914 global.convert_leveldir = NULL;
3916 global.frames_per_second = 0;
3917 global.fps_slowdown = FALSE;
3918 global.fps_slowdown_factor = 1;
3921 void Execute_Command(char *command)
3925 if (strcmp(command, "print graphicsinfo.conf") == 0)
3927 printf("# You can configure additional/alternative image files here.\n");
3928 printf("# (The entries below are default and therefore commented out.)\n");
3930 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3932 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3935 for (i = 0; image_config[i].token != NULL; i++)
3936 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3937 image_config[i].value));
3941 else if (strcmp(command, "print soundsinfo.conf") == 0)
3943 printf("# You can configure additional/alternative sound files here.\n");
3944 printf("# (The entries below are default and therefore commented out.)\n");
3946 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3948 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3951 for (i = 0; sound_config[i].token != NULL; i++)
3952 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3953 sound_config[i].value));
3957 else if (strcmp(command, "print musicinfo.conf") == 0)
3959 printf("# You can configure additional/alternative music files here.\n");
3960 printf("# (The entries below are default and therefore commented out.)\n");
3962 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3964 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3967 for (i = 0; music_config[i].token != NULL; i++)
3968 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3969 music_config[i].value));
3973 else if (strcmp(command, "print editorsetup.conf") == 0)
3975 printf("# You can configure your personal editor element list here.\n");
3976 printf("# (The entries below are default and therefore commented out.)\n");
3979 PrintEditorElementList();
3983 else if (strcmp(command, "print helpanim.conf") == 0)
3985 printf("# You can configure different element help animations here.\n");
3986 printf("# (The entries below are default and therefore commented out.)\n");
3989 for (i = 0; helpanim_config[i].token != NULL; i++)
3991 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3992 helpanim_config[i].value));
3994 if (strcmp(helpanim_config[i].token, "end") == 0)
4000 else if (strcmp(command, "print helptext.conf") == 0)
4002 printf("# You can configure different element help text here.\n");
4003 printf("# (The entries below are default and therefore commented out.)\n");
4006 for (i = 0; helptext_config[i].token != NULL; i++)
4007 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4008 helptext_config[i].value));
4012 else if (strncmp(command, "dump level ", 11) == 0)
4014 char *filename = &command[11];
4016 if (access(filename, F_OK) != 0)
4017 Error(ERR_EXIT, "cannot open file '%s'", filename);
4019 LoadLevelFromFilename(&level, filename);
4024 else if (strncmp(command, "dump tape ", 10) == 0)
4026 char *filename = &command[10];
4028 if (access(filename, F_OK) != 0)
4029 Error(ERR_EXIT, "cannot open file '%s'", filename);
4031 LoadTapeFromFilename(filename);
4036 else if (strncmp(command, "autoplay ", 9) == 0)
4038 char *str_copy = getStringCopy(&command[9]);
4039 char *str_ptr = strchr(str_copy, ' ');
4041 global.autoplay_leveldir = str_copy;
4042 global.autoplay_level_nr = -1;
4044 if (str_ptr != NULL)
4046 *str_ptr++ = '\0'; /* terminate leveldir string */
4047 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4050 else if (strncmp(command, "convert ", 8) == 0)
4052 char *str_copy = getStringCopy(&command[8]);
4053 char *str_ptr = strchr(str_copy, ' ');
4055 global.convert_leveldir = str_copy;
4056 global.convert_level_nr = -1;
4058 if (str_ptr != NULL)
4060 *str_ptr++ = '\0'; /* terminate leveldir string */
4061 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4066 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4070 static void InitSetup()
4072 LoadSetup(); /* global setup info */
4074 /* set some options from setup file */
4076 if (setup.options.verbose)
4077 options.verbose = TRUE;
4080 static void InitPlayerInfo()
4084 /* choose default local player */
4085 local_player = &stored_player[0];
4087 for (i = 0; i < MAX_PLAYERS; i++)
4088 stored_player[i].connected = FALSE;
4090 local_player->connected = TRUE;
4093 static void InitArtworkInfo()
4098 static char *get_string_in_brackets(char *string)
4100 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4102 sprintf(string_in_brackets, "[%s]", string);
4104 return string_in_brackets;
4107 static char *get_level_id_suffix(int id_nr)
4109 char *id_suffix = checked_malloc(1 + 3 + 1);
4111 if (id_nr < 0 || id_nr > 999)
4114 sprintf(id_suffix, ".%03d", id_nr);
4120 static char *get_element_class_token(int element)
4122 char *element_class_name = element_info[element].class_name;
4123 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4125 sprintf(element_class_token, "[%s]", element_class_name);
4127 return element_class_token;
4130 static char *get_action_class_token(int action)
4132 char *action_class_name = &element_action_info[action].suffix[1];
4133 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4135 sprintf(action_class_token, "[%s]", action_class_name);
4137 return action_class_token;
4141 static void InitArtworkConfig()
4143 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4144 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4145 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4146 static char *action_id_suffix[NUM_ACTIONS + 1];
4147 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4148 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4149 static char *level_id_suffix[MAX_LEVELS + 1];
4150 static char *dummy[1] = { NULL };
4151 static char *ignore_generic_tokens[] =
4157 static char **ignore_image_tokens;
4158 static char **ignore_sound_tokens;
4159 static char **ignore_music_tokens;
4160 int num_ignore_generic_tokens;
4161 int num_ignore_image_tokens;
4162 int num_ignore_sound_tokens;
4163 int num_ignore_music_tokens;
4166 /* dynamically determine list of generic tokens to be ignored */
4167 num_ignore_generic_tokens = 0;
4168 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4169 num_ignore_generic_tokens++;
4171 /* dynamically determine list of image tokens to be ignored */
4172 num_ignore_image_tokens = num_ignore_generic_tokens;
4173 for (i = 0; image_config_vars[i].token != NULL; i++)
4174 num_ignore_image_tokens++;
4175 ignore_image_tokens =
4176 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4177 for (i = 0; i < num_ignore_generic_tokens; i++)
4178 ignore_image_tokens[i] = ignore_generic_tokens[i];
4179 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4180 ignore_image_tokens[num_ignore_generic_tokens + i] =
4181 image_config_vars[i].token;
4182 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4184 /* dynamically determine list of sound tokens to be ignored */
4185 num_ignore_sound_tokens = num_ignore_generic_tokens;
4186 ignore_sound_tokens =
4187 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4188 for (i = 0; i < num_ignore_generic_tokens; i++)
4189 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4190 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4192 /* dynamically determine list of music tokens to be ignored */
4193 num_ignore_music_tokens = num_ignore_generic_tokens;
4194 ignore_music_tokens =
4195 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4196 for (i = 0; i < num_ignore_generic_tokens; i++)
4197 ignore_music_tokens[i] = ignore_generic_tokens[i];
4198 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4200 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4201 image_id_prefix[i] = element_info[i].token_name;
4202 for (i = 0; i < NUM_FONTS; i++)
4203 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4204 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4206 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4207 sound_id_prefix[i] = element_info[i].token_name;
4208 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4209 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4210 get_string_in_brackets(element_info[i].class_name);
4211 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4213 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4214 music_id_prefix[i] = music_prefix_info[i].prefix;
4215 music_id_prefix[MAX_LEVELS] = NULL;
4217 for (i = 0; i < NUM_ACTIONS; i++)
4218 action_id_suffix[i] = element_action_info[i].suffix;
4219 action_id_suffix[NUM_ACTIONS] = NULL;
4221 for (i = 0; i < NUM_DIRECTIONS; i++)
4222 direction_id_suffix[i] = element_direction_info[i].suffix;
4223 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4225 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4226 special_id_suffix[i] = special_suffix_info[i].suffix;
4227 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4229 for (i = 0; i < MAX_LEVELS; i++)
4230 level_id_suffix[i] = get_level_id_suffix(i);
4231 level_id_suffix[MAX_LEVELS] = NULL;
4233 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4234 image_id_prefix, action_id_suffix, direction_id_suffix,
4235 special_id_suffix, ignore_image_tokens);
4236 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4237 sound_id_prefix, action_id_suffix, dummy,
4238 special_id_suffix, ignore_sound_tokens);
4239 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4240 music_id_prefix, special_id_suffix, level_id_suffix,
4241 dummy, ignore_music_tokens);
4244 static void InitMixer()
4252 char *filename_font_initial = NULL;
4253 Bitmap *bitmap_font_initial = NULL;
4256 /* determine settings for initial font (for displaying startup messages) */
4257 for (i = 0; image_config[i].token != NULL; i++)
4259 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4261 char font_token[128];
4264 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4265 len_font_token = strlen(font_token);
4267 if (strcmp(image_config[i].token, font_token) == 0)
4268 filename_font_initial = image_config[i].value;
4269 else if (strlen(image_config[i].token) > len_font_token &&
4270 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4272 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4273 font_initial[j].src_x = atoi(image_config[i].value);
4274 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4275 font_initial[j].src_y = atoi(image_config[i].value);
4276 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4277 font_initial[j].width = atoi(image_config[i].value);
4278 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4279 font_initial[j].height = atoi(image_config[i].value);
4284 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4286 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4287 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4290 if (filename_font_initial == NULL) /* should not happen */
4291 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4293 /* create additional image buffers for double-buffering */
4294 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4295 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4297 /* initialize screen properties */
4298 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4299 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4301 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4302 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4303 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4305 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4307 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4308 font_initial[j].bitmap = bitmap_font_initial;
4310 InitFontGraphicInfo();
4312 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4313 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4315 DrawInitText("Loading graphics:", 120, FC_GREEN);
4317 InitTileClipmasks();
4320 void InitGfxBackground()
4324 drawto = backbuffer;
4325 fieldbuffer = bitmap_db_field;
4326 SetDrawtoField(DRAW_BACKBUFFER);
4328 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4329 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4330 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4331 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4333 for (x = 0; x < MAX_BUF_XSIZE; x++)
4334 for (y = 0; y < MAX_BUF_YSIZE; y++)
4337 redraw_mask = REDRAW_ALL;
4340 static void InitLevelInfo()
4342 LoadLevelInfo(); /* global level info */
4343 LoadLevelSetup_LastSeries(); /* last played series info */
4344 LoadLevelSetup_SeriesInfo(); /* last played level info */
4347 void InitLevelArtworkInfo()
4349 LoadLevelArtworkInfo();
4352 static void InitImages()
4355 setLevelArtworkDir(artwork.gfx_first);
4359 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4360 leveldir_current->identifier,
4361 artwork.gfx_current_identifier,
4362 artwork.gfx_current->identifier,
4363 leveldir_current->graphics_set,
4364 leveldir_current->graphics_path);
4367 ReloadCustomImages();
4369 LoadCustomElementDescriptions();
4370 LoadSpecialMenuDesignSettings();
4372 ReinitializeGraphics();
4375 static void InitSound(char *identifier)
4377 if (identifier == NULL)
4378 identifier = artwork.snd_current->identifier;
4381 /* set artwork path to send it to the sound server process */
4382 setLevelArtworkDir(artwork.snd_first);
4385 InitReloadCustomSounds(identifier);
4386 ReinitializeSounds();
4389 static void InitMusic(char *identifier)
4391 if (identifier == NULL)
4392 identifier = artwork.mus_current->identifier;
4395 /* set artwork path to send it to the sound server process */
4396 setLevelArtworkDir(artwork.mus_first);
4399 InitReloadCustomMusic(identifier);
4400 ReinitializeMusic();
4403 void InitNetworkServer()
4405 #if defined(NETWORK_AVALIABLE)
4409 if (!options.network)
4412 #if defined(NETWORK_AVALIABLE)
4413 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4415 if (!ConnectToServer(options.server_host, options.server_port))
4416 Error(ERR_EXIT, "cannot connect to network game server");
4418 SendToServer_PlayerName(setup.player_name);
4419 SendToServer_ProtocolVersion();
4422 SendToServer_NrWanted(nr_wanted);
4426 static char *getNewArtworkIdentifier(int type)
4428 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4429 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4430 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4431 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4432 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4433 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4434 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4435 char *leveldir_identifier = leveldir_current->identifier;
4437 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4438 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4440 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4442 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4443 char *artwork_current_identifier;
4444 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4446 /* leveldir_current may be invalid (level group, parent link) */
4447 if (!validLevelSeries(leveldir_current))
4450 /* 1st step: determine artwork set to be activated in descending order:
4451 --------------------------------------------------------------------
4452 1. setup artwork (when configured to override everything else)
4453 2. artwork set configured in "levelinfo.conf" of current level set
4454 (artwork in level directory will have priority when loading later)
4455 3. artwork in level directory (stored in artwork sub-directory)
4456 4. setup artwork (currently configured in setup menu) */
4458 if (setup_override_artwork)
4459 artwork_current_identifier = setup_artwork_set;
4460 else if (leveldir_artwork_set != NULL)
4461 artwork_current_identifier = leveldir_artwork_set;
4462 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4463 artwork_current_identifier = leveldir_identifier;
4465 artwork_current_identifier = setup_artwork_set;
4468 /* 2nd step: check if it is really needed to reload artwork set
4469 ------------------------------------------------------------ */
4472 if (type == ARTWORK_TYPE_GRAPHICS)
4473 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4474 artwork_new_identifier,
4475 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4476 artwork_current_identifier,
4477 leveldir_current->graphics_set,
4478 leveldir_current->identifier);
4481 /* ---------- reload if level set and also artwork set has changed ------- */
4482 if (leveldir_current_identifier[type] != leveldir_identifier &&
4483 (last_has_level_artwork_set[type] || has_level_artwork_set))
4484 artwork_new_identifier = artwork_current_identifier;
4486 leveldir_current_identifier[type] = leveldir_identifier;
4487 last_has_level_artwork_set[type] = has_level_artwork_set;
4490 if (type == ARTWORK_TYPE_GRAPHICS)
4491 printf("::: 1: '%s'\n", artwork_new_identifier);
4494 /* ---------- reload if "override artwork" setting has changed ----------- */
4495 if (last_override_level_artwork[type] != setup_override_artwork)
4496 artwork_new_identifier = artwork_current_identifier;
4498 last_override_level_artwork[type] = setup_override_artwork;
4501 if (type == ARTWORK_TYPE_GRAPHICS)
4502 printf("::: 2: '%s'\n", artwork_new_identifier);
4505 /* ---------- reload if current artwork identifier has changed ----------- */
4506 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4507 artwork_current_identifier) != 0)
4508 artwork_new_identifier = artwork_current_identifier;
4510 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4513 if (type == ARTWORK_TYPE_GRAPHICS)
4514 printf("::: 3: '%s'\n", artwork_new_identifier);
4517 /* ---------- do not reload directly after starting ---------------------- */
4518 if (!initialized[type])
4519 artwork_new_identifier = NULL;
4521 initialized[type] = TRUE;
4524 if (type == ARTWORK_TYPE_GRAPHICS)
4525 printf("::: 4: '%s'\n", artwork_new_identifier);
4529 if (type == ARTWORK_TYPE_GRAPHICS)
4530 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4531 artwork.gfx_current_identifier, artwork_current_identifier,
4532 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4533 artwork_new_identifier);
4536 return artwork_new_identifier;
4539 void ReloadCustomArtwork(int force_reload)
4541 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4542 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4543 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4544 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4545 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4546 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4547 boolean redraw_screen = FALSE;
4549 if (gfx_new_identifier != NULL || force_reload_gfx)
4552 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4553 artwork.gfx_current_identifier,
4555 artwork.gfx_current->identifier,
4556 leveldir_current->graphics_set);
4559 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4564 printf("... '%s'\n",
4565 leveldir_current->graphics_set);
4568 FreeTileClipmasks();
4569 InitTileClipmasks();
4571 redraw_screen = TRUE;
4574 if (snd_new_identifier != NULL || force_reload_snd)
4576 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4578 InitSound(snd_new_identifier);
4580 redraw_screen = TRUE;
4583 if (mus_new_identifier != NULL || force_reload_mus)
4585 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4587 InitMusic(mus_new_identifier);
4589 redraw_screen = TRUE;
4594 InitGfxBackground();
4596 /* force redraw of (open or closed) door graphics */
4597 SetDoorState(DOOR_OPEN_ALL);
4598 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4602 void KeyboardAutoRepeatOffUnlessAutoplay()
4604 if (global.autoplay_leveldir == NULL)
4605 KeyboardAutoRepeatOff();
4609 /* ========================================================================= */
4611 /* ========================================================================= */
4615 InitGlobal(); /* initialize some global variables */
4617 if (options.execute_command)
4618 Execute_Command(options.execute_command);
4620 if (options.serveronly)
4622 #if defined(PLATFORM_UNIX)
4623 NetworkServer(options.server_port, options.serveronly);
4625 Error(ERR_WARN, "networking only supported in Unix version");
4627 exit(0); /* never reached */
4633 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4634 InitArtworkConfig(); /* needed before forking sound child process */
4639 InitRND(NEW_RANDOMIZE);
4640 InitSimpleRND(NEW_RANDOMIZE);
4645 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4648 InitEventFilter(FilterMouseMotionEvents);
4650 InitElementPropertiesStatic();
4651 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4656 InitLevelArtworkInfo();
4658 InitImages(); /* needs to know current level directory */
4659 InitSound(NULL); /* needs to know current level directory */
4660 InitMusic(NULL); /* needs to know current level directory */
4662 InitGfxBackground();
4664 if (global.autoplay_leveldir)
4669 else if (global.convert_leveldir)
4675 game_status = GAME_MODE_MAIN;
4683 InitNetworkServer();
4686 void CloseAllAndExit(int exit_value)
4691 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4698 FreeTileClipmasks();
4700 #if defined(TARGET_SDL)
4701 if (network_server) /* terminate network server */
4702 SDL_KillThread(server_thread);
4705 CloseVideoDisplay();
4706 ClosePlatformDependentStuff();