1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
82 FreeLevelEditorGadgets();
91 static boolean gadgets_initialized = FALSE;
93 if (gadgets_initialized)
96 CreateLevelEditorGadgets();
100 CreateScreenGadgets();
102 gadgets_initialized = TRUE;
105 inline void InitElementSmallImagesScaledUp(int graphic)
107 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
110 void InitElementSmallImages()
112 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
113 int num_property_mappings = getImageListPropertyMappingSize();
116 /* initialize normal images from static configuration */
117 for (i = 0; element_to_graphic[i].element > -1; i++)
118 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
120 /* initialize special images from static configuration */
121 for (i = 0; element_to_special_graphic[i].element > -1; i++)
122 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
124 /* initialize images from dynamic configuration (may be elements or other) */
125 for (i = 0; i < num_property_mappings; i++)
126 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
130 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
131 void SetBitmaps_EM(Bitmap **em_bitmap)
133 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
134 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
138 static int getFontBitmapID(int font_nr)
142 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
143 special = game_status;
144 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
145 special = GFX_SPECIAL_ARG_MAIN;
146 else if (game_status == GAME_MODE_PLAYING)
147 special = GFX_SPECIAL_ARG_DOOR;
150 return font_info[font_nr].special_bitmap_id[special];
155 void InitFontGraphicInfo()
157 static struct FontBitmapInfo *font_bitmap_info = NULL;
158 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
159 int num_property_mappings = getImageListPropertyMappingSize();
160 int num_font_bitmaps = NUM_FONTS;
163 if (graphic_info == NULL) /* still at startup phase */
165 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
170 /* ---------- initialize font graphic definitions ---------- */
172 /* always start with reliable default values (normal font graphics) */
173 for (i = 0; i < NUM_FONTS; i++)
174 font_info[i].graphic = IMG_FONT_INITIAL_1;
176 /* initialize normal font/graphic mapping from static configuration */
177 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
179 int font_nr = font_to_graphic[i].font_nr;
180 int special = font_to_graphic[i].special;
181 int graphic = font_to_graphic[i].graphic;
186 font_info[font_nr].graphic = graphic;
189 /* always start with reliable default values (special font graphics) */
190 for (i = 0; i < NUM_FONTS; i++)
192 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
194 font_info[i].special_graphic[j] = font_info[i].graphic;
195 font_info[i].special_bitmap_id[j] = i;
199 /* initialize special font/graphic mapping from static configuration */
200 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
202 int font_nr = font_to_graphic[i].font_nr;
203 int special = font_to_graphic[i].special;
204 int graphic = font_to_graphic[i].graphic;
205 int base_graphic = font2baseimg(font_nr);
207 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
209 boolean base_redefined =
210 getImageListEntryFromImageID(base_graphic)->redefined;
211 boolean special_redefined =
212 getImageListEntryFromImageID(graphic)->redefined;
214 /* if the base font ("font.title_1", for example) has been redefined,
215 but not the special font ("font.title_1.LEVELS", for example), do not
216 use an existing (in this case considered obsolete) special font
217 anymore, but use the automatically determined default font */
218 if (base_redefined && !special_redefined)
221 font_info[font_nr].special_graphic[special] = graphic;
222 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
227 /* initialize special element/graphic mapping from dynamic configuration */
228 for (i = 0; i < num_property_mappings; i++)
230 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
231 int special = property_mapping[i].ext3_index;
232 int graphic = property_mapping[i].artwork_index;
237 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
239 font_info[font_nr].special_graphic[special] = graphic;
240 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
245 /* ---------- initialize font bitmap array ---------- */
247 if (font_bitmap_info != NULL)
248 FreeFontInfo(font_bitmap_info);
251 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
253 /* ---------- initialize font bitmap definitions ---------- */
255 for (i = 0; i < NUM_FONTS; i++)
257 if (i < NUM_INITIAL_FONTS)
259 font_bitmap_info[i] = font_initial[i];
263 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
265 int font_bitmap_id = font_info[i].special_bitmap_id[j];
266 int graphic = font_info[i].special_graphic[j];
268 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
269 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
271 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
272 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
275 /* copy font relevant information from graphics information */
276 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
277 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
278 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
279 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
280 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
281 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
282 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
284 font_bitmap_info[font_bitmap_id].num_chars =
285 graphic_info[graphic].anim_frames;
286 font_bitmap_info[font_bitmap_id].num_chars_per_line =
287 graphic_info[graphic].anim_frames_per_line;
291 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
294 void InitElementGraphicInfo()
296 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
297 int num_property_mappings = getImageListPropertyMappingSize();
300 if (graphic_info == NULL) /* still at startup phase */
303 /* set values to -1 to identify later as "uninitialized" values */
304 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
306 for (act = 0; act < NUM_ACTIONS; act++)
308 element_info[i].graphic[act] = -1;
309 element_info[i].crumbled[act] = -1;
311 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
313 element_info[i].direction_graphic[act][dir] = -1;
314 element_info[i].direction_crumbled[act][dir] = -1;
319 /* initialize normal element/graphic mapping from static configuration */
320 for (i = 0; element_to_graphic[i].element > -1; i++)
322 int element = element_to_graphic[i].element;
323 int action = element_to_graphic[i].action;
324 int direction = element_to_graphic[i].direction;
325 boolean crumbled = element_to_graphic[i].crumbled;
326 int graphic = element_to_graphic[i].graphic;
327 int base_graphic = el2baseimg(element);
329 if (graphic_info[graphic].bitmap == NULL)
332 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
335 boolean base_redefined =
336 getImageListEntryFromImageID(base_graphic)->redefined;
337 boolean act_dir_redefined =
338 getImageListEntryFromImageID(graphic)->redefined;
340 /* if the base graphic ("emerald", for example) has been redefined,
341 but not the action graphic ("emerald.falling", for example), do not
342 use an existing (in this case considered obsolete) action graphic
343 anymore, but use the automatically determined default graphic */
344 if (base_redefined && !act_dir_redefined)
349 action = ACTION_DEFAULT;
354 element_info[element].direction_crumbled[action][direction] = graphic;
356 element_info[element].crumbled[action] = graphic;
361 element_info[element].direction_graphic[action][direction] = graphic;
363 element_info[element].graphic[action] = graphic;
367 /* initialize normal element/graphic mapping from dynamic configuration */
368 for (i = 0; i < num_property_mappings; i++)
370 int element = property_mapping[i].base_index;
371 int action = property_mapping[i].ext1_index;
372 int direction = property_mapping[i].ext2_index;
373 int special = property_mapping[i].ext3_index;
374 int graphic = property_mapping[i].artwork_index;
375 boolean crumbled = FALSE;
377 if (special == GFX_SPECIAL_ARG_CRUMBLED)
383 if (graphic_info[graphic].bitmap == NULL)
386 if (element >= MAX_NUM_ELEMENTS || special != -1)
390 action = ACTION_DEFAULT;
395 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
396 element_info[element].direction_crumbled[action][dir] = -1;
399 element_info[element].direction_crumbled[action][direction] = graphic;
401 element_info[element].crumbled[action] = graphic;
406 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
407 element_info[element].direction_graphic[action][dir] = -1;
410 element_info[element].direction_graphic[action][direction] = graphic;
412 element_info[element].graphic[action] = graphic;
416 /* now copy all graphics that are defined to be cloned from other graphics */
417 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
419 int graphic = element_info[i].graphic[ACTION_DEFAULT];
420 int crumbled_like, diggable_like;
425 crumbled_like = graphic_info[graphic].crumbled_like;
426 diggable_like = graphic_info[graphic].diggable_like;
428 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
430 for (act = 0; act < NUM_ACTIONS; act++)
431 element_info[i].crumbled[act] =
432 element_info[crumbled_like].crumbled[act];
433 for (act = 0; act < NUM_ACTIONS; act++)
434 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
435 element_info[i].direction_crumbled[act][dir] =
436 element_info[crumbled_like].direction_crumbled[act][dir];
439 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
441 element_info[i].graphic[ACTION_DIGGING] =
442 element_info[diggable_like].graphic[ACTION_DIGGING];
443 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
444 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
445 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
450 /* set hardcoded definitions for some runtime elements without graphic */
451 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
454 /* now set all undefined/invalid graphics to -1 to set to default after it */
455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
457 for (act = 0; act < NUM_ACTIONS; act++)
461 graphic = element_info[i].graphic[act];
462 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
463 element_info[i].graphic[act] = -1;
465 graphic = element_info[i].crumbled[act];
466 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
467 element_info[i].crumbled[act] = -1;
469 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
471 graphic = element_info[i].direction_graphic[act][dir];
472 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
473 element_info[i].direction_graphic[act][dir] = -1;
475 graphic = element_info[i].direction_crumbled[act][dir];
476 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
477 element_info[i].direction_crumbled[act][dir] = -1;
482 /* adjust graphics with 2nd tile for movement according to direction
483 (do this before correcting '-1' values to minimize calculations) */
484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
486 for (act = 0; act < NUM_ACTIONS; act++)
488 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
490 int graphic = element_info[i].direction_graphic[act][dir];
491 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
493 if (act == ACTION_FALLING) /* special case */
494 graphic = element_info[i].graphic[act];
497 graphic_info[graphic].double_movement &&
498 graphic_info[graphic].swap_double_tiles != 0)
500 struct GraphicInfo *g = &graphic_info[graphic];
501 int src_x_front = g->src_x;
502 int src_y_front = g->src_y;
503 int src_x_back = g->src_x + g->offset2_x;
504 int src_y_back = g->src_y + g->offset2_y;
505 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
507 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
508 src_y_front < src_y_back);
509 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
510 boolean swap_movement_tiles_autodetected =
511 (!frames_are_ordered_diagonally &&
512 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
513 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
514 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
515 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
518 /* swap frontside and backside graphic tile coordinates, if needed */
519 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
521 /* get current (wrong) backside tile coordinates */
522 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
525 /* set frontside tile coordinates to backside tile coordinates */
526 g->src_x = src_x_back;
527 g->src_y = src_y_back;
529 /* invert tile offset to point to new backside tile coordinates */
533 /* do not swap front and backside tiles again after correction */
534 g->swap_double_tiles = 0;
541 /* now set all '-1' values to element specific default values */
542 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
544 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
545 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
546 int default_direction_graphic[NUM_DIRECTIONS];
547 int default_direction_crumbled[NUM_DIRECTIONS];
549 if (default_graphic == -1)
550 default_graphic = IMG_UNKNOWN;
552 if (default_crumbled == -1)
553 default_crumbled = default_graphic;
555 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
556 if (default_crumbled == -1)
557 default_crumbled = IMG_EMPTY;
560 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
562 default_direction_graphic[dir] =
563 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
564 default_direction_crumbled[dir] =
565 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
567 if (default_direction_graphic[dir] == -1)
568 default_direction_graphic[dir] = default_graphic;
570 if (default_direction_crumbled[dir] == -1)
571 default_direction_crumbled[dir] = default_direction_graphic[dir];
573 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
574 if (default_direction_crumbled[dir] == -1)
575 default_direction_crumbled[dir] = default_crumbled;
579 for (act = 0; act < NUM_ACTIONS; act++)
581 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
582 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
583 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
584 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
585 act == ACTION_TURNING_FROM_RIGHT ||
586 act == ACTION_TURNING_FROM_UP ||
587 act == ACTION_TURNING_FROM_DOWN);
589 /* generic default action graphic (defined by "[default]" directive) */
590 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
591 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
592 int default_remove_graphic = IMG_EMPTY;
594 if (act_remove && default_action_graphic != -1)
595 default_remove_graphic = default_action_graphic;
597 /* look for special default action graphic (classic game specific) */
598 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
599 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
600 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
601 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
602 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
603 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
605 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
606 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
607 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
608 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
609 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
610 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
613 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
614 /* !!! make this better !!! */
615 if (i == EL_EMPTY_SPACE)
617 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
618 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
622 if (default_action_graphic == -1)
623 default_action_graphic = default_graphic;
625 if (default_action_crumbled == -1)
626 default_action_crumbled = default_action_graphic;
628 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
629 if (default_action_crumbled == -1)
630 default_action_crumbled = default_crumbled;
633 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
635 /* use action graphic as the default direction graphic, if undefined */
636 int default_action_direction_graphic = element_info[i].graphic[act];
637 int default_action_direction_crumbled = element_info[i].crumbled[act];
639 /* no graphic for current action -- use default direction graphic */
640 if (default_action_direction_graphic == -1)
641 default_action_direction_graphic =
642 (act_remove ? default_remove_graphic :
644 element_info[i].direction_graphic[ACTION_TURNING][dir] :
645 default_action_graphic != default_graphic ?
646 default_action_graphic :
647 default_direction_graphic[dir]);
649 if (element_info[i].direction_graphic[act][dir] == -1)
650 element_info[i].direction_graphic[act][dir] =
651 default_action_direction_graphic;
654 if (default_action_direction_crumbled == -1)
655 default_action_direction_crumbled =
656 element_info[i].direction_graphic[act][dir];
658 if (default_action_direction_crumbled == -1)
659 default_action_direction_crumbled =
660 (act_remove ? default_remove_graphic :
662 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
663 default_action_crumbled != default_crumbled ?
664 default_action_crumbled :
665 default_direction_crumbled[dir]);
668 if (element_info[i].direction_crumbled[act][dir] == -1)
669 element_info[i].direction_crumbled[act][dir] =
670 default_action_direction_crumbled;
673 /* no graphic for this specific action -- use default action graphic */
674 if (element_info[i].graphic[act] == -1)
675 element_info[i].graphic[act] =
676 (act_remove ? default_remove_graphic :
677 act_turning ? element_info[i].graphic[ACTION_TURNING] :
678 default_action_graphic);
680 if (element_info[i].crumbled[act] == -1)
681 element_info[i].crumbled[act] = element_info[i].graphic[act];
683 if (element_info[i].crumbled[act] == -1)
684 element_info[i].crumbled[act] =
685 (act_remove ? default_remove_graphic :
686 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
687 default_action_crumbled);
692 /* set animation mode to "none" for each graphic with only 1 frame */
693 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
695 for (act = 0; act < NUM_ACTIONS; act++)
697 int graphic = element_info[i].graphic[act];
698 int crumbled = element_info[i].crumbled[act];
700 if (graphic_info[graphic].anim_frames == 1)
701 graphic_info[graphic].anim_mode = ANIM_NONE;
702 if (graphic_info[crumbled].anim_frames == 1)
703 graphic_info[crumbled].anim_mode = ANIM_NONE;
705 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
707 graphic = element_info[i].direction_graphic[act][dir];
708 crumbled = element_info[i].direction_crumbled[act][dir];
710 if (graphic_info[graphic].anim_frames == 1)
711 graphic_info[graphic].anim_mode = ANIM_NONE;
712 if (graphic_info[crumbled].anim_frames == 1)
713 graphic_info[crumbled].anim_mode = ANIM_NONE;
722 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
723 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
725 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
726 element_info[i].token_name, i);
732 void InitElementSpecialGraphicInfo()
734 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
735 int num_property_mappings = getImageListPropertyMappingSize();
738 /* always start with reliable default values */
739 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
740 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
741 element_info[i].special_graphic[j] =
742 element_info[i].graphic[ACTION_DEFAULT];
744 /* initialize special element/graphic mapping from static configuration */
745 for (i = 0; element_to_special_graphic[i].element > -1; i++)
747 int element = element_to_special_graphic[i].element;
748 int special = element_to_special_graphic[i].special;
749 int graphic = element_to_special_graphic[i].graphic;
750 int base_graphic = el2baseimg(element);
751 boolean base_redefined =
752 getImageListEntryFromImageID(base_graphic)->redefined;
753 boolean special_redefined =
754 getImageListEntryFromImageID(graphic)->redefined;
756 /* if the base graphic ("emerald", for example) has been redefined,
757 but not the special graphic ("emerald.EDITOR", for example), do not
758 use an existing (in this case considered obsolete) special graphic
759 anymore, but use the automatically created (down-scaled) graphic */
760 if (base_redefined && !special_redefined)
763 element_info[element].special_graphic[special] = graphic;
766 /* initialize special element/graphic mapping from dynamic configuration */
767 for (i = 0; i < num_property_mappings; i++)
769 int element = property_mapping[i].base_index;
770 int special = property_mapping[i].ext3_index;
771 int graphic = property_mapping[i].artwork_index;
773 if (element >= MAX_NUM_ELEMENTS)
776 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
777 element_info[element].special_graphic[special] = graphic;
780 /* now set all undefined/invalid graphics to default */
781 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
782 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
783 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
784 element_info[i].special_graphic[j] =
785 element_info[i].graphic[ACTION_DEFAULT];
788 static int get_element_from_token(char *token)
793 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
794 if (strcmp(element_info[i].token_name, token) == 0)
798 for (i = 0; image_config[i].token != NULL; i++)
800 int len_config_value = strlen(image_config[i].value);
802 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
803 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
804 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
807 if (strcmp(image_config[i].token, token) == 0)
817 static int get_scaled_graphic_width(int graphic)
819 int original_width = getOriginalImageWidthFromImageID(graphic);
820 int scale_up_factor = graphic_info[graphic].scale_up_factor;
822 return original_width * scale_up_factor;
825 static int get_scaled_graphic_height(int graphic)
827 int original_height = getOriginalImageHeightFromImageID(graphic);
828 int scale_up_factor = graphic_info[graphic].scale_up_factor;
830 return original_height * scale_up_factor;
833 static void set_graphic_parameters(int graphic, int graphic_copy_from)
835 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
836 char **parameter_raw = image->parameter;
837 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
838 int parameter[NUM_GFX_ARGS];
839 int anim_frames_per_row = 1, anim_frames_per_col = 1;
840 int anim_frames_per_line = 1;
844 if (graphic != graphic_copy_from)
846 graphic_info[graphic] = graphic_info[graphic_copy_from];
852 /* if fallback to default artwork is done, also use the default parameters */
853 if (image->fallback_to_default)
854 parameter_raw = image->default_parameter;
856 /* get integer values from string parameters */
857 for (i = 0; i < NUM_GFX_ARGS; i++)
860 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
861 image_config_suffix[i].type);
863 if (image_config_suffix[i].type == TYPE_TOKEN)
864 parameter[i] = get_element_from_token(parameter_raw[i]);
867 graphic_info[graphic].bitmap = src_bitmap;
869 /* start with reliable default values */
870 graphic_info[graphic].src_image_width = 0;
871 graphic_info[graphic].src_image_height = 0;
872 graphic_info[graphic].src_x = 0;
873 graphic_info[graphic].src_y = 0;
874 graphic_info[graphic].width = TILEX;
875 graphic_info[graphic].height = TILEY;
876 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
877 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
878 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
879 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
880 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
881 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
882 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
883 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
884 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
885 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
886 graphic_info[graphic].anim_delay_fixed = 0;
887 graphic_info[graphic].anim_delay_random = 0;
888 graphic_info[graphic].post_delay_fixed = 0;
889 graphic_info[graphic].post_delay_random = 0;
891 /* optional x and y tile position of animation frame sequence */
892 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
893 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
894 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
895 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
897 /* optional x and y pixel position of animation frame sequence */
898 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
899 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
900 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
901 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
903 /* optional width and height of each animation frame */
904 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
905 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
906 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
907 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
909 /* optional zoom factor for scaling up the image to a larger size */
910 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
911 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
912 if (graphic_info[graphic].scale_up_factor < 1)
913 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
917 /* get final bitmap size (with scaling, but without small images) */
918 int src_image_width = get_scaled_graphic_width(graphic);
919 int src_image_height = get_scaled_graphic_height(graphic);
921 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
922 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
924 graphic_info[graphic].src_image_width = src_image_width;
925 graphic_info[graphic].src_image_height = src_image_height;
928 /* correct x or y offset dependent of vertical or horizontal frame order */
929 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
931 graphic_info[graphic].offset_y =
932 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
933 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
934 anim_frames_per_line = anim_frames_per_col;
936 else /* frames are ordered horizontally */
938 graphic_info[graphic].offset_x =
939 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
940 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
941 anim_frames_per_line = anim_frames_per_row;
944 /* optionally, the x and y offset of frames can be specified directly */
945 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
947 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
948 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
950 /* optionally, moving animations may have separate start and end graphics */
951 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
953 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
954 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
956 /* correct x or y offset2 dependent of vertical or horizontal frame order */
957 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
958 graphic_info[graphic].offset2_y =
959 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
960 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
961 else /* frames are ordered horizontally */
962 graphic_info[graphic].offset2_x =
963 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
964 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
966 /* optionally, the x and y offset of 2nd graphic can be specified directly */
967 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
968 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
969 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
972 /* optionally, the second movement tile can be specified as start tile */
973 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
976 /* automatically determine correct number of frames, if not defined */
977 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
979 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
980 graphic_info[graphic].anim_frames = anim_frames_per_row;
981 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
982 graphic_info[graphic].anim_frames = anim_frames_per_col;
984 graphic_info[graphic].anim_frames = 1;
986 graphic_info[graphic].anim_frames_per_line =
987 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
988 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
990 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
991 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
992 graphic_info[graphic].anim_delay = 1;
994 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
996 if (graphic_info[graphic].anim_frames == 1)
997 graphic_info[graphic].anim_mode = ANIM_NONE;
1000 /* automatically determine correct start frame, if not defined */
1001 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].anim_start_frame = 0;
1003 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1004 graphic_info[graphic].anim_start_frame =
1005 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1007 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1009 /* animation synchronized with global frame counter, not move position */
1010 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1012 /* optional element for cloning crumble graphics */
1013 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1016 /* optional element for cloning digging graphics */
1017 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1018 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1020 /* optional border size for "crumbling" diggable graphics */
1021 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1022 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1024 /* this is only used for player "boring" and "sleeping" actions */
1025 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1026 graphic_info[graphic].anim_delay_fixed =
1027 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1028 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].anim_delay_random =
1030 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1031 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1032 graphic_info[graphic].post_delay_fixed =
1033 parameter[GFX_ARG_POST_DELAY_FIXED];
1034 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1035 graphic_info[graphic].post_delay_random =
1036 parameter[GFX_ARG_POST_DELAY_RANDOM];
1038 /* this is only used for toon animations */
1039 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1040 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1042 /* this is only used for drawing font characters */
1043 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1044 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1046 /* this is only used for drawing envelope graphics */
1047 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1050 /* optional graphic for cloning all graphics settings */
1051 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1054 /* optional graphic for cloning all graphics settings */
1055 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1057 if (parameter[GFX_ARG_CLONE_FROM] != -1)
1059 int clone_graphic = parameter[GFX_ARG_CLONE_FROM];
1061 graphic_info[graphic] = graphic_info[clone_graphic];
1062 graphic_info[graphic].clone_from = clone_graphic;
1064 printf("::: %d -> %d\n", graphic, clone_graphic);
1070 static void InitGraphicInfo()
1072 int fallback_graphic = IMG_CHAR_EXCLAM;
1073 int num_images = getImageListSize();
1076 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1077 static boolean clipmasks_initialized = FALSE;
1079 XGCValues clip_gc_values;
1080 unsigned long clip_gc_valuemask;
1081 GC copy_clipmask_gc = None;
1084 checked_free(graphic_info);
1086 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1088 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1089 if (clipmasks_initialized)
1091 for (i = 0; i < num_images; i++)
1093 if (graphic_info[i].clip_mask)
1094 XFreePixmap(display, graphic_info[i].clip_mask);
1095 if (graphic_info[i].clip_gc)
1096 XFreeGC(display, graphic_info[i].clip_gc);
1098 graphic_info[i].clip_mask = None;
1099 graphic_info[i].clip_gc = None;
1105 /* first set all graphic paramaters ... */
1106 for (i = 0; i < num_images; i++)
1108 set_graphic_parameters(i, i);
1111 /* ... then copy these parameters for cloned graphics */
1112 for (i = 0; i < num_images; i++)
1114 if (graphic_info[i].clone_from != -1)
1116 int clone_graphic = graphic_info[i].clone_from;
1118 if (graphic_info[clone_graphic].clone_from != -1)
1120 Error(ERR_RETURN_LINE, "-");
1121 Error(ERR_RETURN, "warning: error found in config file:");
1122 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1123 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1125 "error: cannot clone from already cloned graphic '%s'",
1126 getTokenFromImageID(clone_graphic));
1127 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1129 if (i == fallback_graphic)
1130 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1132 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1133 Error(ERR_RETURN_LINE, "-");
1135 set_graphic_parameters(i, fallback_graphic);
1139 graphic_info[i] = graphic_info[clone_graphic];
1140 graphic_info[i].clone_from = clone_graphic;
1143 printf("::: graphic %d ['%s'] is cloned from %d ['%s']\n",
1144 i, getTokenFromImageID(i),
1145 clone_graphic, getTokenFromImageID(clone_graphic));
1152 for (i = 0; i < num_images; i++)
1156 int first_frame, last_frame;
1157 int src_bitmap_width, src_bitmap_height;
1160 printf("::: image # %d: '%s' ['%s']\n",
1161 i, image->token, getTokenFromImageID(i));
1165 set_graphic_parameters(i, i);
1168 /* now check if no animation frames are outside of the loaded image */
1171 if (graphic_info[i].bitmap == NULL)
1172 Error(ERR_WARN, "no bitmap for graphic %d ['%s']",
1173 i, getTokenFromImageID(i));
1176 if (graphic_info[i].bitmap == NULL)
1177 continue; /* skip check for optional images that are undefined */
1180 /* get final bitmap size (with scaling, but without small images) */
1181 src_bitmap_width = graphic_info[i].src_image_width;
1182 src_bitmap_height = graphic_info[i].src_image_height;
1184 /* get final bitmap size (with scaling, but without small images) */
1185 src_bitmap_width = get_scaled_graphic_width(i);
1186 src_bitmap_height = get_scaled_graphic_height(i);
1188 if (graphic_info[i].clone_from != -1)
1190 int clone_graphic = graphic_info[i].clone_from;
1192 src_bitmap_width = get_scaled_graphic_width(clone_graphic);
1193 src_bitmap_height = get_scaled_graphic_height(clone_graphic);
1198 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1199 if (src_x < 0 || src_y < 0 ||
1200 src_x + TILEX > src_bitmap_width ||
1201 src_y + TILEY > src_bitmap_height)
1203 Error(ERR_RETURN_LINE, "-");
1204 Error(ERR_RETURN, "warning: error found in config file:");
1205 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1206 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1207 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1209 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1210 src_x, src_y, src_bitmap_width, src_bitmap_height);
1211 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1213 if (i == fallback_graphic)
1214 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1216 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1217 Error(ERR_RETURN_LINE, "-");
1219 set_graphic_parameters(i, fallback_graphic);
1222 last_frame = graphic_info[i].anim_frames - 1;
1223 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1224 if (src_x < 0 || src_y < 0 ||
1225 src_x + TILEX > src_bitmap_width ||
1226 src_y + TILEY > src_bitmap_height)
1228 Error(ERR_RETURN_LINE, "-");
1229 Error(ERR_RETURN, "warning: error found in config file:");
1230 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1231 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1232 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1234 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1235 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1236 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1238 if (i == fallback_graphic)
1239 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1241 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1242 Error(ERR_RETURN_LINE, "-");
1244 set_graphic_parameters(i, fallback_graphic);
1247 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1248 /* currently we only need a tile clip mask from the first frame */
1249 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1251 if (copy_clipmask_gc == None)
1253 clip_gc_values.graphics_exposures = False;
1254 clip_gc_valuemask = GCGraphicsExposures;
1255 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1256 clip_gc_valuemask, &clip_gc_values);
1259 graphic_info[i].clip_mask =
1260 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1262 src_pixmap = src_bitmap->clip_mask;
1263 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1264 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1266 clip_gc_values.graphics_exposures = False;
1267 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1268 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1270 graphic_info[i].clip_gc =
1271 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1275 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1276 if (copy_clipmask_gc)
1277 XFreeGC(display, copy_clipmask_gc);
1279 clipmasks_initialized = TRUE;
1283 static void InitElementSoundInfo()
1285 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1286 int num_property_mappings = getSoundListPropertyMappingSize();
1289 /* set values to -1 to identify later as "uninitialized" values */
1290 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1291 for (act = 0; act < NUM_ACTIONS; act++)
1292 element_info[i].sound[act] = -1;
1294 /* initialize element/sound mapping from static configuration */
1295 for (i = 0; element_to_sound[i].element > -1; i++)
1297 int element = element_to_sound[i].element;
1298 int action = element_to_sound[i].action;
1299 int sound = element_to_sound[i].sound;
1300 boolean is_class = element_to_sound[i].is_class;
1303 action = ACTION_DEFAULT;
1306 element_info[element].sound[action] = sound;
1308 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1309 if (strcmp(element_info[j].class_name,
1310 element_info[element].class_name) == 0)
1311 element_info[j].sound[action] = sound;
1314 /* initialize element class/sound mapping from dynamic configuration */
1315 for (i = 0; i < num_property_mappings; i++)
1317 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1318 int action = property_mapping[i].ext1_index;
1319 int sound = property_mapping[i].artwork_index;
1321 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1325 action = ACTION_DEFAULT;
1327 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1328 if (strcmp(element_info[j].class_name,
1329 element_info[element_class].class_name) == 0)
1330 element_info[j].sound[action] = sound;
1333 /* initialize element/sound mapping from dynamic configuration */
1334 for (i = 0; i < num_property_mappings; i++)
1336 int element = property_mapping[i].base_index;
1337 int action = property_mapping[i].ext1_index;
1338 int sound = property_mapping[i].artwork_index;
1340 if (element >= MAX_NUM_ELEMENTS)
1344 action = ACTION_DEFAULT;
1346 element_info[element].sound[action] = sound;
1349 /* now set all '-1' values to element specific default values */
1350 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1352 for (act = 0; act < NUM_ACTIONS; act++)
1354 /* generic default action sound (defined by "[default]" directive) */
1355 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1357 /* look for special default action sound (classic game specific) */
1358 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1359 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1360 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1361 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1362 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1363 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1365 /* !!! there's no such thing as a "default action sound" !!! */
1367 /* look for element specific default sound (independent from action) */
1368 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1369 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1373 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1374 /* !!! make this better !!! */
1375 if (i == EL_EMPTY_SPACE)
1376 default_action_sound = element_info[EL_DEFAULT].sound[act];
1379 /* no sound for this specific action -- use default action sound */
1380 if (element_info[i].sound[act] == -1)
1381 element_info[i].sound[act] = default_action_sound;
1385 /* copy sound settings to some elements that are only stored in level file
1386 in native R'n'D levels, but are used by game engine in native EM levels */
1387 for (i = 0; copy_properties[i][0] != -1; i++)
1388 for (j = 1; j <= 4; j++)
1389 for (act = 0; act < NUM_ACTIONS; act++)
1390 element_info[copy_properties[i][j]].sound[act] =
1391 element_info[copy_properties[i][0]].sound[act];
1394 static void InitGameModeSoundInfo()
1398 /* set values to -1 to identify later as "uninitialized" values */
1399 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1402 /* initialize gamemode/sound mapping from static configuration */
1403 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1405 int gamemode = gamemode_to_sound[i].gamemode;
1406 int sound = gamemode_to_sound[i].sound;
1409 gamemode = GAME_MODE_DEFAULT;
1411 menu.sound[gamemode] = sound;
1414 /* now set all '-1' values to levelset specific default values */
1415 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1416 if (menu.sound[i] == -1)
1417 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1420 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1421 if (menu.sound[i] != -1)
1422 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1426 static void set_sound_parameters(int sound, char **parameter_raw)
1428 int parameter[NUM_SND_ARGS];
1431 /* get integer values from string parameters */
1432 for (i = 0; i < NUM_SND_ARGS; i++)
1434 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1435 sound_config_suffix[i].type);
1437 /* explicit loop mode setting in configuration overrides default value */
1438 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1439 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1441 /* sound volume to change the original volume when loading the sound file */
1442 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1444 /* sound priority to give certain sounds a higher or lower priority */
1445 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1448 static void InitSoundInfo()
1450 int *sound_effect_properties;
1451 int num_sounds = getSoundListSize();
1454 checked_free(sound_info);
1456 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1457 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1459 /* initialize sound effect for all elements to "no sound" */
1460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1461 for (j = 0; j < NUM_ACTIONS; j++)
1462 element_info[i].sound[j] = SND_UNDEFINED;
1464 for (i = 0; i < num_sounds; i++)
1466 struct FileInfo *sound = getSoundListEntry(i);
1467 int len_effect_text = strlen(sound->token);
1469 sound_effect_properties[i] = ACTION_OTHER;
1470 sound_info[i].loop = FALSE; /* default: play sound only once */
1473 printf("::: sound %d: '%s'\n", i, sound->token);
1476 /* determine all loop sounds and identify certain sound classes */
1478 for (j = 0; element_action_info[j].suffix; j++)
1480 int len_action_text = strlen(element_action_info[j].suffix);
1482 if (len_action_text < len_effect_text &&
1483 strcmp(&sound->token[len_effect_text - len_action_text],
1484 element_action_info[j].suffix) == 0)
1486 sound_effect_properties[i] = element_action_info[j].value;
1487 sound_info[i].loop = element_action_info[j].is_loop_sound;
1493 /* associate elements and some selected sound actions */
1495 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1497 if (element_info[j].class_name)
1499 int len_class_text = strlen(element_info[j].class_name);
1501 if (len_class_text + 1 < len_effect_text &&
1502 strncmp(sound->token,
1503 element_info[j].class_name, len_class_text) == 0 &&
1504 sound->token[len_class_text] == '.')
1506 int sound_action_value = sound_effect_properties[i];
1508 element_info[j].sound[sound_action_value] = i;
1513 set_sound_parameters(i, sound->parameter);
1516 free(sound_effect_properties);
1519 static void InitGameModeMusicInfo()
1521 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1522 int num_property_mappings = getMusicListPropertyMappingSize();
1523 int default_levelset_music = -1;
1526 /* set values to -1 to identify later as "uninitialized" values */
1527 for (i = 0; i < MAX_LEVELS; i++)
1528 levelset.music[i] = -1;
1529 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1532 /* initialize gamemode/music mapping from static configuration */
1533 for (i = 0; gamemode_to_music[i].music > -1; i++)
1535 int gamemode = gamemode_to_music[i].gamemode;
1536 int music = gamemode_to_music[i].music;
1539 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1543 gamemode = GAME_MODE_DEFAULT;
1545 menu.music[gamemode] = music;
1548 /* initialize gamemode/music mapping from dynamic configuration */
1549 for (i = 0; i < num_property_mappings; i++)
1551 int prefix = property_mapping[i].base_index;
1552 int gamemode = property_mapping[i].ext1_index;
1553 int level = property_mapping[i].ext2_index;
1554 int music = property_mapping[i].artwork_index;
1557 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1558 prefix, gamemode, level, music);
1561 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1565 gamemode = GAME_MODE_DEFAULT;
1567 /* level specific music only allowed for in-game music */
1568 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1569 gamemode = GAME_MODE_PLAYING;
1574 default_levelset_music = music;
1577 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1578 levelset.music[level] = music;
1579 if (gamemode != GAME_MODE_PLAYING)
1580 menu.music[gamemode] = music;
1583 /* now set all '-1' values to menu specific default values */
1584 /* (undefined values of "levelset.music[]" might stay at "-1" to
1585 allow dynamic selection of music files from music directory!) */
1586 for (i = 0; i < MAX_LEVELS; i++)
1587 if (levelset.music[i] == -1)
1588 levelset.music[i] = default_levelset_music;
1589 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1590 if (menu.music[i] == -1)
1591 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1594 for (i = 0; i < MAX_LEVELS; i++)
1595 if (levelset.music[i] != -1)
1596 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1597 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1598 if (menu.music[i] != -1)
1599 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1603 static void set_music_parameters(int music, char **parameter_raw)
1605 int parameter[NUM_MUS_ARGS];
1608 /* get integer values from string parameters */
1609 for (i = 0; i < NUM_MUS_ARGS; i++)
1611 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1612 music_config_suffix[i].type);
1614 /* explicit loop mode setting in configuration overrides default value */
1615 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1616 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1619 static void InitMusicInfo()
1621 int num_music = getMusicListSize();
1624 checked_free(music_info);
1626 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1628 for (i = 0; i < num_music; i++)
1630 struct FileInfo *music = getMusicListEntry(i);
1631 int len_music_text = strlen(music->token);
1633 music_info[i].loop = TRUE; /* default: play music in loop mode */
1635 /* determine all loop music */
1637 for (j = 0; music_prefix_info[j].prefix; j++)
1639 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1641 if (len_prefix_text < len_music_text &&
1642 strncmp(music->token,
1643 music_prefix_info[j].prefix, len_prefix_text) == 0)
1645 music_info[i].loop = music_prefix_info[j].is_loop_music;
1651 set_music_parameters(i, music->parameter);
1655 static void ReinitializeGraphics()
1657 InitGraphicInfo(); /* graphic properties mapping */
1658 InitElementGraphicInfo(); /* element game graphic mapping */
1659 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1661 InitElementSmallImages(); /* scale images to all needed sizes */
1662 InitFontGraphicInfo(); /* initialize text drawing functions */
1664 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1666 SetMainBackgroundImage(IMG_BACKGROUND);
1667 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1673 static void ReinitializeSounds()
1675 InitSoundInfo(); /* sound properties mapping */
1676 InitElementSoundInfo(); /* element game sound mapping */
1677 InitGameModeSoundInfo(); /* game mode sound mapping */
1679 InitPlayLevelSound(); /* internal game sound settings */
1682 static void ReinitializeMusic()
1684 InitMusicInfo(); /* music properties mapping */
1685 InitGameModeMusicInfo(); /* game mode music mapping */
1688 static int get_special_property_bit(int element, int property_bit_nr)
1690 struct PropertyBitInfo
1696 static struct PropertyBitInfo pb_can_move_into_acid[] =
1698 /* the player may be able fall into acid when gravity is activated */
1703 { EL_SP_MURPHY, 0 },
1704 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1706 /* all element that can move may be able to also move into acid */
1709 { EL_BUG_RIGHT, 1 },
1712 { EL_SPACESHIP, 2 },
1713 { EL_SPACESHIP_LEFT, 2 },
1714 { EL_SPACESHIP_RIGHT, 2 },
1715 { EL_SPACESHIP_UP, 2 },
1716 { EL_SPACESHIP_DOWN, 2 },
1717 { EL_BD_BUTTERFLY, 3 },
1718 { EL_BD_BUTTERFLY_LEFT, 3 },
1719 { EL_BD_BUTTERFLY_RIGHT, 3 },
1720 { EL_BD_BUTTERFLY_UP, 3 },
1721 { EL_BD_BUTTERFLY_DOWN, 3 },
1722 { EL_BD_FIREFLY, 4 },
1723 { EL_BD_FIREFLY_LEFT, 4 },
1724 { EL_BD_FIREFLY_RIGHT, 4 },
1725 { EL_BD_FIREFLY_UP, 4 },
1726 { EL_BD_FIREFLY_DOWN, 4 },
1728 { EL_DARK_YAMYAM, 6 },
1731 { EL_PACMAN_LEFT, 8 },
1732 { EL_PACMAN_RIGHT, 8 },
1733 { EL_PACMAN_UP, 8 },
1734 { EL_PACMAN_DOWN, 8 },
1736 { EL_MOLE_LEFT, 9 },
1737 { EL_MOLE_RIGHT, 9 },
1739 { EL_MOLE_DOWN, 9 },
1743 { EL_SATELLITE, 13 },
1744 { EL_SP_SNIKSNAK, 14 },
1745 { EL_SP_ELECTRON, 15 },
1752 static struct PropertyBitInfo pb_dont_collide_with[] =
1754 { EL_SP_SNIKSNAK, 0 },
1755 { EL_SP_ELECTRON, 1 },
1763 struct PropertyBitInfo *pb_info;
1766 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1767 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1772 struct PropertyBitInfo *pb_info = NULL;
1775 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1776 if (pb_definition[i].bit_nr == property_bit_nr)
1777 pb_info = pb_definition[i].pb_info;
1779 if (pb_info == NULL)
1782 for (i = 0; pb_info[i].element != -1; i++)
1783 if (pb_info[i].element == element)
1784 return pb_info[i].bit_nr;
1789 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1790 boolean property_value)
1792 int bit_nr = get_special_property_bit(element, property_bit_nr);
1797 *bitfield |= (1 << bit_nr);
1799 *bitfield &= ~(1 << bit_nr);
1803 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1805 int bit_nr = get_special_property_bit(element, property_bit_nr);
1808 return ((*bitfield & (1 << bit_nr)) != 0);
1813 void InitElementPropertiesStatic()
1815 static int ep_diggable[] =
1820 EL_SP_BUGGY_BASE_ACTIVATING,
1823 EL_INVISIBLE_SAND_ACTIVE,
1826 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1827 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1831 EL_SP_BUGGY_BASE_ACTIVE,
1837 static int ep_collectible_only[] =
1858 EL_DYNABOMB_INCREASE_NUMBER,
1859 EL_DYNABOMB_INCREASE_SIZE,
1860 EL_DYNABOMB_INCREASE_POWER,
1879 static int ep_dont_run_into[] =
1881 /* same elements as in 'ep_dont_touch' */
1887 /* same elements as in 'ep_dont_collide_with' */
1899 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1903 EL_SP_BUGGY_BASE_ACTIVE,
1909 static int ep_dont_collide_with[] =
1911 /* same elements as in 'ep_dont_touch' */
1927 static int ep_dont_touch[] =
1936 static int ep_indestructible[] =
1940 EL_ACID_POOL_TOPLEFT,
1941 EL_ACID_POOL_TOPRIGHT,
1942 EL_ACID_POOL_BOTTOMLEFT,
1943 EL_ACID_POOL_BOTTOM,
1944 EL_ACID_POOL_BOTTOMRIGHT,
1945 EL_SP_HARDWARE_GRAY,
1946 EL_SP_HARDWARE_GREEN,
1947 EL_SP_HARDWARE_BLUE,
1949 EL_SP_HARDWARE_YELLOW,
1950 EL_SP_HARDWARE_BASE_1,
1951 EL_SP_HARDWARE_BASE_2,
1952 EL_SP_HARDWARE_BASE_3,
1953 EL_SP_HARDWARE_BASE_4,
1954 EL_SP_HARDWARE_BASE_5,
1955 EL_SP_HARDWARE_BASE_6,
1956 EL_INVISIBLE_STEELWALL,
1957 EL_INVISIBLE_STEELWALL_ACTIVE,
1958 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1959 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1960 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1961 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1962 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1963 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1964 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1965 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1966 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1967 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1968 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1969 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1971 EL_LIGHT_SWITCH_ACTIVE,
1972 EL_SIGN_EXCLAMATION,
1973 EL_SIGN_RADIOACTIVITY,
1984 EL_STEELWALL_SLIPPERY,
2015 EL_SWITCHGATE_OPENING,
2016 EL_SWITCHGATE_CLOSED,
2017 EL_SWITCHGATE_CLOSING,
2019 EL_SWITCHGATE_SWITCH_UP,
2020 EL_SWITCHGATE_SWITCH_DOWN,
2023 EL_TIMEGATE_OPENING,
2025 EL_TIMEGATE_CLOSING,
2028 EL_TIMEGATE_SWITCH_ACTIVE,
2033 EL_TUBE_VERTICAL_LEFT,
2034 EL_TUBE_VERTICAL_RIGHT,
2035 EL_TUBE_HORIZONTAL_UP,
2036 EL_TUBE_HORIZONTAL_DOWN,
2044 static int ep_slippery[] =
2058 EL_ROBOT_WHEEL_ACTIVE,
2064 EL_ACID_POOL_TOPLEFT,
2065 EL_ACID_POOL_TOPRIGHT,
2075 EL_STEELWALL_SLIPPERY,
2078 EL_EMC_WALL_SLIPPERY_1,
2079 EL_EMC_WALL_SLIPPERY_2,
2080 EL_EMC_WALL_SLIPPERY_3,
2081 EL_EMC_WALL_SLIPPERY_4,
2085 static int ep_can_change[] =
2090 static int ep_can_move[] =
2092 /* same elements as in 'pb_can_move_into_acid' */
2114 static int ep_can_fall[] =
2129 EL_BD_MAGIC_WALL_FULL,
2142 static int ep_can_smash_player[] =
2167 static int ep_can_smash_enemies[] =
2175 static int ep_can_smash_everything[] =
2183 static int ep_explodes_by_fire[] =
2185 /* same elements as in 'ep_explodes_impact' */
2190 /* same elements as in 'ep_explodes_smashed' */
2199 EL_DYNABOMB_PLAYER_1_ACTIVE,
2200 EL_DYNABOMB_PLAYER_2_ACTIVE,
2201 EL_DYNABOMB_PLAYER_3_ACTIVE,
2202 EL_DYNABOMB_PLAYER_4_ACTIVE,
2203 EL_DYNABOMB_INCREASE_NUMBER,
2204 EL_DYNABOMB_INCREASE_SIZE,
2205 EL_DYNABOMB_INCREASE_POWER,
2206 EL_SP_DISK_RED_ACTIVE,
2219 static int ep_explodes_smashed[] =
2221 /* same elements as in 'ep_explodes_impact' */
2234 static int ep_explodes_impact[] =
2242 static int ep_walkable_over[] =
2246 EL_SOKOBAN_FIELD_EMPTY,
2264 static int ep_walkable_inside[] =
2269 EL_TUBE_VERTICAL_LEFT,
2270 EL_TUBE_VERTICAL_RIGHT,
2271 EL_TUBE_HORIZONTAL_UP,
2272 EL_TUBE_HORIZONTAL_DOWN,
2280 static int ep_walkable_under[] =
2285 static int ep_passable_over[] =
2308 static int ep_passable_inside[] =
2314 EL_SP_PORT_HORIZONTAL,
2315 EL_SP_PORT_VERTICAL,
2317 EL_SP_GRAVITY_PORT_LEFT,
2318 EL_SP_GRAVITY_PORT_RIGHT,
2319 EL_SP_GRAVITY_PORT_UP,
2320 EL_SP_GRAVITY_PORT_DOWN,
2321 EL_SP_GRAVITY_ON_PORT_LEFT,
2322 EL_SP_GRAVITY_ON_PORT_RIGHT,
2323 EL_SP_GRAVITY_ON_PORT_UP,
2324 EL_SP_GRAVITY_ON_PORT_DOWN,
2325 EL_SP_GRAVITY_OFF_PORT_LEFT,
2326 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2327 EL_SP_GRAVITY_OFF_PORT_UP,
2328 EL_SP_GRAVITY_OFF_PORT_DOWN,
2332 static int ep_passable_under[] =
2337 static int ep_droppable[] =
2342 static int ep_explodes_1x1_old[] =
2347 static int ep_pushable[] =
2359 EL_SOKOBAN_FIELD_FULL,
2367 static int ep_explodes_cross_old[] =
2372 static int ep_protected[] =
2374 /* same elements as in 'ep_walkable_inside' */
2378 EL_TUBE_VERTICAL_LEFT,
2379 EL_TUBE_VERTICAL_RIGHT,
2380 EL_TUBE_HORIZONTAL_UP,
2381 EL_TUBE_HORIZONTAL_DOWN,
2387 /* same elements as in 'ep_passable_over' */
2407 /* same elements as in 'ep_passable_inside' */
2412 EL_SP_PORT_HORIZONTAL,
2413 EL_SP_PORT_VERTICAL,
2415 EL_SP_GRAVITY_PORT_LEFT,
2416 EL_SP_GRAVITY_PORT_RIGHT,
2417 EL_SP_GRAVITY_PORT_UP,
2418 EL_SP_GRAVITY_PORT_DOWN,
2419 EL_SP_GRAVITY_ON_PORT_LEFT,
2420 EL_SP_GRAVITY_ON_PORT_RIGHT,
2421 EL_SP_GRAVITY_ON_PORT_UP,
2422 EL_SP_GRAVITY_ON_PORT_DOWN,
2423 EL_SP_GRAVITY_OFF_PORT_LEFT,
2424 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2425 EL_SP_GRAVITY_OFF_PORT_UP,
2426 EL_SP_GRAVITY_OFF_PORT_DOWN,
2430 static int ep_throwable[] =
2435 static int ep_can_explode[] =
2437 /* same elements as in 'ep_explodes_impact' */
2442 /* same elements as in 'ep_explodes_smashed' */
2448 /* elements that can explode by explosion or by dragonfire */
2451 EL_DYNABOMB_PLAYER_1_ACTIVE,
2452 EL_DYNABOMB_PLAYER_2_ACTIVE,
2453 EL_DYNABOMB_PLAYER_3_ACTIVE,
2454 EL_DYNABOMB_PLAYER_4_ACTIVE,
2455 EL_DYNABOMB_INCREASE_NUMBER,
2456 EL_DYNABOMB_INCREASE_SIZE,
2457 EL_DYNABOMB_INCREASE_POWER,
2458 EL_SP_DISK_RED_ACTIVE,
2466 /* elements that can explode only by explosion */
2471 static int ep_gravity_reachable[] =
2477 EL_INVISIBLE_SAND_ACTIVE,
2482 EL_SP_PORT_HORIZONTAL,
2483 EL_SP_PORT_VERTICAL,
2485 EL_SP_GRAVITY_PORT_LEFT,
2486 EL_SP_GRAVITY_PORT_RIGHT,
2487 EL_SP_GRAVITY_PORT_UP,
2488 EL_SP_GRAVITY_PORT_DOWN,
2489 EL_SP_GRAVITY_ON_PORT_LEFT,
2490 EL_SP_GRAVITY_ON_PORT_RIGHT,
2491 EL_SP_GRAVITY_ON_PORT_UP,
2492 EL_SP_GRAVITY_ON_PORT_DOWN,
2493 EL_SP_GRAVITY_OFF_PORT_LEFT,
2494 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2495 EL_SP_GRAVITY_OFF_PORT_UP,
2496 EL_SP_GRAVITY_OFF_PORT_DOWN,
2501 static int ep_player[] =
2508 EL_SOKOBAN_FIELD_PLAYER,
2513 static int ep_can_pass_magic_wall[] =
2526 static int ep_switchable[] =
2530 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2531 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2532 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2533 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2534 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2535 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2536 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2537 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2538 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2539 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2540 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2541 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2542 EL_SWITCHGATE_SWITCH_UP,
2543 EL_SWITCHGATE_SWITCH_DOWN,
2545 EL_LIGHT_SWITCH_ACTIVE,
2547 EL_BALLOON_SWITCH_LEFT,
2548 EL_BALLOON_SWITCH_RIGHT,
2549 EL_BALLOON_SWITCH_UP,
2550 EL_BALLOON_SWITCH_DOWN,
2551 EL_BALLOON_SWITCH_ANY,
2554 EL_EMC_MAGIC_BALL_SWITCH,
2558 static int ep_bd_element[] =
2591 static int ep_sp_element[] =
2593 /* should always be valid */
2596 /* standard classic Supaplex elements */
2603 EL_SP_HARDWARE_GRAY,
2611 EL_SP_GRAVITY_PORT_RIGHT,
2612 EL_SP_GRAVITY_PORT_DOWN,
2613 EL_SP_GRAVITY_PORT_LEFT,
2614 EL_SP_GRAVITY_PORT_UP,
2619 EL_SP_PORT_VERTICAL,
2620 EL_SP_PORT_HORIZONTAL,
2626 EL_SP_HARDWARE_BASE_1,
2627 EL_SP_HARDWARE_GREEN,
2628 EL_SP_HARDWARE_BLUE,
2630 EL_SP_HARDWARE_YELLOW,
2631 EL_SP_HARDWARE_BASE_2,
2632 EL_SP_HARDWARE_BASE_3,
2633 EL_SP_HARDWARE_BASE_4,
2634 EL_SP_HARDWARE_BASE_5,
2635 EL_SP_HARDWARE_BASE_6,
2639 /* additional elements that appeared in newer Supaplex levels */
2642 /* additional gravity port elements (not switching, but setting gravity) */
2643 EL_SP_GRAVITY_ON_PORT_LEFT,
2644 EL_SP_GRAVITY_ON_PORT_RIGHT,
2645 EL_SP_GRAVITY_ON_PORT_UP,
2646 EL_SP_GRAVITY_ON_PORT_DOWN,
2647 EL_SP_GRAVITY_OFF_PORT_LEFT,
2648 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2649 EL_SP_GRAVITY_OFF_PORT_UP,
2650 EL_SP_GRAVITY_OFF_PORT_DOWN,
2652 /* more than one Murphy in a level results in an inactive clone */
2655 /* runtime Supaplex elements */
2656 EL_SP_DISK_RED_ACTIVE,
2657 EL_SP_TERMINAL_ACTIVE,
2658 EL_SP_BUGGY_BASE_ACTIVATING,
2659 EL_SP_BUGGY_BASE_ACTIVE,
2665 static int ep_sb_element[] =
2670 EL_SOKOBAN_FIELD_EMPTY,
2671 EL_SOKOBAN_FIELD_FULL,
2672 EL_SOKOBAN_FIELD_PLAYER,
2677 EL_INVISIBLE_STEELWALL,
2681 static int ep_gem[] =
2692 static int ep_food_dark_yamyam[] =
2719 static int ep_food_penguin[] =
2732 static int ep_food_pig[] =
2743 static int ep_historic_wall[] =
2768 EL_EXPANDABLE_WALL_HORIZONTAL,
2769 EL_EXPANDABLE_WALL_VERTICAL,
2770 EL_EXPANDABLE_WALL_ANY,
2771 EL_EXPANDABLE_WALL_GROWING,
2778 EL_SP_HARDWARE_GRAY,
2779 EL_SP_HARDWARE_GREEN,
2780 EL_SP_HARDWARE_BLUE,
2782 EL_SP_HARDWARE_YELLOW,
2783 EL_SP_HARDWARE_BASE_1,
2784 EL_SP_HARDWARE_BASE_2,
2785 EL_SP_HARDWARE_BASE_3,
2786 EL_SP_HARDWARE_BASE_4,
2787 EL_SP_HARDWARE_BASE_5,
2788 EL_SP_HARDWARE_BASE_6,
2790 EL_SP_TERMINAL_ACTIVE,
2793 EL_INVISIBLE_STEELWALL,
2794 EL_INVISIBLE_STEELWALL_ACTIVE,
2796 EL_INVISIBLE_WALL_ACTIVE,
2797 EL_STEELWALL_SLIPPERY,
2813 static int ep_historic_solid[] =
2817 EL_EXPANDABLE_WALL_HORIZONTAL,
2818 EL_EXPANDABLE_WALL_VERTICAL,
2819 EL_EXPANDABLE_WALL_ANY,
2832 EL_QUICKSAND_FILLING,
2833 EL_QUICKSAND_EMPTYING,
2835 EL_MAGIC_WALL_ACTIVE,
2836 EL_MAGIC_WALL_EMPTYING,
2837 EL_MAGIC_WALL_FILLING,
2841 EL_BD_MAGIC_WALL_ACTIVE,
2842 EL_BD_MAGIC_WALL_EMPTYING,
2843 EL_BD_MAGIC_WALL_FULL,
2844 EL_BD_MAGIC_WALL_FILLING,
2845 EL_BD_MAGIC_WALL_DEAD,
2854 EL_SP_TERMINAL_ACTIVE,
2858 EL_INVISIBLE_WALL_ACTIVE,
2859 EL_SWITCHGATE_SWITCH_UP,
2860 EL_SWITCHGATE_SWITCH_DOWN,
2862 EL_TIMEGATE_SWITCH_ACTIVE,
2874 /* the following elements are a direct copy of "indestructible" elements,
2875 except "EL_ACID", which is "indestructible", but not "solid"! */
2880 EL_ACID_POOL_TOPLEFT,
2881 EL_ACID_POOL_TOPRIGHT,
2882 EL_ACID_POOL_BOTTOMLEFT,
2883 EL_ACID_POOL_BOTTOM,
2884 EL_ACID_POOL_BOTTOMRIGHT,
2885 EL_SP_HARDWARE_GRAY,
2886 EL_SP_HARDWARE_GREEN,
2887 EL_SP_HARDWARE_BLUE,
2889 EL_SP_HARDWARE_YELLOW,
2890 EL_SP_HARDWARE_BASE_1,
2891 EL_SP_HARDWARE_BASE_2,
2892 EL_SP_HARDWARE_BASE_3,
2893 EL_SP_HARDWARE_BASE_4,
2894 EL_SP_HARDWARE_BASE_5,
2895 EL_SP_HARDWARE_BASE_6,
2896 EL_INVISIBLE_STEELWALL,
2897 EL_INVISIBLE_STEELWALL_ACTIVE,
2898 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2899 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2900 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2901 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2902 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2903 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2904 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2905 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2906 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2907 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2908 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2909 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2911 EL_LIGHT_SWITCH_ACTIVE,
2912 EL_SIGN_EXCLAMATION,
2913 EL_SIGN_RADIOACTIVITY,
2924 EL_STEELWALL_SLIPPERY,
2947 EL_SWITCHGATE_OPENING,
2948 EL_SWITCHGATE_CLOSED,
2949 EL_SWITCHGATE_CLOSING,
2951 EL_TIMEGATE_OPENING,
2953 EL_TIMEGATE_CLOSING,
2957 EL_TUBE_VERTICAL_LEFT,
2958 EL_TUBE_VERTICAL_RIGHT,
2959 EL_TUBE_HORIZONTAL_UP,
2960 EL_TUBE_HORIZONTAL_DOWN,
2968 static int ep_classic_enemy[] =
2984 static int ep_belt[] =
2986 EL_CONVEYOR_BELT_1_LEFT,
2987 EL_CONVEYOR_BELT_1_MIDDLE,
2988 EL_CONVEYOR_BELT_1_RIGHT,
2989 EL_CONVEYOR_BELT_2_LEFT,
2990 EL_CONVEYOR_BELT_2_MIDDLE,
2991 EL_CONVEYOR_BELT_2_RIGHT,
2992 EL_CONVEYOR_BELT_3_LEFT,
2993 EL_CONVEYOR_BELT_3_MIDDLE,
2994 EL_CONVEYOR_BELT_3_RIGHT,
2995 EL_CONVEYOR_BELT_4_LEFT,
2996 EL_CONVEYOR_BELT_4_MIDDLE,
2997 EL_CONVEYOR_BELT_4_RIGHT,
3001 static int ep_belt_active[] =
3003 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3004 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3005 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3006 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3007 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3008 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3009 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3010 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3011 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3012 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3013 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3014 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3018 static int ep_belt_switch[] =
3020 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3021 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3022 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3023 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3024 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3025 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3026 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3027 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3028 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3029 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3030 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3031 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3035 static int ep_tube[] =
3042 EL_TUBE_HORIZONTAL_UP,
3043 EL_TUBE_HORIZONTAL_DOWN,
3045 EL_TUBE_VERTICAL_LEFT,
3046 EL_TUBE_VERTICAL_RIGHT,
3051 static int ep_keygate[] =
3080 static int ep_amoeboid[] =
3090 static int ep_amoebalive[] =
3099 static int ep_has_content[] =
3109 static int ep_can_turn_each_move[] =
3111 /* !!! do something with this one !!! */
3115 static int ep_can_grow[] =
3127 static int ep_active_bomb[] =
3130 EL_DYNABOMB_PLAYER_1_ACTIVE,
3131 EL_DYNABOMB_PLAYER_2_ACTIVE,
3132 EL_DYNABOMB_PLAYER_3_ACTIVE,
3133 EL_DYNABOMB_PLAYER_4_ACTIVE,
3134 EL_SP_DISK_RED_ACTIVE,
3138 static int ep_inactive[] =
3187 EL_INVISIBLE_STEELWALL,
3195 EL_WALL_EMERALD_YELLOW,
3196 EL_DYNABOMB_INCREASE_NUMBER,
3197 EL_DYNABOMB_INCREASE_SIZE,
3198 EL_DYNABOMB_INCREASE_POWER,
3202 EL_SOKOBAN_FIELD_EMPTY,
3203 EL_SOKOBAN_FIELD_FULL,
3204 EL_WALL_EMERALD_RED,
3205 EL_WALL_EMERALD_PURPLE,
3206 EL_ACID_POOL_TOPLEFT,
3207 EL_ACID_POOL_TOPRIGHT,
3208 EL_ACID_POOL_BOTTOMLEFT,
3209 EL_ACID_POOL_BOTTOM,
3210 EL_ACID_POOL_BOTTOMRIGHT,
3214 EL_BD_MAGIC_WALL_DEAD,
3215 EL_AMOEBA_TO_DIAMOND,
3223 EL_SP_GRAVITY_PORT_RIGHT,
3224 EL_SP_GRAVITY_PORT_DOWN,
3225 EL_SP_GRAVITY_PORT_LEFT,
3226 EL_SP_GRAVITY_PORT_UP,
3227 EL_SP_PORT_HORIZONTAL,
3228 EL_SP_PORT_VERTICAL,
3239 EL_SP_HARDWARE_GRAY,
3240 EL_SP_HARDWARE_GREEN,
3241 EL_SP_HARDWARE_BLUE,
3243 EL_SP_HARDWARE_YELLOW,
3244 EL_SP_HARDWARE_BASE_1,
3245 EL_SP_HARDWARE_BASE_2,
3246 EL_SP_HARDWARE_BASE_3,
3247 EL_SP_HARDWARE_BASE_4,
3248 EL_SP_HARDWARE_BASE_5,
3249 EL_SP_HARDWARE_BASE_6,
3250 EL_SP_GRAVITY_ON_PORT_LEFT,
3251 EL_SP_GRAVITY_ON_PORT_RIGHT,
3252 EL_SP_GRAVITY_ON_PORT_UP,
3253 EL_SP_GRAVITY_ON_PORT_DOWN,
3254 EL_SP_GRAVITY_OFF_PORT_LEFT,
3255 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3256 EL_SP_GRAVITY_OFF_PORT_UP,
3257 EL_SP_GRAVITY_OFF_PORT_DOWN,
3258 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3259 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3260 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3261 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3262 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3263 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3264 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3265 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3266 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3267 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3268 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3269 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3270 EL_SIGN_EXCLAMATION,
3271 EL_SIGN_RADIOACTIVITY,
3282 EL_STEELWALL_SLIPPERY,
3287 EL_EMC_WALL_SLIPPERY_1,
3288 EL_EMC_WALL_SLIPPERY_2,
3289 EL_EMC_WALL_SLIPPERY_3,
3290 EL_EMC_WALL_SLIPPERY_4,
3310 static int ep_em_slippery_wall[] =
3315 static int ep_gfx_crumbled[] =
3328 } element_properties[] =
3330 { ep_diggable, EP_DIGGABLE },
3331 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3332 { ep_dont_run_into, EP_DONT_RUN_INTO },
3333 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3334 { ep_dont_touch, EP_DONT_TOUCH },
3335 { ep_indestructible, EP_INDESTRUCTIBLE },
3336 { ep_slippery, EP_SLIPPERY },
3337 { ep_can_change, EP_CAN_CHANGE },
3338 { ep_can_move, EP_CAN_MOVE },
3339 { ep_can_fall, EP_CAN_FALL },
3340 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3341 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3342 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3343 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3344 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3345 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3346 { ep_walkable_over, EP_WALKABLE_OVER },
3347 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3348 { ep_walkable_under, EP_WALKABLE_UNDER },
3349 { ep_passable_over, EP_PASSABLE_OVER },
3350 { ep_passable_inside, EP_PASSABLE_INSIDE },
3351 { ep_passable_under, EP_PASSABLE_UNDER },
3352 { ep_droppable, EP_DROPPABLE },
3353 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3354 { ep_pushable, EP_PUSHABLE },
3355 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3356 { ep_protected, EP_PROTECTED },
3357 { ep_throwable, EP_THROWABLE },
3358 { ep_can_explode, EP_CAN_EXPLODE },
3359 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3361 { ep_player, EP_PLAYER },
3362 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3363 { ep_switchable, EP_SWITCHABLE },
3364 { ep_bd_element, EP_BD_ELEMENT },
3365 { ep_sp_element, EP_SP_ELEMENT },
3366 { ep_sb_element, EP_SB_ELEMENT },
3368 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3369 { ep_food_penguin, EP_FOOD_PENGUIN },
3370 { ep_food_pig, EP_FOOD_PIG },
3371 { ep_historic_wall, EP_HISTORIC_WALL },
3372 { ep_historic_solid, EP_HISTORIC_SOLID },
3373 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3374 { ep_belt, EP_BELT },
3375 { ep_belt_active, EP_BELT_ACTIVE },
3376 { ep_belt_switch, EP_BELT_SWITCH },
3377 { ep_tube, EP_TUBE },
3378 { ep_keygate, EP_KEYGATE },
3379 { ep_amoeboid, EP_AMOEBOID },
3380 { ep_amoebalive, EP_AMOEBALIVE },
3381 { ep_has_content, EP_HAS_CONTENT },
3382 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3383 { ep_can_grow, EP_CAN_GROW },
3384 { ep_active_bomb, EP_ACTIVE_BOMB },
3385 { ep_inactive, EP_INACTIVE },
3387 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3389 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3396 /* always start with reliable default values (element has no properties) */
3397 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3398 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3399 SET_PROPERTY(i, j, FALSE);
3401 /* set all base element properties from above array definitions */
3402 for (i = 0; element_properties[i].elements != NULL; i++)
3403 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3404 SET_PROPERTY((element_properties[i].elements)[j],
3405 element_properties[i].property, TRUE);
3407 /* copy properties to some elements that are only stored in level file */
3408 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3409 for (j = 0; copy_properties[j][0] != -1; j++)
3410 if (HAS_PROPERTY(copy_properties[j][0], i))
3411 for (k = 1; k <= 4; k++)
3412 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3415 void InitElementPropertiesEngine(int engine_version)
3417 static int no_wall_properties[] =
3420 EP_COLLECTIBLE_ONLY,
3422 EP_DONT_COLLIDE_WITH,
3425 EP_CAN_SMASH_PLAYER,
3426 EP_CAN_SMASH_ENEMIES,
3427 EP_CAN_SMASH_EVERYTHING,
3432 EP_FOOD_DARK_YAMYAM,
3448 /* important: after initialization in InitElementPropertiesStatic(), the
3449 elements are not again initialized to a default value; therefore all
3450 changes have to make sure that they leave the element with a defined
3451 property (which means that conditional property changes must be set to
3452 a reliable default value before) */
3454 /* set all special, combined or engine dependent element properties */
3455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3457 /* ---------- INACTIVE ------------------------------------------------- */
3458 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3460 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3461 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3462 IS_WALKABLE_INSIDE(i) ||
3463 IS_WALKABLE_UNDER(i)));
3465 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3466 IS_PASSABLE_INSIDE(i) ||
3467 IS_PASSABLE_UNDER(i)));
3469 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3470 IS_PASSABLE_OVER(i)));
3472 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3473 IS_PASSABLE_INSIDE(i)));
3475 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3476 IS_PASSABLE_UNDER(i)));
3478 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3481 /* ---------- COLLECTIBLE ---------------------------------------------- */
3482 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3486 /* ---------- SNAPPABLE ------------------------------------------------ */
3487 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3488 IS_COLLECTIBLE(i) ||
3492 /* ---------- WALL ----------------------------------------------------- */
3493 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3495 for (j = 0; no_wall_properties[j] != -1; j++)
3496 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3497 i >= EL_FIRST_RUNTIME_UNREAL)
3498 SET_PROPERTY(i, EP_WALL, FALSE);
3500 if (IS_HISTORIC_WALL(i))
3501 SET_PROPERTY(i, EP_WALL, TRUE);
3503 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3504 if (engine_version < VERSION_IDENT(2,2,0,0))
3505 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3507 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3509 !IS_COLLECTIBLE(i)));
3511 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3513 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3514 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3516 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3517 IS_INDESTRUCTIBLE(i)));
3519 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3521 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3522 else if (engine_version < VERSION_IDENT(2,2,0,0))
3523 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3525 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3529 if (IS_CUSTOM_ELEMENT(i))
3531 /* these are additional properties which are initially false when set */
3533 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3535 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3536 if (DONT_COLLIDE_WITH(i))
3537 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3539 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3540 if (CAN_SMASH_EVERYTHING(i))
3541 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3542 if (CAN_SMASH_ENEMIES(i))
3543 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3546 /* ---------- CAN_SMASH ------------------------------------------------ */
3547 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3548 CAN_SMASH_ENEMIES(i) ||
3549 CAN_SMASH_EVERYTHING(i)));
3551 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3552 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3553 EXPLODES_BY_FIRE(i)));
3555 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3556 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3557 EXPLODES_SMASHED(i)));
3559 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3560 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3561 EXPLODES_IMPACT(i)));
3563 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3564 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3566 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3567 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3568 i == EL_BLACK_ORB));
3570 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3571 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3573 IS_CUSTOM_ELEMENT(i)));
3575 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3576 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3577 i == EL_SP_ELECTRON));
3579 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3580 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3581 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3582 getMoveIntoAcidProperty(&level, i));
3584 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3585 if (MAYBE_DONT_COLLIDE_WITH(i))
3586 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3587 getDontCollideWithProperty(&level, i));
3589 /* ---------- SP_PORT -------------------------------------------------- */
3590 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3591 IS_PASSABLE_INSIDE(i)));
3593 /* ---------- CAN_CHANGE ----------------------------------------------- */
3594 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3595 for (j = 0; j < element_info[i].num_change_pages; j++)
3596 if (element_info[i].change_page[j].can_change)
3597 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3599 /* ---------- HAS_ACTION ----------------------------------------------- */
3600 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3601 for (j = 0; j < element_info[i].num_change_pages; j++)
3602 if (element_info[i].change_page[j].has_action)
3603 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3605 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3606 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3609 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3611 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3612 element_info[i].crumbled[ACTION_DEFAULT] !=
3613 element_info[i].graphic[ACTION_DEFAULT]);
3615 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3616 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3617 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3621 /* dynamically adjust element properties according to game engine version */
3623 static int ep_em_slippery_wall[] =
3628 EL_EXPANDABLE_WALL_HORIZONTAL,
3629 EL_EXPANDABLE_WALL_VERTICAL,
3630 EL_EXPANDABLE_WALL_ANY,
3634 /* special EM style gems behaviour */
3635 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3636 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3637 level.em_slippery_gems);
3639 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3640 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3641 (level.em_slippery_gems &&
3642 engine_version > VERSION_IDENT(2,0,1,0)));
3645 /* set default push delay values (corrected since version 3.0.7-1) */
3646 if (engine_version < VERSION_IDENT(3,0,7,1))
3648 game.default_push_delay_fixed = 2;
3649 game.default_push_delay_random = 8;
3653 game.default_push_delay_fixed = 8;
3654 game.default_push_delay_random = 8;
3657 /* set uninitialized push delay values of custom elements in older levels */
3658 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3660 int element = EL_CUSTOM_START + i;
3662 if (element_info[element].push_delay_fixed == -1)
3663 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3664 if (element_info[element].push_delay_random == -1)
3665 element_info[element].push_delay_random = game.default_push_delay_random;
3668 /* set some other uninitialized values of custom elements in older levels */
3669 if (engine_version < VERSION_IDENT(3,1,0,0))
3671 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3673 int element = EL_CUSTOM_START + i;
3675 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3677 element_info[element].explosion_delay = 17;
3678 element_info[element].ignition_delay = 8;
3683 /* set element properties that were handled incorrectly in older levels */
3684 if (engine_version < VERSION_IDENT(3,1,0,0))
3686 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3687 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3691 /* this is needed because some graphics depend on element properties */
3692 if (game_status == GAME_MODE_PLAYING)
3693 InitElementGraphicInfo();
3696 static void InitGlobal()
3700 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3702 /* check if element_name_info entry defined for each element in "main.h" */
3703 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3704 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3706 element_info[i].token_name = element_name_info[i].token_name;
3707 element_info[i].class_name = element_name_info[i].class_name;
3708 element_info[i].editor_description=element_name_info[i].editor_description;
3711 global.autoplay_leveldir = NULL;
3712 global.convert_leveldir = NULL;
3714 global.frames_per_second = 0;
3715 global.fps_slowdown = FALSE;
3716 global.fps_slowdown_factor = 1;
3719 void Execute_Command(char *command)
3723 if (strcmp(command, "print graphicsinfo.conf") == 0)
3725 printf("# You can configure additional/alternative image files here.\n");
3726 printf("# (The entries below are default and therefore commented out.)\n");
3728 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3730 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3733 for (i = 0; image_config[i].token != NULL; i++)
3734 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3735 image_config[i].value));
3739 else if (strcmp(command, "print soundsinfo.conf") == 0)
3741 printf("# You can configure additional/alternative sound files here.\n");
3742 printf("# (The entries below are default and therefore commented out.)\n");
3744 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3746 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3749 for (i = 0; sound_config[i].token != NULL; i++)
3750 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3751 sound_config[i].value));
3755 else if (strcmp(command, "print musicinfo.conf") == 0)
3757 printf("# You can configure additional/alternative music files here.\n");
3758 printf("# (The entries below are default and therefore commented out.)\n");
3760 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3762 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3765 for (i = 0; music_config[i].token != NULL; i++)
3766 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3767 music_config[i].value));
3771 else if (strcmp(command, "print editorsetup.conf") == 0)
3773 printf("# You can configure your personal editor element list here.\n");
3774 printf("# (The entries below are default and therefore commented out.)\n");
3777 PrintEditorElementList();
3781 else if (strcmp(command, "print helpanim.conf") == 0)
3783 printf("# You can configure different element help animations here.\n");
3784 printf("# (The entries below are default and therefore commented out.)\n");
3787 for (i = 0; helpanim_config[i].token != NULL; i++)
3789 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3790 helpanim_config[i].value));
3792 if (strcmp(helpanim_config[i].token, "end") == 0)
3798 else if (strcmp(command, "print helptext.conf") == 0)
3800 printf("# You can configure different element help text here.\n");
3801 printf("# (The entries below are default and therefore commented out.)\n");
3804 for (i = 0; helptext_config[i].token != NULL; i++)
3805 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3806 helptext_config[i].value));
3810 else if (strncmp(command, "dump level ", 11) == 0)
3812 char *filename = &command[11];
3814 if (!fileExists(filename))
3815 Error(ERR_EXIT, "cannot open file '%s'", filename);
3817 LoadLevelFromFilename(&level, filename);
3822 else if (strncmp(command, "dump tape ", 10) == 0)
3824 char *filename = &command[10];
3826 if (!fileExists(filename))
3827 Error(ERR_EXIT, "cannot open file '%s'", filename);
3829 LoadTapeFromFilename(filename);
3834 else if (strncmp(command, "autoplay ", 9) == 0)
3836 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3838 while (*str_ptr != '\0') /* continue parsing string */
3840 /* cut leading whitespace from string, replace it by string terminator */
3841 while (*str_ptr == ' ' || *str_ptr == '\t')
3844 if (*str_ptr == '\0') /* end of string reached */
3847 if (global.autoplay_leveldir == NULL) /* read level set string */
3849 global.autoplay_leveldir = str_ptr;
3850 global.autoplay_all = TRUE; /* default: play all tapes */
3852 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3853 global.autoplay_level[i] = FALSE;
3855 else /* read level number string */
3857 int level_nr = atoi(str_ptr); /* get level_nr value */
3859 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3860 global.autoplay_level[level_nr] = TRUE;
3862 global.autoplay_all = FALSE;
3865 /* advance string pointer to the next whitespace (or end of string) */
3866 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3870 else if (strncmp(command, "convert ", 8) == 0)
3872 char *str_copy = getStringCopy(&command[8]);
3873 char *str_ptr = strchr(str_copy, ' ');
3875 global.convert_leveldir = str_copy;
3876 global.convert_level_nr = -1;
3878 if (str_ptr != NULL) /* level number follows */
3880 *str_ptr++ = '\0'; /* terminate leveldir string */
3881 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3886 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3890 static void InitSetup()
3892 LoadSetup(); /* global setup info */
3894 /* set some options from setup file */
3896 if (setup.options.verbose)
3897 options.verbose = TRUE;
3900 static void InitGameInfo()
3902 game.restart_level = FALSE;
3905 static void InitPlayerInfo()
3909 /* choose default local player */
3910 local_player = &stored_player[0];
3912 for (i = 0; i < MAX_PLAYERS; i++)
3913 stored_player[i].connected = FALSE;
3915 local_player->connected = TRUE;
3918 static void InitArtworkInfo()
3923 static char *get_string_in_brackets(char *string)
3925 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3927 sprintf(string_in_brackets, "[%s]", string);
3929 return string_in_brackets;
3932 static char *get_level_id_suffix(int id_nr)
3934 char *id_suffix = checked_malloc(1 + 3 + 1);
3936 if (id_nr < 0 || id_nr > 999)
3939 sprintf(id_suffix, ".%03d", id_nr);
3945 static char *get_element_class_token(int element)
3947 char *element_class_name = element_info[element].class_name;
3948 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3950 sprintf(element_class_token, "[%s]", element_class_name);
3952 return element_class_token;
3955 static char *get_action_class_token(int action)
3957 char *action_class_name = &element_action_info[action].suffix[1];
3958 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3960 sprintf(action_class_token, "[%s]", action_class_name);
3962 return action_class_token;
3966 static void InitArtworkConfig()
3968 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3969 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3970 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3971 static char *action_id_suffix[NUM_ACTIONS + 1];
3972 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3973 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3974 static char *level_id_suffix[MAX_LEVELS + 1];
3975 static char *dummy[1] = { NULL };
3976 static char *ignore_generic_tokens[] =
3982 static char **ignore_image_tokens;
3983 static char **ignore_sound_tokens;
3984 static char **ignore_music_tokens;
3985 int num_ignore_generic_tokens;
3986 int num_ignore_image_tokens;
3987 int num_ignore_sound_tokens;
3988 int num_ignore_music_tokens;
3991 /* dynamically determine list of generic tokens to be ignored */
3992 num_ignore_generic_tokens = 0;
3993 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3994 num_ignore_generic_tokens++;
3996 /* dynamically determine list of image tokens to be ignored */
3997 num_ignore_image_tokens = num_ignore_generic_tokens;
3998 for (i = 0; image_config_vars[i].token != NULL; i++)
3999 num_ignore_image_tokens++;
4000 ignore_image_tokens =
4001 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4002 for (i = 0; i < num_ignore_generic_tokens; i++)
4003 ignore_image_tokens[i] = ignore_generic_tokens[i];
4004 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4005 ignore_image_tokens[num_ignore_generic_tokens + i] =
4006 image_config_vars[i].token;
4007 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4009 /* dynamically determine list of sound tokens to be ignored */
4010 num_ignore_sound_tokens = num_ignore_generic_tokens;
4011 ignore_sound_tokens =
4012 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4013 for (i = 0; i < num_ignore_generic_tokens; i++)
4014 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4015 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4017 /* dynamically determine list of music tokens to be ignored */
4018 num_ignore_music_tokens = num_ignore_generic_tokens;
4019 ignore_music_tokens =
4020 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4021 for (i = 0; i < num_ignore_generic_tokens; i++)
4022 ignore_music_tokens[i] = ignore_generic_tokens[i];
4023 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4025 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4026 image_id_prefix[i] = element_info[i].token_name;
4027 for (i = 0; i < NUM_FONTS; i++)
4028 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4029 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4032 sound_id_prefix[i] = element_info[i].token_name;
4033 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4034 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4035 get_string_in_brackets(element_info[i].class_name);
4036 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4038 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4039 music_id_prefix[i] = music_prefix_info[i].prefix;
4040 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4042 for (i = 0; i < NUM_ACTIONS; i++)
4043 action_id_suffix[i] = element_action_info[i].suffix;
4044 action_id_suffix[NUM_ACTIONS] = NULL;
4046 for (i = 0; i < NUM_DIRECTIONS; i++)
4047 direction_id_suffix[i] = element_direction_info[i].suffix;
4048 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4050 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4051 special_id_suffix[i] = special_suffix_info[i].suffix;
4052 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4054 for (i = 0; i < MAX_LEVELS; i++)
4055 level_id_suffix[i] = get_level_id_suffix(i);
4056 level_id_suffix[MAX_LEVELS] = NULL;
4058 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4059 image_id_prefix, action_id_suffix, direction_id_suffix,
4060 special_id_suffix, ignore_image_tokens);
4061 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4062 sound_id_prefix, action_id_suffix, dummy,
4063 special_id_suffix, ignore_sound_tokens);
4064 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4065 music_id_prefix, special_id_suffix, level_id_suffix,
4066 dummy, ignore_music_tokens);
4069 static void InitMixer()
4077 char *filename_font_initial = NULL;
4078 Bitmap *bitmap_font_initial = NULL;
4081 /* determine settings for initial font (for displaying startup messages) */
4082 for (i = 0; image_config[i].token != NULL; i++)
4084 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4086 char font_token[128];
4089 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4090 len_font_token = strlen(font_token);
4092 if (strcmp(image_config[i].token, font_token) == 0)
4093 filename_font_initial = image_config[i].value;
4094 else if (strlen(image_config[i].token) > len_font_token &&
4095 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4097 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4098 font_initial[j].src_x = atoi(image_config[i].value);
4099 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4100 font_initial[j].src_y = atoi(image_config[i].value);
4101 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4102 font_initial[j].width = atoi(image_config[i].value);
4103 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4104 font_initial[j].height = atoi(image_config[i].value);
4109 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4111 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4112 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4115 if (filename_font_initial == NULL) /* should not happen */
4116 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4118 /* create additional image buffers for double-buffering */
4119 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4120 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4122 /* initialize screen properties */
4123 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4124 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4126 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4127 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4128 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4130 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4132 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4133 font_initial[j].bitmap = bitmap_font_initial;
4135 InitFontGraphicInfo();
4137 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4138 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4140 DrawInitText("Loading graphics:", 120, FC_GREEN);
4143 void InitGfxBackground()
4147 drawto = backbuffer;
4148 fieldbuffer = bitmap_db_field;
4149 SetDrawtoField(DRAW_BACKBUFFER);
4151 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4152 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4153 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4154 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4156 for (x = 0; x < MAX_BUF_XSIZE; x++)
4157 for (y = 0; y < MAX_BUF_YSIZE; y++)
4160 redraw_mask = REDRAW_ALL;
4163 static void InitLevelInfo()
4165 LoadLevelInfo(); /* global level info */
4166 LoadLevelSetup_LastSeries(); /* last played series info */
4167 LoadLevelSetup_SeriesInfo(); /* last played level info */
4170 void InitLevelArtworkInfo()
4172 LoadLevelArtworkInfo();
4175 static void InitImages()
4177 setLevelArtworkDir(artwork.gfx_first);
4180 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4181 leveldir_current->identifier,
4182 artwork.gfx_current_identifier,
4183 artwork.gfx_current->identifier,
4184 leveldir_current->graphics_set,
4185 leveldir_current->graphics_path);
4188 ReloadCustomImages();
4190 LoadCustomElementDescriptions();
4191 LoadSpecialMenuDesignSettings();
4193 ReinitializeGraphics();
4196 static void InitSound(char *identifier)
4198 if (identifier == NULL)
4199 identifier = artwork.snd_current->identifier;
4201 /* set artwork path to send it to the sound server process */
4202 setLevelArtworkDir(artwork.snd_first);
4204 InitReloadCustomSounds(identifier);
4205 ReinitializeSounds();
4208 static void InitMusic(char *identifier)
4210 if (identifier == NULL)
4211 identifier = artwork.mus_current->identifier;
4213 /* set artwork path to send it to the sound server process */
4214 setLevelArtworkDir(artwork.mus_first);
4216 InitReloadCustomMusic(identifier);
4217 ReinitializeMusic();
4220 void InitNetworkServer()
4222 #if defined(NETWORK_AVALIABLE)
4226 if (!options.network)
4229 #if defined(NETWORK_AVALIABLE)
4230 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4232 if (!ConnectToServer(options.server_host, options.server_port))
4233 Error(ERR_EXIT, "cannot connect to network game server");
4235 SendToServer_PlayerName(setup.player_name);
4236 SendToServer_ProtocolVersion();
4239 SendToServer_NrWanted(nr_wanted);
4243 static char *getNewArtworkIdentifier(int type)
4245 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4246 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4247 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4248 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4249 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4250 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4251 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4252 char *leveldir_identifier = leveldir_current->identifier;
4254 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4255 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4257 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4259 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4260 char *artwork_current_identifier;
4261 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4263 /* leveldir_current may be invalid (level group, parent link) */
4264 if (!validLevelSeries(leveldir_current))
4267 /* 1st step: determine artwork set to be activated in descending order:
4268 --------------------------------------------------------------------
4269 1. setup artwork (when configured to override everything else)
4270 2. artwork set configured in "levelinfo.conf" of current level set
4271 (artwork in level directory will have priority when loading later)
4272 3. artwork in level directory (stored in artwork sub-directory)
4273 4. setup artwork (currently configured in setup menu) */
4275 if (setup_override_artwork)
4276 artwork_current_identifier = setup_artwork_set;
4277 else if (leveldir_artwork_set != NULL)
4278 artwork_current_identifier = leveldir_artwork_set;
4279 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4280 artwork_current_identifier = leveldir_identifier;
4282 artwork_current_identifier = setup_artwork_set;
4285 /* 2nd step: check if it is really needed to reload artwork set
4286 ------------------------------------------------------------ */
4289 if (type == ARTWORK_TYPE_GRAPHICS)
4290 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4291 artwork_new_identifier,
4292 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4293 artwork_current_identifier,
4294 leveldir_current->graphics_set,
4295 leveldir_current->identifier);
4298 /* ---------- reload if level set and also artwork set has changed ------- */
4299 if (leveldir_current_identifier[type] != leveldir_identifier &&
4300 (last_has_level_artwork_set[type] || has_level_artwork_set))
4301 artwork_new_identifier = artwork_current_identifier;
4303 leveldir_current_identifier[type] = leveldir_identifier;
4304 last_has_level_artwork_set[type] = has_level_artwork_set;
4307 if (type == ARTWORK_TYPE_GRAPHICS)
4308 printf("::: 1: '%s'\n", artwork_new_identifier);
4311 /* ---------- reload if "override artwork" setting has changed ----------- */
4312 if (last_override_level_artwork[type] != setup_override_artwork)
4313 artwork_new_identifier = artwork_current_identifier;
4315 last_override_level_artwork[type] = setup_override_artwork;
4318 if (type == ARTWORK_TYPE_GRAPHICS)
4319 printf("::: 2: '%s'\n", artwork_new_identifier);
4322 /* ---------- reload if current artwork identifier has changed ----------- */
4323 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4324 artwork_current_identifier) != 0)
4325 artwork_new_identifier = artwork_current_identifier;
4327 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4330 if (type == ARTWORK_TYPE_GRAPHICS)
4331 printf("::: 3: '%s'\n", artwork_new_identifier);
4334 /* ---------- do not reload directly after starting ---------------------- */
4335 if (!initialized[type])
4336 artwork_new_identifier = NULL;
4338 initialized[type] = TRUE;
4341 if (type == ARTWORK_TYPE_GRAPHICS)
4342 printf("::: 4: '%s'\n", artwork_new_identifier);
4346 if (type == ARTWORK_TYPE_GRAPHICS)
4347 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4348 artwork.gfx_current_identifier, artwork_current_identifier,
4349 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4350 artwork_new_identifier);
4353 return artwork_new_identifier;
4356 void ReloadCustomArtwork(int force_reload)
4358 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4359 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4360 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4361 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4362 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4363 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4364 boolean redraw_screen = FALSE;
4366 if (gfx_new_identifier != NULL || force_reload_gfx)
4369 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4370 artwork.gfx_current_identifier,
4372 artwork.gfx_current->identifier,
4373 leveldir_current->graphics_set);
4376 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4380 redraw_screen = TRUE;
4383 if (snd_new_identifier != NULL || force_reload_snd)
4385 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4387 InitSound(snd_new_identifier);
4389 redraw_screen = TRUE;
4392 if (mus_new_identifier != NULL || force_reload_mus)
4394 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4396 InitMusic(mus_new_identifier);
4398 redraw_screen = TRUE;
4403 InitGfxBackground();
4405 /* force redraw of (open or closed) door graphics */
4406 SetDoorState(DOOR_OPEN_ALL);
4407 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4411 void KeyboardAutoRepeatOffUnlessAutoplay()
4413 if (global.autoplay_leveldir == NULL)
4414 KeyboardAutoRepeatOff();
4418 /* ========================================================================= */
4420 /* ========================================================================= */
4424 InitGlobal(); /* initialize some global variables */
4426 if (options.execute_command)
4427 Execute_Command(options.execute_command);
4429 if (options.serveronly)
4431 #if defined(PLATFORM_UNIX)
4432 NetworkServer(options.server_port, options.serveronly);
4434 Error(ERR_WARN, "networking only supported in Unix version");
4437 exit(0); /* never reached, server loops forever */
4444 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4445 InitArtworkConfig(); /* needed before forking sound child process */
4450 InitRND(NEW_RANDOMIZE);
4451 InitSimpleRND(NEW_RANDOMIZE);
4456 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4459 InitEventFilter(FilterMouseMotionEvents);
4461 InitElementPropertiesStatic();
4462 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4467 InitLevelArtworkInfo();
4469 InitImages(); /* needs to know current level directory */
4470 InitSound(NULL); /* needs to know current level directory */
4471 InitMusic(NULL); /* needs to know current level directory */
4473 InitGfxBackground();
4475 if (global.autoplay_leveldir)
4480 else if (global.convert_leveldir)
4486 game_status = GAME_MODE_MAIN;
4494 InitNetworkServer();
4497 void CloseAllAndExit(int exit_value)
4502 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4510 #if defined(TARGET_SDL)
4511 if (network_server) /* terminate network server */
4512 SDL_KillThread(server_thread);
4515 CloseVideoDisplay();
4516 ClosePlatformDependentStuff();