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 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
82 FreeLevelEditorGadgets();
91 static boolean gadgets_initialized = FALSE;
93 if (gadgets_initialized)
96 CreateLevelEditorGadgets();
100 CreateScreenGadgets();
102 gadgets_initialized = TRUE;
105 inline void InitElementSmallImagesScaledUp(int graphic)
107 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
110 void InitElementSmallImages()
112 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
113 int num_property_mappings = getImageListPropertyMappingSize();
116 /* initialize normal images from static configuration */
117 for (i = 0; element_to_graphic[i].element > -1; i++)
118 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
120 /* initialize special images from static configuration */
121 for (i = 0; element_to_special_graphic[i].element > -1; i++)
122 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
124 /* initialize images from dynamic configuration (may be elements or other) */
125 for (i = 0; i < num_property_mappings; i++)
126 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
130 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
131 void SetBitmaps_EM(Bitmap **em_bitmap)
133 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
134 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
138 static int getFontBitmapID(int font_nr)
142 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
143 special = game_status;
144 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
145 special = GFX_SPECIAL_ARG_MAIN;
146 else if (game_status == GAME_MODE_PLAYING)
147 special = GFX_SPECIAL_ARG_DOOR;
150 return font_info[font_nr].special_bitmap_id[special];
155 void InitFontGraphicInfo()
157 static struct FontBitmapInfo *font_bitmap_info = NULL;
158 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
159 int num_property_mappings = getImageListPropertyMappingSize();
160 int num_font_bitmaps = NUM_FONTS;
163 if (graphic_info == NULL) /* still at startup phase */
165 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
170 /* ---------- initialize font graphic definitions ---------- */
172 /* always start with reliable default values (normal font graphics) */
173 for (i = 0; i < NUM_FONTS; i++)
174 font_info[i].graphic = IMG_FONT_INITIAL_1;
176 /* initialize normal font/graphic mapping from static configuration */
177 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
179 int font_nr = font_to_graphic[i].font_nr;
180 int special = font_to_graphic[i].special;
181 int graphic = font_to_graphic[i].graphic;
186 font_info[font_nr].graphic = graphic;
189 /* always start with reliable default values (special font graphics) */
190 for (i = 0; i < NUM_FONTS; i++)
192 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
194 font_info[i].special_graphic[j] = font_info[i].graphic;
195 font_info[i].special_bitmap_id[j] = i;
199 /* initialize special font/graphic mapping from static configuration */
200 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
202 int font_nr = font_to_graphic[i].font_nr;
203 int special = font_to_graphic[i].special;
204 int graphic = font_to_graphic[i].graphic;
205 int base_graphic = font2baseimg(font_nr);
207 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
209 boolean base_redefined =
210 getImageListEntryFromImageID(base_graphic)->redefined;
211 boolean special_redefined =
212 getImageListEntryFromImageID(graphic)->redefined;
214 /* if the base font ("font.title_1", for example) has been redefined,
215 but not the special font ("font.title_1.LEVELS", for example), do not
216 use an existing (in this case considered obsolete) special font
217 anymore, but use the automatically determined default font */
218 if (base_redefined && !special_redefined)
221 font_info[font_nr].special_graphic[special] = graphic;
222 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
227 /* initialize special element/graphic mapping from dynamic configuration */
228 for (i = 0; i < num_property_mappings; i++)
230 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
231 int special = property_mapping[i].ext3_index;
232 int graphic = property_mapping[i].artwork_index;
237 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
239 font_info[font_nr].special_graphic[special] = graphic;
240 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
245 /* ---------- initialize font bitmap array ---------- */
247 if (font_bitmap_info != NULL)
248 FreeFontInfo(font_bitmap_info);
251 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
253 /* ---------- initialize font bitmap definitions ---------- */
255 for (i = 0; i < NUM_FONTS; i++)
257 if (i < NUM_INITIAL_FONTS)
259 font_bitmap_info[i] = font_initial[i];
263 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
265 int font_bitmap_id = font_info[i].special_bitmap_id[j];
266 int graphic = font_info[i].special_graphic[j];
268 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
269 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
271 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
272 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
275 /* copy font relevant information from graphics information */
276 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
277 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
278 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
279 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
280 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
281 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
282 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
284 font_bitmap_info[font_bitmap_id].num_chars =
285 graphic_info[graphic].anim_frames;
286 font_bitmap_info[font_bitmap_id].num_chars_per_line =
287 graphic_info[graphic].anim_frames_per_line;
291 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
294 void InitElementGraphicInfo()
296 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
297 int num_property_mappings = getImageListPropertyMappingSize();
300 if (graphic_info == NULL) /* still at startup phase */
303 /* set values to -1 to identify later as "uninitialized" values */
304 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
306 for (act = 0; act < NUM_ACTIONS; act++)
308 element_info[i].graphic[act] = -1;
309 element_info[i].crumbled[act] = -1;
311 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
313 element_info[i].direction_graphic[act][dir] = -1;
314 element_info[i].direction_crumbled[act][dir] = -1;
319 /* initialize normal element/graphic mapping from static configuration */
320 for (i = 0; element_to_graphic[i].element > -1; i++)
322 int element = element_to_graphic[i].element;
323 int action = element_to_graphic[i].action;
324 int direction = element_to_graphic[i].direction;
325 boolean crumbled = element_to_graphic[i].crumbled;
326 int graphic = element_to_graphic[i].graphic;
327 int base_graphic = el2baseimg(element);
329 if (graphic_info[graphic].bitmap == NULL)
332 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
335 boolean base_redefined =
336 getImageListEntryFromImageID(base_graphic)->redefined;
337 boolean act_dir_redefined =
338 getImageListEntryFromImageID(graphic)->redefined;
340 /* if the base graphic ("emerald", for example) has been redefined,
341 but not the action graphic ("emerald.falling", for example), do not
342 use an existing (in this case considered obsolete) action graphic
343 anymore, but use the automatically determined default graphic */
344 if (base_redefined && !act_dir_redefined)
349 action = ACTION_DEFAULT;
354 element_info[element].direction_crumbled[action][direction] = graphic;
356 element_info[element].crumbled[action] = graphic;
361 element_info[element].direction_graphic[action][direction] = graphic;
363 element_info[element].graphic[action] = graphic;
367 /* initialize normal element/graphic mapping from dynamic configuration */
368 for (i = 0; i < num_property_mappings; i++)
370 int element = property_mapping[i].base_index;
371 int action = property_mapping[i].ext1_index;
372 int direction = property_mapping[i].ext2_index;
373 int special = property_mapping[i].ext3_index;
374 int graphic = property_mapping[i].artwork_index;
375 boolean crumbled = FALSE;
377 if (special == GFX_SPECIAL_ARG_CRUMBLED)
383 if (graphic_info[graphic].bitmap == NULL)
386 if (element >= MAX_NUM_ELEMENTS || special != -1)
390 action = ACTION_DEFAULT;
395 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
396 element_info[element].direction_crumbled[action][dir] = -1;
399 element_info[element].direction_crumbled[action][direction] = graphic;
401 element_info[element].crumbled[action] = graphic;
406 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
407 element_info[element].direction_graphic[action][dir] = -1;
410 element_info[element].direction_graphic[action][direction] = graphic;
412 element_info[element].graphic[action] = graphic;
416 /* now copy all graphics that are defined to be cloned from other graphics */
417 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
419 int graphic = element_info[i].graphic[ACTION_DEFAULT];
420 int crumbled_like, diggable_like;
425 crumbled_like = graphic_info[graphic].crumbled_like;
426 diggable_like = graphic_info[graphic].diggable_like;
428 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
430 for (act = 0; act < NUM_ACTIONS; act++)
431 element_info[i].crumbled[act] =
432 element_info[crumbled_like].crumbled[act];
433 for (act = 0; act < NUM_ACTIONS; act++)
434 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
435 element_info[i].direction_crumbled[act][dir] =
436 element_info[crumbled_like].direction_crumbled[act][dir];
439 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
441 element_info[i].graphic[ACTION_DIGGING] =
442 element_info[diggable_like].graphic[ACTION_DIGGING];
443 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
444 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
445 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
450 /* set hardcoded definitions for some runtime elements without graphic */
451 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
455 /* set hardcoded definitions for some internal elements without graphic */
456 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
458 if (IS_EDITOR_CASCADE_INACTIVE(i))
459 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
460 else if (IS_EDITOR_CASCADE_ACTIVE(i))
461 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
465 /* now set all undefined/invalid graphics to -1 to set to default after it */
466 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
468 for (act = 0; act < NUM_ACTIONS; act++)
472 graphic = element_info[i].graphic[act];
473 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
474 element_info[i].graphic[act] = -1;
476 graphic = element_info[i].crumbled[act];
477 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
478 element_info[i].crumbled[act] = -1;
480 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
482 graphic = element_info[i].direction_graphic[act][dir];
483 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
484 element_info[i].direction_graphic[act][dir] = -1;
486 graphic = element_info[i].direction_crumbled[act][dir];
487 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
488 element_info[i].direction_crumbled[act][dir] = -1;
493 /* adjust graphics with 2nd tile for movement according to direction
494 (do this before correcting '-1' values to minimize calculations) */
495 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
497 for (act = 0; act < NUM_ACTIONS; act++)
499 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
501 int graphic = element_info[i].direction_graphic[act][dir];
502 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
504 if (act == ACTION_FALLING) /* special case */
505 graphic = element_info[i].graphic[act];
508 graphic_info[graphic].double_movement &&
509 graphic_info[graphic].swap_double_tiles != 0)
511 struct GraphicInfo *g = &graphic_info[graphic];
512 int src_x_front = g->src_x;
513 int src_y_front = g->src_y;
514 int src_x_back = g->src_x + g->offset2_x;
515 int src_y_back = g->src_y + g->offset2_y;
516 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
518 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
519 src_y_front < src_y_back);
520 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
521 boolean swap_movement_tiles_autodetected =
522 (!frames_are_ordered_diagonally &&
523 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
524 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
525 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
526 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
529 /* swap frontside and backside graphic tile coordinates, if needed */
530 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
532 /* get current (wrong) backside tile coordinates */
533 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
536 /* set frontside tile coordinates to backside tile coordinates */
537 g->src_x = src_x_back;
538 g->src_y = src_y_back;
540 /* invert tile offset to point to new backside tile coordinates */
544 /* do not swap front and backside tiles again after correction */
545 g->swap_double_tiles = 0;
552 /* now set all '-1' values to element specific default values */
553 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
555 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
556 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
557 int default_direction_graphic[NUM_DIRECTIONS];
558 int default_direction_crumbled[NUM_DIRECTIONS];
560 if (default_graphic == -1)
561 default_graphic = IMG_UNKNOWN;
563 if (default_crumbled == -1)
564 default_crumbled = default_graphic;
566 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
567 if (default_crumbled == -1)
568 default_crumbled = IMG_EMPTY;
571 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
573 default_direction_graphic[dir] =
574 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
575 default_direction_crumbled[dir] =
576 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
578 if (default_direction_graphic[dir] == -1)
579 default_direction_graphic[dir] = default_graphic;
581 if (default_direction_crumbled[dir] == -1)
582 default_direction_crumbled[dir] = default_direction_graphic[dir];
584 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
585 if (default_direction_crumbled[dir] == -1)
586 default_direction_crumbled[dir] = default_crumbled;
590 for (act = 0; act < NUM_ACTIONS; act++)
592 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
593 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
594 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
595 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
596 act == ACTION_TURNING_FROM_RIGHT ||
597 act == ACTION_TURNING_FROM_UP ||
598 act == ACTION_TURNING_FROM_DOWN);
600 /* generic default action graphic (defined by "[default]" directive) */
601 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
602 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
603 int default_remove_graphic = IMG_EMPTY;
605 if (act_remove && default_action_graphic != -1)
606 default_remove_graphic = default_action_graphic;
608 /* look for special default action graphic (classic game specific) */
609 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
610 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
611 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
612 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
613 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
614 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
616 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
617 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
618 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
619 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
620 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
621 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
624 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
625 /* !!! make this better !!! */
626 if (i == EL_EMPTY_SPACE)
628 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
629 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
633 if (default_action_graphic == -1)
634 default_action_graphic = default_graphic;
636 if (default_action_crumbled == -1)
637 default_action_crumbled = default_action_graphic;
639 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
640 if (default_action_crumbled == -1)
641 default_action_crumbled = default_crumbled;
644 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
646 /* use action graphic as the default direction graphic, if undefined */
647 int default_action_direction_graphic = element_info[i].graphic[act];
648 int default_action_direction_crumbled = element_info[i].crumbled[act];
650 /* no graphic for current action -- use default direction graphic */
651 if (default_action_direction_graphic == -1)
652 default_action_direction_graphic =
653 (act_remove ? default_remove_graphic :
655 element_info[i].direction_graphic[ACTION_TURNING][dir] :
656 default_action_graphic != default_graphic ?
657 default_action_graphic :
658 default_direction_graphic[dir]);
660 if (element_info[i].direction_graphic[act][dir] == -1)
661 element_info[i].direction_graphic[act][dir] =
662 default_action_direction_graphic;
665 if (default_action_direction_crumbled == -1)
666 default_action_direction_crumbled =
667 element_info[i].direction_graphic[act][dir];
669 if (default_action_direction_crumbled == -1)
670 default_action_direction_crumbled =
671 (act_remove ? default_remove_graphic :
673 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
674 default_action_crumbled != default_crumbled ?
675 default_action_crumbled :
676 default_direction_crumbled[dir]);
679 if (element_info[i].direction_crumbled[act][dir] == -1)
680 element_info[i].direction_crumbled[act][dir] =
681 default_action_direction_crumbled;
684 /* no graphic for this specific action -- use default action graphic */
685 if (element_info[i].graphic[act] == -1)
686 element_info[i].graphic[act] =
687 (act_remove ? default_remove_graphic :
688 act_turning ? element_info[i].graphic[ACTION_TURNING] :
689 default_action_graphic);
691 if (element_info[i].crumbled[act] == -1)
692 element_info[i].crumbled[act] = element_info[i].graphic[act];
694 if (element_info[i].crumbled[act] == -1)
695 element_info[i].crumbled[act] =
696 (act_remove ? default_remove_graphic :
697 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
698 default_action_crumbled);
703 /* set animation mode to "none" for each graphic with only 1 frame */
704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
706 for (act = 0; act < NUM_ACTIONS; act++)
708 int graphic = element_info[i].graphic[act];
709 int crumbled = element_info[i].crumbled[act];
711 if (graphic_info[graphic].anim_frames == 1)
712 graphic_info[graphic].anim_mode = ANIM_NONE;
713 if (graphic_info[crumbled].anim_frames == 1)
714 graphic_info[crumbled].anim_mode = ANIM_NONE;
716 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
718 graphic = element_info[i].direction_graphic[act][dir];
719 crumbled = element_info[i].direction_crumbled[act][dir];
721 if (graphic_info[graphic].anim_frames == 1)
722 graphic_info[graphic].anim_mode = ANIM_NONE;
723 if (graphic_info[crumbled].anim_frames == 1)
724 graphic_info[crumbled].anim_mode = ANIM_NONE;
733 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
734 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
736 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
737 element_info[i].token_name, i);
743 void InitElementSpecialGraphicInfo()
745 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
746 int num_property_mappings = getImageListPropertyMappingSize();
749 /* always start with reliable default values */
750 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
751 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
752 element_info[i].special_graphic[j] =
753 element_info[i].graphic[ACTION_DEFAULT];
755 /* initialize special element/graphic mapping from static configuration */
756 for (i = 0; element_to_special_graphic[i].element > -1; i++)
758 int element = element_to_special_graphic[i].element;
759 int special = element_to_special_graphic[i].special;
760 int graphic = element_to_special_graphic[i].graphic;
761 int base_graphic = el2baseimg(element);
762 boolean base_redefined =
763 getImageListEntryFromImageID(base_graphic)->redefined;
764 boolean special_redefined =
765 getImageListEntryFromImageID(graphic)->redefined;
767 /* if the base graphic ("emerald", for example) has been redefined,
768 but not the special graphic ("emerald.EDITOR", for example), do not
769 use an existing (in this case considered obsolete) special graphic
770 anymore, but use the automatically created (down-scaled) graphic */
771 if (base_redefined && !special_redefined)
774 element_info[element].special_graphic[special] = graphic;
777 /* initialize special element/graphic mapping from dynamic configuration */
778 for (i = 0; i < num_property_mappings; i++)
780 int element = property_mapping[i].base_index;
781 int special = property_mapping[i].ext3_index;
782 int graphic = property_mapping[i].artwork_index;
784 if (element >= MAX_NUM_ELEMENTS)
787 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
788 element_info[element].special_graphic[special] = graphic;
791 /* now set all undefined/invalid graphics to default */
792 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
793 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
794 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
795 element_info[i].special_graphic[j] =
796 element_info[i].graphic[ACTION_DEFAULT];
799 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
804 if (type != TYPE_TOKEN)
805 return get_parameter_value(value_raw, suffix, type);
807 if (strcmp(value_raw, ARG_UNDEFINED) == 0)
808 return ARG_UNDEFINED_VALUE;
810 /* !!! OPTIMIZE THIS BY USING HASH !!! */
811 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
812 if (strcmp(element_info[i].token_name, value_raw) == 0)
815 /* !!! OPTIMIZE THIS BY USING HASH !!! */
816 for (i = 0; image_config[i].token != NULL; i++)
818 int len_config_value = strlen(image_config[i].value);
820 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
821 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
822 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
825 if (strcmp(image_config[i].token, value_raw) == 0)
834 static int get_scaled_graphic_width(int graphic)
836 int original_width = getOriginalImageWidthFromImageID(graphic);
837 int scale_up_factor = graphic_info[graphic].scale_up_factor;
839 return original_width * scale_up_factor;
842 static int get_scaled_graphic_height(int graphic)
844 int original_height = getOriginalImageHeightFromImageID(graphic);
845 int scale_up_factor = graphic_info[graphic].scale_up_factor;
847 return original_height * scale_up_factor;
850 static void set_graphic_parameters(int graphic)
852 struct FileInfo *image = getImageListEntryFromImageID(graphic);
853 char **parameter_raw = image->parameter;
854 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
855 int parameter[NUM_GFX_ARGS];
856 int anim_frames_per_row = 1, anim_frames_per_col = 1;
857 int anim_frames_per_line = 1;
860 /* if fallback to default artwork is done, also use the default parameters */
861 if (image->fallback_to_default)
862 parameter_raw = image->default_parameter;
864 /* get integer values from string parameters */
865 for (i = 0; i < NUM_GFX_ARGS; i++)
866 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
867 image_config_suffix[i].token,
868 image_config_suffix[i].type);
870 graphic_info[graphic].bitmap = src_bitmap;
872 /* start with reliable default values */
873 graphic_info[graphic].src_image_width = 0;
874 graphic_info[graphic].src_image_height = 0;
875 graphic_info[graphic].src_x = 0;
876 graphic_info[graphic].src_y = 0;
877 graphic_info[graphic].width = TILEX;
878 graphic_info[graphic].height = TILEY;
879 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
880 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
881 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
882 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
883 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
884 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
885 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
886 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
887 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
888 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
889 graphic_info[graphic].anim_delay_fixed = 0;
890 graphic_info[graphic].anim_delay_random = 0;
891 graphic_info[graphic].post_delay_fixed = 0;
892 graphic_info[graphic].post_delay_random = 0;
894 /* optional x and y tile position of animation frame sequence */
895 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
896 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
897 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
898 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
900 /* optional x and y pixel position of animation frame sequence */
901 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
902 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
903 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
904 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
906 /* optional width and height of each animation frame */
907 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
908 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
909 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
910 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
912 /* optional zoom factor for scaling up the image to a larger size */
913 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
914 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
915 if (graphic_info[graphic].scale_up_factor < 1)
916 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
920 /* get final bitmap size (with scaling, but without small images) */
921 int src_image_width = get_scaled_graphic_width(graphic);
922 int src_image_height = get_scaled_graphic_height(graphic);
924 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
925 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
927 graphic_info[graphic].src_image_width = src_image_width;
928 graphic_info[graphic].src_image_height = src_image_height;
931 /* correct x or y offset dependent of vertical or horizontal frame order */
932 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
934 graphic_info[graphic].offset_y =
935 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
936 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
937 anim_frames_per_line = anim_frames_per_col;
939 else /* frames are ordered horizontally */
941 graphic_info[graphic].offset_x =
942 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
943 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
944 anim_frames_per_line = anim_frames_per_row;
947 /* optionally, the x and y offset of frames can be specified directly */
948 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
949 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
950 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
951 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
953 /* optionally, moving animations may have separate start and end graphics */
954 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
956 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
957 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
959 /* correct x or y offset2 dependent of vertical or horizontal frame order */
960 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
961 graphic_info[graphic].offset2_y =
962 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
963 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
964 else /* frames are ordered horizontally */
965 graphic_info[graphic].offset2_x =
966 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
967 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
969 /* optionally, the x and y offset of 2nd graphic can be specified directly */
970 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
971 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
972 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
973 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
975 /* optionally, the second movement tile can be specified as start tile */
976 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
977 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
979 /* automatically determine correct number of frames, if not defined */
980 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
981 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
982 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
983 graphic_info[graphic].anim_frames = anim_frames_per_row;
984 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
985 graphic_info[graphic].anim_frames = anim_frames_per_col;
987 graphic_info[graphic].anim_frames = 1;
989 graphic_info[graphic].anim_frames_per_line =
990 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
991 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
993 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
994 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
995 graphic_info[graphic].anim_delay = 1;
997 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
999 if (graphic_info[graphic].anim_frames == 1)
1000 graphic_info[graphic].anim_mode = ANIM_NONE;
1003 /* automatically determine correct start frame, if not defined */
1004 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1005 graphic_info[graphic].anim_start_frame = 0;
1006 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1007 graphic_info[graphic].anim_start_frame =
1008 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1010 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1012 /* animation synchronized with global frame counter, not move position */
1013 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1015 /* optional element for cloning crumble graphics */
1016 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1017 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1019 /* optional element for cloning digging graphics */
1020 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1021 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1023 /* optional border size for "crumbling" diggable graphics */
1024 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1025 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1027 /* this is only used for player "boring" and "sleeping" actions */
1028 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].anim_delay_fixed =
1030 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1031 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1032 graphic_info[graphic].anim_delay_random =
1033 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1034 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1035 graphic_info[graphic].post_delay_fixed =
1036 parameter[GFX_ARG_POST_DELAY_FIXED];
1037 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1038 graphic_info[graphic].post_delay_random =
1039 parameter[GFX_ARG_POST_DELAY_RANDOM];
1041 /* this is only used for toon animations */
1042 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1043 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1045 /* this is only used for drawing font characters */
1046 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1047 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1049 /* this is only used for drawing envelope graphics */
1050 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1052 /* optional graphic for cloning all graphics settings */
1053 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1057 static void set_cloned_graphic_parameters(int graphic)
1059 int fallback_graphic = IMG_CHAR_EXCLAM;
1060 int max_num_images = getImageListSize();
1061 int clone_graphic = graphic_info[graphic].clone_from;
1062 int num_references_followed = 1;
1064 while (graphic_info[clone_graphic].clone_from != -1 &&
1065 num_references_followed < max_num_images)
1067 clone_graphic = graphic_info[clone_graphic].clone_from;
1069 num_references_followed++;
1072 if (num_references_followed >= max_num_images)
1074 Error(ERR_RETURN_LINE, "-");
1075 Error(ERR_RETURN, "warning: error found in config file:");
1076 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1077 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1078 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1079 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1081 if (graphic == fallback_graphic)
1082 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1084 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1085 Error(ERR_RETURN_LINE, "-");
1087 graphic_info[graphic] = graphic_info[fallback_graphic];
1091 graphic_info[graphic] = graphic_info[clone_graphic];
1092 graphic_info[graphic].clone_from = clone_graphic;
1096 static void InitGraphicInfo()
1098 int fallback_graphic = IMG_CHAR_EXCLAM;
1099 int num_images = getImageListSize();
1102 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1103 static boolean clipmasks_initialized = FALSE;
1105 XGCValues clip_gc_values;
1106 unsigned long clip_gc_valuemask;
1107 GC copy_clipmask_gc = None;
1110 checked_free(graphic_info);
1112 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1114 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1115 if (clipmasks_initialized)
1117 for (i = 0; i < num_images; i++)
1119 if (graphic_info[i].clip_mask)
1120 XFreePixmap(display, graphic_info[i].clip_mask);
1121 if (graphic_info[i].clip_gc)
1122 XFreeGC(display, graphic_info[i].clip_gc);
1124 graphic_info[i].clip_mask = None;
1125 graphic_info[i].clip_gc = None;
1130 /* first set all graphic paramaters ... */
1131 for (i = 0; i < num_images; i++)
1132 set_graphic_parameters(i);
1134 /* ... then copy these parameters for cloned graphics */
1135 for (i = 0; i < num_images; i++)
1136 if (graphic_info[i].clone_from != -1)
1137 set_cloned_graphic_parameters(i);
1139 for (i = 0; i < num_images; i++)
1143 int first_frame, last_frame;
1144 int src_bitmap_width, src_bitmap_height;
1146 /* now check if no animation frames are outside of the loaded image */
1148 if (graphic_info[i].bitmap == NULL)
1149 continue; /* skip check for optional images that are undefined */
1151 /* get final bitmap size (with scaling, but without small images) */
1152 src_bitmap_width = graphic_info[i].src_image_width;
1153 src_bitmap_height = graphic_info[i].src_image_height;
1155 /* check if first animation frame is inside specified bitmap */
1158 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1160 if (src_x < 0 || src_y < 0 ||
1161 src_x + TILEX > src_bitmap_width ||
1162 src_y + TILEY > src_bitmap_height)
1164 Error(ERR_RETURN_LINE, "-");
1165 Error(ERR_RETURN, "warning: error found in config file:");
1166 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1167 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1168 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1170 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1171 src_x, src_y, src_bitmap_width, src_bitmap_height);
1172 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1174 if (i == fallback_graphic)
1175 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1177 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1178 Error(ERR_RETURN_LINE, "-");
1180 graphic_info[i] = graphic_info[fallback_graphic];
1183 /* check if last animation frame is inside specified bitmap */
1185 last_frame = graphic_info[i].anim_frames - 1;
1186 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1188 if (src_x < 0 || src_y < 0 ||
1189 src_x + TILEX > src_bitmap_width ||
1190 src_y + TILEY > src_bitmap_height)
1192 Error(ERR_RETURN_LINE, "-");
1193 Error(ERR_RETURN, "warning: error found in config file:");
1194 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1195 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1196 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1198 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1199 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1200 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1202 if (i == fallback_graphic)
1203 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1205 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1206 Error(ERR_RETURN_LINE, "-");
1208 graphic_info[i] = graphic_info[fallback_graphic];
1211 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1212 /* currently we only need a tile clip mask from the first frame */
1213 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1215 if (copy_clipmask_gc == None)
1217 clip_gc_values.graphics_exposures = False;
1218 clip_gc_valuemask = GCGraphicsExposures;
1219 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1220 clip_gc_valuemask, &clip_gc_values);
1223 graphic_info[i].clip_mask =
1224 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1226 src_pixmap = src_bitmap->clip_mask;
1227 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1228 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1230 clip_gc_values.graphics_exposures = False;
1231 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1232 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1234 graphic_info[i].clip_gc =
1235 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1239 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1240 if (copy_clipmask_gc)
1241 XFreeGC(display, copy_clipmask_gc);
1243 clipmasks_initialized = TRUE;
1247 static void InitElementSoundInfo()
1249 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1250 int num_property_mappings = getSoundListPropertyMappingSize();
1253 /* set values to -1 to identify later as "uninitialized" values */
1254 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1255 for (act = 0; act < NUM_ACTIONS; act++)
1256 element_info[i].sound[act] = -1;
1258 /* initialize element/sound mapping from static configuration */
1259 for (i = 0; element_to_sound[i].element > -1; i++)
1261 int element = element_to_sound[i].element;
1262 int action = element_to_sound[i].action;
1263 int sound = element_to_sound[i].sound;
1264 boolean is_class = element_to_sound[i].is_class;
1267 action = ACTION_DEFAULT;
1270 element_info[element].sound[action] = sound;
1272 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1273 if (strcmp(element_info[j].class_name,
1274 element_info[element].class_name) == 0)
1275 element_info[j].sound[action] = sound;
1278 /* initialize element class/sound mapping from dynamic configuration */
1279 for (i = 0; i < num_property_mappings; i++)
1281 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1282 int action = property_mapping[i].ext1_index;
1283 int sound = property_mapping[i].artwork_index;
1285 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1289 action = ACTION_DEFAULT;
1291 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1292 if (strcmp(element_info[j].class_name,
1293 element_info[element_class].class_name) == 0)
1294 element_info[j].sound[action] = sound;
1297 /* initialize element/sound mapping from dynamic configuration */
1298 for (i = 0; i < num_property_mappings; i++)
1300 int element = property_mapping[i].base_index;
1301 int action = property_mapping[i].ext1_index;
1302 int sound = property_mapping[i].artwork_index;
1304 if (element >= MAX_NUM_ELEMENTS)
1308 action = ACTION_DEFAULT;
1310 element_info[element].sound[action] = sound;
1313 /* now set all '-1' values to element specific default values */
1314 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1316 for (act = 0; act < NUM_ACTIONS; act++)
1318 /* generic default action sound (defined by "[default]" directive) */
1319 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1321 /* look for special default action sound (classic game specific) */
1322 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1323 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1324 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1325 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1326 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1327 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1329 /* !!! there's no such thing as a "default action sound" !!! */
1331 /* look for element specific default sound (independent from action) */
1332 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1333 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1337 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1338 /* !!! make this better !!! */
1339 if (i == EL_EMPTY_SPACE)
1340 default_action_sound = element_info[EL_DEFAULT].sound[act];
1343 /* no sound for this specific action -- use default action sound */
1344 if (element_info[i].sound[act] == -1)
1345 element_info[i].sound[act] = default_action_sound;
1349 /* copy sound settings to some elements that are only stored in level file
1350 in native R'n'D levels, but are used by game engine in native EM levels */
1351 for (i = 0; copy_properties[i][0] != -1; i++)
1352 for (j = 1; j <= 4; j++)
1353 for (act = 0; act < NUM_ACTIONS; act++)
1354 element_info[copy_properties[i][j]].sound[act] =
1355 element_info[copy_properties[i][0]].sound[act];
1358 static void InitGameModeSoundInfo()
1362 /* set values to -1 to identify later as "uninitialized" values */
1363 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1366 /* initialize gamemode/sound mapping from static configuration */
1367 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1369 int gamemode = gamemode_to_sound[i].gamemode;
1370 int sound = gamemode_to_sound[i].sound;
1373 gamemode = GAME_MODE_DEFAULT;
1375 menu.sound[gamemode] = sound;
1378 /* now set all '-1' values to levelset specific default values */
1379 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1380 if (menu.sound[i] == -1)
1381 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1384 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1385 if (menu.sound[i] != -1)
1386 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1390 static void set_sound_parameters(int sound, char **parameter_raw)
1392 int parameter[NUM_SND_ARGS];
1395 /* get integer values from string parameters */
1396 for (i = 0; i < NUM_SND_ARGS; i++)
1398 get_parameter_value(parameter_raw[i],
1399 sound_config_suffix[i].token,
1400 sound_config_suffix[i].type);
1402 /* explicit loop mode setting in configuration overrides default value */
1403 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1404 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1406 /* sound volume to change the original volume when loading the sound file */
1407 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1409 /* sound priority to give certain sounds a higher or lower priority */
1410 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1413 static void InitSoundInfo()
1415 int *sound_effect_properties;
1416 int num_sounds = getSoundListSize();
1419 checked_free(sound_info);
1421 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1422 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1424 /* initialize sound effect for all elements to "no sound" */
1425 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1426 for (j = 0; j < NUM_ACTIONS; j++)
1427 element_info[i].sound[j] = SND_UNDEFINED;
1429 for (i = 0; i < num_sounds; i++)
1431 struct FileInfo *sound = getSoundListEntry(i);
1432 int len_effect_text = strlen(sound->token);
1434 sound_effect_properties[i] = ACTION_OTHER;
1435 sound_info[i].loop = FALSE; /* default: play sound only once */
1438 printf("::: sound %d: '%s'\n", i, sound->token);
1441 /* determine all loop sounds and identify certain sound classes */
1443 for (j = 0; element_action_info[j].suffix; j++)
1445 int len_action_text = strlen(element_action_info[j].suffix);
1447 if (len_action_text < len_effect_text &&
1448 strcmp(&sound->token[len_effect_text - len_action_text],
1449 element_action_info[j].suffix) == 0)
1451 sound_effect_properties[i] = element_action_info[j].value;
1452 sound_info[i].loop = element_action_info[j].is_loop_sound;
1458 /* associate elements and some selected sound actions */
1460 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1462 if (element_info[j].class_name)
1464 int len_class_text = strlen(element_info[j].class_name);
1466 if (len_class_text + 1 < len_effect_text &&
1467 strncmp(sound->token,
1468 element_info[j].class_name, len_class_text) == 0 &&
1469 sound->token[len_class_text] == '.')
1471 int sound_action_value = sound_effect_properties[i];
1473 element_info[j].sound[sound_action_value] = i;
1478 set_sound_parameters(i, sound->parameter);
1481 free(sound_effect_properties);
1484 static void InitGameModeMusicInfo()
1486 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1487 int num_property_mappings = getMusicListPropertyMappingSize();
1488 int default_levelset_music = -1;
1491 /* set values to -1 to identify later as "uninitialized" values */
1492 for (i = 0; i < MAX_LEVELS; i++)
1493 levelset.music[i] = -1;
1494 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1497 /* initialize gamemode/music mapping from static configuration */
1498 for (i = 0; gamemode_to_music[i].music > -1; i++)
1500 int gamemode = gamemode_to_music[i].gamemode;
1501 int music = gamemode_to_music[i].music;
1504 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1508 gamemode = GAME_MODE_DEFAULT;
1510 menu.music[gamemode] = music;
1513 /* initialize gamemode/music mapping from dynamic configuration */
1514 for (i = 0; i < num_property_mappings; i++)
1516 int prefix = property_mapping[i].base_index;
1517 int gamemode = property_mapping[i].ext1_index;
1518 int level = property_mapping[i].ext2_index;
1519 int music = property_mapping[i].artwork_index;
1522 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1523 prefix, gamemode, level, music);
1526 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1530 gamemode = GAME_MODE_DEFAULT;
1532 /* level specific music only allowed for in-game music */
1533 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1534 gamemode = GAME_MODE_PLAYING;
1539 default_levelset_music = music;
1542 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1543 levelset.music[level] = music;
1544 if (gamemode != GAME_MODE_PLAYING)
1545 menu.music[gamemode] = music;
1548 /* now set all '-1' values to menu specific default values */
1549 /* (undefined values of "levelset.music[]" might stay at "-1" to
1550 allow dynamic selection of music files from music directory!) */
1551 for (i = 0; i < MAX_LEVELS; i++)
1552 if (levelset.music[i] == -1)
1553 levelset.music[i] = default_levelset_music;
1554 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1555 if (menu.music[i] == -1)
1556 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1559 for (i = 0; i < MAX_LEVELS; i++)
1560 if (levelset.music[i] != -1)
1561 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1562 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1563 if (menu.music[i] != -1)
1564 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1568 static void set_music_parameters(int music, char **parameter_raw)
1570 int parameter[NUM_MUS_ARGS];
1573 /* get integer values from string parameters */
1574 for (i = 0; i < NUM_MUS_ARGS; i++)
1576 get_parameter_value(parameter_raw[i],
1577 music_config_suffix[i].token,
1578 music_config_suffix[i].type);
1580 /* explicit loop mode setting in configuration overrides default value */
1581 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1582 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1585 static void InitMusicInfo()
1587 int num_music = getMusicListSize();
1590 checked_free(music_info);
1592 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1594 for (i = 0; i < num_music; i++)
1596 struct FileInfo *music = getMusicListEntry(i);
1597 int len_music_text = strlen(music->token);
1599 music_info[i].loop = TRUE; /* default: play music in loop mode */
1601 /* determine all loop music */
1603 for (j = 0; music_prefix_info[j].prefix; j++)
1605 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1607 if (len_prefix_text < len_music_text &&
1608 strncmp(music->token,
1609 music_prefix_info[j].prefix, len_prefix_text) == 0)
1611 music_info[i].loop = music_prefix_info[j].is_loop_music;
1617 set_music_parameters(i, music->parameter);
1621 static void ReinitializeGraphics()
1623 InitGraphicInfo(); /* graphic properties mapping */
1624 InitElementGraphicInfo(); /* element game graphic mapping */
1625 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1627 InitElementSmallImages(); /* scale images to all needed sizes */
1628 InitFontGraphicInfo(); /* initialize text drawing functions */
1630 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1632 SetMainBackgroundImage(IMG_BACKGROUND);
1633 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1639 static void ReinitializeSounds()
1641 InitSoundInfo(); /* sound properties mapping */
1642 InitElementSoundInfo(); /* element game sound mapping */
1643 InitGameModeSoundInfo(); /* game mode sound mapping */
1645 InitPlayLevelSound(); /* internal game sound settings */
1648 static void ReinitializeMusic()
1650 InitMusicInfo(); /* music properties mapping */
1651 InitGameModeMusicInfo(); /* game mode music mapping */
1654 static int get_special_property_bit(int element, int property_bit_nr)
1656 struct PropertyBitInfo
1662 static struct PropertyBitInfo pb_can_move_into_acid[] =
1664 /* the player may be able fall into acid when gravity is activated */
1669 { EL_SP_MURPHY, 0 },
1670 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1672 /* all element that can move may be able to also move into acid */
1675 { EL_BUG_RIGHT, 1 },
1678 { EL_SPACESHIP, 2 },
1679 { EL_SPACESHIP_LEFT, 2 },
1680 { EL_SPACESHIP_RIGHT, 2 },
1681 { EL_SPACESHIP_UP, 2 },
1682 { EL_SPACESHIP_DOWN, 2 },
1683 { EL_BD_BUTTERFLY, 3 },
1684 { EL_BD_BUTTERFLY_LEFT, 3 },
1685 { EL_BD_BUTTERFLY_RIGHT, 3 },
1686 { EL_BD_BUTTERFLY_UP, 3 },
1687 { EL_BD_BUTTERFLY_DOWN, 3 },
1688 { EL_BD_FIREFLY, 4 },
1689 { EL_BD_FIREFLY_LEFT, 4 },
1690 { EL_BD_FIREFLY_RIGHT, 4 },
1691 { EL_BD_FIREFLY_UP, 4 },
1692 { EL_BD_FIREFLY_DOWN, 4 },
1694 { EL_DARK_YAMYAM, 6 },
1697 { EL_PACMAN_LEFT, 8 },
1698 { EL_PACMAN_RIGHT, 8 },
1699 { EL_PACMAN_UP, 8 },
1700 { EL_PACMAN_DOWN, 8 },
1702 { EL_MOLE_LEFT, 9 },
1703 { EL_MOLE_RIGHT, 9 },
1705 { EL_MOLE_DOWN, 9 },
1709 { EL_SATELLITE, 13 },
1710 { EL_SP_SNIKSNAK, 14 },
1711 { EL_SP_ELECTRON, 15 },
1718 static struct PropertyBitInfo pb_dont_collide_with[] =
1720 { EL_SP_SNIKSNAK, 0 },
1721 { EL_SP_ELECTRON, 1 },
1729 struct PropertyBitInfo *pb_info;
1732 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1733 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1738 struct PropertyBitInfo *pb_info = NULL;
1741 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1742 if (pb_definition[i].bit_nr == property_bit_nr)
1743 pb_info = pb_definition[i].pb_info;
1745 if (pb_info == NULL)
1748 for (i = 0; pb_info[i].element != -1; i++)
1749 if (pb_info[i].element == element)
1750 return pb_info[i].bit_nr;
1755 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1756 boolean property_value)
1758 int bit_nr = get_special_property_bit(element, property_bit_nr);
1763 *bitfield |= (1 << bit_nr);
1765 *bitfield &= ~(1 << bit_nr);
1769 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1771 int bit_nr = get_special_property_bit(element, property_bit_nr);
1774 return ((*bitfield & (1 << bit_nr)) != 0);
1779 void InitElementPropertiesStatic()
1781 static int ep_diggable[] =
1786 EL_SP_BUGGY_BASE_ACTIVATING,
1789 EL_INVISIBLE_SAND_ACTIVE,
1792 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1793 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1797 EL_SP_BUGGY_BASE_ACTIVE,
1803 static int ep_collectible_only[] =
1824 EL_DYNABOMB_INCREASE_NUMBER,
1825 EL_DYNABOMB_INCREASE_SIZE,
1826 EL_DYNABOMB_INCREASE_POWER,
1845 static int ep_dont_run_into[] =
1847 /* same elements as in 'ep_dont_touch' */
1853 /* same elements as in 'ep_dont_collide_with' */
1865 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1869 EL_SP_BUGGY_BASE_ACTIVE,
1875 static int ep_dont_collide_with[] =
1877 /* same elements as in 'ep_dont_touch' */
1893 static int ep_dont_touch[] =
1902 static int ep_indestructible[] =
1906 EL_ACID_POOL_TOPLEFT,
1907 EL_ACID_POOL_TOPRIGHT,
1908 EL_ACID_POOL_BOTTOMLEFT,
1909 EL_ACID_POOL_BOTTOM,
1910 EL_ACID_POOL_BOTTOMRIGHT,
1911 EL_SP_HARDWARE_GRAY,
1912 EL_SP_HARDWARE_GREEN,
1913 EL_SP_HARDWARE_BLUE,
1915 EL_SP_HARDWARE_YELLOW,
1916 EL_SP_HARDWARE_BASE_1,
1917 EL_SP_HARDWARE_BASE_2,
1918 EL_SP_HARDWARE_BASE_3,
1919 EL_SP_HARDWARE_BASE_4,
1920 EL_SP_HARDWARE_BASE_5,
1921 EL_SP_HARDWARE_BASE_6,
1922 EL_INVISIBLE_STEELWALL,
1923 EL_INVISIBLE_STEELWALL_ACTIVE,
1924 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1925 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1926 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1927 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1928 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1929 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1930 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1931 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1932 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1933 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1934 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1935 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1937 EL_LIGHT_SWITCH_ACTIVE,
1938 EL_SIGN_EXCLAMATION,
1939 EL_SIGN_RADIOACTIVITY,
1950 EL_STEELWALL_SLIPPERY,
1964 EL_GATE_1_GRAY_ACTIVE,
1965 EL_GATE_2_GRAY_ACTIVE,
1966 EL_GATE_3_GRAY_ACTIVE,
1967 EL_GATE_4_GRAY_ACTIVE,
1976 EL_EM_GATE_1_GRAY_ACTIVE,
1977 EL_EM_GATE_2_GRAY_ACTIVE,
1978 EL_EM_GATE_3_GRAY_ACTIVE,
1979 EL_EM_GATE_4_GRAY_ACTIVE,
1988 EL_EMC_GATE_5_GRAY_ACTIVE,
1989 EL_EMC_GATE_6_GRAY_ACTIVE,
1990 EL_EMC_GATE_7_GRAY_ACTIVE,
1991 EL_EMC_GATE_8_GRAY_ACTIVE,
1993 EL_SWITCHGATE_OPENING,
1994 EL_SWITCHGATE_CLOSED,
1995 EL_SWITCHGATE_CLOSING,
1997 EL_SWITCHGATE_SWITCH_UP,
1998 EL_SWITCHGATE_SWITCH_DOWN,
2001 EL_TIMEGATE_OPENING,
2003 EL_TIMEGATE_CLOSING,
2006 EL_TIMEGATE_SWITCH_ACTIVE,
2011 EL_TUBE_VERTICAL_LEFT,
2012 EL_TUBE_VERTICAL_RIGHT,
2013 EL_TUBE_HORIZONTAL_UP,
2014 EL_TUBE_HORIZONTAL_DOWN,
2022 static int ep_slippery[] =
2036 EL_ROBOT_WHEEL_ACTIVE,
2042 EL_ACID_POOL_TOPLEFT,
2043 EL_ACID_POOL_TOPRIGHT,
2053 EL_STEELWALL_SLIPPERY,
2056 EL_EMC_WALL_SLIPPERY_1,
2057 EL_EMC_WALL_SLIPPERY_2,
2058 EL_EMC_WALL_SLIPPERY_3,
2059 EL_EMC_WALL_SLIPPERY_4,
2063 static int ep_can_change[] =
2068 static int ep_can_move[] =
2070 /* same elements as in 'pb_can_move_into_acid' */
2092 static int ep_can_fall[] =
2107 EL_BD_MAGIC_WALL_FULL,
2120 static int ep_can_smash_player[] =
2145 static int ep_can_smash_enemies[] =
2153 static int ep_can_smash_everything[] =
2161 static int ep_explodes_by_fire[] =
2163 /* same elements as in 'ep_explodes_impact' */
2168 /* same elements as in 'ep_explodes_smashed' */
2177 EL_DYNABOMB_PLAYER_1_ACTIVE,
2178 EL_DYNABOMB_PLAYER_2_ACTIVE,
2179 EL_DYNABOMB_PLAYER_3_ACTIVE,
2180 EL_DYNABOMB_PLAYER_4_ACTIVE,
2181 EL_DYNABOMB_INCREASE_NUMBER,
2182 EL_DYNABOMB_INCREASE_SIZE,
2183 EL_DYNABOMB_INCREASE_POWER,
2184 EL_SP_DISK_RED_ACTIVE,
2197 static int ep_explodes_smashed[] =
2199 /* same elements as in 'ep_explodes_impact' */
2212 static int ep_explodes_impact[] =
2220 static int ep_walkable_over[] =
2224 EL_SOKOBAN_FIELD_EMPTY,
2236 EL_GATE_1_GRAY_ACTIVE,
2237 EL_GATE_2_GRAY_ACTIVE,
2238 EL_GATE_3_GRAY_ACTIVE,
2239 EL_GATE_4_GRAY_ACTIVE,
2246 static int ep_walkable_inside[] =
2251 EL_TUBE_VERTICAL_LEFT,
2252 EL_TUBE_VERTICAL_RIGHT,
2253 EL_TUBE_HORIZONTAL_UP,
2254 EL_TUBE_HORIZONTAL_DOWN,
2262 static int ep_walkable_under[] =
2267 static int ep_passable_over[] =
2277 EL_EM_GATE_1_GRAY_ACTIVE,
2278 EL_EM_GATE_2_GRAY_ACTIVE,
2279 EL_EM_GATE_3_GRAY_ACTIVE,
2280 EL_EM_GATE_4_GRAY_ACTIVE,
2289 EL_EMC_GATE_5_GRAY_ACTIVE,
2290 EL_EMC_GATE_6_GRAY_ACTIVE,
2291 EL_EMC_GATE_7_GRAY_ACTIVE,
2292 EL_EMC_GATE_8_GRAY_ACTIVE,
2298 static int ep_passable_inside[] =
2304 EL_SP_PORT_HORIZONTAL,
2305 EL_SP_PORT_VERTICAL,
2307 EL_SP_GRAVITY_PORT_LEFT,
2308 EL_SP_GRAVITY_PORT_RIGHT,
2309 EL_SP_GRAVITY_PORT_UP,
2310 EL_SP_GRAVITY_PORT_DOWN,
2311 EL_SP_GRAVITY_ON_PORT_LEFT,
2312 EL_SP_GRAVITY_ON_PORT_RIGHT,
2313 EL_SP_GRAVITY_ON_PORT_UP,
2314 EL_SP_GRAVITY_ON_PORT_DOWN,
2315 EL_SP_GRAVITY_OFF_PORT_LEFT,
2316 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2317 EL_SP_GRAVITY_OFF_PORT_UP,
2318 EL_SP_GRAVITY_OFF_PORT_DOWN,
2322 static int ep_passable_under[] =
2327 static int ep_droppable[] =
2332 static int ep_explodes_1x1_old[] =
2337 static int ep_pushable[] =
2349 EL_SOKOBAN_FIELD_FULL,
2357 static int ep_explodes_cross_old[] =
2362 static int ep_protected[] =
2364 /* same elements as in 'ep_walkable_inside' */
2368 EL_TUBE_VERTICAL_LEFT,
2369 EL_TUBE_VERTICAL_RIGHT,
2370 EL_TUBE_HORIZONTAL_UP,
2371 EL_TUBE_HORIZONTAL_DOWN,
2377 /* same elements as in 'ep_passable_over' */
2386 EL_EM_GATE_1_GRAY_ACTIVE,
2387 EL_EM_GATE_2_GRAY_ACTIVE,
2388 EL_EM_GATE_3_GRAY_ACTIVE,
2389 EL_EM_GATE_4_GRAY_ACTIVE,
2398 EL_EMC_GATE_5_GRAY_ACTIVE,
2399 EL_EMC_GATE_6_GRAY_ACTIVE,
2400 EL_EMC_GATE_7_GRAY_ACTIVE,
2401 EL_EMC_GATE_8_GRAY_ACTIVE,
2405 /* same elements as in 'ep_passable_inside' */
2410 EL_SP_PORT_HORIZONTAL,
2411 EL_SP_PORT_VERTICAL,
2413 EL_SP_GRAVITY_PORT_LEFT,
2414 EL_SP_GRAVITY_PORT_RIGHT,
2415 EL_SP_GRAVITY_PORT_UP,
2416 EL_SP_GRAVITY_PORT_DOWN,
2417 EL_SP_GRAVITY_ON_PORT_LEFT,
2418 EL_SP_GRAVITY_ON_PORT_RIGHT,
2419 EL_SP_GRAVITY_ON_PORT_UP,
2420 EL_SP_GRAVITY_ON_PORT_DOWN,
2421 EL_SP_GRAVITY_OFF_PORT_LEFT,
2422 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2423 EL_SP_GRAVITY_OFF_PORT_UP,
2424 EL_SP_GRAVITY_OFF_PORT_DOWN,
2428 static int ep_throwable[] =
2433 static int ep_can_explode[] =
2435 /* same elements as in 'ep_explodes_impact' */
2440 /* same elements as in 'ep_explodes_smashed' */
2446 /* elements that can explode by explosion or by dragonfire */
2449 EL_DYNABOMB_PLAYER_1_ACTIVE,
2450 EL_DYNABOMB_PLAYER_2_ACTIVE,
2451 EL_DYNABOMB_PLAYER_3_ACTIVE,
2452 EL_DYNABOMB_PLAYER_4_ACTIVE,
2453 EL_DYNABOMB_INCREASE_NUMBER,
2454 EL_DYNABOMB_INCREASE_SIZE,
2455 EL_DYNABOMB_INCREASE_POWER,
2456 EL_SP_DISK_RED_ACTIVE,
2464 /* elements that can explode only by explosion */
2469 static int ep_gravity_reachable[] =
2475 EL_INVISIBLE_SAND_ACTIVE,
2480 EL_SP_PORT_HORIZONTAL,
2481 EL_SP_PORT_VERTICAL,
2483 EL_SP_GRAVITY_PORT_LEFT,
2484 EL_SP_GRAVITY_PORT_RIGHT,
2485 EL_SP_GRAVITY_PORT_UP,
2486 EL_SP_GRAVITY_PORT_DOWN,
2487 EL_SP_GRAVITY_ON_PORT_LEFT,
2488 EL_SP_GRAVITY_ON_PORT_RIGHT,
2489 EL_SP_GRAVITY_ON_PORT_UP,
2490 EL_SP_GRAVITY_ON_PORT_DOWN,
2491 EL_SP_GRAVITY_OFF_PORT_LEFT,
2492 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2493 EL_SP_GRAVITY_OFF_PORT_UP,
2494 EL_SP_GRAVITY_OFF_PORT_DOWN,
2499 static int ep_player[] =
2506 EL_SOKOBAN_FIELD_PLAYER,
2511 static int ep_can_pass_magic_wall[] =
2524 static int ep_switchable[] =
2528 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2529 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2530 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2531 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2532 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2533 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2534 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2535 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2536 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2537 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2538 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2539 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2540 EL_SWITCHGATE_SWITCH_UP,
2541 EL_SWITCHGATE_SWITCH_DOWN,
2543 EL_LIGHT_SWITCH_ACTIVE,
2545 EL_BALLOON_SWITCH_LEFT,
2546 EL_BALLOON_SWITCH_RIGHT,
2547 EL_BALLOON_SWITCH_UP,
2548 EL_BALLOON_SWITCH_DOWN,
2549 EL_BALLOON_SWITCH_ANY,
2550 EL_BALLOON_SWITCH_NONE,
2553 EL_EMC_MAGIC_BALL_SWITCH,
2557 static int ep_bd_element[] =
2590 static int ep_sp_element[] =
2592 /* should always be valid */
2595 /* standard classic Supaplex elements */
2602 EL_SP_HARDWARE_GRAY,
2610 EL_SP_GRAVITY_PORT_RIGHT,
2611 EL_SP_GRAVITY_PORT_DOWN,
2612 EL_SP_GRAVITY_PORT_LEFT,
2613 EL_SP_GRAVITY_PORT_UP,
2618 EL_SP_PORT_VERTICAL,
2619 EL_SP_PORT_HORIZONTAL,
2625 EL_SP_HARDWARE_BASE_1,
2626 EL_SP_HARDWARE_GREEN,
2627 EL_SP_HARDWARE_BLUE,
2629 EL_SP_HARDWARE_YELLOW,
2630 EL_SP_HARDWARE_BASE_2,
2631 EL_SP_HARDWARE_BASE_3,
2632 EL_SP_HARDWARE_BASE_4,
2633 EL_SP_HARDWARE_BASE_5,
2634 EL_SP_HARDWARE_BASE_6,
2638 /* additional elements that appeared in newer Supaplex levels */
2641 /* additional gravity port elements (not switching, but setting gravity) */
2642 EL_SP_GRAVITY_ON_PORT_LEFT,
2643 EL_SP_GRAVITY_ON_PORT_RIGHT,
2644 EL_SP_GRAVITY_ON_PORT_UP,
2645 EL_SP_GRAVITY_ON_PORT_DOWN,
2646 EL_SP_GRAVITY_OFF_PORT_LEFT,
2647 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2648 EL_SP_GRAVITY_OFF_PORT_UP,
2649 EL_SP_GRAVITY_OFF_PORT_DOWN,
2651 /* more than one Murphy in a level results in an inactive clone */
2654 /* runtime Supaplex elements */
2655 EL_SP_DISK_RED_ACTIVE,
2656 EL_SP_TERMINAL_ACTIVE,
2657 EL_SP_BUGGY_BASE_ACTIVATING,
2658 EL_SP_BUGGY_BASE_ACTIVE,
2664 static int ep_sb_element[] =
2669 EL_SOKOBAN_FIELD_EMPTY,
2670 EL_SOKOBAN_FIELD_FULL,
2671 EL_SOKOBAN_FIELD_PLAYER,
2676 EL_INVISIBLE_STEELWALL,
2680 static int ep_gem[] =
2691 static int ep_food_dark_yamyam[] =
2718 static int ep_food_penguin[] =
2731 static int ep_food_pig[] =
2742 static int ep_historic_wall[] =
2753 EL_GATE_1_GRAY_ACTIVE,
2754 EL_GATE_2_GRAY_ACTIVE,
2755 EL_GATE_3_GRAY_ACTIVE,
2756 EL_GATE_4_GRAY_ACTIVE,
2765 EL_EM_GATE_1_GRAY_ACTIVE,
2766 EL_EM_GATE_2_GRAY_ACTIVE,
2767 EL_EM_GATE_3_GRAY_ACTIVE,
2768 EL_EM_GATE_4_GRAY_ACTIVE,
2775 EL_EXPANDABLE_WALL_HORIZONTAL,
2776 EL_EXPANDABLE_WALL_VERTICAL,
2777 EL_EXPANDABLE_WALL_ANY,
2778 EL_EXPANDABLE_WALL_GROWING,
2785 EL_SP_HARDWARE_GRAY,
2786 EL_SP_HARDWARE_GREEN,
2787 EL_SP_HARDWARE_BLUE,
2789 EL_SP_HARDWARE_YELLOW,
2790 EL_SP_HARDWARE_BASE_1,
2791 EL_SP_HARDWARE_BASE_2,
2792 EL_SP_HARDWARE_BASE_3,
2793 EL_SP_HARDWARE_BASE_4,
2794 EL_SP_HARDWARE_BASE_5,
2795 EL_SP_HARDWARE_BASE_6,
2797 EL_SP_TERMINAL_ACTIVE,
2800 EL_INVISIBLE_STEELWALL,
2801 EL_INVISIBLE_STEELWALL_ACTIVE,
2803 EL_INVISIBLE_WALL_ACTIVE,
2804 EL_STEELWALL_SLIPPERY,
2820 static int ep_historic_solid[] =
2824 EL_EXPANDABLE_WALL_HORIZONTAL,
2825 EL_EXPANDABLE_WALL_VERTICAL,
2826 EL_EXPANDABLE_WALL_ANY,
2839 EL_QUICKSAND_FILLING,
2840 EL_QUICKSAND_EMPTYING,
2842 EL_MAGIC_WALL_ACTIVE,
2843 EL_MAGIC_WALL_EMPTYING,
2844 EL_MAGIC_WALL_FILLING,
2848 EL_BD_MAGIC_WALL_ACTIVE,
2849 EL_BD_MAGIC_WALL_EMPTYING,
2850 EL_BD_MAGIC_WALL_FULL,
2851 EL_BD_MAGIC_WALL_FILLING,
2852 EL_BD_MAGIC_WALL_DEAD,
2861 EL_SP_TERMINAL_ACTIVE,
2865 EL_INVISIBLE_WALL_ACTIVE,
2866 EL_SWITCHGATE_SWITCH_UP,
2867 EL_SWITCHGATE_SWITCH_DOWN,
2869 EL_TIMEGATE_SWITCH_ACTIVE,
2881 /* the following elements are a direct copy of "indestructible" elements,
2882 except "EL_ACID", which is "indestructible", but not "solid"! */
2887 EL_ACID_POOL_TOPLEFT,
2888 EL_ACID_POOL_TOPRIGHT,
2889 EL_ACID_POOL_BOTTOMLEFT,
2890 EL_ACID_POOL_BOTTOM,
2891 EL_ACID_POOL_BOTTOMRIGHT,
2892 EL_SP_HARDWARE_GRAY,
2893 EL_SP_HARDWARE_GREEN,
2894 EL_SP_HARDWARE_BLUE,
2896 EL_SP_HARDWARE_YELLOW,
2897 EL_SP_HARDWARE_BASE_1,
2898 EL_SP_HARDWARE_BASE_2,
2899 EL_SP_HARDWARE_BASE_3,
2900 EL_SP_HARDWARE_BASE_4,
2901 EL_SP_HARDWARE_BASE_5,
2902 EL_SP_HARDWARE_BASE_6,
2903 EL_INVISIBLE_STEELWALL,
2904 EL_INVISIBLE_STEELWALL_ACTIVE,
2905 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2906 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2907 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2908 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2909 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2910 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2911 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2912 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2913 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2914 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2915 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2916 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2918 EL_LIGHT_SWITCH_ACTIVE,
2919 EL_SIGN_EXCLAMATION,
2920 EL_SIGN_RADIOACTIVITY,
2931 EL_STEELWALL_SLIPPERY,
2945 EL_GATE_1_GRAY_ACTIVE,
2946 EL_GATE_2_GRAY_ACTIVE,
2947 EL_GATE_3_GRAY_ACTIVE,
2948 EL_GATE_4_GRAY_ACTIVE,
2957 EL_EM_GATE_1_GRAY_ACTIVE,
2958 EL_EM_GATE_2_GRAY_ACTIVE,
2959 EL_EM_GATE_3_GRAY_ACTIVE,
2960 EL_EM_GATE_4_GRAY_ACTIVE,
2962 EL_SWITCHGATE_OPENING,
2963 EL_SWITCHGATE_CLOSED,
2964 EL_SWITCHGATE_CLOSING,
2966 EL_TIMEGATE_OPENING,
2968 EL_TIMEGATE_CLOSING,
2972 EL_TUBE_VERTICAL_LEFT,
2973 EL_TUBE_VERTICAL_RIGHT,
2974 EL_TUBE_HORIZONTAL_UP,
2975 EL_TUBE_HORIZONTAL_DOWN,
2983 static int ep_classic_enemy[] =
2999 static int ep_belt[] =
3001 EL_CONVEYOR_BELT_1_LEFT,
3002 EL_CONVEYOR_BELT_1_MIDDLE,
3003 EL_CONVEYOR_BELT_1_RIGHT,
3004 EL_CONVEYOR_BELT_2_LEFT,
3005 EL_CONVEYOR_BELT_2_MIDDLE,
3006 EL_CONVEYOR_BELT_2_RIGHT,
3007 EL_CONVEYOR_BELT_3_LEFT,
3008 EL_CONVEYOR_BELT_3_MIDDLE,
3009 EL_CONVEYOR_BELT_3_RIGHT,
3010 EL_CONVEYOR_BELT_4_LEFT,
3011 EL_CONVEYOR_BELT_4_MIDDLE,
3012 EL_CONVEYOR_BELT_4_RIGHT,
3016 static int ep_belt_active[] =
3018 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3019 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3020 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3021 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3022 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3023 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3024 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3025 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3026 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3027 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3028 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3029 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3033 static int ep_belt_switch[] =
3035 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3036 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3037 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3038 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3039 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3040 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3041 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3042 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3043 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3044 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3045 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3046 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3050 static int ep_tube[] =
3057 EL_TUBE_HORIZONTAL_UP,
3058 EL_TUBE_HORIZONTAL_DOWN,
3060 EL_TUBE_VERTICAL_LEFT,
3061 EL_TUBE_VERTICAL_RIGHT,
3066 static int ep_keygate[] =
3076 EL_GATE_1_GRAY_ACTIVE,
3077 EL_GATE_2_GRAY_ACTIVE,
3078 EL_GATE_3_GRAY_ACTIVE,
3079 EL_GATE_4_GRAY_ACTIVE,
3088 EL_EM_GATE_1_GRAY_ACTIVE,
3089 EL_EM_GATE_2_GRAY_ACTIVE,
3090 EL_EM_GATE_3_GRAY_ACTIVE,
3091 EL_EM_GATE_4_GRAY_ACTIVE,
3100 EL_EMC_GATE_5_GRAY_ACTIVE,
3101 EL_EMC_GATE_6_GRAY_ACTIVE,
3102 EL_EMC_GATE_7_GRAY_ACTIVE,
3103 EL_EMC_GATE_8_GRAY_ACTIVE,
3107 static int ep_amoeboid[] =
3117 static int ep_amoebalive[] =
3126 static int ep_has_content[] =
3137 static int ep_can_turn_each_move[] =
3139 /* !!! do something with this one !!! */
3143 static int ep_can_grow[] =
3155 static int ep_active_bomb[] =
3158 EL_DYNABOMB_PLAYER_1_ACTIVE,
3159 EL_DYNABOMB_PLAYER_2_ACTIVE,
3160 EL_DYNABOMB_PLAYER_3_ACTIVE,
3161 EL_DYNABOMB_PLAYER_4_ACTIVE,
3162 EL_SP_DISK_RED_ACTIVE,
3166 static int ep_inactive[] =
3198 EL_GATE_1_GRAY_ACTIVE,
3199 EL_GATE_2_GRAY_ACTIVE,
3200 EL_GATE_3_GRAY_ACTIVE,
3201 EL_GATE_4_GRAY_ACTIVE,
3210 EL_EM_GATE_1_GRAY_ACTIVE,
3211 EL_EM_GATE_2_GRAY_ACTIVE,
3212 EL_EM_GATE_3_GRAY_ACTIVE,
3213 EL_EM_GATE_4_GRAY_ACTIVE,
3222 EL_EMC_GATE_5_GRAY_ACTIVE,
3223 EL_EMC_GATE_6_GRAY_ACTIVE,
3224 EL_EMC_GATE_7_GRAY_ACTIVE,
3225 EL_EMC_GATE_8_GRAY_ACTIVE,
3227 EL_INVISIBLE_STEELWALL,
3235 EL_WALL_EMERALD_YELLOW,
3236 EL_DYNABOMB_INCREASE_NUMBER,
3237 EL_DYNABOMB_INCREASE_SIZE,
3238 EL_DYNABOMB_INCREASE_POWER,
3242 EL_SOKOBAN_FIELD_EMPTY,
3243 EL_SOKOBAN_FIELD_FULL,
3244 EL_WALL_EMERALD_RED,
3245 EL_WALL_EMERALD_PURPLE,
3246 EL_ACID_POOL_TOPLEFT,
3247 EL_ACID_POOL_TOPRIGHT,
3248 EL_ACID_POOL_BOTTOMLEFT,
3249 EL_ACID_POOL_BOTTOM,
3250 EL_ACID_POOL_BOTTOMRIGHT,
3254 EL_BD_MAGIC_WALL_DEAD,
3255 EL_AMOEBA_TO_DIAMOND,
3263 EL_SP_GRAVITY_PORT_RIGHT,
3264 EL_SP_GRAVITY_PORT_DOWN,
3265 EL_SP_GRAVITY_PORT_LEFT,
3266 EL_SP_GRAVITY_PORT_UP,
3267 EL_SP_PORT_HORIZONTAL,
3268 EL_SP_PORT_VERTICAL,
3279 EL_SP_HARDWARE_GRAY,
3280 EL_SP_HARDWARE_GREEN,
3281 EL_SP_HARDWARE_BLUE,
3283 EL_SP_HARDWARE_YELLOW,
3284 EL_SP_HARDWARE_BASE_1,
3285 EL_SP_HARDWARE_BASE_2,
3286 EL_SP_HARDWARE_BASE_3,
3287 EL_SP_HARDWARE_BASE_4,
3288 EL_SP_HARDWARE_BASE_5,
3289 EL_SP_HARDWARE_BASE_6,
3290 EL_SP_GRAVITY_ON_PORT_LEFT,
3291 EL_SP_GRAVITY_ON_PORT_RIGHT,
3292 EL_SP_GRAVITY_ON_PORT_UP,
3293 EL_SP_GRAVITY_ON_PORT_DOWN,
3294 EL_SP_GRAVITY_OFF_PORT_LEFT,
3295 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3296 EL_SP_GRAVITY_OFF_PORT_UP,
3297 EL_SP_GRAVITY_OFF_PORT_DOWN,
3298 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3299 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3300 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3301 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3302 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3303 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3304 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3305 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3306 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3307 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3308 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3309 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3310 EL_SIGN_EXCLAMATION,
3311 EL_SIGN_RADIOACTIVITY,
3322 EL_STEELWALL_SLIPPERY,
3327 EL_EMC_WALL_SLIPPERY_1,
3328 EL_EMC_WALL_SLIPPERY_2,
3329 EL_EMC_WALL_SLIPPERY_3,
3330 EL_EMC_WALL_SLIPPERY_4,
3350 static int ep_em_slippery_wall[] =
3355 static int ep_gfx_crumbled[] =
3364 static int ep_editor_cascade_active[] =
3366 EL_INTERNAL_CASCADE_BD_ACTIVE,
3367 EL_INTERNAL_CASCADE_EM_ACTIVE,
3368 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3369 EL_INTERNAL_CASCADE_RND_ACTIVE,
3370 EL_INTERNAL_CASCADE_SB_ACTIVE,
3371 EL_INTERNAL_CASCADE_SP_ACTIVE,
3372 EL_INTERNAL_CASCADE_DC_ACTIVE,
3373 EL_INTERNAL_CASCADE_DX_ACTIVE,
3374 EL_INTERNAL_CASCADE_TEXT_ACTIVE,
3375 EL_INTERNAL_CASCADE_CE_ACTIVE,
3376 EL_INTERNAL_CASCADE_GE_ACTIVE,
3377 EL_INTERNAL_CASCADE_USER_ACTIVE,
3378 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3379 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3383 static int ep_editor_cascade_inactive[] =
3385 EL_INTERNAL_CASCADE_BD,
3386 EL_INTERNAL_CASCADE_EM,
3387 EL_INTERNAL_CASCADE_EMC,
3388 EL_INTERNAL_CASCADE_RND,
3389 EL_INTERNAL_CASCADE_SB,
3390 EL_INTERNAL_CASCADE_SP,
3391 EL_INTERNAL_CASCADE_DC,
3392 EL_INTERNAL_CASCADE_DX,
3393 EL_INTERNAL_CASCADE_TEXT,
3394 EL_INTERNAL_CASCADE_CE,
3395 EL_INTERNAL_CASCADE_GE,
3396 EL_INTERNAL_CASCADE_USER,
3397 EL_INTERNAL_CASCADE_GENERIC,
3398 EL_INTERNAL_CASCADE_DYNAMIC,
3406 } element_properties[] =
3408 { ep_diggable, EP_DIGGABLE },
3409 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3410 { ep_dont_run_into, EP_DONT_RUN_INTO },
3411 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3412 { ep_dont_touch, EP_DONT_TOUCH },
3413 { ep_indestructible, EP_INDESTRUCTIBLE },
3414 { ep_slippery, EP_SLIPPERY },
3415 { ep_can_change, EP_CAN_CHANGE },
3416 { ep_can_move, EP_CAN_MOVE },
3417 { ep_can_fall, EP_CAN_FALL },
3418 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3419 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3420 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3421 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3422 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3423 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3424 { ep_walkable_over, EP_WALKABLE_OVER },
3425 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3426 { ep_walkable_under, EP_WALKABLE_UNDER },
3427 { ep_passable_over, EP_PASSABLE_OVER },
3428 { ep_passable_inside, EP_PASSABLE_INSIDE },
3429 { ep_passable_under, EP_PASSABLE_UNDER },
3430 { ep_droppable, EP_DROPPABLE },
3431 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3432 { ep_pushable, EP_PUSHABLE },
3433 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3434 { ep_protected, EP_PROTECTED },
3435 { ep_throwable, EP_THROWABLE },
3436 { ep_can_explode, EP_CAN_EXPLODE },
3437 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3439 { ep_player, EP_PLAYER },
3440 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3441 { ep_switchable, EP_SWITCHABLE },
3442 { ep_bd_element, EP_BD_ELEMENT },
3443 { ep_sp_element, EP_SP_ELEMENT },
3444 { ep_sb_element, EP_SB_ELEMENT },
3446 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3447 { ep_food_penguin, EP_FOOD_PENGUIN },
3448 { ep_food_pig, EP_FOOD_PIG },
3449 { ep_historic_wall, EP_HISTORIC_WALL },
3450 { ep_historic_solid, EP_HISTORIC_SOLID },
3451 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3452 { ep_belt, EP_BELT },
3453 { ep_belt_active, EP_BELT_ACTIVE },
3454 { ep_belt_switch, EP_BELT_SWITCH },
3455 { ep_tube, EP_TUBE },
3456 { ep_keygate, EP_KEYGATE },
3457 { ep_amoeboid, EP_AMOEBOID },
3458 { ep_amoebalive, EP_AMOEBALIVE },
3459 { ep_has_content, EP_HAS_CONTENT },
3460 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3461 { ep_can_grow, EP_CAN_GROW },
3462 { ep_active_bomb, EP_ACTIVE_BOMB },
3463 { ep_inactive, EP_INACTIVE },
3465 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3467 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3469 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3470 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3477 /* always start with reliable default values (element has no properties) */
3478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3479 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3480 SET_PROPERTY(i, j, FALSE);
3482 /* set all base element properties from above array definitions */
3483 for (i = 0; element_properties[i].elements != NULL; i++)
3484 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3485 SET_PROPERTY((element_properties[i].elements)[j],
3486 element_properties[i].property, TRUE);
3488 /* copy properties to some elements that are only stored in level file */
3489 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3490 for (j = 0; copy_properties[j][0] != -1; j++)
3491 if (HAS_PROPERTY(copy_properties[j][0], i))
3492 for (k = 1; k <= 4; k++)
3493 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3496 void InitElementPropertiesEngine(int engine_version)
3498 static int no_wall_properties[] =
3501 EP_COLLECTIBLE_ONLY,
3503 EP_DONT_COLLIDE_WITH,
3506 EP_CAN_SMASH_PLAYER,
3507 EP_CAN_SMASH_ENEMIES,
3508 EP_CAN_SMASH_EVERYTHING,
3513 EP_FOOD_DARK_YAMYAM,
3529 /* important: after initialization in InitElementPropertiesStatic(), the
3530 elements are not again initialized to a default value; therefore all
3531 changes have to make sure that they leave the element with a defined
3532 property (which means that conditional property changes must be set to
3533 a reliable default value before) */
3535 /* set all special, combined or engine dependent element properties */
3536 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3538 /* ---------- INACTIVE ------------------------------------------------- */
3539 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3541 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3542 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3543 IS_WALKABLE_INSIDE(i) ||
3544 IS_WALKABLE_UNDER(i)));
3546 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3547 IS_PASSABLE_INSIDE(i) ||
3548 IS_PASSABLE_UNDER(i)));
3550 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3551 IS_PASSABLE_OVER(i)));
3553 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3554 IS_PASSABLE_INSIDE(i)));
3556 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3557 IS_PASSABLE_UNDER(i)));
3559 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3562 /* ---------- COLLECTIBLE ---------------------------------------------- */
3563 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3567 /* ---------- SNAPPABLE ------------------------------------------------ */
3568 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3569 IS_COLLECTIBLE(i) ||
3573 /* ---------- WALL ----------------------------------------------------- */
3574 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3576 for (j = 0; no_wall_properties[j] != -1; j++)
3577 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3578 i >= EL_FIRST_RUNTIME_UNREAL)
3579 SET_PROPERTY(i, EP_WALL, FALSE);
3581 if (IS_HISTORIC_WALL(i))
3582 SET_PROPERTY(i, EP_WALL, TRUE);
3584 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3585 if (engine_version < VERSION_IDENT(2,2,0,0))
3586 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3588 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3590 !IS_COLLECTIBLE(i)));
3592 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3594 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3595 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3597 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3598 IS_INDESTRUCTIBLE(i)));
3600 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3602 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3603 else if (engine_version < VERSION_IDENT(2,2,0,0))
3604 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3606 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3610 if (IS_CUSTOM_ELEMENT(i))
3612 /* these are additional properties which are initially false when set */
3614 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3616 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3617 if (DONT_COLLIDE_WITH(i))
3618 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3620 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3621 if (CAN_SMASH_EVERYTHING(i))
3622 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3623 if (CAN_SMASH_ENEMIES(i))
3624 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3627 /* ---------- CAN_SMASH ------------------------------------------------ */
3628 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3629 CAN_SMASH_ENEMIES(i) ||
3630 CAN_SMASH_EVERYTHING(i)));
3632 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3633 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3634 EXPLODES_BY_FIRE(i)));
3636 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3637 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3638 EXPLODES_SMASHED(i)));
3640 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3641 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3642 EXPLODES_IMPACT(i)));
3644 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3645 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3647 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3648 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3649 i == EL_BLACK_ORB));
3651 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3652 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3654 IS_CUSTOM_ELEMENT(i)));
3656 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3657 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3658 i == EL_SP_ELECTRON));
3660 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3661 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3662 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3663 getMoveIntoAcidProperty(&level, i));
3665 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3666 if (MAYBE_DONT_COLLIDE_WITH(i))
3667 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3668 getDontCollideWithProperty(&level, i));
3670 /* ---------- SP_PORT -------------------------------------------------- */
3671 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3672 IS_PASSABLE_INSIDE(i)));
3674 /* ---------- CAN_CHANGE ----------------------------------------------- */
3675 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3676 for (j = 0; j < element_info[i].num_change_pages; j++)
3677 if (element_info[i].change_page[j].can_change)
3678 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3680 /* ---------- HAS_ACTION ----------------------------------------------- */
3681 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3682 for (j = 0; j < element_info[i].num_change_pages; j++)
3683 if (element_info[i].change_page[j].has_action)
3684 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3686 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3687 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3690 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3692 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3693 element_info[i].crumbled[ACTION_DEFAULT] !=
3694 element_info[i].graphic[ACTION_DEFAULT]);
3696 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3697 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3698 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3701 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3702 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3703 IS_EDITOR_CASCADE_INACTIVE(i)));
3706 /* dynamically adjust element properties according to game engine version */
3708 static int ep_em_slippery_wall[] =
3713 EL_EXPANDABLE_WALL_HORIZONTAL,
3714 EL_EXPANDABLE_WALL_VERTICAL,
3715 EL_EXPANDABLE_WALL_ANY,
3719 /* special EM style gems behaviour */
3720 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3721 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3722 level.em_slippery_gems);
3724 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3725 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3726 (level.em_slippery_gems &&
3727 engine_version > VERSION_IDENT(2,0,1,0)));
3730 /* set default push delay values (corrected since version 3.0.7-1) */
3731 if (engine_version < VERSION_IDENT(3,0,7,1))
3733 game.default_push_delay_fixed = 2;
3734 game.default_push_delay_random = 8;
3738 game.default_push_delay_fixed = 8;
3739 game.default_push_delay_random = 8;
3742 /* set uninitialized push delay values of custom elements in older levels */
3743 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3745 int element = EL_CUSTOM_START + i;
3747 if (element_info[element].push_delay_fixed == -1)
3748 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3749 if (element_info[element].push_delay_random == -1)
3750 element_info[element].push_delay_random = game.default_push_delay_random;
3753 /* set some other uninitialized values of custom elements in older levels */
3754 if (engine_version < VERSION_IDENT(3,1,0,0))
3756 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3758 int element = EL_CUSTOM_START + i;
3760 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3762 element_info[element].explosion_delay = 17;
3763 element_info[element].ignition_delay = 8;
3768 /* set element properties that were handled incorrectly in older levels */
3769 if (engine_version < VERSION_IDENT(3,1,0,0))
3771 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3772 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3776 /* this is needed because some graphics depend on element properties */
3777 if (game_status == GAME_MODE_PLAYING)
3778 InitElementGraphicInfo();
3781 static void InitGlobal()
3785 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3787 /* check if element_name_info entry defined for each element in "main.h" */
3788 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3789 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3791 element_info[i].token_name = element_name_info[i].token_name;
3792 element_info[i].class_name = element_name_info[i].class_name;
3793 element_info[i].editor_description=element_name_info[i].editor_description;
3796 global.autoplay_leveldir = NULL;
3797 global.convert_leveldir = NULL;
3799 global.frames_per_second = 0;
3800 global.fps_slowdown = FALSE;
3801 global.fps_slowdown_factor = 1;
3804 void Execute_Command(char *command)
3808 if (strcmp(command, "print graphicsinfo.conf") == 0)
3810 printf("# You can configure additional/alternative image files here.\n");
3811 printf("# (The entries below are default and therefore commented out.)\n");
3813 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3815 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3818 for (i = 0; image_config[i].token != NULL; i++)
3819 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3820 image_config[i].value));
3824 else if (strcmp(command, "print soundsinfo.conf") == 0)
3826 printf("# You can configure additional/alternative sound files here.\n");
3827 printf("# (The entries below are default and therefore commented out.)\n");
3829 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3831 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3834 for (i = 0; sound_config[i].token != NULL; i++)
3835 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3836 sound_config[i].value));
3840 else if (strcmp(command, "print musicinfo.conf") == 0)
3842 printf("# You can configure additional/alternative music files here.\n");
3843 printf("# (The entries below are default and therefore commented out.)\n");
3845 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3847 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3850 for (i = 0; music_config[i].token != NULL; i++)
3851 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3852 music_config[i].value));
3856 else if (strcmp(command, "print editorsetup.conf") == 0)
3858 printf("# You can configure your personal editor element list here.\n");
3859 printf("# (The entries below are default and therefore commented out.)\n");
3862 PrintEditorElementList();
3866 else if (strcmp(command, "print helpanim.conf") == 0)
3868 printf("# You can configure different element help animations here.\n");
3869 printf("# (The entries below are default and therefore commented out.)\n");
3872 for (i = 0; helpanim_config[i].token != NULL; i++)
3874 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3875 helpanim_config[i].value));
3877 if (strcmp(helpanim_config[i].token, "end") == 0)
3883 else if (strcmp(command, "print helptext.conf") == 0)
3885 printf("# You can configure different element help text here.\n");
3886 printf("# (The entries below are default and therefore commented out.)\n");
3889 for (i = 0; helptext_config[i].token != NULL; i++)
3890 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3891 helptext_config[i].value));
3895 else if (strncmp(command, "dump level ", 11) == 0)
3897 char *filename = &command[11];
3899 if (!fileExists(filename))
3900 Error(ERR_EXIT, "cannot open file '%s'", filename);
3902 LoadLevelFromFilename(&level, filename);
3907 else if (strncmp(command, "dump tape ", 10) == 0)
3909 char *filename = &command[10];
3911 if (!fileExists(filename))
3912 Error(ERR_EXIT, "cannot open file '%s'", filename);
3914 LoadTapeFromFilename(filename);
3919 else if (strncmp(command, "autoplay ", 9) == 0)
3921 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3923 while (*str_ptr != '\0') /* continue parsing string */
3925 /* cut leading whitespace from string, replace it by string terminator */
3926 while (*str_ptr == ' ' || *str_ptr == '\t')
3929 if (*str_ptr == '\0') /* end of string reached */
3932 if (global.autoplay_leveldir == NULL) /* read level set string */
3934 global.autoplay_leveldir = str_ptr;
3935 global.autoplay_all = TRUE; /* default: play all tapes */
3937 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3938 global.autoplay_level[i] = FALSE;
3940 else /* read level number string */
3942 int level_nr = atoi(str_ptr); /* get level_nr value */
3944 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3945 global.autoplay_level[level_nr] = TRUE;
3947 global.autoplay_all = FALSE;
3950 /* advance string pointer to the next whitespace (or end of string) */
3951 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3955 else if (strncmp(command, "convert ", 8) == 0)
3957 char *str_copy = getStringCopy(&command[8]);
3958 char *str_ptr = strchr(str_copy, ' ');
3960 global.convert_leveldir = str_copy;
3961 global.convert_level_nr = -1;
3963 if (str_ptr != NULL) /* level number follows */
3965 *str_ptr++ = '\0'; /* terminate leveldir string */
3966 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3971 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3975 static void InitSetup()
3977 LoadSetup(); /* global setup info */
3979 /* set some options from setup file */
3981 if (setup.options.verbose)
3982 options.verbose = TRUE;
3985 static void InitGameInfo()
3987 game.restart_level = FALSE;
3990 static void InitPlayerInfo()
3994 /* choose default local player */
3995 local_player = &stored_player[0];
3997 for (i = 0; i < MAX_PLAYERS; i++)
3998 stored_player[i].connected = FALSE;
4000 local_player->connected = TRUE;
4003 static void InitArtworkInfo()
4008 static char *get_string_in_brackets(char *string)
4010 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4012 sprintf(string_in_brackets, "[%s]", string);
4014 return string_in_brackets;
4017 static char *get_level_id_suffix(int id_nr)
4019 char *id_suffix = checked_malloc(1 + 3 + 1);
4021 if (id_nr < 0 || id_nr > 999)
4024 sprintf(id_suffix, ".%03d", id_nr);
4030 static char *get_element_class_token(int element)
4032 char *element_class_name = element_info[element].class_name;
4033 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4035 sprintf(element_class_token, "[%s]", element_class_name);
4037 return element_class_token;
4040 static char *get_action_class_token(int action)
4042 char *action_class_name = &element_action_info[action].suffix[1];
4043 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4045 sprintf(action_class_token, "[%s]", action_class_name);
4047 return action_class_token;
4051 static void InitArtworkConfig()
4053 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4054 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4055 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4056 static char *action_id_suffix[NUM_ACTIONS + 1];
4057 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4058 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4059 static char *level_id_suffix[MAX_LEVELS + 1];
4060 static char *dummy[1] = { NULL };
4061 static char *ignore_generic_tokens[] =
4067 static char **ignore_image_tokens;
4068 static char **ignore_sound_tokens;
4069 static char **ignore_music_tokens;
4070 int num_ignore_generic_tokens;
4071 int num_ignore_image_tokens;
4072 int num_ignore_sound_tokens;
4073 int num_ignore_music_tokens;
4076 /* dynamically determine list of generic tokens to be ignored */
4077 num_ignore_generic_tokens = 0;
4078 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4079 num_ignore_generic_tokens++;
4081 /* dynamically determine list of image tokens to be ignored */
4082 num_ignore_image_tokens = num_ignore_generic_tokens;
4083 for (i = 0; image_config_vars[i].token != NULL; i++)
4084 num_ignore_image_tokens++;
4085 ignore_image_tokens =
4086 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4087 for (i = 0; i < num_ignore_generic_tokens; i++)
4088 ignore_image_tokens[i] = ignore_generic_tokens[i];
4089 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4090 ignore_image_tokens[num_ignore_generic_tokens + i] =
4091 image_config_vars[i].token;
4092 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4094 /* dynamically determine list of sound tokens to be ignored */
4095 num_ignore_sound_tokens = num_ignore_generic_tokens;
4096 ignore_sound_tokens =
4097 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4098 for (i = 0; i < num_ignore_generic_tokens; i++)
4099 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4100 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4102 /* dynamically determine list of music tokens to be ignored */
4103 num_ignore_music_tokens = num_ignore_generic_tokens;
4104 ignore_music_tokens =
4105 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4106 for (i = 0; i < num_ignore_generic_tokens; i++)
4107 ignore_music_tokens[i] = ignore_generic_tokens[i];
4108 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4110 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4111 image_id_prefix[i] = element_info[i].token_name;
4112 for (i = 0; i < NUM_FONTS; i++)
4113 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4114 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4116 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4117 sound_id_prefix[i] = element_info[i].token_name;
4118 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4119 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4120 get_string_in_brackets(element_info[i].class_name);
4121 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4123 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4124 music_id_prefix[i] = music_prefix_info[i].prefix;
4125 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4127 for (i = 0; i < NUM_ACTIONS; i++)
4128 action_id_suffix[i] = element_action_info[i].suffix;
4129 action_id_suffix[NUM_ACTIONS] = NULL;
4131 for (i = 0; i < NUM_DIRECTIONS; i++)
4132 direction_id_suffix[i] = element_direction_info[i].suffix;
4133 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4135 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4136 special_id_suffix[i] = special_suffix_info[i].suffix;
4137 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4139 for (i = 0; i < MAX_LEVELS; i++)
4140 level_id_suffix[i] = get_level_id_suffix(i);
4141 level_id_suffix[MAX_LEVELS] = NULL;
4143 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4144 image_id_prefix, action_id_suffix, direction_id_suffix,
4145 special_id_suffix, ignore_image_tokens);
4146 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4147 sound_id_prefix, action_id_suffix, dummy,
4148 special_id_suffix, ignore_sound_tokens);
4149 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4150 music_id_prefix, special_id_suffix, level_id_suffix,
4151 dummy, ignore_music_tokens);
4154 static void InitMixer()
4162 char *filename_font_initial = NULL;
4163 Bitmap *bitmap_font_initial = NULL;
4166 /* determine settings for initial font (for displaying startup messages) */
4167 for (i = 0; image_config[i].token != NULL; i++)
4169 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4171 char font_token[128];
4174 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4175 len_font_token = strlen(font_token);
4177 if (strcmp(image_config[i].token, font_token) == 0)
4178 filename_font_initial = image_config[i].value;
4179 else if (strlen(image_config[i].token) > len_font_token &&
4180 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4182 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4183 font_initial[j].src_x = atoi(image_config[i].value);
4184 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4185 font_initial[j].src_y = atoi(image_config[i].value);
4186 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4187 font_initial[j].width = atoi(image_config[i].value);
4188 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4189 font_initial[j].height = atoi(image_config[i].value);
4194 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4196 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4197 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4200 if (filename_font_initial == NULL) /* should not happen */
4201 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4203 /* create additional image buffers for double-buffering */
4204 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4205 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4207 /* initialize screen properties */
4208 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4209 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4211 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4212 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4213 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4215 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4217 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4218 font_initial[j].bitmap = bitmap_font_initial;
4220 InitFontGraphicInfo();
4222 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4223 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4225 DrawInitText("Loading graphics:", 120, FC_GREEN);
4228 void InitGfxBackground()
4232 drawto = backbuffer;
4233 fieldbuffer = bitmap_db_field;
4234 SetDrawtoField(DRAW_BACKBUFFER);
4236 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4237 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4238 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4239 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4241 for (x = 0; x < MAX_BUF_XSIZE; x++)
4242 for (y = 0; y < MAX_BUF_YSIZE; y++)
4245 redraw_mask = REDRAW_ALL;
4248 static void InitLevelInfo()
4250 LoadLevelInfo(); /* global level info */
4251 LoadLevelSetup_LastSeries(); /* last played series info */
4252 LoadLevelSetup_SeriesInfo(); /* last played level info */
4255 void InitLevelArtworkInfo()
4257 LoadLevelArtworkInfo();
4260 static void InitImages()
4262 setLevelArtworkDir(artwork.gfx_first);
4265 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4266 leveldir_current->identifier,
4267 artwork.gfx_current_identifier,
4268 artwork.gfx_current->identifier,
4269 leveldir_current->graphics_set,
4270 leveldir_current->graphics_path);
4273 ReloadCustomImages();
4275 LoadCustomElementDescriptions();
4276 LoadSpecialMenuDesignSettings();
4278 ReinitializeGraphics();
4281 static void InitSound(char *identifier)
4283 if (identifier == NULL)
4284 identifier = artwork.snd_current->identifier;
4286 /* set artwork path to send it to the sound server process */
4287 setLevelArtworkDir(artwork.snd_first);
4289 InitReloadCustomSounds(identifier);
4290 ReinitializeSounds();
4293 static void InitMusic(char *identifier)
4295 if (identifier == NULL)
4296 identifier = artwork.mus_current->identifier;
4298 /* set artwork path to send it to the sound server process */
4299 setLevelArtworkDir(artwork.mus_first);
4301 InitReloadCustomMusic(identifier);
4302 ReinitializeMusic();
4305 void InitNetworkServer()
4307 #if defined(NETWORK_AVALIABLE)
4311 if (!options.network)
4314 #if defined(NETWORK_AVALIABLE)
4315 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4317 if (!ConnectToServer(options.server_host, options.server_port))
4318 Error(ERR_EXIT, "cannot connect to network game server");
4320 SendToServer_PlayerName(setup.player_name);
4321 SendToServer_ProtocolVersion();
4324 SendToServer_NrWanted(nr_wanted);
4328 static char *getNewArtworkIdentifier(int type)
4330 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4331 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4332 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4333 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4334 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4335 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4336 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4337 char *leveldir_identifier = leveldir_current->identifier;
4339 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4340 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4342 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4344 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4345 char *artwork_current_identifier;
4346 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4348 /* leveldir_current may be invalid (level group, parent link) */
4349 if (!validLevelSeries(leveldir_current))
4352 /* 1st step: determine artwork set to be activated in descending order:
4353 --------------------------------------------------------------------
4354 1. setup artwork (when configured to override everything else)
4355 2. artwork set configured in "levelinfo.conf" of current level set
4356 (artwork in level directory will have priority when loading later)
4357 3. artwork in level directory (stored in artwork sub-directory)
4358 4. setup artwork (currently configured in setup menu) */
4360 if (setup_override_artwork)
4361 artwork_current_identifier = setup_artwork_set;
4362 else if (leveldir_artwork_set != NULL)
4363 artwork_current_identifier = leveldir_artwork_set;
4364 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4365 artwork_current_identifier = leveldir_identifier;
4367 artwork_current_identifier = setup_artwork_set;
4370 /* 2nd step: check if it is really needed to reload artwork set
4371 ------------------------------------------------------------ */
4374 if (type == ARTWORK_TYPE_GRAPHICS)
4375 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4376 artwork_new_identifier,
4377 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4378 artwork_current_identifier,
4379 leveldir_current->graphics_set,
4380 leveldir_current->identifier);
4383 /* ---------- reload if level set and also artwork set has changed ------- */
4384 if (leveldir_current_identifier[type] != leveldir_identifier &&
4385 (last_has_level_artwork_set[type] || has_level_artwork_set))
4386 artwork_new_identifier = artwork_current_identifier;
4388 leveldir_current_identifier[type] = leveldir_identifier;
4389 last_has_level_artwork_set[type] = has_level_artwork_set;
4392 if (type == ARTWORK_TYPE_GRAPHICS)
4393 printf("::: 1: '%s'\n", artwork_new_identifier);
4396 /* ---------- reload if "override artwork" setting has changed ----------- */
4397 if (last_override_level_artwork[type] != setup_override_artwork)
4398 artwork_new_identifier = artwork_current_identifier;
4400 last_override_level_artwork[type] = setup_override_artwork;
4403 if (type == ARTWORK_TYPE_GRAPHICS)
4404 printf("::: 2: '%s'\n", artwork_new_identifier);
4407 /* ---------- reload if current artwork identifier has changed ----------- */
4408 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4409 artwork_current_identifier) != 0)
4410 artwork_new_identifier = artwork_current_identifier;
4412 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4415 if (type == ARTWORK_TYPE_GRAPHICS)
4416 printf("::: 3: '%s'\n", artwork_new_identifier);
4419 /* ---------- do not reload directly after starting ---------------------- */
4420 if (!initialized[type])
4421 artwork_new_identifier = NULL;
4423 initialized[type] = TRUE;
4426 if (type == ARTWORK_TYPE_GRAPHICS)
4427 printf("::: 4: '%s'\n", artwork_new_identifier);
4431 if (type == ARTWORK_TYPE_GRAPHICS)
4432 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4433 artwork.gfx_current_identifier, artwork_current_identifier,
4434 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4435 artwork_new_identifier);
4438 return artwork_new_identifier;
4441 void ReloadCustomArtwork(int force_reload)
4443 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4444 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4445 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4446 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4447 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4448 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4449 boolean redraw_screen = FALSE;
4451 if (gfx_new_identifier != NULL || force_reload_gfx)
4454 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4455 artwork.gfx_current_identifier,
4457 artwork.gfx_current->identifier,
4458 leveldir_current->graphics_set);
4461 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4465 redraw_screen = TRUE;
4468 if (snd_new_identifier != NULL || force_reload_snd)
4470 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4472 InitSound(snd_new_identifier);
4474 redraw_screen = TRUE;
4477 if (mus_new_identifier != NULL || force_reload_mus)
4479 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4481 InitMusic(mus_new_identifier);
4483 redraw_screen = TRUE;
4488 InitGfxBackground();
4490 /* force redraw of (open or closed) door graphics */
4491 SetDoorState(DOOR_OPEN_ALL);
4492 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4496 void KeyboardAutoRepeatOffUnlessAutoplay()
4498 if (global.autoplay_leveldir == NULL)
4499 KeyboardAutoRepeatOff();
4503 /* ========================================================================= */
4505 /* ========================================================================= */
4509 InitGlobal(); /* initialize some global variables */
4511 if (options.execute_command)
4512 Execute_Command(options.execute_command);
4514 if (options.serveronly)
4516 #if defined(PLATFORM_UNIX)
4517 NetworkServer(options.server_port, options.serveronly);
4519 Error(ERR_WARN, "networking only supported in Unix version");
4522 exit(0); /* never reached, server loops forever */
4529 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4530 InitArtworkConfig(); /* needed before forking sound child process */
4535 InitRND(NEW_RANDOMIZE);
4536 InitSimpleRND(NEW_RANDOMIZE);
4541 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4544 InitEventFilter(FilterMouseMotionEvents);
4546 InitElementPropertiesStatic();
4547 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4552 InitLevelArtworkInfo();
4554 InitImages(); /* needs to know current level directory */
4555 InitSound(NULL); /* needs to know current level directory */
4556 InitMusic(NULL); /* needs to know current level directory */
4558 InitGfxBackground();
4560 if (global.autoplay_leveldir)
4565 else if (global.convert_leveldir)
4571 game_status = GAME_MODE_MAIN;
4579 InitNetworkServer();
4582 void CloseAllAndExit(int exit_value)
4587 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4595 #if defined(TARGET_SDL)
4596 if (network_server) /* terminate network server */
4597 SDL_KillThread(server_thread);
4600 CloseVideoDisplay();
4601 ClosePlatformDependentStuff();