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;
206 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
208 font_info[font_nr].special_graphic[special] = graphic;
209 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
214 /* initialize special element/graphic mapping from dynamic configuration */
215 for (i = 0; i < num_property_mappings; i++)
217 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
218 int special = property_mapping[i].ext3_index;
219 int graphic = property_mapping[i].artwork_index;
224 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
226 font_info[font_nr].special_graphic[special] = graphic;
227 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
232 /* ---------- initialize font bitmap array ---------- */
234 if (font_bitmap_info != NULL)
235 FreeFontInfo(font_bitmap_info);
238 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
240 /* ---------- initialize font bitmap definitions ---------- */
242 for (i = 0; i < NUM_FONTS; i++)
244 if (i < NUM_INITIAL_FONTS)
246 font_bitmap_info[i] = font_initial[i];
250 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
252 int font_bitmap_id = font_info[i].special_bitmap_id[j];
253 int graphic = font_info[i].special_graphic[j];
255 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
256 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
258 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
259 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
262 /* copy font relevant information from graphics information */
263 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
264 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
265 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
266 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
267 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
268 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
269 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
271 font_bitmap_info[font_bitmap_id].num_chars =
272 graphic_info[graphic].anim_frames;
273 font_bitmap_info[font_bitmap_id].num_chars_per_line =
274 graphic_info[graphic].anim_frames_per_line;
278 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
281 void InitElementGraphicInfo()
283 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
284 int num_property_mappings = getImageListPropertyMappingSize();
287 if (graphic_info == NULL) /* still at startup phase */
290 /* set values to -1 to identify later as "uninitialized" values */
291 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
293 for (act = 0; act < NUM_ACTIONS; act++)
295 element_info[i].graphic[act] = -1;
296 element_info[i].crumbled[act] = -1;
298 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
300 element_info[i].direction_graphic[act][dir] = -1;
301 element_info[i].direction_crumbled[act][dir] = -1;
306 /* initialize normal element/graphic mapping from static configuration */
307 for (i = 0; element_to_graphic[i].element > -1; i++)
309 int element = element_to_graphic[i].element;
310 int action = element_to_graphic[i].action;
311 int direction = element_to_graphic[i].direction;
312 boolean crumbled = element_to_graphic[i].crumbled;
313 int graphic = element_to_graphic[i].graphic;
314 int base_graphic = el2baseimg(element);
316 if (graphic_info[graphic].bitmap == NULL)
319 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
322 boolean base_redefined =
323 getImageListEntryFromImageID(base_graphic)->redefined;
324 boolean act_dir_redefined =
325 getImageListEntryFromImageID(graphic)->redefined;
327 /* if the base graphic ("emerald", for example) has been redefined,
328 but not the action graphic ("emerald.falling", for example), do not
329 use an existing (in this case considered obsolete) action graphic
330 anymore, but use the automatically determined default graphic */
331 if (base_redefined && !act_dir_redefined)
336 action = ACTION_DEFAULT;
341 element_info[element].direction_crumbled[action][direction] = graphic;
343 element_info[element].crumbled[action] = graphic;
348 element_info[element].direction_graphic[action][direction] = graphic;
350 element_info[element].graphic[action] = graphic;
354 /* initialize normal element/graphic mapping from dynamic configuration */
355 for (i = 0; i < num_property_mappings; i++)
357 int element = property_mapping[i].base_index;
358 int action = property_mapping[i].ext1_index;
359 int direction = property_mapping[i].ext2_index;
360 int special = property_mapping[i].ext3_index;
361 int graphic = property_mapping[i].artwork_index;
362 boolean crumbled = FALSE;
364 if (special == GFX_SPECIAL_ARG_CRUMBLED)
370 if (graphic_info[graphic].bitmap == NULL)
373 if (element >= MAX_NUM_ELEMENTS || special != -1)
377 action = ACTION_DEFAULT;
382 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
383 element_info[element].direction_crumbled[action][dir] = -1;
386 element_info[element].direction_crumbled[action][direction] = graphic;
388 element_info[element].crumbled[action] = graphic;
393 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
394 element_info[element].direction_graphic[action][dir] = -1;
397 element_info[element].direction_graphic[action][direction] = graphic;
399 element_info[element].graphic[action] = graphic;
403 /* now copy all graphics that are defined to be cloned from other graphics */
404 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
406 int graphic = element_info[i].graphic[ACTION_DEFAULT];
407 int crumbled_like, diggable_like;
412 crumbled_like = graphic_info[graphic].crumbled_like;
413 diggable_like = graphic_info[graphic].diggable_like;
415 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
417 for (act = 0; act < NUM_ACTIONS; act++)
418 element_info[i].crumbled[act] =
419 element_info[crumbled_like].crumbled[act];
420 for (act = 0; act < NUM_ACTIONS; act++)
421 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
422 element_info[i].direction_crumbled[act][dir] =
423 element_info[crumbled_like].direction_crumbled[act][dir];
426 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
428 element_info[i].graphic[ACTION_DIGGING] =
429 element_info[diggable_like].graphic[ACTION_DIGGING];
430 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
431 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
432 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
437 /* set hardcoded definitions for some runtime elements without graphic */
438 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
441 /* now set all undefined/invalid graphics to -1 to set to default after it */
442 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
444 for (act = 0; act < NUM_ACTIONS; act++)
448 graphic = element_info[i].graphic[act];
449 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
450 element_info[i].graphic[act] = -1;
452 graphic = element_info[i].crumbled[act];
453 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
454 element_info[i].crumbled[act] = -1;
456 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
458 graphic = element_info[i].direction_graphic[act][dir];
459 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
460 element_info[i].direction_graphic[act][dir] = -1;
462 graphic = element_info[i].direction_crumbled[act][dir];
463 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
464 element_info[i].direction_crumbled[act][dir] = -1;
469 /* adjust graphics with 2nd tile for movement according to direction
470 (do this before correcting '-1' values to minimize calculations) */
471 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
473 for (act = 0; act < NUM_ACTIONS; act++)
475 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
477 int graphic = element_info[i].direction_graphic[act][dir];
478 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
480 if (act == ACTION_FALLING) /* special case */
481 graphic = element_info[i].graphic[act];
484 graphic_info[graphic].double_movement &&
485 graphic_info[graphic].swap_double_tiles != 0)
487 struct GraphicInfo *g = &graphic_info[graphic];
488 int src_x_front = g->src_x;
489 int src_y_front = g->src_y;
490 int src_x_back = g->src_x + g->offset2_x;
491 int src_y_back = g->src_y + g->offset2_y;
492 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
494 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
495 src_y_front < src_y_back);
496 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
497 boolean swap_movement_tiles_autodetected =
498 (!frames_are_ordered_diagonally &&
499 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
500 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
501 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
502 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
505 /* swap frontside and backside graphic tile coordinates, if needed */
506 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
508 /* get current (wrong) backside tile coordinates */
509 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
512 /* set frontside tile coordinates to backside tile coordinates */
513 g->src_x = src_x_back;
514 g->src_y = src_y_back;
516 /* invert tile offset to point to new backside tile coordinates */
520 /* do not swap front and backside tiles again after correction */
521 g->swap_double_tiles = 0;
528 /* now set all '-1' values to element specific default values */
529 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
531 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
532 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
533 int default_direction_graphic[NUM_DIRECTIONS];
534 int default_direction_crumbled[NUM_DIRECTIONS];
536 if (default_graphic == -1)
537 default_graphic = IMG_UNKNOWN;
539 if (default_crumbled == -1)
540 default_crumbled = default_graphic;
542 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
543 if (default_crumbled == -1)
544 default_crumbled = IMG_EMPTY;
547 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
549 default_direction_graphic[dir] =
550 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
551 default_direction_crumbled[dir] =
552 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
554 if (default_direction_graphic[dir] == -1)
555 default_direction_graphic[dir] = default_graphic;
557 if (default_direction_crumbled[dir] == -1)
558 default_direction_crumbled[dir] = default_direction_graphic[dir];
560 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
561 if (default_direction_crumbled[dir] == -1)
562 default_direction_crumbled[dir] = default_crumbled;
566 for (act = 0; act < NUM_ACTIONS; act++)
568 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
569 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
570 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
571 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
572 act == ACTION_TURNING_FROM_RIGHT ||
573 act == ACTION_TURNING_FROM_UP ||
574 act == ACTION_TURNING_FROM_DOWN);
576 /* generic default action graphic (defined by "[default]" directive) */
577 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
578 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
579 int default_remove_graphic = IMG_EMPTY;
581 if (act_remove && default_action_graphic != -1)
582 default_remove_graphic = default_action_graphic;
584 /* look for special default action graphic (classic game specific) */
585 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
586 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
587 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
588 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
589 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
590 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
592 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
593 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
594 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
595 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
596 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
597 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
600 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
601 /* !!! make this better !!! */
602 if (i == EL_EMPTY_SPACE)
604 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
605 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
609 if (default_action_graphic == -1)
610 default_action_graphic = default_graphic;
612 if (default_action_crumbled == -1)
613 default_action_crumbled = default_action_graphic;
615 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
616 if (default_action_crumbled == -1)
617 default_action_crumbled = default_crumbled;
620 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
622 /* use action graphic as the default direction graphic, if undefined */
623 int default_action_direction_graphic = element_info[i].graphic[act];
624 int default_action_direction_crumbled = element_info[i].crumbled[act];
626 /* no graphic for current action -- use default direction graphic */
627 if (default_action_direction_graphic == -1)
628 default_action_direction_graphic =
629 (act_remove ? default_remove_graphic :
631 element_info[i].direction_graphic[ACTION_TURNING][dir] :
632 default_action_graphic != default_graphic ?
633 default_action_graphic :
634 default_direction_graphic[dir]);
636 if (element_info[i].direction_graphic[act][dir] == -1)
637 element_info[i].direction_graphic[act][dir] =
638 default_action_direction_graphic;
641 if (default_action_direction_crumbled == -1)
642 default_action_direction_crumbled =
643 element_info[i].direction_graphic[act][dir];
645 if (default_action_direction_crumbled == -1)
646 default_action_direction_crumbled =
647 (act_remove ? default_remove_graphic :
649 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
650 default_action_crumbled != default_crumbled ?
651 default_action_crumbled :
652 default_direction_crumbled[dir]);
655 if (element_info[i].direction_crumbled[act][dir] == -1)
656 element_info[i].direction_crumbled[act][dir] =
657 default_action_direction_crumbled;
660 /* no graphic for this specific action -- use default action graphic */
661 if (element_info[i].graphic[act] == -1)
662 element_info[i].graphic[act] =
663 (act_remove ? default_remove_graphic :
664 act_turning ? element_info[i].graphic[ACTION_TURNING] :
665 default_action_graphic);
667 if (element_info[i].crumbled[act] == -1)
668 element_info[i].crumbled[act] = element_info[i].graphic[act];
670 if (element_info[i].crumbled[act] == -1)
671 element_info[i].crumbled[act] =
672 (act_remove ? default_remove_graphic :
673 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
674 default_action_crumbled);
679 /* set animation mode to "none" for each graphic with only 1 frame */
680 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
682 for (act = 0; act < NUM_ACTIONS; act++)
684 int graphic = element_info[i].graphic[act];
685 int crumbled = element_info[i].crumbled[act];
687 if (graphic_info[graphic].anim_frames == 1)
688 graphic_info[graphic].anim_mode = ANIM_NONE;
689 if (graphic_info[crumbled].anim_frames == 1)
690 graphic_info[crumbled].anim_mode = ANIM_NONE;
692 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
694 graphic = element_info[i].direction_graphic[act][dir];
695 crumbled = element_info[i].direction_crumbled[act][dir];
697 if (graphic_info[graphic].anim_frames == 1)
698 graphic_info[graphic].anim_mode = ANIM_NONE;
699 if (graphic_info[crumbled].anim_frames == 1)
700 graphic_info[crumbled].anim_mode = ANIM_NONE;
709 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
710 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
712 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
713 element_info[i].token_name, i);
719 void InitElementSpecialGraphicInfo()
721 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
722 int num_property_mappings = getImageListPropertyMappingSize();
725 /* always start with reliable default values */
726 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
727 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
728 element_info[i].special_graphic[j] =
729 element_info[i].graphic[ACTION_DEFAULT];
731 /* initialize special element/graphic mapping from static configuration */
732 for (i = 0; element_to_special_graphic[i].element > -1; i++)
734 int element = element_to_special_graphic[i].element;
735 int special = element_to_special_graphic[i].special;
736 int graphic = element_to_special_graphic[i].graphic;
737 int base_graphic = el2baseimg(element);
738 boolean base_redefined =
739 getImageListEntryFromImageID(base_graphic)->redefined;
740 boolean special_redefined =
741 getImageListEntryFromImageID(graphic)->redefined;
743 /* if the base graphic ("emerald", for example) has been redefined,
744 but not the special graphic ("emerald.EDITOR", for example), do not
745 use an existing (in this case considered obsolete) special graphic
746 anymore, but use the automatically created (down-scaled) graphic */
747 if (base_redefined && !special_redefined)
750 element_info[element].special_graphic[special] = graphic;
753 /* initialize special element/graphic mapping from dynamic configuration */
754 for (i = 0; i < num_property_mappings; i++)
756 int element = property_mapping[i].base_index;
757 int special = property_mapping[i].ext3_index;
758 int graphic = property_mapping[i].artwork_index;
760 if (element >= MAX_NUM_ELEMENTS)
763 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
764 element_info[element].special_graphic[special] = graphic;
767 /* now set all undefined/invalid graphics to default */
768 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
769 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
770 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
771 element_info[i].special_graphic[j] =
772 element_info[i].graphic[ACTION_DEFAULT];
775 static int get_element_from_token(char *token)
779 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
780 if (strcmp(element_info[i].token_name, token) == 0)
786 static int get_scaled_graphic_width(int graphic)
788 int original_width = getOriginalImageWidthFromImageID(graphic);
789 int scale_up_factor = graphic_info[graphic].scale_up_factor;
791 return original_width * scale_up_factor;
794 static int get_scaled_graphic_height(int graphic)
796 int original_height = getOriginalImageHeightFromImageID(graphic);
797 int scale_up_factor = graphic_info[graphic].scale_up_factor;
799 return original_height * scale_up_factor;
802 static void set_graphic_parameters(int graphic, int graphic_copy_from)
804 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
805 char **parameter_raw = image->parameter;
806 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
807 int parameter[NUM_GFX_ARGS];
808 int anim_frames_per_row = 1, anim_frames_per_col = 1;
809 int anim_frames_per_line = 1;
812 /* if fallback to default artwork is done, also use the default parameters */
813 if (image->fallback_to_default)
814 parameter_raw = image->default_parameter;
816 /* get integer values from string parameters */
817 for (i = 0; i < NUM_GFX_ARGS; i++)
820 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
821 image_config_suffix[i].type);
823 if (image_config_suffix[i].type == TYPE_TOKEN)
824 parameter[i] = get_element_from_token(parameter_raw[i]);
827 graphic_info[graphic].bitmap = src_bitmap;
829 /* start with reliable default values */
830 graphic_info[graphic].src_x = 0;
831 graphic_info[graphic].src_y = 0;
832 graphic_info[graphic].width = TILEX;
833 graphic_info[graphic].height = TILEY;
834 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
835 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
836 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
837 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
838 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
839 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
840 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
841 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
842 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
843 graphic_info[graphic].anim_delay_fixed = 0;
844 graphic_info[graphic].anim_delay_random = 0;
845 graphic_info[graphic].post_delay_fixed = 0;
846 graphic_info[graphic].post_delay_random = 0;
848 /* optional x and y tile position of animation frame sequence */
849 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
850 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
851 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
852 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
854 /* optional x and y pixel position of animation frame sequence */
855 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
856 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
857 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
858 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
860 /* optional width and height of each animation frame */
861 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
862 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
863 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
864 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
866 /* optional zoom factor for scaling up the image to a larger size */
867 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
868 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
869 if (graphic_info[graphic].scale_up_factor < 1)
870 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
874 /* get final bitmap size (with scaling, but without small images) */
875 int src_bitmap_width = get_scaled_graphic_width(graphic);
876 int src_bitmap_height = get_scaled_graphic_height(graphic);
878 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
879 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
882 /* correct x or y offset dependent of vertical or horizontal frame order */
883 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
885 graphic_info[graphic].offset_y =
886 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
887 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
888 anim_frames_per_line = anim_frames_per_col;
890 else /* frames are ordered horizontally */
892 graphic_info[graphic].offset_x =
893 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
894 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
895 anim_frames_per_line = anim_frames_per_row;
898 /* optionally, the x and y offset of frames can be specified directly */
899 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
900 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
901 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
902 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
904 /* optionally, moving animations may have separate start and end graphics */
905 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
907 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
908 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
910 /* correct x or y offset2 dependent of vertical or horizontal frame order */
911 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
912 graphic_info[graphic].offset2_y =
913 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
914 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
915 else /* frames are ordered horizontally */
916 graphic_info[graphic].offset2_x =
917 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
918 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
920 /* optionally, the x and y offset of 2nd graphic can be specified directly */
921 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
922 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
923 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
924 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
926 /* optionally, the second movement tile can be specified as start tile */
927 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
928 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
930 /* automatically determine correct number of frames, if not defined */
931 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
932 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
933 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
934 graphic_info[graphic].anim_frames = anim_frames_per_row;
935 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
936 graphic_info[graphic].anim_frames = anim_frames_per_col;
938 graphic_info[graphic].anim_frames = 1;
940 graphic_info[graphic].anim_frames_per_line =
941 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
942 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
944 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
945 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
946 graphic_info[graphic].anim_delay = 1;
948 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
950 if (graphic_info[graphic].anim_frames == 1)
951 graphic_info[graphic].anim_mode = ANIM_NONE;
954 /* automatically determine correct start frame, if not defined */
955 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
956 graphic_info[graphic].anim_start_frame = 0;
957 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
958 graphic_info[graphic].anim_start_frame =
959 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
961 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
963 /* animation synchronized with global frame counter, not move position */
964 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
966 /* optional element for cloning crumble graphics */
967 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
968 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
970 /* optional element for cloning digging graphics */
971 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
972 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
974 /* optional border size for "crumbling" diggable graphics */
975 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
976 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
978 /* this is only used for player "boring" and "sleeping" actions */
979 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
980 graphic_info[graphic].anim_delay_fixed =
981 parameter[GFX_ARG_ANIM_DELAY_FIXED];
982 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
983 graphic_info[graphic].anim_delay_random =
984 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
985 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
986 graphic_info[graphic].post_delay_fixed =
987 parameter[GFX_ARG_POST_DELAY_FIXED];
988 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
989 graphic_info[graphic].post_delay_random =
990 parameter[GFX_ARG_POST_DELAY_RANDOM];
992 /* this is only used for toon animations */
993 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
994 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
996 /* this is only used for drawing font characters */
997 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
998 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1000 /* this is only used for drawing envelope graphics */
1001 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1004 static void InitGraphicInfo()
1006 int fallback_graphic = IMG_CHAR_EXCLAM;
1007 int num_images = getImageListSize();
1010 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1011 static boolean clipmasks_initialized = FALSE;
1013 XGCValues clip_gc_values;
1014 unsigned long clip_gc_valuemask;
1015 GC copy_clipmask_gc = None;
1018 checked_free(graphic_info);
1020 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1022 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1023 if (clipmasks_initialized)
1025 for (i = 0; i < num_images; i++)
1027 if (graphic_info[i].clip_mask)
1028 XFreePixmap(display, graphic_info[i].clip_mask);
1029 if (graphic_info[i].clip_gc)
1030 XFreeGC(display, graphic_info[i].clip_gc);
1032 graphic_info[i].clip_mask = None;
1033 graphic_info[i].clip_gc = None;
1038 for (i = 0; i < num_images; i++)
1042 int first_frame, last_frame;
1043 int src_bitmap_width, src_bitmap_height;
1046 printf("::: image # %d: '%s' ['%s']\n",
1047 i, image->token, getTokenFromImageID(i));
1050 set_graphic_parameters(i, i);
1052 /* now check if no animation frames are outside of the loaded image */
1054 if (graphic_info[i].bitmap == NULL)
1055 continue; /* skip check for optional images that are undefined */
1057 /* get final bitmap size (with scaling, but without small images) */
1058 src_bitmap_width = get_scaled_graphic_width(i);
1059 src_bitmap_height = get_scaled_graphic_height(i);
1062 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1063 if (src_x < 0 || src_y < 0 ||
1064 src_x + TILEX > src_bitmap_width ||
1065 src_y + TILEY > src_bitmap_height)
1067 Error(ERR_RETURN_LINE, "-");
1068 Error(ERR_RETURN, "warning: error found in config file:");
1069 Error(ERR_RETURN, "- config file: '%s'",
1070 getImageConfigFilename());
1071 Error(ERR_RETURN, "- config token: '%s'",
1072 getTokenFromImageID(i));
1073 Error(ERR_RETURN, "- image file: '%s'",
1074 src_bitmap->source_filename);
1076 "error: first animation frame out of bounds (%d, %d)",
1078 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1080 if (i == fallback_graphic)
1081 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1083 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1084 Error(ERR_RETURN_LINE, "-");
1086 set_graphic_parameters(i, fallback_graphic);
1089 last_frame = graphic_info[i].anim_frames - 1;
1090 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1091 if (src_x < 0 || src_y < 0 ||
1092 src_x + TILEX > src_bitmap_width ||
1093 src_y + TILEY > src_bitmap_height)
1095 Error(ERR_RETURN_LINE, "-");
1096 Error(ERR_RETURN, "warning: error found in config file:");
1097 Error(ERR_RETURN, "- config file: '%s'",
1098 getImageConfigFilename());
1099 Error(ERR_RETURN, "- config token: '%s'",
1100 getTokenFromImageID(i));
1101 Error(ERR_RETURN, "- image file: '%s'",
1102 src_bitmap->source_filename);
1104 "error: last animation frame (%d) out of bounds (%d, %d)",
1105 last_frame, src_x, src_y);
1106 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1108 if (i == fallback_graphic)
1109 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1111 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1112 Error(ERR_RETURN_LINE, "-");
1114 set_graphic_parameters(i, fallback_graphic);
1117 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1118 /* currently we only need a tile clip mask from the first frame */
1119 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1121 if (copy_clipmask_gc == None)
1123 clip_gc_values.graphics_exposures = False;
1124 clip_gc_valuemask = GCGraphicsExposures;
1125 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1126 clip_gc_valuemask, &clip_gc_values);
1129 graphic_info[i].clip_mask =
1130 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1132 src_pixmap = src_bitmap->clip_mask;
1133 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1134 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1136 clip_gc_values.graphics_exposures = False;
1137 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1138 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1140 graphic_info[i].clip_gc =
1141 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1145 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1146 if (copy_clipmask_gc)
1147 XFreeGC(display, copy_clipmask_gc);
1149 clipmasks_initialized = TRUE;
1153 static void InitElementSoundInfo()
1155 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1156 int num_property_mappings = getSoundListPropertyMappingSize();
1159 /* set values to -1 to identify later as "uninitialized" values */
1160 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1161 for (act = 0; act < NUM_ACTIONS; act++)
1162 element_info[i].sound[act] = -1;
1164 /* initialize element/sound mapping from static configuration */
1165 for (i = 0; element_to_sound[i].element > -1; i++)
1167 int element = element_to_sound[i].element;
1168 int action = element_to_sound[i].action;
1169 int sound = element_to_sound[i].sound;
1170 boolean is_class = element_to_sound[i].is_class;
1173 action = ACTION_DEFAULT;
1176 element_info[element].sound[action] = sound;
1178 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1179 if (strcmp(element_info[j].class_name,
1180 element_info[element].class_name) == 0)
1181 element_info[j].sound[action] = sound;
1184 /* initialize element class/sound mapping from dynamic configuration */
1185 for (i = 0; i < num_property_mappings; i++)
1187 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1188 int action = property_mapping[i].ext1_index;
1189 int sound = property_mapping[i].artwork_index;
1191 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1195 action = ACTION_DEFAULT;
1197 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1198 if (strcmp(element_info[j].class_name,
1199 element_info[element_class].class_name) == 0)
1200 element_info[j].sound[action] = sound;
1203 /* initialize element/sound mapping from dynamic configuration */
1204 for (i = 0; i < num_property_mappings; i++)
1206 int element = property_mapping[i].base_index;
1207 int action = property_mapping[i].ext1_index;
1208 int sound = property_mapping[i].artwork_index;
1210 if (element >= MAX_NUM_ELEMENTS)
1214 action = ACTION_DEFAULT;
1216 element_info[element].sound[action] = sound;
1219 /* now set all '-1' values to element specific default values */
1220 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1222 for (act = 0; act < NUM_ACTIONS; act++)
1224 /* generic default action sound (defined by "[default]" directive) */
1225 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1227 /* look for special default action sound (classic game specific) */
1228 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1229 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1230 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1231 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1232 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1233 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1235 /* !!! there's no such thing as a "default action sound" !!! */
1237 /* look for element specific default sound (independent from action) */
1238 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1239 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1243 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1244 /* !!! make this better !!! */
1245 if (i == EL_EMPTY_SPACE)
1246 default_action_sound = element_info[EL_DEFAULT].sound[act];
1249 /* no sound for this specific action -- use default action sound */
1250 if (element_info[i].sound[act] == -1)
1251 element_info[i].sound[act] = default_action_sound;
1255 /* copy sound settings to some elements that are only stored in level file
1256 in native R'n'D levels, but are used by game engine in native EM levels */
1257 for (i = 0; copy_properties[i][0] != -1; i++)
1258 for (j = 1; j <= 4; j++)
1259 for (act = 0; act < NUM_ACTIONS; act++)
1260 element_info[copy_properties[i][j]].sound[act] =
1261 element_info[copy_properties[i][0]].sound[act];
1264 static void InitGameModeSoundInfo()
1268 /* set values to -1 to identify later as "uninitialized" values */
1269 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1272 /* initialize gamemode/sound mapping from static configuration */
1273 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1275 int gamemode = gamemode_to_sound[i].gamemode;
1276 int sound = gamemode_to_sound[i].sound;
1279 gamemode = GAME_MODE_DEFAULT;
1281 menu.sound[gamemode] = sound;
1284 /* now set all '-1' values to levelset specific default values */
1285 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1286 if (menu.sound[i] == -1)
1287 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1290 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1291 if (menu.sound[i] != -1)
1292 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1296 static void set_sound_parameters(int sound, char **parameter_raw)
1298 int parameter[NUM_SND_ARGS];
1301 /* get integer values from string parameters */
1302 for (i = 0; i < NUM_SND_ARGS; i++)
1304 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1305 sound_config_suffix[i].type);
1307 /* explicit loop mode setting in configuration overrides default value */
1308 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1309 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1311 /* sound volume to change the original volume when loading the sound file */
1312 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1314 /* sound priority to give certain sounds a higher or lower priority */
1315 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1318 static void InitSoundInfo()
1320 int *sound_effect_properties;
1321 int num_sounds = getSoundListSize();
1324 checked_free(sound_info);
1326 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1327 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1329 /* initialize sound effect for all elements to "no sound" */
1330 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1331 for (j = 0; j < NUM_ACTIONS; j++)
1332 element_info[i].sound[j] = SND_UNDEFINED;
1334 for (i = 0; i < num_sounds; i++)
1336 struct FileInfo *sound = getSoundListEntry(i);
1337 int len_effect_text = strlen(sound->token);
1339 sound_effect_properties[i] = ACTION_OTHER;
1340 sound_info[i].loop = FALSE; /* default: play sound only once */
1343 printf("::: sound %d: '%s'\n", i, sound->token);
1346 /* determine all loop sounds and identify certain sound classes */
1348 for (j = 0; element_action_info[j].suffix; j++)
1350 int len_action_text = strlen(element_action_info[j].suffix);
1352 if (len_action_text < len_effect_text &&
1353 strcmp(&sound->token[len_effect_text - len_action_text],
1354 element_action_info[j].suffix) == 0)
1356 sound_effect_properties[i] = element_action_info[j].value;
1357 sound_info[i].loop = element_action_info[j].is_loop_sound;
1363 /* associate elements and some selected sound actions */
1365 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1367 if (element_info[j].class_name)
1369 int len_class_text = strlen(element_info[j].class_name);
1371 if (len_class_text + 1 < len_effect_text &&
1372 strncmp(sound->token,
1373 element_info[j].class_name, len_class_text) == 0 &&
1374 sound->token[len_class_text] == '.')
1376 int sound_action_value = sound_effect_properties[i];
1378 element_info[j].sound[sound_action_value] = i;
1383 set_sound_parameters(i, sound->parameter);
1386 free(sound_effect_properties);
1389 static void InitGameModeMusicInfo()
1391 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1392 int num_property_mappings = getMusicListPropertyMappingSize();
1393 int default_levelset_music = -1;
1396 /* set values to -1 to identify later as "uninitialized" values */
1397 for (i = 0; i < MAX_LEVELS; i++)
1398 levelset.music[i] = -1;
1399 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1402 /* initialize gamemode/music mapping from static configuration */
1403 for (i = 0; gamemode_to_music[i].music > -1; i++)
1405 int gamemode = gamemode_to_music[i].gamemode;
1406 int music = gamemode_to_music[i].music;
1409 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1413 gamemode = GAME_MODE_DEFAULT;
1415 menu.music[gamemode] = music;
1418 /* initialize gamemode/music mapping from dynamic configuration */
1419 for (i = 0; i < num_property_mappings; i++)
1421 int prefix = property_mapping[i].base_index;
1422 int gamemode = property_mapping[i].ext1_index;
1423 int level = property_mapping[i].ext2_index;
1424 int music = property_mapping[i].artwork_index;
1427 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1428 prefix, gamemode, level, music);
1431 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1435 gamemode = GAME_MODE_DEFAULT;
1437 /* level specific music only allowed for in-game music */
1438 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1439 gamemode = GAME_MODE_PLAYING;
1444 default_levelset_music = music;
1447 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1448 levelset.music[level] = music;
1449 if (gamemode != GAME_MODE_PLAYING)
1450 menu.music[gamemode] = music;
1453 /* now set all '-1' values to menu specific default values */
1454 /* (undefined values of "levelset.music[]" might stay at "-1" to
1455 allow dynamic selection of music files from music directory!) */
1456 for (i = 0; i < MAX_LEVELS; i++)
1457 if (levelset.music[i] == -1)
1458 levelset.music[i] = default_levelset_music;
1459 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1460 if (menu.music[i] == -1)
1461 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1464 for (i = 0; i < MAX_LEVELS; i++)
1465 if (levelset.music[i] != -1)
1466 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1467 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1468 if (menu.music[i] != -1)
1469 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1473 static void set_music_parameters(int music, char **parameter_raw)
1475 int parameter[NUM_MUS_ARGS];
1478 /* get integer values from string parameters */
1479 for (i = 0; i < NUM_MUS_ARGS; i++)
1481 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1482 music_config_suffix[i].type);
1484 /* explicit loop mode setting in configuration overrides default value */
1485 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1486 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1489 static void InitMusicInfo()
1491 int num_music = getMusicListSize();
1494 checked_free(music_info);
1496 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1498 for (i = 0; i < num_music; i++)
1500 struct FileInfo *music = getMusicListEntry(i);
1501 int len_music_text = strlen(music->token);
1503 music_info[i].loop = TRUE; /* default: play music in loop mode */
1505 /* determine all loop music */
1507 for (j = 0; music_prefix_info[j].prefix; j++)
1509 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1511 if (len_prefix_text < len_music_text &&
1512 strncmp(music->token,
1513 music_prefix_info[j].prefix, len_prefix_text) == 0)
1515 music_info[i].loop = music_prefix_info[j].is_loop_music;
1521 set_music_parameters(i, music->parameter);
1525 static void ReinitializeGraphics()
1527 InitGraphicInfo(); /* graphic properties mapping */
1528 InitElementGraphicInfo(); /* element game graphic mapping */
1529 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1531 InitElementSmallImages(); /* scale images to all needed sizes */
1532 InitFontGraphicInfo(); /* initialize text drawing functions */
1534 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1536 SetMainBackgroundImage(IMG_BACKGROUND);
1537 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1543 static void ReinitializeSounds()
1545 InitSoundInfo(); /* sound properties mapping */
1546 InitElementSoundInfo(); /* element game sound mapping */
1547 InitGameModeSoundInfo(); /* game mode sound mapping */
1549 InitPlayLevelSound(); /* internal game sound settings */
1552 static void ReinitializeMusic()
1554 InitMusicInfo(); /* music properties mapping */
1555 InitGameModeMusicInfo(); /* game mode music mapping */
1558 static int get_special_property_bit(int element, int property_bit_nr)
1560 struct PropertyBitInfo
1566 static struct PropertyBitInfo pb_can_move_into_acid[] =
1568 /* the player may be able fall into acid when gravity is activated */
1573 { EL_SP_MURPHY, 0 },
1574 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1576 /* all element that can move may be able to also move into acid */
1579 { EL_BUG_RIGHT, 1 },
1582 { EL_SPACESHIP, 2 },
1583 { EL_SPACESHIP_LEFT, 2 },
1584 { EL_SPACESHIP_RIGHT, 2 },
1585 { EL_SPACESHIP_UP, 2 },
1586 { EL_SPACESHIP_DOWN, 2 },
1587 { EL_BD_BUTTERFLY, 3 },
1588 { EL_BD_BUTTERFLY_LEFT, 3 },
1589 { EL_BD_BUTTERFLY_RIGHT, 3 },
1590 { EL_BD_BUTTERFLY_UP, 3 },
1591 { EL_BD_BUTTERFLY_DOWN, 3 },
1592 { EL_BD_FIREFLY, 4 },
1593 { EL_BD_FIREFLY_LEFT, 4 },
1594 { EL_BD_FIREFLY_RIGHT, 4 },
1595 { EL_BD_FIREFLY_UP, 4 },
1596 { EL_BD_FIREFLY_DOWN, 4 },
1598 { EL_DARK_YAMYAM, 6 },
1601 { EL_PACMAN_LEFT, 8 },
1602 { EL_PACMAN_RIGHT, 8 },
1603 { EL_PACMAN_UP, 8 },
1604 { EL_PACMAN_DOWN, 8 },
1606 { EL_MOLE_LEFT, 9 },
1607 { EL_MOLE_RIGHT, 9 },
1609 { EL_MOLE_DOWN, 9 },
1613 { EL_SATELLITE, 13 },
1614 { EL_SP_SNIKSNAK, 14 },
1615 { EL_SP_ELECTRON, 15 },
1622 static struct PropertyBitInfo pb_dont_collide_with[] =
1624 { EL_SP_SNIKSNAK, 0 },
1625 { EL_SP_ELECTRON, 1 },
1633 struct PropertyBitInfo *pb_info;
1636 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1637 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1642 struct PropertyBitInfo *pb_info = NULL;
1645 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1646 if (pb_definition[i].bit_nr == property_bit_nr)
1647 pb_info = pb_definition[i].pb_info;
1649 if (pb_info == NULL)
1652 for (i = 0; pb_info[i].element != -1; i++)
1653 if (pb_info[i].element == element)
1654 return pb_info[i].bit_nr;
1659 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1660 boolean property_value)
1662 int bit_nr = get_special_property_bit(element, property_bit_nr);
1667 *bitfield |= (1 << bit_nr);
1669 *bitfield &= ~(1 << bit_nr);
1673 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1675 int bit_nr = get_special_property_bit(element, property_bit_nr);
1678 return ((*bitfield & (1 << bit_nr)) != 0);
1683 void InitElementPropertiesStatic()
1685 static int ep_diggable[] =
1690 EL_SP_BUGGY_BASE_ACTIVATING,
1693 EL_INVISIBLE_SAND_ACTIVE,
1696 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1697 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1701 EL_SP_BUGGY_BASE_ACTIVE,
1707 static int ep_collectible_only[] =
1728 EL_DYNABOMB_INCREASE_NUMBER,
1729 EL_DYNABOMB_INCREASE_SIZE,
1730 EL_DYNABOMB_INCREASE_POWER,
1749 static int ep_dont_run_into[] =
1751 /* same elements as in 'ep_dont_touch' */
1757 /* same elements as in 'ep_dont_collide_with' */
1769 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1773 EL_SP_BUGGY_BASE_ACTIVE,
1779 static int ep_dont_collide_with[] =
1781 /* same elements as in 'ep_dont_touch' */
1797 static int ep_dont_touch[] =
1806 static int ep_indestructible[] =
1810 EL_ACID_POOL_TOPLEFT,
1811 EL_ACID_POOL_TOPRIGHT,
1812 EL_ACID_POOL_BOTTOMLEFT,
1813 EL_ACID_POOL_BOTTOM,
1814 EL_ACID_POOL_BOTTOMRIGHT,
1815 EL_SP_HARDWARE_GRAY,
1816 EL_SP_HARDWARE_GREEN,
1817 EL_SP_HARDWARE_BLUE,
1819 EL_SP_HARDWARE_YELLOW,
1820 EL_SP_HARDWARE_BASE_1,
1821 EL_SP_HARDWARE_BASE_2,
1822 EL_SP_HARDWARE_BASE_3,
1823 EL_SP_HARDWARE_BASE_4,
1824 EL_SP_HARDWARE_BASE_5,
1825 EL_SP_HARDWARE_BASE_6,
1826 EL_INVISIBLE_STEELWALL,
1827 EL_INVISIBLE_STEELWALL_ACTIVE,
1828 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1829 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1830 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1831 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1832 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1833 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1834 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1835 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1836 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1837 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1838 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1839 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1841 EL_LIGHT_SWITCH_ACTIVE,
1842 EL_SIGN_EXCLAMATION,
1843 EL_SIGN_RADIOACTIVITY,
1854 EL_STEELWALL_SLIPPERY,
1885 EL_SWITCHGATE_OPENING,
1886 EL_SWITCHGATE_CLOSED,
1887 EL_SWITCHGATE_CLOSING,
1889 EL_SWITCHGATE_SWITCH_UP,
1890 EL_SWITCHGATE_SWITCH_DOWN,
1893 EL_TIMEGATE_OPENING,
1895 EL_TIMEGATE_CLOSING,
1898 EL_TIMEGATE_SWITCH_ACTIVE,
1903 EL_TUBE_VERTICAL_LEFT,
1904 EL_TUBE_VERTICAL_RIGHT,
1905 EL_TUBE_HORIZONTAL_UP,
1906 EL_TUBE_HORIZONTAL_DOWN,
1914 static int ep_slippery[] =
1928 EL_ROBOT_WHEEL_ACTIVE,
1934 EL_ACID_POOL_TOPLEFT,
1935 EL_ACID_POOL_TOPRIGHT,
1945 EL_STEELWALL_SLIPPERY,
1948 EL_EMC_WALL_SLIPPERY_1,
1949 EL_EMC_WALL_SLIPPERY_2,
1950 EL_EMC_WALL_SLIPPERY_3,
1951 EL_EMC_WALL_SLIPPERY_4,
1955 static int ep_can_change[] =
1960 static int ep_can_move[] =
1962 /* same elements as in 'pb_can_move_into_acid' */
1984 static int ep_can_fall[] =
1999 EL_BD_MAGIC_WALL_FULL,
2012 static int ep_can_smash_player[] =
2037 static int ep_can_smash_enemies[] =
2045 static int ep_can_smash_everything[] =
2053 static int ep_explodes_by_fire[] =
2055 /* same elements as in 'ep_explodes_impact' */
2060 /* same elements as in 'ep_explodes_smashed' */
2069 EL_DYNABOMB_PLAYER_1_ACTIVE,
2070 EL_DYNABOMB_PLAYER_2_ACTIVE,
2071 EL_DYNABOMB_PLAYER_3_ACTIVE,
2072 EL_DYNABOMB_PLAYER_4_ACTIVE,
2073 EL_DYNABOMB_INCREASE_NUMBER,
2074 EL_DYNABOMB_INCREASE_SIZE,
2075 EL_DYNABOMB_INCREASE_POWER,
2076 EL_SP_DISK_RED_ACTIVE,
2089 static int ep_explodes_smashed[] =
2091 /* same elements as in 'ep_explodes_impact' */
2104 static int ep_explodes_impact[] =
2112 static int ep_walkable_over[] =
2116 EL_SOKOBAN_FIELD_EMPTY,
2134 static int ep_walkable_inside[] =
2139 EL_TUBE_VERTICAL_LEFT,
2140 EL_TUBE_VERTICAL_RIGHT,
2141 EL_TUBE_HORIZONTAL_UP,
2142 EL_TUBE_HORIZONTAL_DOWN,
2150 static int ep_walkable_under[] =
2155 static int ep_passable_over[] =
2178 static int ep_passable_inside[] =
2184 EL_SP_PORT_HORIZONTAL,
2185 EL_SP_PORT_VERTICAL,
2187 EL_SP_GRAVITY_PORT_LEFT,
2188 EL_SP_GRAVITY_PORT_RIGHT,
2189 EL_SP_GRAVITY_PORT_UP,
2190 EL_SP_GRAVITY_PORT_DOWN,
2191 EL_SP_GRAVITY_ON_PORT_LEFT,
2192 EL_SP_GRAVITY_ON_PORT_RIGHT,
2193 EL_SP_GRAVITY_ON_PORT_UP,
2194 EL_SP_GRAVITY_ON_PORT_DOWN,
2195 EL_SP_GRAVITY_OFF_PORT_LEFT,
2196 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2197 EL_SP_GRAVITY_OFF_PORT_UP,
2198 EL_SP_GRAVITY_OFF_PORT_DOWN,
2202 static int ep_passable_under[] =
2207 static int ep_droppable[] =
2212 static int ep_explodes_1x1_old[] =
2217 static int ep_pushable[] =
2229 EL_SOKOBAN_FIELD_FULL,
2237 static int ep_explodes_cross_old[] =
2242 static int ep_protected[] =
2244 /* same elements as in 'ep_walkable_inside' */
2248 EL_TUBE_VERTICAL_LEFT,
2249 EL_TUBE_VERTICAL_RIGHT,
2250 EL_TUBE_HORIZONTAL_UP,
2251 EL_TUBE_HORIZONTAL_DOWN,
2257 /* same elements as in 'ep_passable_over' */
2277 /* same elements as in 'ep_passable_inside' */
2282 EL_SP_PORT_HORIZONTAL,
2283 EL_SP_PORT_VERTICAL,
2285 EL_SP_GRAVITY_PORT_LEFT,
2286 EL_SP_GRAVITY_PORT_RIGHT,
2287 EL_SP_GRAVITY_PORT_UP,
2288 EL_SP_GRAVITY_PORT_DOWN,
2289 EL_SP_GRAVITY_ON_PORT_LEFT,
2290 EL_SP_GRAVITY_ON_PORT_RIGHT,
2291 EL_SP_GRAVITY_ON_PORT_UP,
2292 EL_SP_GRAVITY_ON_PORT_DOWN,
2293 EL_SP_GRAVITY_OFF_PORT_LEFT,
2294 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2295 EL_SP_GRAVITY_OFF_PORT_UP,
2296 EL_SP_GRAVITY_OFF_PORT_DOWN,
2300 static int ep_throwable[] =
2305 static int ep_can_explode[] =
2307 /* same elements as in 'ep_explodes_impact' */
2312 /* same elements as in 'ep_explodes_smashed' */
2318 /* elements that can explode by explosion or by dragonfire */
2321 EL_DYNABOMB_PLAYER_1_ACTIVE,
2322 EL_DYNABOMB_PLAYER_2_ACTIVE,
2323 EL_DYNABOMB_PLAYER_3_ACTIVE,
2324 EL_DYNABOMB_PLAYER_4_ACTIVE,
2325 EL_DYNABOMB_INCREASE_NUMBER,
2326 EL_DYNABOMB_INCREASE_SIZE,
2327 EL_DYNABOMB_INCREASE_POWER,
2328 EL_SP_DISK_RED_ACTIVE,
2336 /* elements that can explode only by explosion */
2341 static int ep_gravity_reachable[] =
2347 EL_INVISIBLE_SAND_ACTIVE,
2352 EL_SP_PORT_HORIZONTAL,
2353 EL_SP_PORT_VERTICAL,
2355 EL_SP_GRAVITY_PORT_LEFT,
2356 EL_SP_GRAVITY_PORT_RIGHT,
2357 EL_SP_GRAVITY_PORT_UP,
2358 EL_SP_GRAVITY_PORT_DOWN,
2359 EL_SP_GRAVITY_ON_PORT_LEFT,
2360 EL_SP_GRAVITY_ON_PORT_RIGHT,
2361 EL_SP_GRAVITY_ON_PORT_UP,
2362 EL_SP_GRAVITY_ON_PORT_DOWN,
2363 EL_SP_GRAVITY_OFF_PORT_LEFT,
2364 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2365 EL_SP_GRAVITY_OFF_PORT_UP,
2366 EL_SP_GRAVITY_OFF_PORT_DOWN,
2371 static int ep_player[] =
2378 EL_SOKOBAN_FIELD_PLAYER,
2383 static int ep_can_pass_magic_wall[] =
2396 static int ep_switchable[] =
2400 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2401 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2402 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2403 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2404 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2405 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2406 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2407 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2408 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2409 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2410 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2411 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2412 EL_SWITCHGATE_SWITCH_UP,
2413 EL_SWITCHGATE_SWITCH_DOWN,
2415 EL_LIGHT_SWITCH_ACTIVE,
2417 EL_BALLOON_SWITCH_LEFT,
2418 EL_BALLOON_SWITCH_RIGHT,
2419 EL_BALLOON_SWITCH_UP,
2420 EL_BALLOON_SWITCH_DOWN,
2421 EL_BALLOON_SWITCH_ANY,
2424 EL_EMC_MAGIC_BALL_SWITCH,
2428 static int ep_bd_element[] =
2461 static int ep_sp_element[] =
2463 /* should always be valid */
2466 /* standard classic Supaplex elements */
2473 EL_SP_HARDWARE_GRAY,
2481 EL_SP_GRAVITY_PORT_RIGHT,
2482 EL_SP_GRAVITY_PORT_DOWN,
2483 EL_SP_GRAVITY_PORT_LEFT,
2484 EL_SP_GRAVITY_PORT_UP,
2489 EL_SP_PORT_VERTICAL,
2490 EL_SP_PORT_HORIZONTAL,
2496 EL_SP_HARDWARE_BASE_1,
2497 EL_SP_HARDWARE_GREEN,
2498 EL_SP_HARDWARE_BLUE,
2500 EL_SP_HARDWARE_YELLOW,
2501 EL_SP_HARDWARE_BASE_2,
2502 EL_SP_HARDWARE_BASE_3,
2503 EL_SP_HARDWARE_BASE_4,
2504 EL_SP_HARDWARE_BASE_5,
2505 EL_SP_HARDWARE_BASE_6,
2509 /* additional elements that appeared in newer Supaplex levels */
2512 /* additional gravity port elements (not switching, but setting gravity) */
2513 EL_SP_GRAVITY_ON_PORT_LEFT,
2514 EL_SP_GRAVITY_ON_PORT_RIGHT,
2515 EL_SP_GRAVITY_ON_PORT_UP,
2516 EL_SP_GRAVITY_ON_PORT_DOWN,
2517 EL_SP_GRAVITY_OFF_PORT_LEFT,
2518 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2519 EL_SP_GRAVITY_OFF_PORT_UP,
2520 EL_SP_GRAVITY_OFF_PORT_DOWN,
2522 /* more than one Murphy in a level results in an inactive clone */
2525 /* runtime Supaplex elements */
2526 EL_SP_DISK_RED_ACTIVE,
2527 EL_SP_TERMINAL_ACTIVE,
2528 EL_SP_BUGGY_BASE_ACTIVATING,
2529 EL_SP_BUGGY_BASE_ACTIVE,
2535 static int ep_sb_element[] =
2540 EL_SOKOBAN_FIELD_EMPTY,
2541 EL_SOKOBAN_FIELD_FULL,
2542 EL_SOKOBAN_FIELD_PLAYER,
2547 EL_INVISIBLE_STEELWALL,
2551 static int ep_gem[] =
2562 static int ep_food_dark_yamyam[] =
2589 static int ep_food_penguin[] =
2602 static int ep_food_pig[] =
2613 static int ep_historic_wall[] =
2638 EL_EXPANDABLE_WALL_HORIZONTAL,
2639 EL_EXPANDABLE_WALL_VERTICAL,
2640 EL_EXPANDABLE_WALL_ANY,
2641 EL_EXPANDABLE_WALL_GROWING,
2648 EL_SP_HARDWARE_GRAY,
2649 EL_SP_HARDWARE_GREEN,
2650 EL_SP_HARDWARE_BLUE,
2652 EL_SP_HARDWARE_YELLOW,
2653 EL_SP_HARDWARE_BASE_1,
2654 EL_SP_HARDWARE_BASE_2,
2655 EL_SP_HARDWARE_BASE_3,
2656 EL_SP_HARDWARE_BASE_4,
2657 EL_SP_HARDWARE_BASE_5,
2658 EL_SP_HARDWARE_BASE_6,
2660 EL_SP_TERMINAL_ACTIVE,
2663 EL_INVISIBLE_STEELWALL,
2664 EL_INVISIBLE_STEELWALL_ACTIVE,
2666 EL_INVISIBLE_WALL_ACTIVE,
2667 EL_STEELWALL_SLIPPERY,
2683 static int ep_historic_solid[] =
2687 EL_EXPANDABLE_WALL_HORIZONTAL,
2688 EL_EXPANDABLE_WALL_VERTICAL,
2689 EL_EXPANDABLE_WALL_ANY,
2702 EL_QUICKSAND_FILLING,
2703 EL_QUICKSAND_EMPTYING,
2705 EL_MAGIC_WALL_ACTIVE,
2706 EL_MAGIC_WALL_EMPTYING,
2707 EL_MAGIC_WALL_FILLING,
2711 EL_BD_MAGIC_WALL_ACTIVE,
2712 EL_BD_MAGIC_WALL_EMPTYING,
2713 EL_BD_MAGIC_WALL_FULL,
2714 EL_BD_MAGIC_WALL_FILLING,
2715 EL_BD_MAGIC_WALL_DEAD,
2724 EL_SP_TERMINAL_ACTIVE,
2728 EL_INVISIBLE_WALL_ACTIVE,
2729 EL_SWITCHGATE_SWITCH_UP,
2730 EL_SWITCHGATE_SWITCH_DOWN,
2732 EL_TIMEGATE_SWITCH_ACTIVE,
2744 /* the following elements are a direct copy of "indestructible" elements,
2745 except "EL_ACID", which is "indestructible", but not "solid"! */
2750 EL_ACID_POOL_TOPLEFT,
2751 EL_ACID_POOL_TOPRIGHT,
2752 EL_ACID_POOL_BOTTOMLEFT,
2753 EL_ACID_POOL_BOTTOM,
2754 EL_ACID_POOL_BOTTOMRIGHT,
2755 EL_SP_HARDWARE_GRAY,
2756 EL_SP_HARDWARE_GREEN,
2757 EL_SP_HARDWARE_BLUE,
2759 EL_SP_HARDWARE_YELLOW,
2760 EL_SP_HARDWARE_BASE_1,
2761 EL_SP_HARDWARE_BASE_2,
2762 EL_SP_HARDWARE_BASE_3,
2763 EL_SP_HARDWARE_BASE_4,
2764 EL_SP_HARDWARE_BASE_5,
2765 EL_SP_HARDWARE_BASE_6,
2766 EL_INVISIBLE_STEELWALL,
2767 EL_INVISIBLE_STEELWALL_ACTIVE,
2768 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2769 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2770 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2771 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2772 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2773 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2774 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2775 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2776 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2777 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2778 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2779 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2781 EL_LIGHT_SWITCH_ACTIVE,
2782 EL_SIGN_EXCLAMATION,
2783 EL_SIGN_RADIOACTIVITY,
2794 EL_STEELWALL_SLIPPERY,
2817 EL_SWITCHGATE_OPENING,
2818 EL_SWITCHGATE_CLOSED,
2819 EL_SWITCHGATE_CLOSING,
2821 EL_TIMEGATE_OPENING,
2823 EL_TIMEGATE_CLOSING,
2827 EL_TUBE_VERTICAL_LEFT,
2828 EL_TUBE_VERTICAL_RIGHT,
2829 EL_TUBE_HORIZONTAL_UP,
2830 EL_TUBE_HORIZONTAL_DOWN,
2838 static int ep_classic_enemy[] =
2854 static int ep_belt[] =
2856 EL_CONVEYOR_BELT_1_LEFT,
2857 EL_CONVEYOR_BELT_1_MIDDLE,
2858 EL_CONVEYOR_BELT_1_RIGHT,
2859 EL_CONVEYOR_BELT_2_LEFT,
2860 EL_CONVEYOR_BELT_2_MIDDLE,
2861 EL_CONVEYOR_BELT_2_RIGHT,
2862 EL_CONVEYOR_BELT_3_LEFT,
2863 EL_CONVEYOR_BELT_3_MIDDLE,
2864 EL_CONVEYOR_BELT_3_RIGHT,
2865 EL_CONVEYOR_BELT_4_LEFT,
2866 EL_CONVEYOR_BELT_4_MIDDLE,
2867 EL_CONVEYOR_BELT_4_RIGHT,
2871 static int ep_belt_active[] =
2873 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2874 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2875 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2876 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2877 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2878 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2879 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2880 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2881 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2882 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2883 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2884 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2888 static int ep_belt_switch[] =
2890 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2891 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2892 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2893 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2894 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2895 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2896 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2897 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2898 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2899 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2900 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2901 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2905 static int ep_tube[] =
2912 EL_TUBE_HORIZONTAL_UP,
2913 EL_TUBE_HORIZONTAL_DOWN,
2915 EL_TUBE_VERTICAL_LEFT,
2916 EL_TUBE_VERTICAL_RIGHT,
2921 static int ep_keygate[] =
2950 static int ep_amoeboid[] =
2960 static int ep_amoebalive[] =
2969 static int ep_has_content[] =
2979 static int ep_can_turn_each_move[] =
2981 /* !!! do something with this one !!! */
2985 static int ep_can_grow[] =
2997 static int ep_active_bomb[] =
3000 EL_DYNABOMB_PLAYER_1_ACTIVE,
3001 EL_DYNABOMB_PLAYER_2_ACTIVE,
3002 EL_DYNABOMB_PLAYER_3_ACTIVE,
3003 EL_DYNABOMB_PLAYER_4_ACTIVE,
3004 EL_SP_DISK_RED_ACTIVE,
3008 static int ep_inactive[] =
3057 EL_INVISIBLE_STEELWALL,
3065 EL_WALL_EMERALD_YELLOW,
3066 EL_DYNABOMB_INCREASE_NUMBER,
3067 EL_DYNABOMB_INCREASE_SIZE,
3068 EL_DYNABOMB_INCREASE_POWER,
3072 EL_SOKOBAN_FIELD_EMPTY,
3073 EL_SOKOBAN_FIELD_FULL,
3074 EL_WALL_EMERALD_RED,
3075 EL_WALL_EMERALD_PURPLE,
3076 EL_ACID_POOL_TOPLEFT,
3077 EL_ACID_POOL_TOPRIGHT,
3078 EL_ACID_POOL_BOTTOMLEFT,
3079 EL_ACID_POOL_BOTTOM,
3080 EL_ACID_POOL_BOTTOMRIGHT,
3084 EL_BD_MAGIC_WALL_DEAD,
3085 EL_AMOEBA_TO_DIAMOND,
3093 EL_SP_GRAVITY_PORT_RIGHT,
3094 EL_SP_GRAVITY_PORT_DOWN,
3095 EL_SP_GRAVITY_PORT_LEFT,
3096 EL_SP_GRAVITY_PORT_UP,
3097 EL_SP_PORT_HORIZONTAL,
3098 EL_SP_PORT_VERTICAL,
3109 EL_SP_HARDWARE_GRAY,
3110 EL_SP_HARDWARE_GREEN,
3111 EL_SP_HARDWARE_BLUE,
3113 EL_SP_HARDWARE_YELLOW,
3114 EL_SP_HARDWARE_BASE_1,
3115 EL_SP_HARDWARE_BASE_2,
3116 EL_SP_HARDWARE_BASE_3,
3117 EL_SP_HARDWARE_BASE_4,
3118 EL_SP_HARDWARE_BASE_5,
3119 EL_SP_HARDWARE_BASE_6,
3120 EL_SP_GRAVITY_ON_PORT_LEFT,
3121 EL_SP_GRAVITY_ON_PORT_RIGHT,
3122 EL_SP_GRAVITY_ON_PORT_UP,
3123 EL_SP_GRAVITY_ON_PORT_DOWN,
3124 EL_SP_GRAVITY_OFF_PORT_LEFT,
3125 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3126 EL_SP_GRAVITY_OFF_PORT_UP,
3127 EL_SP_GRAVITY_OFF_PORT_DOWN,
3128 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3129 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3130 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3131 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3132 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3133 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3134 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3135 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3136 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3137 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3138 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3139 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3140 EL_SIGN_EXCLAMATION,
3141 EL_SIGN_RADIOACTIVITY,
3152 EL_STEELWALL_SLIPPERY,
3157 EL_EMC_WALL_SLIPPERY_1,
3158 EL_EMC_WALL_SLIPPERY_2,
3159 EL_EMC_WALL_SLIPPERY_3,
3160 EL_EMC_WALL_SLIPPERY_4,
3180 static int ep_em_slippery_wall[] =
3185 static int ep_gfx_crumbled[] =
3198 } element_properties[] =
3200 { ep_diggable, EP_DIGGABLE },
3201 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3202 { ep_dont_run_into, EP_DONT_RUN_INTO },
3203 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3204 { ep_dont_touch, EP_DONT_TOUCH },
3205 { ep_indestructible, EP_INDESTRUCTIBLE },
3206 { ep_slippery, EP_SLIPPERY },
3207 { ep_can_change, EP_CAN_CHANGE },
3208 { ep_can_move, EP_CAN_MOVE },
3209 { ep_can_fall, EP_CAN_FALL },
3210 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3211 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3212 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3213 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3214 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3215 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3216 { ep_walkable_over, EP_WALKABLE_OVER },
3217 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3218 { ep_walkable_under, EP_WALKABLE_UNDER },
3219 { ep_passable_over, EP_PASSABLE_OVER },
3220 { ep_passable_inside, EP_PASSABLE_INSIDE },
3221 { ep_passable_under, EP_PASSABLE_UNDER },
3222 { ep_droppable, EP_DROPPABLE },
3223 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3224 { ep_pushable, EP_PUSHABLE },
3225 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3226 { ep_protected, EP_PROTECTED },
3227 { ep_throwable, EP_THROWABLE },
3228 { ep_can_explode, EP_CAN_EXPLODE },
3229 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3231 { ep_player, EP_PLAYER },
3232 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3233 { ep_switchable, EP_SWITCHABLE },
3234 { ep_bd_element, EP_BD_ELEMENT },
3235 { ep_sp_element, EP_SP_ELEMENT },
3236 { ep_sb_element, EP_SB_ELEMENT },
3238 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3239 { ep_food_penguin, EP_FOOD_PENGUIN },
3240 { ep_food_pig, EP_FOOD_PIG },
3241 { ep_historic_wall, EP_HISTORIC_WALL },
3242 { ep_historic_solid, EP_HISTORIC_SOLID },
3243 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3244 { ep_belt, EP_BELT },
3245 { ep_belt_active, EP_BELT_ACTIVE },
3246 { ep_belt_switch, EP_BELT_SWITCH },
3247 { ep_tube, EP_TUBE },
3248 { ep_keygate, EP_KEYGATE },
3249 { ep_amoeboid, EP_AMOEBOID },
3250 { ep_amoebalive, EP_AMOEBALIVE },
3251 { ep_has_content, EP_HAS_CONTENT },
3252 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3253 { ep_can_grow, EP_CAN_GROW },
3254 { ep_active_bomb, EP_ACTIVE_BOMB },
3255 { ep_inactive, EP_INACTIVE },
3257 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3259 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3266 /* always start with reliable default values (element has no properties) */
3267 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3268 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3269 SET_PROPERTY(i, j, FALSE);
3271 /* set all base element properties from above array definitions */
3272 for (i = 0; element_properties[i].elements != NULL; i++)
3273 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3274 SET_PROPERTY((element_properties[i].elements)[j],
3275 element_properties[i].property, TRUE);
3277 /* copy properties to some elements that are only stored in level file */
3278 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3279 for (j = 0; copy_properties[j][0] != -1; j++)
3280 if (HAS_PROPERTY(copy_properties[j][0], i))
3281 for (k = 1; k <= 4; k++)
3282 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3285 void InitElementPropertiesEngine(int engine_version)
3287 static int no_wall_properties[] =
3290 EP_COLLECTIBLE_ONLY,
3292 EP_DONT_COLLIDE_WITH,
3295 EP_CAN_SMASH_PLAYER,
3296 EP_CAN_SMASH_ENEMIES,
3297 EP_CAN_SMASH_EVERYTHING,
3302 EP_FOOD_DARK_YAMYAM,
3318 /* important: after initialization in InitElementPropertiesStatic(), the
3319 elements are not again initialized to a default value; therefore all
3320 changes have to make sure that they leave the element with a defined
3321 property (which means that conditional property changes must be set to
3322 a reliable default value before) */
3324 /* set all special, combined or engine dependent element properties */
3325 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3327 /* ---------- INACTIVE ------------------------------------------------- */
3328 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3330 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3331 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3332 IS_WALKABLE_INSIDE(i) ||
3333 IS_WALKABLE_UNDER(i)));
3335 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3336 IS_PASSABLE_INSIDE(i) ||
3337 IS_PASSABLE_UNDER(i)));
3339 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3340 IS_PASSABLE_OVER(i)));
3342 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3343 IS_PASSABLE_INSIDE(i)));
3345 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3346 IS_PASSABLE_UNDER(i)));
3348 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3351 /* ---------- COLLECTIBLE ---------------------------------------------- */
3352 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3356 /* ---------- SNAPPABLE ------------------------------------------------ */
3357 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3358 IS_COLLECTIBLE(i) ||
3362 /* ---------- WALL ----------------------------------------------------- */
3363 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3365 for (j = 0; no_wall_properties[j] != -1; j++)
3366 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3367 i >= EL_FIRST_RUNTIME_UNREAL)
3368 SET_PROPERTY(i, EP_WALL, FALSE);
3370 if (IS_HISTORIC_WALL(i))
3371 SET_PROPERTY(i, EP_WALL, TRUE);
3373 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3374 if (engine_version < VERSION_IDENT(2,2,0,0))
3375 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3377 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3379 !IS_COLLECTIBLE(i)));
3381 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3383 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3384 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3386 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3387 IS_INDESTRUCTIBLE(i)));
3389 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3391 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3392 else if (engine_version < VERSION_IDENT(2,2,0,0))
3393 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3395 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3399 if (IS_CUSTOM_ELEMENT(i))
3401 /* these are additional properties which are initially false when set */
3403 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3405 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3406 if (DONT_COLLIDE_WITH(i))
3407 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3409 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3410 if (CAN_SMASH_EVERYTHING(i))
3411 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3412 if (CAN_SMASH_ENEMIES(i))
3413 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3416 /* ---------- CAN_SMASH ------------------------------------------------ */
3417 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3418 CAN_SMASH_ENEMIES(i) ||
3419 CAN_SMASH_EVERYTHING(i)));
3421 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3422 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3423 EXPLODES_BY_FIRE(i)));
3425 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3426 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3427 EXPLODES_SMASHED(i)));
3429 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3430 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3431 EXPLODES_IMPACT(i)));
3433 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3434 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3436 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3437 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3438 i == EL_BLACK_ORB));
3440 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3441 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3443 IS_CUSTOM_ELEMENT(i)));
3445 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3446 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3447 i == EL_SP_ELECTRON));
3449 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3450 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3451 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3452 getMoveIntoAcidProperty(&level, i));
3454 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3455 if (MAYBE_DONT_COLLIDE_WITH(i))
3456 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3457 getDontCollideWithProperty(&level, i));
3459 /* ---------- SP_PORT -------------------------------------------------- */
3460 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3461 IS_PASSABLE_INSIDE(i)));
3463 /* ---------- CAN_CHANGE ----------------------------------------------- */
3464 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3465 for (j = 0; j < element_info[i].num_change_pages; j++)
3466 if (element_info[i].change_page[j].can_change)
3467 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3469 /* ---------- HAS_ACTION ----------------------------------------------- */
3470 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3471 for (j = 0; j < element_info[i].num_change_pages; j++)
3472 if (element_info[i].change_page[j].has_action)
3473 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3475 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3476 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3479 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3481 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3482 element_info[i].crumbled[ACTION_DEFAULT] !=
3483 element_info[i].graphic[ACTION_DEFAULT]);
3485 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3486 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3487 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3491 /* dynamically adjust element properties according to game engine version */
3493 static int ep_em_slippery_wall[] =
3498 EL_EXPANDABLE_WALL_HORIZONTAL,
3499 EL_EXPANDABLE_WALL_VERTICAL,
3500 EL_EXPANDABLE_WALL_ANY,
3504 /* special EM style gems behaviour */
3505 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3506 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3507 level.em_slippery_gems);
3509 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3510 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3511 (level.em_slippery_gems &&
3512 engine_version > VERSION_IDENT(2,0,1,0)));
3515 /* set default push delay values (corrected since version 3.0.7-1) */
3516 if (engine_version < VERSION_IDENT(3,0,7,1))
3518 game.default_push_delay_fixed = 2;
3519 game.default_push_delay_random = 8;
3523 game.default_push_delay_fixed = 8;
3524 game.default_push_delay_random = 8;
3527 /* set uninitialized push delay values of custom elements in older levels */
3528 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3530 int element = EL_CUSTOM_START + i;
3532 if (element_info[element].push_delay_fixed == -1)
3533 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3534 if (element_info[element].push_delay_random == -1)
3535 element_info[element].push_delay_random = game.default_push_delay_random;
3538 /* set some other uninitialized values of custom elements in older levels */
3539 if (engine_version < VERSION_IDENT(3,1,0,0))
3541 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3543 int element = EL_CUSTOM_START + i;
3545 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3547 element_info[element].explosion_delay = 17;
3548 element_info[element].ignition_delay = 8;
3553 /* set element properties that were handled incorrectly in older levels */
3554 if (engine_version < VERSION_IDENT(3,1,0,0))
3556 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3557 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3561 /* this is needed because some graphics depend on element properties */
3562 if (game_status == GAME_MODE_PLAYING)
3563 InitElementGraphicInfo();
3566 static void InitGlobal()
3570 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3572 /* check if element_name_info entry defined for each element in "main.h" */
3573 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3574 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3576 element_info[i].token_name = element_name_info[i].token_name;
3577 element_info[i].class_name = element_name_info[i].class_name;
3578 element_info[i].editor_description=element_name_info[i].editor_description;
3581 global.autoplay_leveldir = NULL;
3582 global.convert_leveldir = NULL;
3584 global.frames_per_second = 0;
3585 global.fps_slowdown = FALSE;
3586 global.fps_slowdown_factor = 1;
3589 void Execute_Command(char *command)
3593 if (strcmp(command, "print graphicsinfo.conf") == 0)
3595 printf("# You can configure additional/alternative image files here.\n");
3596 printf("# (The entries below are default and therefore commented out.)\n");
3598 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3600 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3603 for (i = 0; image_config[i].token != NULL; i++)
3604 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3605 image_config[i].value));
3609 else if (strcmp(command, "print soundsinfo.conf") == 0)
3611 printf("# You can configure additional/alternative sound files here.\n");
3612 printf("# (The entries below are default and therefore commented out.)\n");
3614 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3616 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3619 for (i = 0; sound_config[i].token != NULL; i++)
3620 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3621 sound_config[i].value));
3625 else if (strcmp(command, "print musicinfo.conf") == 0)
3627 printf("# You can configure additional/alternative music files here.\n");
3628 printf("# (The entries below are default and therefore commented out.)\n");
3630 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3632 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3635 for (i = 0; music_config[i].token != NULL; i++)
3636 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3637 music_config[i].value));
3641 else if (strcmp(command, "print editorsetup.conf") == 0)
3643 printf("# You can configure your personal editor element list here.\n");
3644 printf("# (The entries below are default and therefore commented out.)\n");
3647 PrintEditorElementList();
3651 else if (strcmp(command, "print helpanim.conf") == 0)
3653 printf("# You can configure different element help animations here.\n");
3654 printf("# (The entries below are default and therefore commented out.)\n");
3657 for (i = 0; helpanim_config[i].token != NULL; i++)
3659 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3660 helpanim_config[i].value));
3662 if (strcmp(helpanim_config[i].token, "end") == 0)
3668 else if (strcmp(command, "print helptext.conf") == 0)
3670 printf("# You can configure different element help text here.\n");
3671 printf("# (The entries below are default and therefore commented out.)\n");
3674 for (i = 0; helptext_config[i].token != NULL; i++)
3675 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3676 helptext_config[i].value));
3680 else if (strncmp(command, "dump level ", 11) == 0)
3682 char *filename = &command[11];
3684 if (!fileExists(filename))
3685 Error(ERR_EXIT, "cannot open file '%s'", filename);
3687 LoadLevelFromFilename(&level, filename);
3692 else if (strncmp(command, "dump tape ", 10) == 0)
3694 char *filename = &command[10];
3696 if (!fileExists(filename))
3697 Error(ERR_EXIT, "cannot open file '%s'", filename);
3699 LoadTapeFromFilename(filename);
3704 else if (strncmp(command, "autoplay ", 9) == 0)
3706 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3708 while (*str_ptr != '\0') /* continue parsing string */
3710 /* cut leading whitespace from string, replace it by string terminator */
3711 while (*str_ptr == ' ' || *str_ptr == '\t')
3714 if (*str_ptr == '\0') /* end of string reached */
3717 if (global.autoplay_leveldir == NULL) /* read level set string */
3719 global.autoplay_leveldir = str_ptr;
3720 global.autoplay_all = TRUE; /* default: play all tapes */
3722 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3723 global.autoplay_level[i] = FALSE;
3725 else /* read level number string */
3727 int level_nr = atoi(str_ptr); /* get level_nr value */
3729 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3730 global.autoplay_level[level_nr] = TRUE;
3732 global.autoplay_all = FALSE;
3735 /* advance string pointer to the next whitespace (or end of string) */
3736 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3740 else if (strncmp(command, "convert ", 8) == 0)
3742 char *str_copy = getStringCopy(&command[8]);
3743 char *str_ptr = strchr(str_copy, ' ');
3745 global.convert_leveldir = str_copy;
3746 global.convert_level_nr = -1;
3748 if (str_ptr != NULL) /* level number follows */
3750 *str_ptr++ = '\0'; /* terminate leveldir string */
3751 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3756 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3760 static void InitSetup()
3762 LoadSetup(); /* global setup info */
3764 /* set some options from setup file */
3766 if (setup.options.verbose)
3767 options.verbose = TRUE;
3770 static void InitGameInfo()
3772 game.restart_level = FALSE;
3775 static void InitPlayerInfo()
3779 /* choose default local player */
3780 local_player = &stored_player[0];
3782 for (i = 0; i < MAX_PLAYERS; i++)
3783 stored_player[i].connected = FALSE;
3785 local_player->connected = TRUE;
3788 static void InitArtworkInfo()
3793 static char *get_string_in_brackets(char *string)
3795 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3797 sprintf(string_in_brackets, "[%s]", string);
3799 return string_in_brackets;
3802 static char *get_level_id_suffix(int id_nr)
3804 char *id_suffix = checked_malloc(1 + 3 + 1);
3806 if (id_nr < 0 || id_nr > 999)
3809 sprintf(id_suffix, ".%03d", id_nr);
3815 static char *get_element_class_token(int element)
3817 char *element_class_name = element_info[element].class_name;
3818 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3820 sprintf(element_class_token, "[%s]", element_class_name);
3822 return element_class_token;
3825 static char *get_action_class_token(int action)
3827 char *action_class_name = &element_action_info[action].suffix[1];
3828 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3830 sprintf(action_class_token, "[%s]", action_class_name);
3832 return action_class_token;
3836 static void InitArtworkConfig()
3838 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3839 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3840 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3841 static char *action_id_suffix[NUM_ACTIONS + 1];
3842 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3843 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3844 static char *level_id_suffix[MAX_LEVELS + 1];
3845 static char *dummy[1] = { NULL };
3846 static char *ignore_generic_tokens[] =
3852 static char **ignore_image_tokens;
3853 static char **ignore_sound_tokens;
3854 static char **ignore_music_tokens;
3855 int num_ignore_generic_tokens;
3856 int num_ignore_image_tokens;
3857 int num_ignore_sound_tokens;
3858 int num_ignore_music_tokens;
3861 /* dynamically determine list of generic tokens to be ignored */
3862 num_ignore_generic_tokens = 0;
3863 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3864 num_ignore_generic_tokens++;
3866 /* dynamically determine list of image tokens to be ignored */
3867 num_ignore_image_tokens = num_ignore_generic_tokens;
3868 for (i = 0; image_config_vars[i].token != NULL; i++)
3869 num_ignore_image_tokens++;
3870 ignore_image_tokens =
3871 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3872 for (i = 0; i < num_ignore_generic_tokens; i++)
3873 ignore_image_tokens[i] = ignore_generic_tokens[i];
3874 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3875 ignore_image_tokens[num_ignore_generic_tokens + i] =
3876 image_config_vars[i].token;
3877 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3879 /* dynamically determine list of sound tokens to be ignored */
3880 num_ignore_sound_tokens = num_ignore_generic_tokens;
3881 ignore_sound_tokens =
3882 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3883 for (i = 0; i < num_ignore_generic_tokens; i++)
3884 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3885 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3887 /* dynamically determine list of music tokens to be ignored */
3888 num_ignore_music_tokens = num_ignore_generic_tokens;
3889 ignore_music_tokens =
3890 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3891 for (i = 0; i < num_ignore_generic_tokens; i++)
3892 ignore_music_tokens[i] = ignore_generic_tokens[i];
3893 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3895 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3896 image_id_prefix[i] = element_info[i].token_name;
3897 for (i = 0; i < NUM_FONTS; i++)
3898 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3899 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3901 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3902 sound_id_prefix[i] = element_info[i].token_name;
3903 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3904 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3905 get_string_in_brackets(element_info[i].class_name);
3906 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3908 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3909 music_id_prefix[i] = music_prefix_info[i].prefix;
3910 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
3912 for (i = 0; i < NUM_ACTIONS; i++)
3913 action_id_suffix[i] = element_action_info[i].suffix;
3914 action_id_suffix[NUM_ACTIONS] = NULL;
3916 for (i = 0; i < NUM_DIRECTIONS; i++)
3917 direction_id_suffix[i] = element_direction_info[i].suffix;
3918 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3920 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3921 special_id_suffix[i] = special_suffix_info[i].suffix;
3922 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3924 for (i = 0; i < MAX_LEVELS; i++)
3925 level_id_suffix[i] = get_level_id_suffix(i);
3926 level_id_suffix[MAX_LEVELS] = NULL;
3928 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3929 image_id_prefix, action_id_suffix, direction_id_suffix,
3930 special_id_suffix, ignore_image_tokens);
3931 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3932 sound_id_prefix, action_id_suffix, dummy,
3933 special_id_suffix, ignore_sound_tokens);
3934 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3935 music_id_prefix, special_id_suffix, level_id_suffix,
3936 dummy, ignore_music_tokens);
3939 static void InitMixer()
3947 char *filename_font_initial = NULL;
3948 Bitmap *bitmap_font_initial = NULL;
3951 /* determine settings for initial font (for displaying startup messages) */
3952 for (i = 0; image_config[i].token != NULL; i++)
3954 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3956 char font_token[128];
3959 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3960 len_font_token = strlen(font_token);
3962 if (strcmp(image_config[i].token, font_token) == 0)
3963 filename_font_initial = image_config[i].value;
3964 else if (strlen(image_config[i].token) > len_font_token &&
3965 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3967 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3968 font_initial[j].src_x = atoi(image_config[i].value);
3969 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3970 font_initial[j].src_y = atoi(image_config[i].value);
3971 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3972 font_initial[j].width = atoi(image_config[i].value);
3973 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3974 font_initial[j].height = atoi(image_config[i].value);
3979 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3981 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3982 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3985 if (filename_font_initial == NULL) /* should not happen */
3986 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3988 /* create additional image buffers for double-buffering */
3989 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3990 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3992 /* initialize screen properties */
3993 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3994 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3996 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3997 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3998 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4000 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4002 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4003 font_initial[j].bitmap = bitmap_font_initial;
4005 InitFontGraphicInfo();
4007 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4008 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4010 DrawInitText("Loading graphics:", 120, FC_GREEN);
4013 void InitGfxBackground()
4017 drawto = backbuffer;
4018 fieldbuffer = bitmap_db_field;
4019 SetDrawtoField(DRAW_BACKBUFFER);
4021 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4022 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4023 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4024 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4026 for (x = 0; x < MAX_BUF_XSIZE; x++)
4027 for (y = 0; y < MAX_BUF_YSIZE; y++)
4030 redraw_mask = REDRAW_ALL;
4033 static void InitLevelInfo()
4035 LoadLevelInfo(); /* global level info */
4036 LoadLevelSetup_LastSeries(); /* last played series info */
4037 LoadLevelSetup_SeriesInfo(); /* last played level info */
4040 void InitLevelArtworkInfo()
4042 LoadLevelArtworkInfo();
4045 static void InitImages()
4047 setLevelArtworkDir(artwork.gfx_first);
4050 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4051 leveldir_current->identifier,
4052 artwork.gfx_current_identifier,
4053 artwork.gfx_current->identifier,
4054 leveldir_current->graphics_set,
4055 leveldir_current->graphics_path);
4058 ReloadCustomImages();
4060 LoadCustomElementDescriptions();
4061 LoadSpecialMenuDesignSettings();
4063 ReinitializeGraphics();
4066 static void InitSound(char *identifier)
4068 if (identifier == NULL)
4069 identifier = artwork.snd_current->identifier;
4071 /* set artwork path to send it to the sound server process */
4072 setLevelArtworkDir(artwork.snd_first);
4074 InitReloadCustomSounds(identifier);
4075 ReinitializeSounds();
4078 static void InitMusic(char *identifier)
4080 if (identifier == NULL)
4081 identifier = artwork.mus_current->identifier;
4083 /* set artwork path to send it to the sound server process */
4084 setLevelArtworkDir(artwork.mus_first);
4086 InitReloadCustomMusic(identifier);
4087 ReinitializeMusic();
4090 void InitNetworkServer()
4092 #if defined(NETWORK_AVALIABLE)
4096 if (!options.network)
4099 #if defined(NETWORK_AVALIABLE)
4100 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4102 if (!ConnectToServer(options.server_host, options.server_port))
4103 Error(ERR_EXIT, "cannot connect to network game server");
4105 SendToServer_PlayerName(setup.player_name);
4106 SendToServer_ProtocolVersion();
4109 SendToServer_NrWanted(nr_wanted);
4113 static char *getNewArtworkIdentifier(int type)
4115 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4116 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4117 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4118 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4119 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4120 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4121 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4122 char *leveldir_identifier = leveldir_current->identifier;
4124 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4125 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4127 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4129 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4130 char *artwork_current_identifier;
4131 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4133 /* leveldir_current may be invalid (level group, parent link) */
4134 if (!validLevelSeries(leveldir_current))
4137 /* 1st step: determine artwork set to be activated in descending order:
4138 --------------------------------------------------------------------
4139 1. setup artwork (when configured to override everything else)
4140 2. artwork set configured in "levelinfo.conf" of current level set
4141 (artwork in level directory will have priority when loading later)
4142 3. artwork in level directory (stored in artwork sub-directory)
4143 4. setup artwork (currently configured in setup menu) */
4145 if (setup_override_artwork)
4146 artwork_current_identifier = setup_artwork_set;
4147 else if (leveldir_artwork_set != NULL)
4148 artwork_current_identifier = leveldir_artwork_set;
4149 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4150 artwork_current_identifier = leveldir_identifier;
4152 artwork_current_identifier = setup_artwork_set;
4155 /* 2nd step: check if it is really needed to reload artwork set
4156 ------------------------------------------------------------ */
4159 if (type == ARTWORK_TYPE_GRAPHICS)
4160 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4161 artwork_new_identifier,
4162 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4163 artwork_current_identifier,
4164 leveldir_current->graphics_set,
4165 leveldir_current->identifier);
4168 /* ---------- reload if level set and also artwork set has changed ------- */
4169 if (leveldir_current_identifier[type] != leveldir_identifier &&
4170 (last_has_level_artwork_set[type] || has_level_artwork_set))
4171 artwork_new_identifier = artwork_current_identifier;
4173 leveldir_current_identifier[type] = leveldir_identifier;
4174 last_has_level_artwork_set[type] = has_level_artwork_set;
4177 if (type == ARTWORK_TYPE_GRAPHICS)
4178 printf("::: 1: '%s'\n", artwork_new_identifier);
4181 /* ---------- reload if "override artwork" setting has changed ----------- */
4182 if (last_override_level_artwork[type] != setup_override_artwork)
4183 artwork_new_identifier = artwork_current_identifier;
4185 last_override_level_artwork[type] = setup_override_artwork;
4188 if (type == ARTWORK_TYPE_GRAPHICS)
4189 printf("::: 2: '%s'\n", artwork_new_identifier);
4192 /* ---------- reload if current artwork identifier has changed ----------- */
4193 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4194 artwork_current_identifier) != 0)
4195 artwork_new_identifier = artwork_current_identifier;
4197 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4200 if (type == ARTWORK_TYPE_GRAPHICS)
4201 printf("::: 3: '%s'\n", artwork_new_identifier);
4204 /* ---------- do not reload directly after starting ---------------------- */
4205 if (!initialized[type])
4206 artwork_new_identifier = NULL;
4208 initialized[type] = TRUE;
4211 if (type == ARTWORK_TYPE_GRAPHICS)
4212 printf("::: 4: '%s'\n", artwork_new_identifier);
4216 if (type == ARTWORK_TYPE_GRAPHICS)
4217 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4218 artwork.gfx_current_identifier, artwork_current_identifier,
4219 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4220 artwork_new_identifier);
4223 return artwork_new_identifier;
4226 void ReloadCustomArtwork(int force_reload)
4228 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4229 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4230 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4231 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4232 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4233 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4234 boolean redraw_screen = FALSE;
4236 if (gfx_new_identifier != NULL || force_reload_gfx)
4239 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4240 artwork.gfx_current_identifier,
4242 artwork.gfx_current->identifier,
4243 leveldir_current->graphics_set);
4246 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4250 redraw_screen = TRUE;
4253 if (snd_new_identifier != NULL || force_reload_snd)
4255 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4257 InitSound(snd_new_identifier);
4259 redraw_screen = TRUE;
4262 if (mus_new_identifier != NULL || force_reload_mus)
4264 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4266 InitMusic(mus_new_identifier);
4268 redraw_screen = TRUE;
4273 InitGfxBackground();
4275 /* force redraw of (open or closed) door graphics */
4276 SetDoorState(DOOR_OPEN_ALL);
4277 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4281 void KeyboardAutoRepeatOffUnlessAutoplay()
4283 if (global.autoplay_leveldir == NULL)
4284 KeyboardAutoRepeatOff();
4288 /* ========================================================================= */
4290 /* ========================================================================= */
4294 InitGlobal(); /* initialize some global variables */
4296 if (options.execute_command)
4297 Execute_Command(options.execute_command);
4299 if (options.serveronly)
4301 #if defined(PLATFORM_UNIX)
4302 NetworkServer(options.server_port, options.serveronly);
4304 Error(ERR_WARN, "networking only supported in Unix version");
4307 exit(0); /* never reached, server loops forever */
4314 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4315 InitArtworkConfig(); /* needed before forking sound child process */
4320 InitRND(NEW_RANDOMIZE);
4321 InitSimpleRND(NEW_RANDOMIZE);
4326 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4329 InitEventFilter(FilterMouseMotionEvents);
4331 InitElementPropertiesStatic();
4332 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4337 InitLevelArtworkInfo();
4339 InitImages(); /* needs to know current level directory */
4340 InitSound(NULL); /* needs to know current level directory */
4341 InitMusic(NULL); /* needs to know current level directory */
4343 InitGfxBackground();
4345 if (global.autoplay_leveldir)
4350 else if (global.convert_leveldir)
4356 game_status = GAME_MODE_MAIN;
4364 InitNetworkServer();
4367 void CloseAllAndExit(int exit_value)
4372 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4380 #if defined(TARGET_SDL)
4381 if (network_server) /* terminate network server */
4382 SDL_KillThread(server_thread);
4385 CloseVideoDisplay();
4386 ClosePlatformDependentStuff();