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];
643 graphic_info[graphic].double_movement &&
644 graphic_info[graphic].swap_double_tiles != 0)
646 struct GraphicInfo *g = &graphic_info[graphic];
647 int src_x_front = g->src_x;
648 int src_y_front = g->src_y;
649 int src_x_back = g->src_x + g->offset2_x;
650 int src_y_back = g->src_y + g->offset2_y;
651 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
653 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
654 src_y_front < src_y_back);
656 boolean second_tile_is_back =
657 ((move_dir == MV_BIT_LEFT && front_is_left_or_upper) ||
658 (move_dir == MV_BIT_UP && front_is_left_or_upper));
659 boolean second_tile_is_front =
660 ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
661 (move_dir == MV_BIT_DOWN && front_is_left_or_upper));
662 boolean second_tile_should_be_front =
663 (g->second_tile_is_start == 0);
664 boolean second_tile_should_be_back =
665 (g->second_tile_is_start == 1);
667 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
668 boolean swap_movement_tiles_autodetected =
669 (!frames_are_ordered_diagonally &&
670 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
671 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
672 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
673 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
677 printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
678 i, element_info[i].token_name,
679 element_action_info[act].suffix, move_dir,
680 g->swap_double_tiles,
681 swap_movement_tiles_never,
682 swap_movement_tiles_always,
683 swap_movement_tiles_autodetected,
684 swap_movement_tiles);
687 /* swap frontside and backside graphic tile coordinates, if needed */
688 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
690 /* get current (wrong) backside tile coordinates */
691 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
694 /* set frontside tile coordinates to backside tile coordinates */
695 g->src_x = src_x_back;
696 g->src_y = src_y_back;
698 /* invert tile offset to point to new backside tile coordinates */
702 /* do not swap front and backside tiles again after correction */
703 g->swap_double_tiles = 0;
706 printf(" CORRECTED\n");
715 /* now set all '-1' values to element specific default values */
716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
719 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
720 int default_direction_graphic[NUM_DIRECTIONS];
721 int default_direction_crumbled[NUM_DIRECTIONS];
723 if (default_graphic == -1)
724 default_graphic = IMG_UNKNOWN;
725 if (default_crumbled == -1)
726 default_crumbled = IMG_EMPTY;
728 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
730 default_direction_graphic[dir] =
731 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
732 default_direction_crumbled[dir] =
733 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
735 if (default_direction_graphic[dir] == -1)
736 default_direction_graphic[dir] = default_graphic;
737 if (default_direction_crumbled[dir] == -1)
738 default_direction_crumbled[dir] = default_crumbled;
741 for (act = 0; act < NUM_ACTIONS; act++)
743 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
744 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
745 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
746 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
747 act == ACTION_TURNING_FROM_RIGHT ||
748 act == ACTION_TURNING_FROM_UP ||
749 act == ACTION_TURNING_FROM_DOWN);
751 /* generic default action graphic (defined by "[default]" directive) */
752 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
753 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
754 int default_remove_graphic = IMG_EMPTY;
756 if (act_remove && default_action_graphic != -1)
757 default_remove_graphic = default_action_graphic;
759 /* look for special default action graphic (classic game specific) */
760 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
761 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
762 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
763 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
764 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
765 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
767 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
768 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
769 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
770 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
771 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
772 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
775 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
776 /* !!! make this better !!! */
777 if (i == EL_EMPTY_SPACE)
779 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
780 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
784 if (default_action_graphic == -1)
785 default_action_graphic = default_graphic;
786 if (default_action_crumbled == -1)
787 default_action_crumbled = default_crumbled;
789 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
791 int default_action_direction_graphic = element_info[i].graphic[act];
792 int default_action_direction_crumbled = element_info[i].crumbled[act];
794 /* no graphic for current action -- use default direction graphic */
795 /* !!! maybe it's better to use default _action_ graphic here !!! */
796 if (default_action_direction_graphic == -1)
797 default_action_direction_graphic =
798 (act_remove ? default_remove_graphic :
800 element_info[i].direction_graphic[ACTION_TURNING][dir] :
801 default_direction_graphic[dir]);
802 if (default_action_direction_crumbled == -1)
803 default_action_direction_crumbled =
804 (act_remove ? default_remove_graphic :
806 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
807 default_direction_crumbled[dir]);
809 if (element_info[i].direction_graphic[act][dir] == -1)
810 element_info[i].direction_graphic[act][dir] =
811 default_action_direction_graphic;
812 if (element_info[i].direction_crumbled[act][dir] == -1)
813 element_info[i].direction_crumbled[act][dir] =
814 default_action_direction_crumbled;
817 /* no graphic for this specific action -- use default action graphic */
818 if (element_info[i].graphic[act] == -1)
819 element_info[i].graphic[act] =
820 (act_remove ? default_remove_graphic :
821 act_turning ? element_info[i].graphic[ACTION_TURNING] :
822 default_action_graphic);
823 if (element_info[i].crumbled[act] == -1)
824 element_info[i].crumbled[act] =
825 (act_remove ? default_remove_graphic :
826 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
827 default_action_crumbled);
832 /* set animation mode to "none" for each graphic with only 1 frame */
833 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
835 for (act = 0; act < NUM_ACTIONS; act++)
837 int graphic = element_info[i].graphic[act];
838 int crumbled = element_info[i].crumbled[act];
840 if (graphic_info[graphic].anim_frames == 1)
841 graphic_info[graphic].anim_mode = ANIM_NONE;
842 if (graphic_info[crumbled].anim_frames == 1)
843 graphic_info[crumbled].anim_mode = ANIM_NONE;
845 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
847 graphic = element_info[i].direction_graphic[act][dir];
848 crumbled = element_info[i].direction_crumbled[act][dir];
850 if (graphic_info[graphic].anim_frames == 1)
851 graphic_info[graphic].anim_mode = ANIM_NONE;
852 if (graphic_info[crumbled].anim_frames == 1)
853 graphic_info[crumbled].anim_mode = ANIM_NONE;
863 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
864 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
866 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
867 element_info[i].token_name, i);
873 void InitElementSpecialGraphicInfo()
875 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
876 int num_property_mappings = getImageListPropertyMappingSize();
879 /* always start with reliable default values */
880 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
881 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
882 element_info[i].special_graphic[j] =
883 element_info[i].graphic[ACTION_DEFAULT];
885 /* initialize special element/graphic mapping from static configuration */
886 for (i = 0; element_to_special_graphic[i].element > -1; i++)
888 int element = element_to_special_graphic[i].element;
889 int special = element_to_special_graphic[i].special;
890 int graphic = element_to_special_graphic[i].graphic;
891 int base_graphic = el2baseimg(element);
892 boolean base_redefined =
893 getImageListEntryFromImageID(base_graphic)->redefined;
894 boolean special_redefined =
895 getImageListEntryFromImageID(graphic)->redefined;
897 /* if the base graphic ("emerald", for example) has been redefined,
898 but not the special graphic ("emerald.EDITOR", for example), do not
899 use an existing (in this case considered obsolete) special graphic
900 anymore, but use the automatically created (down-scaled) graphic */
901 if (base_redefined && !special_redefined)
904 element_info[element].special_graphic[special] = graphic;
907 /* initialize special element/graphic mapping from dynamic configuration */
908 for (i = 0; i < num_property_mappings; i++)
910 int element = property_mapping[i].base_index;
911 int special = property_mapping[i].ext3_index;
912 int graphic = property_mapping[i].artwork_index;
914 if (element >= MAX_NUM_ELEMENTS)
917 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
918 element_info[element].special_graphic[special] = graphic;
922 /* now set all undefined/invalid graphics to default */
923 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
924 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
925 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
926 element_info[i].special_graphic[j] =
927 element_info[i].graphic[ACTION_DEFAULT];
931 static int get_element_from_token(char *token)
935 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
936 if (strcmp(element_info[i].token_name, token) == 0)
942 static int get_scaled_graphic_width(int graphic)
944 int original_width = getOriginalImageWidthFromImageID(graphic);
945 int scale_up_factor = graphic_info[graphic].scale_up_factor;
947 return original_width * scale_up_factor;
950 static int get_scaled_graphic_height(int graphic)
952 int original_height = getOriginalImageHeightFromImageID(graphic);
953 int scale_up_factor = graphic_info[graphic].scale_up_factor;
955 return original_height * scale_up_factor;
958 static void set_graphic_parameters(int graphic, int graphic_copy_from)
960 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
961 char **parameter_raw = image->parameter;
962 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
963 int parameter[NUM_GFX_ARGS];
964 int anim_frames_per_row = 1, anim_frames_per_col = 1;
965 int anim_frames_per_line = 1;
968 /* get integer values from string parameters */
969 for (i = 0; i < NUM_GFX_ARGS; i++)
972 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
973 image_config_suffix[i].type);
975 if (image_config_suffix[i].type == TYPE_TOKEN)
976 parameter[i] = get_element_from_token(parameter_raw[i]);
979 graphic_info[graphic].bitmap = src_bitmap;
981 /* start with reliable default values */
982 graphic_info[graphic].src_x = 0;
983 graphic_info[graphic].src_y = 0;
984 graphic_info[graphic].width = TILEX;
985 graphic_info[graphic].height = TILEY;
986 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
987 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
988 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
989 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
990 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
991 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
992 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
993 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
994 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
995 graphic_info[graphic].anim_delay_fixed = 0;
996 graphic_info[graphic].anim_delay_random = 0;
997 graphic_info[graphic].post_delay_fixed = 0;
998 graphic_info[graphic].post_delay_random = 0;
1000 /* optional x and y tile position of animation frame sequence */
1001 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1003 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1006 /* optional x and y pixel position of animation frame sequence */
1007 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1008 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1009 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1012 /* optional width and height of each animation frame */
1013 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1015 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1016 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1018 /* optional zoom factor for scaling up the image to a larger size */
1019 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1020 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1021 if (graphic_info[graphic].scale_up_factor < 1)
1022 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1026 /* get final bitmap size (with scaling, but without small images) */
1027 int src_bitmap_width = get_scaled_graphic_width(graphic);
1028 int src_bitmap_height = get_scaled_graphic_height(graphic);
1030 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1031 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1034 /* correct x or y offset dependent of vertical or horizontal frame order */
1035 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1037 graphic_info[graphic].offset_y =
1038 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1039 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1040 anim_frames_per_line = anim_frames_per_col;
1042 else /* frames are ordered horizontally */
1044 graphic_info[graphic].offset_x =
1045 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1046 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1047 anim_frames_per_line = anim_frames_per_row;
1050 /* optionally, the x and y offset of frames can be specified directly */
1051 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1053 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1056 /* optionally, moving animations may have separate start and end graphics */
1057 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1059 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1060 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1062 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1063 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1064 graphic_info[graphic].offset2_y =
1065 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1066 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1067 else /* frames are ordered horizontally */
1068 graphic_info[graphic].offset2_x =
1069 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1070 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1072 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1073 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1074 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1075 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1076 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1078 /* optionally, the second movement tile can be specified as start tile */
1079 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1080 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1082 /* automatically determine correct number of frames, if not defined */
1083 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1084 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1085 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1086 graphic_info[graphic].anim_frames = anim_frames_per_row;
1087 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1088 graphic_info[graphic].anim_frames = anim_frames_per_col;
1090 graphic_info[graphic].anim_frames = 1;
1092 graphic_info[graphic].anim_frames_per_line =
1093 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1094 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1096 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1097 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1098 graphic_info[graphic].anim_delay = 1;
1100 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1102 if (graphic_info[graphic].anim_frames == 1)
1103 graphic_info[graphic].anim_mode = ANIM_NONE;
1106 /* automatically determine correct start frame, if not defined */
1107 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1108 graphic_info[graphic].anim_start_frame = 0;
1109 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1110 graphic_info[graphic].anim_start_frame =
1111 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1113 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1115 /* animation synchronized with global frame counter, not move position */
1116 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1118 /* optional element for cloning crumble graphics */
1119 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1120 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1122 /* optional element for cloning digging graphics */
1123 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1126 /* optional border size for "crumbling" diggable graphics */
1127 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1130 /* this is only used for player "boring" and "sleeping" actions */
1131 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].anim_delay_fixed =
1133 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1134 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1135 graphic_info[graphic].anim_delay_random =
1136 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1137 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1138 graphic_info[graphic].post_delay_fixed =
1139 parameter[GFX_ARG_POST_DELAY_FIXED];
1140 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1141 graphic_info[graphic].post_delay_random =
1142 parameter[GFX_ARG_POST_DELAY_RANDOM];
1144 /* this is only used for toon animations */
1145 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1146 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1148 /* this is only used for drawing font characters */
1149 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1150 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1152 /* this is only used for drawing envelope graphics */
1153 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1156 static void InitGraphicInfo()
1158 int fallback_graphic = IMG_CHAR_EXCLAM;
1159 int num_images = getImageListSize();
1162 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1163 static boolean clipmasks_initialized = FALSE;
1165 XGCValues clip_gc_values;
1166 unsigned long clip_gc_valuemask;
1167 GC copy_clipmask_gc = None;
1170 checked_free(graphic_info);
1172 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1175 printf("::: graphic_info: %d entries\n", num_images);
1178 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1179 if (clipmasks_initialized)
1181 for (i = 0; i < num_images; i++)
1183 if (graphic_info[i].clip_mask)
1184 XFreePixmap(display, graphic_info[i].clip_mask);
1185 if (graphic_info[i].clip_gc)
1186 XFreeGC(display, graphic_info[i].clip_gc);
1188 graphic_info[i].clip_mask = None;
1189 graphic_info[i].clip_gc = None;
1194 for (i = 0; i < num_images; i++)
1198 int first_frame, last_frame;
1199 int src_bitmap_width, src_bitmap_height;
1202 printf("::: image: '%s' [%d]\n", image->token, i);
1206 printf("::: image # %d: '%s' ['%s']\n",
1208 getTokenFromImageID(i));
1211 set_graphic_parameters(i, i);
1213 /* now check if no animation frames are outside of the loaded image */
1215 if (graphic_info[i].bitmap == NULL)
1216 continue; /* skip check for optional images that are undefined */
1218 /* get final bitmap size (with scaling, but without small images) */
1219 src_bitmap_width = get_scaled_graphic_width(i);
1220 src_bitmap_height = get_scaled_graphic_height(i);
1223 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1224 if (src_x < 0 || src_y < 0 ||
1225 src_x + TILEX > src_bitmap_width ||
1226 src_y + TILEY > src_bitmap_height)
1228 Error(ERR_RETURN_LINE, "-");
1229 Error(ERR_RETURN, "warning: error found in config file:");
1230 Error(ERR_RETURN, "- config file: '%s'",
1231 getImageConfigFilename());
1232 Error(ERR_RETURN, "- config token: '%s'",
1233 getTokenFromImageID(i));
1234 Error(ERR_RETURN, "- image file: '%s'",
1235 src_bitmap->source_filename);
1237 "error: first animation frame out of bounds (%d, %d)",
1239 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1242 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1245 if (i == fallback_graphic)
1246 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1248 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1249 Error(ERR_RETURN_LINE, "-");
1251 set_graphic_parameters(i, fallback_graphic);
1254 last_frame = graphic_info[i].anim_frames - 1;
1255 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1256 if (src_x < 0 || src_y < 0 ||
1257 src_x + TILEX > src_bitmap_width ||
1258 src_y + TILEY > src_bitmap_height)
1260 Error(ERR_RETURN_LINE, "-");
1261 Error(ERR_RETURN, "warning: error found in config file:");
1262 Error(ERR_RETURN, "- config file: '%s'",
1263 getImageConfigFilename());
1264 Error(ERR_RETURN, "- config token: '%s'",
1265 getTokenFromImageID(i));
1266 Error(ERR_RETURN, "- image file: '%s'",
1267 src_bitmap->source_filename);
1269 "error: last animation frame (%d) out of bounds (%d, %d)",
1270 last_frame, src_x, src_y);
1271 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1273 if (i == fallback_graphic)
1274 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1276 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1277 Error(ERR_RETURN_LINE, "-");
1279 set_graphic_parameters(i, fallback_graphic);
1282 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1283 /* currently we only need a tile clip mask from the first frame */
1284 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1286 if (copy_clipmask_gc == None)
1288 clip_gc_values.graphics_exposures = False;
1289 clip_gc_valuemask = GCGraphicsExposures;
1290 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1291 clip_gc_valuemask, &clip_gc_values);
1294 graphic_info[i].clip_mask =
1295 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1297 src_pixmap = src_bitmap->clip_mask;
1298 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1299 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1301 clip_gc_values.graphics_exposures = False;
1302 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1303 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1305 graphic_info[i].clip_gc =
1306 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1310 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1311 if (copy_clipmask_gc)
1312 XFreeGC(display, copy_clipmask_gc);
1314 clipmasks_initialized = TRUE;
1318 static void InitElementSoundInfo()
1320 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1321 int num_property_mappings = getSoundListPropertyMappingSize();
1324 /* set values to -1 to identify later as "uninitialized" values */
1325 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1326 for (act = 0; act < NUM_ACTIONS; act++)
1327 element_info[i].sound[act] = -1;
1329 /* initialize element/sound mapping from static configuration */
1330 for (i = 0; element_to_sound[i].element > -1; i++)
1332 int element = element_to_sound[i].element;
1333 int action = element_to_sound[i].action;
1334 int sound = element_to_sound[i].sound;
1335 boolean is_class = element_to_sound[i].is_class;
1338 action = ACTION_DEFAULT;
1341 element_info[element].sound[action] = sound;
1343 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1344 if (strcmp(element_info[j].class_name,
1345 element_info[element].class_name) == 0)
1346 element_info[j].sound[action] = sound;
1349 /* initialize element class/sound mapping from dynamic configuration */
1350 for (i = 0; i < num_property_mappings; i++)
1352 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1353 int action = property_mapping[i].ext1_index;
1354 int sound = property_mapping[i].artwork_index;
1356 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1360 action = ACTION_DEFAULT;
1362 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1363 if (strcmp(element_info[j].class_name,
1364 element_info[element_class].class_name) == 0)
1365 element_info[j].sound[action] = sound;
1368 /* initialize element/sound mapping from dynamic configuration */
1369 for (i = 0; i < num_property_mappings; i++)
1371 int element = property_mapping[i].base_index;
1372 int action = property_mapping[i].ext1_index;
1373 int sound = property_mapping[i].artwork_index;
1375 if (element >= MAX_NUM_ELEMENTS)
1379 action = ACTION_DEFAULT;
1381 element_info[element].sound[action] = sound;
1384 /* now set all '-1' values to element specific default values */
1385 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1387 for (act = 0; act < NUM_ACTIONS; act++)
1389 /* generic default action sound (defined by "[default]" directive) */
1390 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1392 /* look for special default action sound (classic game specific) */
1393 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1394 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1395 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1396 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1397 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1398 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1400 /* !!! there's no such thing as a "default action sound" !!! */
1402 /* look for element specific default sound (independent from action) */
1403 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1404 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1408 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1409 /* !!! make this better !!! */
1410 if (i == EL_EMPTY_SPACE)
1411 default_action_sound = element_info[EL_DEFAULT].sound[act];
1414 /* no sound for this specific action -- use default action sound */
1415 if (element_info[i].sound[act] == -1)
1416 element_info[i].sound[act] = default_action_sound;
1421 static void InitGameModeSoundInfo()
1425 /* set values to -1 to identify later as "uninitialized" values */
1426 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1429 /* initialize gamemode/sound mapping from static configuration */
1430 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1432 int gamemode = gamemode_to_sound[i].gamemode;
1433 int sound = gamemode_to_sound[i].sound;
1436 gamemode = GAME_MODE_DEFAULT;
1438 menu.sound[gamemode] = sound;
1441 /* now set all '-1' values to levelset specific default values */
1442 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1443 if (menu.sound[i] == -1)
1444 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1448 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1449 if (menu.sound[i] != -1)
1450 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1454 static void set_sound_parameters(int sound, char **parameter_raw)
1456 int parameter[NUM_SND_ARGS];
1459 /* get integer values from string parameters */
1460 for (i = 0; i < NUM_SND_ARGS; i++)
1462 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1463 sound_config_suffix[i].type);
1465 /* explicit loop mode setting in configuration overrides default value */
1466 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1467 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1469 /* sound volume to change the original volume when loading the sound file */
1470 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1472 /* sound priority to give certain sounds a higher or lower priority */
1473 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1476 static void InitSoundInfo()
1479 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1480 int num_property_mappings = getSoundListPropertyMappingSize();
1482 int *sound_effect_properties;
1483 int num_sounds = getSoundListSize();
1486 checked_free(sound_info);
1488 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1489 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1491 /* initialize sound effect for all elements to "no sound" */
1492 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1493 for (j = 0; j < NUM_ACTIONS; j++)
1494 element_info[i].sound[j] = SND_UNDEFINED;
1496 for (i = 0; i < num_sounds; i++)
1498 struct FileInfo *sound = getSoundListEntry(i);
1499 int len_effect_text = strlen(sound->token);
1501 sound_effect_properties[i] = ACTION_OTHER;
1502 sound_info[i].loop = FALSE; /* default: play sound only once */
1505 printf("::: sound %d: '%s'\n", i, sound->token);
1508 /* determine all loop sounds and identify certain sound classes */
1510 for (j = 0; element_action_info[j].suffix; j++)
1512 int len_action_text = strlen(element_action_info[j].suffix);
1514 if (len_action_text < len_effect_text &&
1515 strcmp(&sound->token[len_effect_text - len_action_text],
1516 element_action_info[j].suffix) == 0)
1518 sound_effect_properties[i] = element_action_info[j].value;
1519 sound_info[i].loop = element_action_info[j].is_loop_sound;
1526 if (strcmp(sound->token, "custom_42") == 0)
1527 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1530 /* associate elements and some selected sound actions */
1532 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1534 if (element_info[j].class_name)
1536 int len_class_text = strlen(element_info[j].class_name);
1538 if (len_class_text + 1 < len_effect_text &&
1539 strncmp(sound->token,
1540 element_info[j].class_name, len_class_text) == 0 &&
1541 sound->token[len_class_text] == '.')
1543 int sound_action_value = sound_effect_properties[i];
1545 element_info[j].sound[sound_action_value] = i;
1550 set_sound_parameters(i, sound->parameter);
1553 free(sound_effect_properties);
1556 /* !!! now handled in InitElementSoundInfo() !!! */
1557 /* initialize element/sound mapping from dynamic configuration */
1558 for (i = 0; i < num_property_mappings; i++)
1560 int element = property_mapping[i].base_index;
1561 int action = property_mapping[i].ext1_index;
1562 int sound = property_mapping[i].artwork_index;
1565 action = ACTION_DEFAULT;
1567 printf("::: %d: %d, %d, %d ['%s']\n",
1568 i, element, action, sound, element_info[element].token_name);
1570 element_info[element].sound[action] = sound;
1577 int element = EL_CUSTOM_11;
1580 while (element_action_info[j].suffix)
1582 printf("element %d, sound action '%s' == %d\n",
1583 element, element_action_info[j].suffix,
1584 element_info[element].sound[j]);
1589 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1595 int element = EL_SAND;
1596 int sound_action = ACTION_DIGGING;
1599 while (element_action_info[j].suffix)
1601 if (element_action_info[j].value == sound_action)
1602 printf("element %d, sound action '%s' == %d\n",
1603 element, element_action_info[j].suffix,
1604 element_info[element].sound[sound_action]);
1611 static void InitGameModeMusicInfo()
1613 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1614 int num_property_mappings = getMusicListPropertyMappingSize();
1615 int default_levelset_music = -1;
1618 /* set values to -1 to identify later as "uninitialized" values */
1619 for (i = 0; i < MAX_LEVELS; i++)
1620 levelset.music[i] = -1;
1621 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1624 /* initialize gamemode/music mapping from static configuration */
1625 for (i = 0; gamemode_to_music[i].music > -1; i++)
1627 int gamemode = gamemode_to_music[i].gamemode;
1628 int music = gamemode_to_music[i].music;
1631 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1635 gamemode = GAME_MODE_DEFAULT;
1637 menu.music[gamemode] = music;
1640 /* initialize gamemode/music mapping from dynamic configuration */
1641 for (i = 0; i < num_property_mappings; i++)
1643 int prefix = property_mapping[i].base_index;
1644 int gamemode = property_mapping[i].ext1_index;
1645 int level = property_mapping[i].ext2_index;
1646 int music = property_mapping[i].artwork_index;
1649 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1650 prefix, gamemode, level, music);
1653 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1657 gamemode = GAME_MODE_DEFAULT;
1659 /* level specific music only allowed for in-game music */
1660 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1661 gamemode = GAME_MODE_PLAYING;
1666 default_levelset_music = music;
1669 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1670 levelset.music[level] = music;
1671 if (gamemode != GAME_MODE_PLAYING)
1672 menu.music[gamemode] = music;
1675 /* now set all '-1' values to menu specific default values */
1676 /* (undefined values of "levelset.music[]" might stay at "-1" to
1677 allow dynamic selection of music files from music directory!) */
1678 for (i = 0; i < MAX_LEVELS; i++)
1679 if (levelset.music[i] == -1)
1680 levelset.music[i] = default_levelset_music;
1681 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1682 if (menu.music[i] == -1)
1683 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1687 for (i = 0; i < MAX_LEVELS; i++)
1688 if (levelset.music[i] != -1)
1689 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1690 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1691 if (menu.music[i] != -1)
1692 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1696 static void set_music_parameters(int music, char **parameter_raw)
1698 int parameter[NUM_MUS_ARGS];
1701 /* get integer values from string parameters */
1702 for (i = 0; i < NUM_MUS_ARGS; i++)
1704 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1705 music_config_suffix[i].type);
1707 /* explicit loop mode setting in configuration overrides default value */
1708 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1709 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1712 static void InitMusicInfo()
1714 int num_music = getMusicListSize();
1717 checked_free(music_info);
1719 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1721 for (i = 0; i < num_music; i++)
1723 struct FileInfo *music = getMusicListEntry(i);
1724 int len_music_text = strlen(music->token);
1726 music_info[i].loop = TRUE; /* default: play music in loop mode */
1728 /* determine all loop music */
1730 for (j = 0; music_prefix_info[j].prefix; j++)
1732 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1734 if (len_prefix_text < len_music_text &&
1735 strncmp(music->token,
1736 music_prefix_info[j].prefix, len_prefix_text) == 0)
1738 music_info[i].loop = music_prefix_info[j].is_loop_music;
1744 set_music_parameters(i, music->parameter);
1748 static void ReinitializeGraphics()
1750 InitGraphicInfo(); /* graphic properties mapping */
1751 InitElementGraphicInfo(); /* element game graphic mapping */
1752 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1754 InitElementSmallImages(); /* scale images to all needed sizes */
1755 InitFontGraphicInfo(); /* initialize text drawing functions */
1757 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1759 SetMainBackgroundImage(IMG_BACKGROUND);
1760 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1766 static void ReinitializeSounds()
1768 InitSoundInfo(); /* sound properties mapping */
1769 InitElementSoundInfo(); /* element game sound mapping */
1770 InitGameModeSoundInfo(); /* game mode sound mapping */
1772 InitPlayLevelSound(); /* internal game sound settings */
1775 static void ReinitializeMusic()
1777 InitMusicInfo(); /* music properties mapping */
1778 InitGameModeMusicInfo(); /* game mode music mapping */
1781 static int get_special_property_bit(int element, int property_bit_nr)
1783 struct PropertyBitInfo
1789 static struct PropertyBitInfo pb_can_move_into_acid[] =
1791 /* the player may be able fall into acid when gravity is activated */
1796 { EL_SP_MURPHY, 0 },
1797 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1799 /* all element that can move may be able to also move into acid */
1802 { EL_BUG_RIGHT, 1 },
1805 { EL_SPACESHIP, 2 },
1806 { EL_SPACESHIP_LEFT, 2 },
1807 { EL_SPACESHIP_RIGHT, 2 },
1808 { EL_SPACESHIP_UP, 2 },
1809 { EL_SPACESHIP_DOWN, 2 },
1810 { EL_BD_BUTTERFLY, 3 },
1811 { EL_BD_BUTTERFLY_LEFT, 3 },
1812 { EL_BD_BUTTERFLY_RIGHT, 3 },
1813 { EL_BD_BUTTERFLY_UP, 3 },
1814 { EL_BD_BUTTERFLY_DOWN, 3 },
1815 { EL_BD_FIREFLY, 4 },
1816 { EL_BD_FIREFLY_LEFT, 4 },
1817 { EL_BD_FIREFLY_RIGHT, 4 },
1818 { EL_BD_FIREFLY_UP, 4 },
1819 { EL_BD_FIREFLY_DOWN, 4 },
1821 { EL_DARK_YAMYAM, 6 },
1824 { EL_PACMAN_LEFT, 8 },
1825 { EL_PACMAN_RIGHT, 8 },
1826 { EL_PACMAN_UP, 8 },
1827 { EL_PACMAN_DOWN, 8 },
1829 { EL_MOLE_LEFT, 9 },
1830 { EL_MOLE_RIGHT, 9 },
1832 { EL_MOLE_DOWN, 9 },
1836 { EL_SATELLITE, 13 },
1837 { EL_SP_SNIKSNAK, 14 },
1838 { EL_SP_ELECTRON, 15 },
1845 static struct PropertyBitInfo pb_dont_collide_with[] =
1847 { EL_SP_SNIKSNAK, 0 },
1848 { EL_SP_ELECTRON, 1 },
1856 struct PropertyBitInfo *pb_info;
1859 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1860 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1865 struct PropertyBitInfo *pb_info = NULL;
1868 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1869 if (pb_definition[i].bit_nr == property_bit_nr)
1870 pb_info = pb_definition[i].pb_info;
1872 if (pb_info == NULL)
1875 for (i = 0; pb_info[i].element != -1; i++)
1876 if (pb_info[i].element == element)
1877 return pb_info[i].bit_nr;
1883 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1884 boolean property_value)
1886 int bit_nr = get_special_property_bit(element, property_bit_nr);
1891 *bitfield |= (1 << bit_nr);
1893 *bitfield &= ~(1 << bit_nr);
1897 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1899 int bit_nr = get_special_property_bit(element, property_bit_nr);
1902 return ((*bitfield & (1 << bit_nr)) != 0);
1909 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1911 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1915 level->can_move_into_acid_bits &= ~(1 << bit_nr);
1918 level->can_move_into_acid_bits |= (1 << bit_nr);
1922 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1924 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1927 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1933 void InitElementPropertiesStatic()
1935 static int ep_diggable[] =
1940 EL_SP_BUGGY_BASE_ACTIVATING,
1943 EL_INVISIBLE_SAND_ACTIVE,
1946 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1947 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1951 EL_SP_BUGGY_BASE_ACTIVE,
1957 static int ep_collectible_only[] =
1978 EL_DYNABOMB_INCREASE_NUMBER,
1979 EL_DYNABOMB_INCREASE_SIZE,
1980 EL_DYNABOMB_INCREASE_POWER,
1999 static int ep_dont_run_into[] =
2001 /* same elements as in 'ep_dont_touch' */
2007 /* same elements as in 'ep_dont_collide_with' */
2019 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2023 EL_SP_BUGGY_BASE_ACTIVE,
2029 static int ep_dont_collide_with[] =
2031 /* same elements as in 'ep_dont_touch' */
2047 static int ep_dont_touch[] =
2056 static int ep_indestructible[] =
2060 EL_ACID_POOL_TOPLEFT,
2061 EL_ACID_POOL_TOPRIGHT,
2062 EL_ACID_POOL_BOTTOMLEFT,
2063 EL_ACID_POOL_BOTTOM,
2064 EL_ACID_POOL_BOTTOMRIGHT,
2065 EL_SP_HARDWARE_GRAY,
2066 EL_SP_HARDWARE_GREEN,
2067 EL_SP_HARDWARE_BLUE,
2069 EL_SP_HARDWARE_YELLOW,
2070 EL_SP_HARDWARE_BASE_1,
2071 EL_SP_HARDWARE_BASE_2,
2072 EL_SP_HARDWARE_BASE_3,
2073 EL_SP_HARDWARE_BASE_4,
2074 EL_SP_HARDWARE_BASE_5,
2075 EL_SP_HARDWARE_BASE_6,
2076 EL_INVISIBLE_STEELWALL,
2077 EL_INVISIBLE_STEELWALL_ACTIVE,
2078 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2079 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2080 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2081 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2082 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2083 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2084 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2085 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2086 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2087 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2088 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2089 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2091 EL_LIGHT_SWITCH_ACTIVE,
2092 EL_SIGN_EXCLAMATION,
2093 EL_SIGN_RADIOACTIVITY,
2104 EL_STEELWALL_SLIPPERY,
2127 EL_SWITCHGATE_OPENING,
2128 EL_SWITCHGATE_CLOSED,
2129 EL_SWITCHGATE_CLOSING,
2131 EL_SWITCHGATE_SWITCH_UP,
2132 EL_SWITCHGATE_SWITCH_DOWN,
2135 EL_TIMEGATE_OPENING,
2137 EL_TIMEGATE_CLOSING,
2140 EL_TIMEGATE_SWITCH_ACTIVE,
2145 EL_TUBE_VERTICAL_LEFT,
2146 EL_TUBE_VERTICAL_RIGHT,
2147 EL_TUBE_HORIZONTAL_UP,
2148 EL_TUBE_HORIZONTAL_DOWN,
2156 static int ep_slippery[] =
2170 EL_ROBOT_WHEEL_ACTIVE,
2176 EL_ACID_POOL_TOPLEFT,
2177 EL_ACID_POOL_TOPRIGHT,
2187 EL_STEELWALL_SLIPPERY,
2190 EL_EMC_WALL_SLIPPERY_1,
2191 EL_EMC_WALL_SLIPPERY_2,
2192 EL_EMC_WALL_SLIPPERY_3,
2193 EL_EMC_WALL_SLIPPERY_4,
2197 static int ep_can_change[] =
2202 static int ep_can_move[] =
2204 /* same elements as in 'pb_can_move_into_acid' */
2226 static int ep_can_fall[] =
2241 EL_BD_MAGIC_WALL_FULL,
2254 static int ep_can_smash_player[] =
2279 static int ep_can_smash_enemies[] =
2287 static int ep_can_smash_everything[] =
2295 static int ep_explodes_by_fire[] =
2297 /* same elements as in 'ep_explodes_impact' */
2302 /* same elements as in 'ep_explodes_smashed' */
2311 EL_DYNABOMB_PLAYER_1_ACTIVE,
2312 EL_DYNABOMB_PLAYER_2_ACTIVE,
2313 EL_DYNABOMB_PLAYER_3_ACTIVE,
2314 EL_DYNABOMB_PLAYER_4_ACTIVE,
2315 EL_DYNABOMB_INCREASE_NUMBER,
2316 EL_DYNABOMB_INCREASE_SIZE,
2317 EL_DYNABOMB_INCREASE_POWER,
2318 EL_SP_DISK_RED_ACTIVE,
2331 static int ep_explodes_smashed[] =
2333 /* same elements as in 'ep_explodes_impact' */
2346 static int ep_explodes_impact[] =
2354 static int ep_walkable_over[] =
2358 EL_SOKOBAN_FIELD_EMPTY,
2376 static int ep_walkable_inside[] =
2381 EL_TUBE_VERTICAL_LEFT,
2382 EL_TUBE_VERTICAL_RIGHT,
2383 EL_TUBE_HORIZONTAL_UP,
2384 EL_TUBE_HORIZONTAL_DOWN,
2392 static int ep_walkable_under[] =
2397 static int ep_passable_over[] =
2420 static int ep_passable_inside[] =
2426 EL_SP_PORT_HORIZONTAL,
2427 EL_SP_PORT_VERTICAL,
2429 EL_SP_GRAVITY_PORT_LEFT,
2430 EL_SP_GRAVITY_PORT_RIGHT,
2431 EL_SP_GRAVITY_PORT_UP,
2432 EL_SP_GRAVITY_PORT_DOWN,
2433 EL_SP_GRAVITY_ON_PORT_LEFT,
2434 EL_SP_GRAVITY_ON_PORT_RIGHT,
2435 EL_SP_GRAVITY_ON_PORT_UP,
2436 EL_SP_GRAVITY_ON_PORT_DOWN,
2437 EL_SP_GRAVITY_OFF_PORT_LEFT,
2438 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2439 EL_SP_GRAVITY_OFF_PORT_UP,
2440 EL_SP_GRAVITY_OFF_PORT_DOWN,
2444 static int ep_passable_under[] =
2449 static int ep_droppable[] =
2454 static int ep_explodes_1x1_old[] =
2459 static int ep_pushable[] =
2471 EL_SOKOBAN_FIELD_FULL,
2479 static int ep_explodes_cross_old[] =
2484 static int ep_protected[] =
2486 /* same elements as in 'ep_walkable_inside' */
2490 EL_TUBE_VERTICAL_LEFT,
2491 EL_TUBE_VERTICAL_RIGHT,
2492 EL_TUBE_HORIZONTAL_UP,
2493 EL_TUBE_HORIZONTAL_DOWN,
2499 /* same elements as in 'ep_passable_over' */
2519 /* same elements as in 'ep_passable_inside' */
2524 EL_SP_PORT_HORIZONTAL,
2525 EL_SP_PORT_VERTICAL,
2527 EL_SP_GRAVITY_PORT_LEFT,
2528 EL_SP_GRAVITY_PORT_RIGHT,
2529 EL_SP_GRAVITY_PORT_UP,
2530 EL_SP_GRAVITY_PORT_DOWN,
2531 EL_SP_GRAVITY_ON_PORT_LEFT,
2532 EL_SP_GRAVITY_ON_PORT_RIGHT,
2533 EL_SP_GRAVITY_ON_PORT_UP,
2534 EL_SP_GRAVITY_ON_PORT_DOWN,
2535 EL_SP_GRAVITY_OFF_PORT_LEFT,
2536 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2537 EL_SP_GRAVITY_OFF_PORT_UP,
2538 EL_SP_GRAVITY_OFF_PORT_DOWN,
2542 static int ep_throwable[] =
2547 static int ep_can_explode[] =
2549 /* same elements as in 'ep_explodes_impact' */
2554 /* same elements as in 'ep_explodes_smashed' */
2560 /* elements that can explode by explosion or by dragonfire */
2563 EL_DYNABOMB_PLAYER_1_ACTIVE,
2564 EL_DYNABOMB_PLAYER_2_ACTIVE,
2565 EL_DYNABOMB_PLAYER_3_ACTIVE,
2566 EL_DYNABOMB_PLAYER_4_ACTIVE,
2567 EL_DYNABOMB_INCREASE_NUMBER,
2568 EL_DYNABOMB_INCREASE_SIZE,
2569 EL_DYNABOMB_INCREASE_POWER,
2570 EL_SP_DISK_RED_ACTIVE,
2578 /* elements that can explode only by explosion */
2583 static int ep_gravity_reachable[] =
2589 EL_INVISIBLE_SAND_ACTIVE,
2594 EL_SP_PORT_HORIZONTAL,
2595 EL_SP_PORT_VERTICAL,
2597 EL_SP_GRAVITY_PORT_LEFT,
2598 EL_SP_GRAVITY_PORT_RIGHT,
2599 EL_SP_GRAVITY_PORT_UP,
2600 EL_SP_GRAVITY_PORT_DOWN,
2601 EL_SP_GRAVITY_ON_PORT_LEFT,
2602 EL_SP_GRAVITY_ON_PORT_RIGHT,
2603 EL_SP_GRAVITY_ON_PORT_UP,
2604 EL_SP_GRAVITY_ON_PORT_DOWN,
2605 EL_SP_GRAVITY_OFF_PORT_LEFT,
2606 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2607 EL_SP_GRAVITY_OFF_PORT_UP,
2608 EL_SP_GRAVITY_OFF_PORT_DOWN,
2613 static int ep_player[] =
2620 EL_SOKOBAN_FIELD_PLAYER,
2625 static int ep_can_pass_magic_wall[] =
2638 static int ep_switchable[] =
2642 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2643 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2644 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2645 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2646 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2647 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2648 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2649 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2650 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2651 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2652 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2653 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2654 EL_SWITCHGATE_SWITCH_UP,
2655 EL_SWITCHGATE_SWITCH_DOWN,
2657 EL_LIGHT_SWITCH_ACTIVE,
2659 EL_BALLOON_SWITCH_LEFT,
2660 EL_BALLOON_SWITCH_RIGHT,
2661 EL_BALLOON_SWITCH_UP,
2662 EL_BALLOON_SWITCH_DOWN,
2663 EL_BALLOON_SWITCH_ANY,
2666 EL_EMC_MAGIC_BALL_SWITCH,
2670 static int ep_bd_element[] =
2703 static int ep_sp_element[] =
2705 /* should always be valid */
2708 /* standard classic Supaplex elements */
2715 EL_SP_HARDWARE_GRAY,
2723 EL_SP_GRAVITY_PORT_RIGHT,
2724 EL_SP_GRAVITY_PORT_DOWN,
2725 EL_SP_GRAVITY_PORT_LEFT,
2726 EL_SP_GRAVITY_PORT_UP,
2731 EL_SP_PORT_VERTICAL,
2732 EL_SP_PORT_HORIZONTAL,
2738 EL_SP_HARDWARE_BASE_1,
2739 EL_SP_HARDWARE_GREEN,
2740 EL_SP_HARDWARE_BLUE,
2742 EL_SP_HARDWARE_YELLOW,
2743 EL_SP_HARDWARE_BASE_2,
2744 EL_SP_HARDWARE_BASE_3,
2745 EL_SP_HARDWARE_BASE_4,
2746 EL_SP_HARDWARE_BASE_5,
2747 EL_SP_HARDWARE_BASE_6,
2751 /* additional elements that appeared in newer Supaplex levels */
2754 /* additional gravity port elements (not switching, but setting gravity) */
2755 EL_SP_GRAVITY_ON_PORT_LEFT,
2756 EL_SP_GRAVITY_ON_PORT_RIGHT,
2757 EL_SP_GRAVITY_ON_PORT_UP,
2758 EL_SP_GRAVITY_ON_PORT_DOWN,
2759 EL_SP_GRAVITY_OFF_PORT_LEFT,
2760 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2761 EL_SP_GRAVITY_OFF_PORT_UP,
2762 EL_SP_GRAVITY_OFF_PORT_DOWN,
2764 /* more than one Murphy in a level results in an inactive clone */
2767 /* runtime Supaplex elements */
2768 EL_SP_DISK_RED_ACTIVE,
2769 EL_SP_TERMINAL_ACTIVE,
2770 EL_SP_BUGGY_BASE_ACTIVATING,
2771 EL_SP_BUGGY_BASE_ACTIVE,
2777 static int ep_sb_element[] =
2782 EL_SOKOBAN_FIELD_EMPTY,
2783 EL_SOKOBAN_FIELD_FULL,
2784 EL_SOKOBAN_FIELD_PLAYER,
2789 EL_INVISIBLE_STEELWALL,
2793 static int ep_gem[] =
2804 static int ep_food_dark_yamyam[] =
2831 static int ep_food_penguin[] =
2844 static int ep_food_pig[] =
2855 static int ep_historic_wall[] =
2880 EL_EXPANDABLE_WALL_HORIZONTAL,
2881 EL_EXPANDABLE_WALL_VERTICAL,
2882 EL_EXPANDABLE_WALL_ANY,
2883 EL_EXPANDABLE_WALL_GROWING,
2890 EL_SP_HARDWARE_GRAY,
2891 EL_SP_HARDWARE_GREEN,
2892 EL_SP_HARDWARE_BLUE,
2894 EL_SP_HARDWARE_YELLOW,
2895 EL_SP_HARDWARE_BASE_1,
2896 EL_SP_HARDWARE_BASE_2,
2897 EL_SP_HARDWARE_BASE_3,
2898 EL_SP_HARDWARE_BASE_4,
2899 EL_SP_HARDWARE_BASE_5,
2900 EL_SP_HARDWARE_BASE_6,
2902 EL_SP_TERMINAL_ACTIVE,
2905 EL_INVISIBLE_STEELWALL,
2906 EL_INVISIBLE_STEELWALL_ACTIVE,
2908 EL_INVISIBLE_WALL_ACTIVE,
2909 EL_STEELWALL_SLIPPERY,
2925 static int ep_historic_solid[] =
2929 EL_EXPANDABLE_WALL_HORIZONTAL,
2930 EL_EXPANDABLE_WALL_VERTICAL,
2931 EL_EXPANDABLE_WALL_ANY,
2944 EL_QUICKSAND_FILLING,
2945 EL_QUICKSAND_EMPTYING,
2947 EL_MAGIC_WALL_ACTIVE,
2948 EL_MAGIC_WALL_EMPTYING,
2949 EL_MAGIC_WALL_FILLING,
2953 EL_BD_MAGIC_WALL_ACTIVE,
2954 EL_BD_MAGIC_WALL_EMPTYING,
2955 EL_BD_MAGIC_WALL_FULL,
2956 EL_BD_MAGIC_WALL_FILLING,
2957 EL_BD_MAGIC_WALL_DEAD,
2966 EL_SP_TERMINAL_ACTIVE,
2970 EL_INVISIBLE_WALL_ACTIVE,
2971 EL_SWITCHGATE_SWITCH_UP,
2972 EL_SWITCHGATE_SWITCH_DOWN,
2974 EL_TIMEGATE_SWITCH_ACTIVE,
2986 /* the following elements are a direct copy of "indestructible" elements,
2987 except "EL_ACID", which is "indestructible", but not "solid"! */
2992 EL_ACID_POOL_TOPLEFT,
2993 EL_ACID_POOL_TOPRIGHT,
2994 EL_ACID_POOL_BOTTOMLEFT,
2995 EL_ACID_POOL_BOTTOM,
2996 EL_ACID_POOL_BOTTOMRIGHT,
2997 EL_SP_HARDWARE_GRAY,
2998 EL_SP_HARDWARE_GREEN,
2999 EL_SP_HARDWARE_BLUE,
3001 EL_SP_HARDWARE_YELLOW,
3002 EL_SP_HARDWARE_BASE_1,
3003 EL_SP_HARDWARE_BASE_2,
3004 EL_SP_HARDWARE_BASE_3,
3005 EL_SP_HARDWARE_BASE_4,
3006 EL_SP_HARDWARE_BASE_5,
3007 EL_SP_HARDWARE_BASE_6,
3008 EL_INVISIBLE_STEELWALL,
3009 EL_INVISIBLE_STEELWALL_ACTIVE,
3010 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3011 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3012 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3013 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3014 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3015 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3016 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3017 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3018 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3019 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3020 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3021 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3023 EL_LIGHT_SWITCH_ACTIVE,
3024 EL_SIGN_EXCLAMATION,
3025 EL_SIGN_RADIOACTIVITY,
3036 EL_STEELWALL_SLIPPERY,
3059 EL_SWITCHGATE_OPENING,
3060 EL_SWITCHGATE_CLOSED,
3061 EL_SWITCHGATE_CLOSING,
3063 EL_TIMEGATE_OPENING,
3065 EL_TIMEGATE_CLOSING,
3069 EL_TUBE_VERTICAL_LEFT,
3070 EL_TUBE_VERTICAL_RIGHT,
3071 EL_TUBE_HORIZONTAL_UP,
3072 EL_TUBE_HORIZONTAL_DOWN,
3080 static int ep_classic_enemy[] =
3096 static int ep_belt[] =
3098 EL_CONVEYOR_BELT_1_LEFT,
3099 EL_CONVEYOR_BELT_1_MIDDLE,
3100 EL_CONVEYOR_BELT_1_RIGHT,
3101 EL_CONVEYOR_BELT_2_LEFT,
3102 EL_CONVEYOR_BELT_2_MIDDLE,
3103 EL_CONVEYOR_BELT_2_RIGHT,
3104 EL_CONVEYOR_BELT_3_LEFT,
3105 EL_CONVEYOR_BELT_3_MIDDLE,
3106 EL_CONVEYOR_BELT_3_RIGHT,
3107 EL_CONVEYOR_BELT_4_LEFT,
3108 EL_CONVEYOR_BELT_4_MIDDLE,
3109 EL_CONVEYOR_BELT_4_RIGHT,
3113 static int ep_belt_active[] =
3115 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3116 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3117 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3118 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3119 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3120 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3121 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3122 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3123 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3124 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3125 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3126 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3130 static int ep_belt_switch[] =
3132 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3133 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3134 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3135 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3136 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3137 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3138 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3139 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3140 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3141 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3142 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3143 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3147 static int ep_tube[] =
3154 EL_TUBE_HORIZONTAL_UP,
3155 EL_TUBE_HORIZONTAL_DOWN,
3157 EL_TUBE_VERTICAL_LEFT,
3158 EL_TUBE_VERTICAL_RIGHT,
3163 static int ep_keygate[] =
3192 static int ep_amoeboid[] =
3202 static int ep_amoebalive[] =
3211 static int ep_has_content[] =
3221 static int ep_can_turn_each_move[] =
3223 /* !!! do something with this one !!! */
3227 static int ep_can_grow[] =
3239 static int ep_active_bomb[] =
3242 EL_DYNABOMB_PLAYER_1_ACTIVE,
3243 EL_DYNABOMB_PLAYER_2_ACTIVE,
3244 EL_DYNABOMB_PLAYER_3_ACTIVE,
3245 EL_DYNABOMB_PLAYER_4_ACTIVE,
3246 EL_SP_DISK_RED_ACTIVE,
3250 static int ep_inactive[] =
3299 EL_INVISIBLE_STEELWALL,
3307 EL_WALL_EMERALD_YELLOW,
3308 EL_DYNABOMB_INCREASE_NUMBER,
3309 EL_DYNABOMB_INCREASE_SIZE,
3310 EL_DYNABOMB_INCREASE_POWER,
3314 EL_SOKOBAN_FIELD_EMPTY,
3315 EL_SOKOBAN_FIELD_FULL,
3316 EL_WALL_EMERALD_RED,
3317 EL_WALL_EMERALD_PURPLE,
3318 EL_ACID_POOL_TOPLEFT,
3319 EL_ACID_POOL_TOPRIGHT,
3320 EL_ACID_POOL_BOTTOMLEFT,
3321 EL_ACID_POOL_BOTTOM,
3322 EL_ACID_POOL_BOTTOMRIGHT,
3326 EL_BD_MAGIC_WALL_DEAD,
3327 EL_AMOEBA_TO_DIAMOND,
3335 EL_SP_GRAVITY_PORT_RIGHT,
3336 EL_SP_GRAVITY_PORT_DOWN,
3337 EL_SP_GRAVITY_PORT_LEFT,
3338 EL_SP_GRAVITY_PORT_UP,
3339 EL_SP_PORT_HORIZONTAL,
3340 EL_SP_PORT_VERTICAL,
3351 EL_SP_HARDWARE_GRAY,
3352 EL_SP_HARDWARE_GREEN,
3353 EL_SP_HARDWARE_BLUE,
3355 EL_SP_HARDWARE_YELLOW,
3356 EL_SP_HARDWARE_BASE_1,
3357 EL_SP_HARDWARE_BASE_2,
3358 EL_SP_HARDWARE_BASE_3,
3359 EL_SP_HARDWARE_BASE_4,
3360 EL_SP_HARDWARE_BASE_5,
3361 EL_SP_HARDWARE_BASE_6,
3362 EL_SP_GRAVITY_ON_PORT_LEFT,
3363 EL_SP_GRAVITY_ON_PORT_RIGHT,
3364 EL_SP_GRAVITY_ON_PORT_UP,
3365 EL_SP_GRAVITY_ON_PORT_DOWN,
3366 EL_SP_GRAVITY_OFF_PORT_LEFT,
3367 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3368 EL_SP_GRAVITY_OFF_PORT_UP,
3369 EL_SP_GRAVITY_OFF_PORT_DOWN,
3370 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3371 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3372 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3373 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3374 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3375 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3376 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3377 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3378 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3379 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3380 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3381 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3382 EL_SIGN_EXCLAMATION,
3383 EL_SIGN_RADIOACTIVITY,
3394 EL_STEELWALL_SLIPPERY,
3399 EL_EMC_WALL_SLIPPERY_1,
3400 EL_EMC_WALL_SLIPPERY_2,
3401 EL_EMC_WALL_SLIPPERY_3,
3402 EL_EMC_WALL_SLIPPERY_4,
3422 static int ep_em_slippery_wall[] =
3427 static int ep_gfx_crumbled[] =
3440 } element_properties[] =
3442 { ep_diggable, EP_DIGGABLE },
3443 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3444 { ep_dont_run_into, EP_DONT_RUN_INTO },
3445 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3446 { ep_dont_touch, EP_DONT_TOUCH },
3447 { ep_indestructible, EP_INDESTRUCTIBLE },
3448 { ep_slippery, EP_SLIPPERY },
3449 { ep_can_change, EP_CAN_CHANGE },
3450 { ep_can_move, EP_CAN_MOVE },
3451 { ep_can_fall, EP_CAN_FALL },
3452 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3453 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3454 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3455 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3456 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3457 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3458 { ep_walkable_over, EP_WALKABLE_OVER },
3459 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3460 { ep_walkable_under, EP_WALKABLE_UNDER },
3461 { ep_passable_over, EP_PASSABLE_OVER },
3462 { ep_passable_inside, EP_PASSABLE_INSIDE },
3463 { ep_passable_under, EP_PASSABLE_UNDER },
3464 { ep_droppable, EP_DROPPABLE },
3465 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3466 { ep_pushable, EP_PUSHABLE },
3467 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3468 { ep_protected, EP_PROTECTED },
3469 { ep_throwable, EP_THROWABLE },
3470 { ep_can_explode, EP_CAN_EXPLODE },
3471 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3473 { ep_player, EP_PLAYER },
3474 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3475 { ep_switchable, EP_SWITCHABLE },
3476 { ep_bd_element, EP_BD_ELEMENT },
3477 { ep_sp_element, EP_SP_ELEMENT },
3478 { ep_sb_element, EP_SB_ELEMENT },
3480 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3481 { ep_food_penguin, EP_FOOD_PENGUIN },
3482 { ep_food_pig, EP_FOOD_PIG },
3483 { ep_historic_wall, EP_HISTORIC_WALL },
3484 { ep_historic_solid, EP_HISTORIC_SOLID },
3485 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3486 { ep_belt, EP_BELT },
3487 { ep_belt_active, EP_BELT_ACTIVE },
3488 { ep_belt_switch, EP_BELT_SWITCH },
3489 { ep_tube, EP_TUBE },
3490 { ep_keygate, EP_KEYGATE },
3491 { ep_amoeboid, EP_AMOEBOID },
3492 { ep_amoebalive, EP_AMOEBALIVE },
3493 { ep_has_content, EP_HAS_CONTENT },
3494 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3495 { ep_can_grow, EP_CAN_GROW },
3496 { ep_active_bomb, EP_ACTIVE_BOMB },
3497 { ep_inactive, EP_INACTIVE },
3499 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3501 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3506 static int copy_properties[][5] =
3510 EL_BUG_LEFT, EL_BUG_RIGHT,
3511 EL_BUG_UP, EL_BUG_DOWN
3515 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
3516 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
3520 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
3521 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
3525 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
3526 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
3530 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
3531 EL_PACMAN_UP, EL_PACMAN_DOWN
3535 EL_MOLE_LEFT, EL_MOLE_RIGHT,
3536 EL_MOLE_UP, EL_MOLE_DOWN
3546 /* always start with reliable default values (element has no properties) */
3547 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3548 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3549 SET_PROPERTY(i, j, FALSE);
3551 /* set all base element properties from above array definitions */
3552 for (i = 0; element_properties[i].elements != NULL; i++)
3553 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3554 SET_PROPERTY((element_properties[i].elements)[j],
3555 element_properties[i].property, TRUE);
3557 /* copy properties to some elements that are only stored in level file */
3558 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3559 for (j = 0; copy_properties[j][0] != -1; j++)
3560 if (HAS_PROPERTY(copy_properties[j][0], i))
3561 for (k = 1; k <= 4; k++)
3562 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3565 void InitElementPropertiesEngine(int engine_version)
3568 static int active_properties[] =
3573 EP_DONT_COLLIDE_WITH,
3577 EP_CAN_PASS_MAGIC_WALL,
3582 EP_EXPLODES_BY_FIRE,
3595 EP_EM_SLIPPERY_WALL,
3599 static int no_wall_properties[] =
3602 EP_COLLECTIBLE_ONLY,
3604 EP_DONT_COLLIDE_WITH,
3607 EP_CAN_SMASH_PLAYER,
3608 EP_CAN_SMASH_ENEMIES,
3609 EP_CAN_SMASH_EVERYTHING,
3614 EP_FOOD_DARK_YAMYAM,
3631 InitElementPropertiesStatic();
3634 /* important: after initialization in InitElementPropertiesStatic(), the
3635 elements are not again initialized to a default value; therefore all
3636 changes have to make sure that they leave the element with a defined
3637 property (which means that conditional property changes must be set to
3638 a reliable default value before) */
3640 /* set all special, combined or engine dependent element properties */
3641 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3644 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3645 SET_PROPERTY(i, j, FALSE);
3648 /* ---------- INACTIVE ------------------------------------------------- */
3649 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3651 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3652 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3653 IS_WALKABLE_INSIDE(i) ||
3654 IS_WALKABLE_UNDER(i)));
3656 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3657 IS_PASSABLE_INSIDE(i) ||
3658 IS_PASSABLE_UNDER(i)));
3660 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3661 IS_PASSABLE_OVER(i)));
3663 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3664 IS_PASSABLE_INSIDE(i)));
3666 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3667 IS_PASSABLE_UNDER(i)));
3669 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3672 /* ---------- COLLECTIBLE ---------------------------------------------- */
3673 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3677 /* ---------- SNAPPABLE ------------------------------------------------ */
3678 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3679 IS_COLLECTIBLE(i) ||
3683 /* ---------- WALL ----------------------------------------------------- */
3684 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3686 for (j = 0; no_wall_properties[j] != -1; j++)
3687 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3688 i >= EL_FIRST_RUNTIME_UNREAL)
3689 SET_PROPERTY(i, EP_WALL, FALSE);
3691 if (IS_HISTORIC_WALL(i))
3692 SET_PROPERTY(i, EP_WALL, TRUE);
3694 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3695 if (engine_version < VERSION_IDENT(2,2,0,0))
3696 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3698 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3700 !IS_COLLECTIBLE(i)));
3703 /* ---------- PROTECTED ------------------------------------------------ */
3704 if (IS_ACCESSIBLE_INSIDE(i))
3705 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3708 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3710 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3711 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3713 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3714 IS_INDESTRUCTIBLE(i)));
3716 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3718 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3719 else if (engine_version < VERSION_IDENT(2,2,0,0))
3720 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3723 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3728 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3729 !IS_WALKABLE_OVER(i) &&
3730 !IS_WALKABLE_UNDER(i)));
3732 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3737 if (IS_CUSTOM_ELEMENT(i))
3739 /* these are additional properties which are initially false when set */
3741 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3743 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3744 if (DONT_COLLIDE_WITH(i))
3745 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3747 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3748 if (CAN_SMASH_EVERYTHING(i))
3749 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3750 if (CAN_SMASH_ENEMIES(i))
3751 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3754 /* ---------- CAN_SMASH ------------------------------------------------ */
3755 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3756 CAN_SMASH_ENEMIES(i) ||
3757 CAN_SMASH_EVERYTHING(i)));
3760 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3761 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3762 CAN_EXPLODE_SMASHED(i) ||
3763 CAN_EXPLODE_IMPACT(i)));
3767 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3769 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3770 !CAN_EXPLODE_CROSS(i)));
3772 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3773 !CAN_EXPLODE_1X1(i) &&
3774 !CAN_EXPLODE_CROSS(i)));
3778 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3779 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3780 EXPLODES_BY_FIRE(i)));
3782 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3783 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3784 EXPLODES_SMASHED(i)));
3786 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3787 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3788 EXPLODES_IMPACT(i)));
3790 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3791 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3793 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3794 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3795 i == EL_BLACK_ORB));
3797 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3798 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3800 IS_CUSTOM_ELEMENT(i)));
3802 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3803 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3804 i == EL_SP_ELECTRON));
3806 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3807 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3808 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3809 getMoveIntoAcidProperty(&level, i));
3811 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3812 if (MAYBE_DONT_COLLIDE_WITH(i))
3813 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3814 getDontCollideWithProperty(&level, i));
3816 /* ---------- SP_PORT -------------------------------------------------- */
3817 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3818 IS_PASSABLE_INSIDE(i)));
3820 /* ---------- CAN_CHANGE ----------------------------------------------- */
3821 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3822 for (j = 0; j < element_info[i].num_change_pages; j++)
3823 if (element_info[i].change_page[j].can_change)
3824 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3826 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3827 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3828 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3832 /* determine inactive elements (used for engine main loop optimization) */
3833 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3835 boolean active = FALSE;
3837 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3839 if (HAS_PROPERTY(i, j))
3845 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3850 /* dynamically adjust element properties according to game engine version */
3852 static int ep_em_slippery_wall[] =
3857 EL_EXPANDABLE_WALL_HORIZONTAL,
3858 EL_EXPANDABLE_WALL_VERTICAL,
3859 EL_EXPANDABLE_WALL_ANY,
3863 /* special EM style gems behaviour */
3864 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3865 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3866 level.em_slippery_gems);
3868 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3869 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3870 (level.em_slippery_gems &&
3871 engine_version > VERSION_IDENT(2,0,1,0)));
3875 /* set default push delay values (corrected since version 3.0.7-1) */
3876 if (engine_version < VERSION_IDENT(3,0,7,1))
3878 game.default_push_delay_fixed = 2;
3879 game.default_push_delay_random = 8;
3883 game.default_push_delay_fixed = 8;
3884 game.default_push_delay_random = 8;
3887 /* set uninitialized push delay values of custom elements in older levels */
3888 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3890 int element = EL_CUSTOM_START + i;
3892 if (element_info[element].push_delay_fixed == -1)
3893 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3894 if (element_info[element].push_delay_random == -1)
3895 element_info[element].push_delay_random = game.default_push_delay_random;
3898 /* set some other uninitialized values of custom elements in older levels */
3899 if (engine_version < VERSION_IDENT(3,1,0,0))
3901 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3903 int element = EL_CUSTOM_START + i;
3905 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3907 element_info[element].explosion_delay = 17;
3908 element_info[element].ignition_delay = 8;
3913 /* set element properties that were handled incorrectly in older levels */
3914 if (engine_version < VERSION_IDENT(3,1,0,0))
3916 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3917 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3923 /* this is needed because some graphics depend on element properties */
3924 if (game_status == GAME_MODE_PLAYING)
3925 InitElementGraphicInfo();
3928 static void InitGlobal()
3932 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3934 /* check if element_name_info entry defined for each element in "main.h" */
3935 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3936 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3938 element_info[i].token_name = element_name_info[i].token_name;
3939 element_info[i].class_name = element_name_info[i].class_name;
3940 element_info[i].editor_description=element_name_info[i].editor_description;
3943 global.autoplay_leveldir = NULL;
3944 global.convert_leveldir = NULL;
3946 global.frames_per_second = 0;
3947 global.fps_slowdown = FALSE;
3948 global.fps_slowdown_factor = 1;
3951 void Execute_Command(char *command)
3955 if (strcmp(command, "print graphicsinfo.conf") == 0)
3957 printf("# You can configure additional/alternative image files here.\n");
3958 printf("# (The entries below are default and therefore commented out.)\n");
3960 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3962 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3965 for (i = 0; image_config[i].token != NULL; i++)
3966 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3967 image_config[i].value));
3971 else if (strcmp(command, "print soundsinfo.conf") == 0)
3973 printf("# You can configure additional/alternative sound files here.\n");
3974 printf("# (The entries below are default and therefore commented out.)\n");
3976 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3978 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3981 for (i = 0; sound_config[i].token != NULL; i++)
3982 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3983 sound_config[i].value));
3987 else if (strcmp(command, "print musicinfo.conf") == 0)
3989 printf("# You can configure additional/alternative music files here.\n");
3990 printf("# (The entries below are default and therefore commented out.)\n");
3992 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3994 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3997 for (i = 0; music_config[i].token != NULL; i++)
3998 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3999 music_config[i].value));
4003 else if (strcmp(command, "print editorsetup.conf") == 0)
4005 printf("# You can configure your personal editor element list here.\n");
4006 printf("# (The entries below are default and therefore commented out.)\n");
4009 PrintEditorElementList();
4013 else if (strcmp(command, "print helpanim.conf") == 0)
4015 printf("# You can configure different element help animations here.\n");
4016 printf("# (The entries below are default and therefore commented out.)\n");
4019 for (i = 0; helpanim_config[i].token != NULL; i++)
4021 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4022 helpanim_config[i].value));
4024 if (strcmp(helpanim_config[i].token, "end") == 0)
4030 else if (strcmp(command, "print helptext.conf") == 0)
4032 printf("# You can configure different element help text here.\n");
4033 printf("# (The entries below are default and therefore commented out.)\n");
4036 for (i = 0; helptext_config[i].token != NULL; i++)
4037 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4038 helptext_config[i].value));
4042 else if (strncmp(command, "dump level ", 11) == 0)
4044 char *filename = &command[11];
4046 if (access(filename, F_OK) != 0)
4047 Error(ERR_EXIT, "cannot open file '%s'", filename);
4049 LoadLevelFromFilename(&level, filename);
4054 else if (strncmp(command, "dump tape ", 10) == 0)
4056 char *filename = &command[10];
4058 if (access(filename, F_OK) != 0)
4059 Error(ERR_EXIT, "cannot open file '%s'", filename);
4061 LoadTapeFromFilename(filename);
4066 else if (strncmp(command, "autoplay ", 9) == 0)
4068 char *str_copy = getStringCopy(&command[9]);
4069 char *str_ptr = strchr(str_copy, ' ');
4071 global.autoplay_leveldir = str_copy;
4072 global.autoplay_level_nr = -1;
4074 if (str_ptr != NULL)
4076 *str_ptr++ = '\0'; /* terminate leveldir string */
4077 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4080 else if (strncmp(command, "convert ", 8) == 0)
4082 char *str_copy = getStringCopy(&command[8]);
4083 char *str_ptr = strchr(str_copy, ' ');
4085 global.convert_leveldir = str_copy;
4086 global.convert_level_nr = -1;
4088 if (str_ptr != NULL)
4090 *str_ptr++ = '\0'; /* terminate leveldir string */
4091 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4096 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4100 static void InitSetup()
4102 LoadSetup(); /* global setup info */
4104 /* set some options from setup file */
4106 if (setup.options.verbose)
4107 options.verbose = TRUE;
4110 static void InitPlayerInfo()
4114 /* choose default local player */
4115 local_player = &stored_player[0];
4117 for (i = 0; i < MAX_PLAYERS; i++)
4118 stored_player[i].connected = FALSE;
4120 local_player->connected = TRUE;
4123 static void InitArtworkInfo()
4128 static char *get_string_in_brackets(char *string)
4130 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4132 sprintf(string_in_brackets, "[%s]", string);
4134 return string_in_brackets;
4137 static char *get_level_id_suffix(int id_nr)
4139 char *id_suffix = checked_malloc(1 + 3 + 1);
4141 if (id_nr < 0 || id_nr > 999)
4144 sprintf(id_suffix, ".%03d", id_nr);
4150 static char *get_element_class_token(int element)
4152 char *element_class_name = element_info[element].class_name;
4153 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4155 sprintf(element_class_token, "[%s]", element_class_name);
4157 return element_class_token;
4160 static char *get_action_class_token(int action)
4162 char *action_class_name = &element_action_info[action].suffix[1];
4163 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4165 sprintf(action_class_token, "[%s]", action_class_name);
4167 return action_class_token;
4171 static void InitArtworkConfig()
4173 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4174 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4175 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4176 static char *action_id_suffix[NUM_ACTIONS + 1];
4177 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4178 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4179 static char *level_id_suffix[MAX_LEVELS + 1];
4180 static char *dummy[1] = { NULL };
4181 static char *ignore_generic_tokens[] =
4187 static char **ignore_image_tokens;
4188 static char **ignore_sound_tokens;
4189 static char **ignore_music_tokens;
4190 int num_ignore_generic_tokens;
4191 int num_ignore_image_tokens;
4192 int num_ignore_sound_tokens;
4193 int num_ignore_music_tokens;
4196 /* dynamically determine list of generic tokens to be ignored */
4197 num_ignore_generic_tokens = 0;
4198 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4199 num_ignore_generic_tokens++;
4201 /* dynamically determine list of image tokens to be ignored */
4202 num_ignore_image_tokens = num_ignore_generic_tokens;
4203 for (i = 0; image_config_vars[i].token != NULL; i++)
4204 num_ignore_image_tokens++;
4205 ignore_image_tokens =
4206 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4207 for (i = 0; i < num_ignore_generic_tokens; i++)
4208 ignore_image_tokens[i] = ignore_generic_tokens[i];
4209 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4210 ignore_image_tokens[num_ignore_generic_tokens + i] =
4211 image_config_vars[i].token;
4212 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4214 /* dynamically determine list of sound tokens to be ignored */
4215 num_ignore_sound_tokens = num_ignore_generic_tokens;
4216 ignore_sound_tokens =
4217 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4218 for (i = 0; i < num_ignore_generic_tokens; i++)
4219 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4220 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4222 /* dynamically determine list of music tokens to be ignored */
4223 num_ignore_music_tokens = num_ignore_generic_tokens;
4224 ignore_music_tokens =
4225 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4226 for (i = 0; i < num_ignore_generic_tokens; i++)
4227 ignore_music_tokens[i] = ignore_generic_tokens[i];
4228 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4230 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4231 image_id_prefix[i] = element_info[i].token_name;
4232 for (i = 0; i < NUM_FONTS; i++)
4233 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4234 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4236 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4237 sound_id_prefix[i] = element_info[i].token_name;
4238 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4239 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4240 get_string_in_brackets(element_info[i].class_name);
4241 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4243 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4244 music_id_prefix[i] = music_prefix_info[i].prefix;
4245 music_id_prefix[MAX_LEVELS] = NULL;
4247 for (i = 0; i < NUM_ACTIONS; i++)
4248 action_id_suffix[i] = element_action_info[i].suffix;
4249 action_id_suffix[NUM_ACTIONS] = NULL;
4251 for (i = 0; i < NUM_DIRECTIONS; i++)
4252 direction_id_suffix[i] = element_direction_info[i].suffix;
4253 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4255 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4256 special_id_suffix[i] = special_suffix_info[i].suffix;
4257 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4259 for (i = 0; i < MAX_LEVELS; i++)
4260 level_id_suffix[i] = get_level_id_suffix(i);
4261 level_id_suffix[MAX_LEVELS] = NULL;
4263 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4264 image_id_prefix, action_id_suffix, direction_id_suffix,
4265 special_id_suffix, ignore_image_tokens);
4266 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4267 sound_id_prefix, action_id_suffix, dummy,
4268 special_id_suffix, ignore_sound_tokens);
4269 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4270 music_id_prefix, special_id_suffix, level_id_suffix,
4271 dummy, ignore_music_tokens);
4274 static void InitMixer()
4282 char *filename_font_initial = NULL;
4283 Bitmap *bitmap_font_initial = NULL;
4286 /* determine settings for initial font (for displaying startup messages) */
4287 for (i = 0; image_config[i].token != NULL; i++)
4289 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4291 char font_token[128];
4294 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4295 len_font_token = strlen(font_token);
4297 if (strcmp(image_config[i].token, font_token) == 0)
4298 filename_font_initial = image_config[i].value;
4299 else if (strlen(image_config[i].token) > len_font_token &&
4300 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4302 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4303 font_initial[j].src_x = atoi(image_config[i].value);
4304 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4305 font_initial[j].src_y = atoi(image_config[i].value);
4306 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4307 font_initial[j].width = atoi(image_config[i].value);
4308 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4309 font_initial[j].height = atoi(image_config[i].value);
4314 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4316 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4317 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4320 if (filename_font_initial == NULL) /* should not happen */
4321 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4323 /* create additional image buffers for double-buffering */
4324 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4325 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4327 /* initialize screen properties */
4328 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4329 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4331 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4332 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4333 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4335 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4337 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4338 font_initial[j].bitmap = bitmap_font_initial;
4340 InitFontGraphicInfo();
4342 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4343 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4345 DrawInitText("Loading graphics:", 120, FC_GREEN);
4347 InitTileClipmasks();
4350 void InitGfxBackground()
4354 drawto = backbuffer;
4355 fieldbuffer = bitmap_db_field;
4356 SetDrawtoField(DRAW_BACKBUFFER);
4358 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4359 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4360 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4361 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4363 for (x = 0; x < MAX_BUF_XSIZE; x++)
4364 for (y = 0; y < MAX_BUF_YSIZE; y++)
4367 redraw_mask = REDRAW_ALL;
4370 static void InitLevelInfo()
4372 LoadLevelInfo(); /* global level info */
4373 LoadLevelSetup_LastSeries(); /* last played series info */
4374 LoadLevelSetup_SeriesInfo(); /* last played level info */
4377 void InitLevelArtworkInfo()
4379 LoadLevelArtworkInfo();
4382 static void InitImages()
4385 setLevelArtworkDir(artwork.gfx_first);
4389 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4390 leveldir_current->identifier,
4391 artwork.gfx_current_identifier,
4392 artwork.gfx_current->identifier,
4393 leveldir_current->graphics_set,
4394 leveldir_current->graphics_path);
4397 ReloadCustomImages();
4399 LoadCustomElementDescriptions();
4400 LoadSpecialMenuDesignSettings();
4402 ReinitializeGraphics();
4405 static void InitSound(char *identifier)
4407 if (identifier == NULL)
4408 identifier = artwork.snd_current->identifier;
4411 /* set artwork path to send it to the sound server process */
4412 setLevelArtworkDir(artwork.snd_first);
4415 InitReloadCustomSounds(identifier);
4416 ReinitializeSounds();
4419 static void InitMusic(char *identifier)
4421 if (identifier == NULL)
4422 identifier = artwork.mus_current->identifier;
4425 /* set artwork path to send it to the sound server process */
4426 setLevelArtworkDir(artwork.mus_first);
4429 InitReloadCustomMusic(identifier);
4430 ReinitializeMusic();
4433 void InitNetworkServer()
4435 #if defined(NETWORK_AVALIABLE)
4439 if (!options.network)
4442 #if defined(NETWORK_AVALIABLE)
4443 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4445 if (!ConnectToServer(options.server_host, options.server_port))
4446 Error(ERR_EXIT, "cannot connect to network game server");
4448 SendToServer_PlayerName(setup.player_name);
4449 SendToServer_ProtocolVersion();
4452 SendToServer_NrWanted(nr_wanted);
4456 static char *getNewArtworkIdentifier(int type)
4458 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4459 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4460 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4461 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4462 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4463 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4464 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4465 char *leveldir_identifier = leveldir_current->identifier;
4467 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4468 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4470 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4472 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4473 char *artwork_current_identifier;
4474 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4476 /* leveldir_current may be invalid (level group, parent link) */
4477 if (!validLevelSeries(leveldir_current))
4480 /* 1st step: determine artwork set to be activated in descending order:
4481 --------------------------------------------------------------------
4482 1. setup artwork (when configured to override everything else)
4483 2. artwork set configured in "levelinfo.conf" of current level set
4484 (artwork in level directory will have priority when loading later)
4485 3. artwork in level directory (stored in artwork sub-directory)
4486 4. setup artwork (currently configured in setup menu) */
4488 if (setup_override_artwork)
4489 artwork_current_identifier = setup_artwork_set;
4490 else if (leveldir_artwork_set != NULL)
4491 artwork_current_identifier = leveldir_artwork_set;
4492 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4493 artwork_current_identifier = leveldir_identifier;
4495 artwork_current_identifier = setup_artwork_set;
4498 /* 2nd step: check if it is really needed to reload artwork set
4499 ------------------------------------------------------------ */
4502 if (type == ARTWORK_TYPE_GRAPHICS)
4503 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4504 artwork_new_identifier,
4505 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4506 artwork_current_identifier,
4507 leveldir_current->graphics_set,
4508 leveldir_current->identifier);
4511 /* ---------- reload if level set and also artwork set has changed ------- */
4512 if (leveldir_current_identifier[type] != leveldir_identifier &&
4513 (last_has_level_artwork_set[type] || has_level_artwork_set))
4514 artwork_new_identifier = artwork_current_identifier;
4516 leveldir_current_identifier[type] = leveldir_identifier;
4517 last_has_level_artwork_set[type] = has_level_artwork_set;
4520 if (type == ARTWORK_TYPE_GRAPHICS)
4521 printf("::: 1: '%s'\n", artwork_new_identifier);
4524 /* ---------- reload if "override artwork" setting has changed ----------- */
4525 if (last_override_level_artwork[type] != setup_override_artwork)
4526 artwork_new_identifier = artwork_current_identifier;
4528 last_override_level_artwork[type] = setup_override_artwork;
4531 if (type == ARTWORK_TYPE_GRAPHICS)
4532 printf("::: 2: '%s'\n", artwork_new_identifier);
4535 /* ---------- reload if current artwork identifier has changed ----------- */
4536 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4537 artwork_current_identifier) != 0)
4538 artwork_new_identifier = artwork_current_identifier;
4540 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4543 if (type == ARTWORK_TYPE_GRAPHICS)
4544 printf("::: 3: '%s'\n", artwork_new_identifier);
4547 /* ---------- do not reload directly after starting ---------------------- */
4548 if (!initialized[type])
4549 artwork_new_identifier = NULL;
4551 initialized[type] = TRUE;
4554 if (type == ARTWORK_TYPE_GRAPHICS)
4555 printf("::: 4: '%s'\n", artwork_new_identifier);
4559 if (type == ARTWORK_TYPE_GRAPHICS)
4560 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4561 artwork.gfx_current_identifier, artwork_current_identifier,
4562 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4563 artwork_new_identifier);
4566 return artwork_new_identifier;
4569 void ReloadCustomArtwork(int force_reload)
4571 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4572 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4573 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4574 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4575 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4576 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4577 boolean redraw_screen = FALSE;
4579 if (gfx_new_identifier != NULL || force_reload_gfx)
4582 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4583 artwork.gfx_current_identifier,
4585 artwork.gfx_current->identifier,
4586 leveldir_current->graphics_set);
4589 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4594 printf("... '%s'\n",
4595 leveldir_current->graphics_set);
4598 FreeTileClipmasks();
4599 InitTileClipmasks();
4601 redraw_screen = TRUE;
4604 if (snd_new_identifier != NULL || force_reload_snd)
4606 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4608 InitSound(snd_new_identifier);
4610 redraw_screen = TRUE;
4613 if (mus_new_identifier != NULL || force_reload_mus)
4615 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4617 InitMusic(mus_new_identifier);
4619 redraw_screen = TRUE;
4624 InitGfxBackground();
4626 /* force redraw of (open or closed) door graphics */
4627 SetDoorState(DOOR_OPEN_ALL);
4628 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4632 void KeyboardAutoRepeatOffUnlessAutoplay()
4634 if (global.autoplay_leveldir == NULL)
4635 KeyboardAutoRepeatOff();
4639 /* ========================================================================= */
4641 /* ========================================================================= */
4645 InitGlobal(); /* initialize some global variables */
4647 if (options.execute_command)
4648 Execute_Command(options.execute_command);
4650 if (options.serveronly)
4652 #if defined(PLATFORM_UNIX)
4653 NetworkServer(options.server_port, options.serveronly);
4655 Error(ERR_WARN, "networking only supported in Unix version");
4657 exit(0); /* never reached */
4663 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4664 InitArtworkConfig(); /* needed before forking sound child process */
4669 InitRND(NEW_RANDOMIZE);
4670 InitSimpleRND(NEW_RANDOMIZE);
4675 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4678 InitEventFilter(FilterMouseMotionEvents);
4680 InitElementPropertiesStatic();
4681 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4686 InitLevelArtworkInfo();
4688 InitImages(); /* needs to know current level directory */
4689 InitSound(NULL); /* needs to know current level directory */
4690 InitMusic(NULL); /* needs to know current level directory */
4692 InitGfxBackground();
4694 if (global.autoplay_leveldir)
4699 else if (global.convert_leveldir)
4705 game_status = GAME_MODE_MAIN;
4713 InitNetworkServer();
4716 void CloseAllAndExit(int exit_value)
4721 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4728 FreeTileClipmasks();
4730 #if defined(TARGET_SDL)
4731 if (network_server) /* terminate network server */
4732 SDL_KillThread(server_thread);
4735 CloseVideoDisplay();
4736 ClosePlatformDependentStuff();