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_graphic_parameter_value(char *value_raw, char *suffix, int type)
793 if (type != TYPE_TOKEN)
794 return get_parameter_value(value_raw, suffix, type);
796 if (strcmp(value_raw, ARG_UNDEFINED) == 0)
797 return ARG_UNDEFINED_VALUE;
799 /* !!! OPTIMIZE THIS BY USING HASH !!! */
800 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
801 if (strcmp(element_info[i].token_name, value_raw) == 0)
804 /* !!! OPTIMIZE THIS BY USING HASH !!! */
805 for (i = 0; image_config[i].token != NULL; i++)
807 int len_config_value = strlen(image_config[i].value);
809 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
810 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
811 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
814 if (strcmp(image_config[i].token, value_raw) == 0)
823 static int get_scaled_graphic_width(int graphic)
825 int original_width = getOriginalImageWidthFromImageID(graphic);
826 int scale_up_factor = graphic_info[graphic].scale_up_factor;
828 return original_width * scale_up_factor;
831 static int get_scaled_graphic_height(int graphic)
833 int original_height = getOriginalImageHeightFromImageID(graphic);
834 int scale_up_factor = graphic_info[graphic].scale_up_factor;
836 return original_height * scale_up_factor;
839 static void set_graphic_parameters(int graphic)
841 struct FileInfo *image = getImageListEntryFromImageID(graphic);
842 char **parameter_raw = image->parameter;
843 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
844 int parameter[NUM_GFX_ARGS];
845 int anim_frames_per_row = 1, anim_frames_per_col = 1;
846 int anim_frames_per_line = 1;
849 /* if fallback to default artwork is done, also use the default parameters */
850 if (image->fallback_to_default)
851 parameter_raw = image->default_parameter;
853 /* get integer values from string parameters */
854 for (i = 0; i < NUM_GFX_ARGS; i++)
855 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
856 image_config_suffix[i].token,
857 image_config_suffix[i].type);
859 graphic_info[graphic].bitmap = src_bitmap;
861 /* start with reliable default values */
862 graphic_info[graphic].src_image_width = 0;
863 graphic_info[graphic].src_image_height = 0;
864 graphic_info[graphic].src_x = 0;
865 graphic_info[graphic].src_y = 0;
866 graphic_info[graphic].width = TILEX;
867 graphic_info[graphic].height = TILEY;
868 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
869 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
870 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
871 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
872 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
873 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
874 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
875 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
876 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
877 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
878 graphic_info[graphic].anim_delay_fixed = 0;
879 graphic_info[graphic].anim_delay_random = 0;
880 graphic_info[graphic].post_delay_fixed = 0;
881 graphic_info[graphic].post_delay_random = 0;
883 /* optional x and y tile position of animation frame sequence */
884 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
886 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
887 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
889 /* optional x and y pixel position of animation frame sequence */
890 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
891 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
892 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
893 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
895 /* optional width and height of each animation frame */
896 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
897 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
898 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
899 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
901 /* optional zoom factor for scaling up the image to a larger size */
902 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
903 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
904 if (graphic_info[graphic].scale_up_factor < 1)
905 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
909 /* get final bitmap size (with scaling, but without small images) */
910 int src_image_width = get_scaled_graphic_width(graphic);
911 int src_image_height = get_scaled_graphic_height(graphic);
913 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
914 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
916 graphic_info[graphic].src_image_width = src_image_width;
917 graphic_info[graphic].src_image_height = src_image_height;
920 /* correct x or y offset dependent of vertical or horizontal frame order */
921 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
923 graphic_info[graphic].offset_y =
924 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
925 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
926 anim_frames_per_line = anim_frames_per_col;
928 else /* frames are ordered horizontally */
930 graphic_info[graphic].offset_x =
931 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
932 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
933 anim_frames_per_line = anim_frames_per_row;
936 /* optionally, the x and y offset of frames can be specified directly */
937 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
938 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
939 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
940 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
942 /* optionally, moving animations may have separate start and end graphics */
943 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
945 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
946 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
948 /* correct x or y offset2 dependent of vertical or horizontal frame order */
949 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
950 graphic_info[graphic].offset2_y =
951 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
952 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
953 else /* frames are ordered horizontally */
954 graphic_info[graphic].offset2_x =
955 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
956 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
958 /* optionally, the x and y offset of 2nd graphic can be specified directly */
959 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
960 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
961 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
962 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
964 /* optionally, the second movement tile can be specified as start tile */
965 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
966 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
968 /* automatically determine correct number of frames, if not defined */
969 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
971 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
972 graphic_info[graphic].anim_frames = anim_frames_per_row;
973 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
974 graphic_info[graphic].anim_frames = anim_frames_per_col;
976 graphic_info[graphic].anim_frames = 1;
978 graphic_info[graphic].anim_frames_per_line =
979 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
980 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
982 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
983 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
984 graphic_info[graphic].anim_delay = 1;
986 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
988 if (graphic_info[graphic].anim_frames == 1)
989 graphic_info[graphic].anim_mode = ANIM_NONE;
992 /* automatically determine correct start frame, if not defined */
993 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].anim_start_frame = 0;
995 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
996 graphic_info[graphic].anim_start_frame =
997 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
999 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1001 /* animation synchronized with global frame counter, not move position */
1002 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1004 /* optional element for cloning crumble graphics */
1005 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1008 /* optional element for cloning digging graphics */
1009 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1012 /* optional border size for "crumbling" diggable graphics */
1013 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1016 /* this is only used for player "boring" and "sleeping" actions */
1017 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1018 graphic_info[graphic].anim_delay_fixed =
1019 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1020 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1021 graphic_info[graphic].anim_delay_random =
1022 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1023 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1024 graphic_info[graphic].post_delay_fixed =
1025 parameter[GFX_ARG_POST_DELAY_FIXED];
1026 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1027 graphic_info[graphic].post_delay_random =
1028 parameter[GFX_ARG_POST_DELAY_RANDOM];
1030 /* this is only used for toon animations */
1031 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1032 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1034 /* this is only used for drawing font characters */
1035 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1036 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1038 /* this is only used for drawing envelope graphics */
1039 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1041 /* optional graphic for cloning all graphics settings */
1042 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1043 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1046 static void set_cloned_graphic_parameters(int graphic)
1048 int fallback_graphic = IMG_CHAR_EXCLAM;
1049 int max_num_images = getImageListSize();
1050 int clone_graphic = graphic_info[graphic].clone_from;
1051 int num_references_followed = 1;
1053 while (graphic_info[clone_graphic].clone_from != -1 &&
1054 num_references_followed < max_num_images)
1056 clone_graphic = graphic_info[clone_graphic].clone_from;
1058 num_references_followed++;
1061 if (num_references_followed >= max_num_images)
1063 Error(ERR_RETURN_LINE, "-");
1064 Error(ERR_RETURN, "warning: error found in config file:");
1065 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1066 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1067 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1068 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1070 if (graphic == fallback_graphic)
1071 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1073 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1074 Error(ERR_RETURN_LINE, "-");
1076 graphic_info[graphic] = graphic_info[fallback_graphic];
1080 graphic_info[graphic] = graphic_info[clone_graphic];
1081 graphic_info[graphic].clone_from = clone_graphic;
1085 static void InitGraphicInfo()
1087 int fallback_graphic = IMG_CHAR_EXCLAM;
1088 int num_images = getImageListSize();
1091 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1092 static boolean clipmasks_initialized = FALSE;
1094 XGCValues clip_gc_values;
1095 unsigned long clip_gc_valuemask;
1096 GC copy_clipmask_gc = None;
1099 checked_free(graphic_info);
1101 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1103 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1104 if (clipmasks_initialized)
1106 for (i = 0; i < num_images; i++)
1108 if (graphic_info[i].clip_mask)
1109 XFreePixmap(display, graphic_info[i].clip_mask);
1110 if (graphic_info[i].clip_gc)
1111 XFreeGC(display, graphic_info[i].clip_gc);
1113 graphic_info[i].clip_mask = None;
1114 graphic_info[i].clip_gc = None;
1119 /* first set all graphic paramaters ... */
1120 for (i = 0; i < num_images; i++)
1121 set_graphic_parameters(i);
1123 /* ... then copy these parameters for cloned graphics */
1124 for (i = 0; i < num_images; i++)
1125 if (graphic_info[i].clone_from != -1)
1126 set_cloned_graphic_parameters(i);
1128 for (i = 0; i < num_images; i++)
1132 int first_frame, last_frame;
1133 int src_bitmap_width, src_bitmap_height;
1135 /* now check if no animation frames are outside of the loaded image */
1137 if (graphic_info[i].bitmap == NULL)
1138 continue; /* skip check for optional images that are undefined */
1140 /* get final bitmap size (with scaling, but without small images) */
1141 src_bitmap_width = graphic_info[i].src_image_width;
1142 src_bitmap_height = graphic_info[i].src_image_height;
1144 /* check if first animation frame is inside specified bitmap */
1147 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1149 if (src_x < 0 || src_y < 0 ||
1150 src_x + TILEX > src_bitmap_width ||
1151 src_y + TILEY > src_bitmap_height)
1153 Error(ERR_RETURN_LINE, "-");
1154 Error(ERR_RETURN, "warning: error found in config file:");
1155 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1156 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1157 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1159 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1160 src_x, src_y, src_bitmap_width, src_bitmap_height);
1161 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1163 if (i == fallback_graphic)
1164 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1166 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1167 Error(ERR_RETURN_LINE, "-");
1169 graphic_info[i] = graphic_info[fallback_graphic];
1172 /* check if last animation frame is inside specified bitmap */
1174 last_frame = graphic_info[i].anim_frames - 1;
1175 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1177 if (src_x < 0 || src_y < 0 ||
1178 src_x + TILEX > src_bitmap_width ||
1179 src_y + TILEY > src_bitmap_height)
1181 Error(ERR_RETURN_LINE, "-");
1182 Error(ERR_RETURN, "warning: error found in config file:");
1183 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1184 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1185 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1187 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1188 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1189 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1191 if (i == fallback_graphic)
1192 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1194 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1195 Error(ERR_RETURN_LINE, "-");
1197 graphic_info[i] = graphic_info[fallback_graphic];
1200 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1201 /* currently we only need a tile clip mask from the first frame */
1202 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1204 if (copy_clipmask_gc == None)
1206 clip_gc_values.graphics_exposures = False;
1207 clip_gc_valuemask = GCGraphicsExposures;
1208 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1209 clip_gc_valuemask, &clip_gc_values);
1212 graphic_info[i].clip_mask =
1213 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1215 src_pixmap = src_bitmap->clip_mask;
1216 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1217 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1219 clip_gc_values.graphics_exposures = False;
1220 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1221 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1223 graphic_info[i].clip_gc =
1224 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1228 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1229 if (copy_clipmask_gc)
1230 XFreeGC(display, copy_clipmask_gc);
1232 clipmasks_initialized = TRUE;
1236 static void InitElementSoundInfo()
1238 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1239 int num_property_mappings = getSoundListPropertyMappingSize();
1242 /* set values to -1 to identify later as "uninitialized" values */
1243 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1244 for (act = 0; act < NUM_ACTIONS; act++)
1245 element_info[i].sound[act] = -1;
1247 /* initialize element/sound mapping from static configuration */
1248 for (i = 0; element_to_sound[i].element > -1; i++)
1250 int element = element_to_sound[i].element;
1251 int action = element_to_sound[i].action;
1252 int sound = element_to_sound[i].sound;
1253 boolean is_class = element_to_sound[i].is_class;
1256 action = ACTION_DEFAULT;
1259 element_info[element].sound[action] = sound;
1261 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1262 if (strcmp(element_info[j].class_name,
1263 element_info[element].class_name) == 0)
1264 element_info[j].sound[action] = sound;
1267 /* initialize element class/sound mapping from dynamic configuration */
1268 for (i = 0; i < num_property_mappings; i++)
1270 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1271 int action = property_mapping[i].ext1_index;
1272 int sound = property_mapping[i].artwork_index;
1274 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1278 action = ACTION_DEFAULT;
1280 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1281 if (strcmp(element_info[j].class_name,
1282 element_info[element_class].class_name) == 0)
1283 element_info[j].sound[action] = sound;
1286 /* initialize element/sound mapping from dynamic configuration */
1287 for (i = 0; i < num_property_mappings; i++)
1289 int element = property_mapping[i].base_index;
1290 int action = property_mapping[i].ext1_index;
1291 int sound = property_mapping[i].artwork_index;
1293 if (element >= MAX_NUM_ELEMENTS)
1297 action = ACTION_DEFAULT;
1299 element_info[element].sound[action] = sound;
1302 /* now set all '-1' values to element specific default values */
1303 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1305 for (act = 0; act < NUM_ACTIONS; act++)
1307 /* generic default action sound (defined by "[default]" directive) */
1308 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1310 /* look for special default action sound (classic game specific) */
1311 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1312 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1313 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1314 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1315 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1316 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1318 /* !!! there's no such thing as a "default action sound" !!! */
1320 /* look for element specific default sound (independent from action) */
1321 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1322 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1326 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1327 /* !!! make this better !!! */
1328 if (i == EL_EMPTY_SPACE)
1329 default_action_sound = element_info[EL_DEFAULT].sound[act];
1332 /* no sound for this specific action -- use default action sound */
1333 if (element_info[i].sound[act] == -1)
1334 element_info[i].sound[act] = default_action_sound;
1338 /* copy sound settings to some elements that are only stored in level file
1339 in native R'n'D levels, but are used by game engine in native EM levels */
1340 for (i = 0; copy_properties[i][0] != -1; i++)
1341 for (j = 1; j <= 4; j++)
1342 for (act = 0; act < NUM_ACTIONS; act++)
1343 element_info[copy_properties[i][j]].sound[act] =
1344 element_info[copy_properties[i][0]].sound[act];
1347 static void InitGameModeSoundInfo()
1351 /* set values to -1 to identify later as "uninitialized" values */
1352 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1355 /* initialize gamemode/sound mapping from static configuration */
1356 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1358 int gamemode = gamemode_to_sound[i].gamemode;
1359 int sound = gamemode_to_sound[i].sound;
1362 gamemode = GAME_MODE_DEFAULT;
1364 menu.sound[gamemode] = sound;
1367 /* now set all '-1' values to levelset specific default values */
1368 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1369 if (menu.sound[i] == -1)
1370 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1373 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1374 if (menu.sound[i] != -1)
1375 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1379 static void set_sound_parameters(int sound, char **parameter_raw)
1381 int parameter[NUM_SND_ARGS];
1384 /* get integer values from string parameters */
1385 for (i = 0; i < NUM_SND_ARGS; i++)
1387 get_parameter_value(parameter_raw[i],
1388 sound_config_suffix[i].token,
1389 sound_config_suffix[i].type);
1391 /* explicit loop mode setting in configuration overrides default value */
1392 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1393 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1395 /* sound volume to change the original volume when loading the sound file */
1396 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1398 /* sound priority to give certain sounds a higher or lower priority */
1399 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1402 static void InitSoundInfo()
1404 int *sound_effect_properties;
1405 int num_sounds = getSoundListSize();
1408 checked_free(sound_info);
1410 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1411 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1413 /* initialize sound effect for all elements to "no sound" */
1414 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1415 for (j = 0; j < NUM_ACTIONS; j++)
1416 element_info[i].sound[j] = SND_UNDEFINED;
1418 for (i = 0; i < num_sounds; i++)
1420 struct FileInfo *sound = getSoundListEntry(i);
1421 int len_effect_text = strlen(sound->token);
1423 sound_effect_properties[i] = ACTION_OTHER;
1424 sound_info[i].loop = FALSE; /* default: play sound only once */
1427 printf("::: sound %d: '%s'\n", i, sound->token);
1430 /* determine all loop sounds and identify certain sound classes */
1432 for (j = 0; element_action_info[j].suffix; j++)
1434 int len_action_text = strlen(element_action_info[j].suffix);
1436 if (len_action_text < len_effect_text &&
1437 strcmp(&sound->token[len_effect_text - len_action_text],
1438 element_action_info[j].suffix) == 0)
1440 sound_effect_properties[i] = element_action_info[j].value;
1441 sound_info[i].loop = element_action_info[j].is_loop_sound;
1447 /* associate elements and some selected sound actions */
1449 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1451 if (element_info[j].class_name)
1453 int len_class_text = strlen(element_info[j].class_name);
1455 if (len_class_text + 1 < len_effect_text &&
1456 strncmp(sound->token,
1457 element_info[j].class_name, len_class_text) == 0 &&
1458 sound->token[len_class_text] == '.')
1460 int sound_action_value = sound_effect_properties[i];
1462 element_info[j].sound[sound_action_value] = i;
1467 set_sound_parameters(i, sound->parameter);
1470 free(sound_effect_properties);
1473 static void InitGameModeMusicInfo()
1475 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1476 int num_property_mappings = getMusicListPropertyMappingSize();
1477 int default_levelset_music = -1;
1480 /* set values to -1 to identify later as "uninitialized" values */
1481 for (i = 0; i < MAX_LEVELS; i++)
1482 levelset.music[i] = -1;
1483 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1486 /* initialize gamemode/music mapping from static configuration */
1487 for (i = 0; gamemode_to_music[i].music > -1; i++)
1489 int gamemode = gamemode_to_music[i].gamemode;
1490 int music = gamemode_to_music[i].music;
1493 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1497 gamemode = GAME_MODE_DEFAULT;
1499 menu.music[gamemode] = music;
1502 /* initialize gamemode/music mapping from dynamic configuration */
1503 for (i = 0; i < num_property_mappings; i++)
1505 int prefix = property_mapping[i].base_index;
1506 int gamemode = property_mapping[i].ext1_index;
1507 int level = property_mapping[i].ext2_index;
1508 int music = property_mapping[i].artwork_index;
1511 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1512 prefix, gamemode, level, music);
1515 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1519 gamemode = GAME_MODE_DEFAULT;
1521 /* level specific music only allowed for in-game music */
1522 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1523 gamemode = GAME_MODE_PLAYING;
1528 default_levelset_music = music;
1531 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1532 levelset.music[level] = music;
1533 if (gamemode != GAME_MODE_PLAYING)
1534 menu.music[gamemode] = music;
1537 /* now set all '-1' values to menu specific default values */
1538 /* (undefined values of "levelset.music[]" might stay at "-1" to
1539 allow dynamic selection of music files from music directory!) */
1540 for (i = 0; i < MAX_LEVELS; i++)
1541 if (levelset.music[i] == -1)
1542 levelset.music[i] = default_levelset_music;
1543 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1544 if (menu.music[i] == -1)
1545 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1548 for (i = 0; i < MAX_LEVELS; i++)
1549 if (levelset.music[i] != -1)
1550 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1551 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1552 if (menu.music[i] != -1)
1553 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1557 static void set_music_parameters(int music, char **parameter_raw)
1559 int parameter[NUM_MUS_ARGS];
1562 /* get integer values from string parameters */
1563 for (i = 0; i < NUM_MUS_ARGS; i++)
1565 get_parameter_value(parameter_raw[i],
1566 music_config_suffix[i].token,
1567 music_config_suffix[i].type);
1569 /* explicit loop mode setting in configuration overrides default value */
1570 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1571 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1574 static void InitMusicInfo()
1576 int num_music = getMusicListSize();
1579 checked_free(music_info);
1581 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1583 for (i = 0; i < num_music; i++)
1585 struct FileInfo *music = getMusicListEntry(i);
1586 int len_music_text = strlen(music->token);
1588 music_info[i].loop = TRUE; /* default: play music in loop mode */
1590 /* determine all loop music */
1592 for (j = 0; music_prefix_info[j].prefix; j++)
1594 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1596 if (len_prefix_text < len_music_text &&
1597 strncmp(music->token,
1598 music_prefix_info[j].prefix, len_prefix_text) == 0)
1600 music_info[i].loop = music_prefix_info[j].is_loop_music;
1606 set_music_parameters(i, music->parameter);
1610 static void ReinitializeGraphics()
1612 InitGraphicInfo(); /* graphic properties mapping */
1613 InitElementGraphicInfo(); /* element game graphic mapping */
1614 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1616 InitElementSmallImages(); /* scale images to all needed sizes */
1617 InitFontGraphicInfo(); /* initialize text drawing functions */
1619 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1621 SetMainBackgroundImage(IMG_BACKGROUND);
1622 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1628 static void ReinitializeSounds()
1630 InitSoundInfo(); /* sound properties mapping */
1631 InitElementSoundInfo(); /* element game sound mapping */
1632 InitGameModeSoundInfo(); /* game mode sound mapping */
1634 InitPlayLevelSound(); /* internal game sound settings */
1637 static void ReinitializeMusic()
1639 InitMusicInfo(); /* music properties mapping */
1640 InitGameModeMusicInfo(); /* game mode music mapping */
1643 static int get_special_property_bit(int element, int property_bit_nr)
1645 struct PropertyBitInfo
1651 static struct PropertyBitInfo pb_can_move_into_acid[] =
1653 /* the player may be able fall into acid when gravity is activated */
1658 { EL_SP_MURPHY, 0 },
1659 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1661 /* all element that can move may be able to also move into acid */
1664 { EL_BUG_RIGHT, 1 },
1667 { EL_SPACESHIP, 2 },
1668 { EL_SPACESHIP_LEFT, 2 },
1669 { EL_SPACESHIP_RIGHT, 2 },
1670 { EL_SPACESHIP_UP, 2 },
1671 { EL_SPACESHIP_DOWN, 2 },
1672 { EL_BD_BUTTERFLY, 3 },
1673 { EL_BD_BUTTERFLY_LEFT, 3 },
1674 { EL_BD_BUTTERFLY_RIGHT, 3 },
1675 { EL_BD_BUTTERFLY_UP, 3 },
1676 { EL_BD_BUTTERFLY_DOWN, 3 },
1677 { EL_BD_FIREFLY, 4 },
1678 { EL_BD_FIREFLY_LEFT, 4 },
1679 { EL_BD_FIREFLY_RIGHT, 4 },
1680 { EL_BD_FIREFLY_UP, 4 },
1681 { EL_BD_FIREFLY_DOWN, 4 },
1683 { EL_DARK_YAMYAM, 6 },
1686 { EL_PACMAN_LEFT, 8 },
1687 { EL_PACMAN_RIGHT, 8 },
1688 { EL_PACMAN_UP, 8 },
1689 { EL_PACMAN_DOWN, 8 },
1691 { EL_MOLE_LEFT, 9 },
1692 { EL_MOLE_RIGHT, 9 },
1694 { EL_MOLE_DOWN, 9 },
1698 { EL_SATELLITE, 13 },
1699 { EL_SP_SNIKSNAK, 14 },
1700 { EL_SP_ELECTRON, 15 },
1707 static struct PropertyBitInfo pb_dont_collide_with[] =
1709 { EL_SP_SNIKSNAK, 0 },
1710 { EL_SP_ELECTRON, 1 },
1718 struct PropertyBitInfo *pb_info;
1721 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1722 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1727 struct PropertyBitInfo *pb_info = NULL;
1730 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1731 if (pb_definition[i].bit_nr == property_bit_nr)
1732 pb_info = pb_definition[i].pb_info;
1734 if (pb_info == NULL)
1737 for (i = 0; pb_info[i].element != -1; i++)
1738 if (pb_info[i].element == element)
1739 return pb_info[i].bit_nr;
1744 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1745 boolean property_value)
1747 int bit_nr = get_special_property_bit(element, property_bit_nr);
1752 *bitfield |= (1 << bit_nr);
1754 *bitfield &= ~(1 << bit_nr);
1758 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1760 int bit_nr = get_special_property_bit(element, property_bit_nr);
1763 return ((*bitfield & (1 << bit_nr)) != 0);
1768 void InitElementPropertiesStatic()
1770 static int ep_diggable[] =
1775 EL_SP_BUGGY_BASE_ACTIVATING,
1778 EL_INVISIBLE_SAND_ACTIVE,
1781 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1782 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1786 EL_SP_BUGGY_BASE_ACTIVE,
1792 static int ep_collectible_only[] =
1813 EL_DYNABOMB_INCREASE_NUMBER,
1814 EL_DYNABOMB_INCREASE_SIZE,
1815 EL_DYNABOMB_INCREASE_POWER,
1834 static int ep_dont_run_into[] =
1836 /* same elements as in 'ep_dont_touch' */
1842 /* same elements as in 'ep_dont_collide_with' */
1854 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1858 EL_SP_BUGGY_BASE_ACTIVE,
1864 static int ep_dont_collide_with[] =
1866 /* same elements as in 'ep_dont_touch' */
1882 static int ep_dont_touch[] =
1891 static int ep_indestructible[] =
1895 EL_ACID_POOL_TOPLEFT,
1896 EL_ACID_POOL_TOPRIGHT,
1897 EL_ACID_POOL_BOTTOMLEFT,
1898 EL_ACID_POOL_BOTTOM,
1899 EL_ACID_POOL_BOTTOMRIGHT,
1900 EL_SP_HARDWARE_GRAY,
1901 EL_SP_HARDWARE_GREEN,
1902 EL_SP_HARDWARE_BLUE,
1904 EL_SP_HARDWARE_YELLOW,
1905 EL_SP_HARDWARE_BASE_1,
1906 EL_SP_HARDWARE_BASE_2,
1907 EL_SP_HARDWARE_BASE_3,
1908 EL_SP_HARDWARE_BASE_4,
1909 EL_SP_HARDWARE_BASE_5,
1910 EL_SP_HARDWARE_BASE_6,
1911 EL_INVISIBLE_STEELWALL,
1912 EL_INVISIBLE_STEELWALL_ACTIVE,
1913 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1914 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1915 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1916 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1917 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1918 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1919 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1920 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1921 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1922 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1923 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1924 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1926 EL_LIGHT_SWITCH_ACTIVE,
1927 EL_SIGN_EXCLAMATION,
1928 EL_SIGN_RADIOACTIVITY,
1939 EL_STEELWALL_SLIPPERY,
1970 EL_SWITCHGATE_OPENING,
1971 EL_SWITCHGATE_CLOSED,
1972 EL_SWITCHGATE_CLOSING,
1974 EL_SWITCHGATE_SWITCH_UP,
1975 EL_SWITCHGATE_SWITCH_DOWN,
1978 EL_TIMEGATE_OPENING,
1980 EL_TIMEGATE_CLOSING,
1983 EL_TIMEGATE_SWITCH_ACTIVE,
1988 EL_TUBE_VERTICAL_LEFT,
1989 EL_TUBE_VERTICAL_RIGHT,
1990 EL_TUBE_HORIZONTAL_UP,
1991 EL_TUBE_HORIZONTAL_DOWN,
1999 static int ep_slippery[] =
2013 EL_ROBOT_WHEEL_ACTIVE,
2019 EL_ACID_POOL_TOPLEFT,
2020 EL_ACID_POOL_TOPRIGHT,
2030 EL_STEELWALL_SLIPPERY,
2033 EL_EMC_WALL_SLIPPERY_1,
2034 EL_EMC_WALL_SLIPPERY_2,
2035 EL_EMC_WALL_SLIPPERY_3,
2036 EL_EMC_WALL_SLIPPERY_4,
2040 static int ep_can_change[] =
2045 static int ep_can_move[] =
2047 /* same elements as in 'pb_can_move_into_acid' */
2069 static int ep_can_fall[] =
2084 EL_BD_MAGIC_WALL_FULL,
2097 static int ep_can_smash_player[] =
2122 static int ep_can_smash_enemies[] =
2130 static int ep_can_smash_everything[] =
2138 static int ep_explodes_by_fire[] =
2140 /* same elements as in 'ep_explodes_impact' */
2145 /* same elements as in 'ep_explodes_smashed' */
2154 EL_DYNABOMB_PLAYER_1_ACTIVE,
2155 EL_DYNABOMB_PLAYER_2_ACTIVE,
2156 EL_DYNABOMB_PLAYER_3_ACTIVE,
2157 EL_DYNABOMB_PLAYER_4_ACTIVE,
2158 EL_DYNABOMB_INCREASE_NUMBER,
2159 EL_DYNABOMB_INCREASE_SIZE,
2160 EL_DYNABOMB_INCREASE_POWER,
2161 EL_SP_DISK_RED_ACTIVE,
2174 static int ep_explodes_smashed[] =
2176 /* same elements as in 'ep_explodes_impact' */
2189 static int ep_explodes_impact[] =
2197 static int ep_walkable_over[] =
2201 EL_SOKOBAN_FIELD_EMPTY,
2219 static int ep_walkable_inside[] =
2224 EL_TUBE_VERTICAL_LEFT,
2225 EL_TUBE_VERTICAL_RIGHT,
2226 EL_TUBE_HORIZONTAL_UP,
2227 EL_TUBE_HORIZONTAL_DOWN,
2235 static int ep_walkable_under[] =
2240 static int ep_passable_over[] =
2263 static int ep_passable_inside[] =
2269 EL_SP_PORT_HORIZONTAL,
2270 EL_SP_PORT_VERTICAL,
2272 EL_SP_GRAVITY_PORT_LEFT,
2273 EL_SP_GRAVITY_PORT_RIGHT,
2274 EL_SP_GRAVITY_PORT_UP,
2275 EL_SP_GRAVITY_PORT_DOWN,
2276 EL_SP_GRAVITY_ON_PORT_LEFT,
2277 EL_SP_GRAVITY_ON_PORT_RIGHT,
2278 EL_SP_GRAVITY_ON_PORT_UP,
2279 EL_SP_GRAVITY_ON_PORT_DOWN,
2280 EL_SP_GRAVITY_OFF_PORT_LEFT,
2281 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2282 EL_SP_GRAVITY_OFF_PORT_UP,
2283 EL_SP_GRAVITY_OFF_PORT_DOWN,
2287 static int ep_passable_under[] =
2292 static int ep_droppable[] =
2297 static int ep_explodes_1x1_old[] =
2302 static int ep_pushable[] =
2314 EL_SOKOBAN_FIELD_FULL,
2322 static int ep_explodes_cross_old[] =
2327 static int ep_protected[] =
2329 /* same elements as in 'ep_walkable_inside' */
2333 EL_TUBE_VERTICAL_LEFT,
2334 EL_TUBE_VERTICAL_RIGHT,
2335 EL_TUBE_HORIZONTAL_UP,
2336 EL_TUBE_HORIZONTAL_DOWN,
2342 /* same elements as in 'ep_passable_over' */
2362 /* same elements as in 'ep_passable_inside' */
2367 EL_SP_PORT_HORIZONTAL,
2368 EL_SP_PORT_VERTICAL,
2370 EL_SP_GRAVITY_PORT_LEFT,
2371 EL_SP_GRAVITY_PORT_RIGHT,
2372 EL_SP_GRAVITY_PORT_UP,
2373 EL_SP_GRAVITY_PORT_DOWN,
2374 EL_SP_GRAVITY_ON_PORT_LEFT,
2375 EL_SP_GRAVITY_ON_PORT_RIGHT,
2376 EL_SP_GRAVITY_ON_PORT_UP,
2377 EL_SP_GRAVITY_ON_PORT_DOWN,
2378 EL_SP_GRAVITY_OFF_PORT_LEFT,
2379 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2380 EL_SP_GRAVITY_OFF_PORT_UP,
2381 EL_SP_GRAVITY_OFF_PORT_DOWN,
2385 static int ep_throwable[] =
2390 static int ep_can_explode[] =
2392 /* same elements as in 'ep_explodes_impact' */
2397 /* same elements as in 'ep_explodes_smashed' */
2403 /* elements that can explode by explosion or by dragonfire */
2406 EL_DYNABOMB_PLAYER_1_ACTIVE,
2407 EL_DYNABOMB_PLAYER_2_ACTIVE,
2408 EL_DYNABOMB_PLAYER_3_ACTIVE,
2409 EL_DYNABOMB_PLAYER_4_ACTIVE,
2410 EL_DYNABOMB_INCREASE_NUMBER,
2411 EL_DYNABOMB_INCREASE_SIZE,
2412 EL_DYNABOMB_INCREASE_POWER,
2413 EL_SP_DISK_RED_ACTIVE,
2421 /* elements that can explode only by explosion */
2426 static int ep_gravity_reachable[] =
2432 EL_INVISIBLE_SAND_ACTIVE,
2437 EL_SP_PORT_HORIZONTAL,
2438 EL_SP_PORT_VERTICAL,
2440 EL_SP_GRAVITY_PORT_LEFT,
2441 EL_SP_GRAVITY_PORT_RIGHT,
2442 EL_SP_GRAVITY_PORT_UP,
2443 EL_SP_GRAVITY_PORT_DOWN,
2444 EL_SP_GRAVITY_ON_PORT_LEFT,
2445 EL_SP_GRAVITY_ON_PORT_RIGHT,
2446 EL_SP_GRAVITY_ON_PORT_UP,
2447 EL_SP_GRAVITY_ON_PORT_DOWN,
2448 EL_SP_GRAVITY_OFF_PORT_LEFT,
2449 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2450 EL_SP_GRAVITY_OFF_PORT_UP,
2451 EL_SP_GRAVITY_OFF_PORT_DOWN,
2456 static int ep_player[] =
2463 EL_SOKOBAN_FIELD_PLAYER,
2468 static int ep_can_pass_magic_wall[] =
2481 static int ep_switchable[] =
2485 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2486 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2487 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2488 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2489 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2490 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2491 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2492 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2493 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2494 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2495 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2496 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2497 EL_SWITCHGATE_SWITCH_UP,
2498 EL_SWITCHGATE_SWITCH_DOWN,
2500 EL_LIGHT_SWITCH_ACTIVE,
2502 EL_BALLOON_SWITCH_LEFT,
2503 EL_BALLOON_SWITCH_RIGHT,
2504 EL_BALLOON_SWITCH_UP,
2505 EL_BALLOON_SWITCH_DOWN,
2506 EL_BALLOON_SWITCH_ANY,
2509 EL_EMC_MAGIC_BALL_SWITCH,
2513 static int ep_bd_element[] =
2546 static int ep_sp_element[] =
2548 /* should always be valid */
2551 /* standard classic Supaplex elements */
2558 EL_SP_HARDWARE_GRAY,
2566 EL_SP_GRAVITY_PORT_RIGHT,
2567 EL_SP_GRAVITY_PORT_DOWN,
2568 EL_SP_GRAVITY_PORT_LEFT,
2569 EL_SP_GRAVITY_PORT_UP,
2574 EL_SP_PORT_VERTICAL,
2575 EL_SP_PORT_HORIZONTAL,
2581 EL_SP_HARDWARE_BASE_1,
2582 EL_SP_HARDWARE_GREEN,
2583 EL_SP_HARDWARE_BLUE,
2585 EL_SP_HARDWARE_YELLOW,
2586 EL_SP_HARDWARE_BASE_2,
2587 EL_SP_HARDWARE_BASE_3,
2588 EL_SP_HARDWARE_BASE_4,
2589 EL_SP_HARDWARE_BASE_5,
2590 EL_SP_HARDWARE_BASE_6,
2594 /* additional elements that appeared in newer Supaplex levels */
2597 /* additional gravity port elements (not switching, but setting gravity) */
2598 EL_SP_GRAVITY_ON_PORT_LEFT,
2599 EL_SP_GRAVITY_ON_PORT_RIGHT,
2600 EL_SP_GRAVITY_ON_PORT_UP,
2601 EL_SP_GRAVITY_ON_PORT_DOWN,
2602 EL_SP_GRAVITY_OFF_PORT_LEFT,
2603 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2604 EL_SP_GRAVITY_OFF_PORT_UP,
2605 EL_SP_GRAVITY_OFF_PORT_DOWN,
2607 /* more than one Murphy in a level results in an inactive clone */
2610 /* runtime Supaplex elements */
2611 EL_SP_DISK_RED_ACTIVE,
2612 EL_SP_TERMINAL_ACTIVE,
2613 EL_SP_BUGGY_BASE_ACTIVATING,
2614 EL_SP_BUGGY_BASE_ACTIVE,
2620 static int ep_sb_element[] =
2625 EL_SOKOBAN_FIELD_EMPTY,
2626 EL_SOKOBAN_FIELD_FULL,
2627 EL_SOKOBAN_FIELD_PLAYER,
2632 EL_INVISIBLE_STEELWALL,
2636 static int ep_gem[] =
2647 static int ep_food_dark_yamyam[] =
2674 static int ep_food_penguin[] =
2687 static int ep_food_pig[] =
2698 static int ep_historic_wall[] =
2723 EL_EXPANDABLE_WALL_HORIZONTAL,
2724 EL_EXPANDABLE_WALL_VERTICAL,
2725 EL_EXPANDABLE_WALL_ANY,
2726 EL_EXPANDABLE_WALL_GROWING,
2733 EL_SP_HARDWARE_GRAY,
2734 EL_SP_HARDWARE_GREEN,
2735 EL_SP_HARDWARE_BLUE,
2737 EL_SP_HARDWARE_YELLOW,
2738 EL_SP_HARDWARE_BASE_1,
2739 EL_SP_HARDWARE_BASE_2,
2740 EL_SP_HARDWARE_BASE_3,
2741 EL_SP_HARDWARE_BASE_4,
2742 EL_SP_HARDWARE_BASE_5,
2743 EL_SP_HARDWARE_BASE_6,
2745 EL_SP_TERMINAL_ACTIVE,
2748 EL_INVISIBLE_STEELWALL,
2749 EL_INVISIBLE_STEELWALL_ACTIVE,
2751 EL_INVISIBLE_WALL_ACTIVE,
2752 EL_STEELWALL_SLIPPERY,
2768 static int ep_historic_solid[] =
2772 EL_EXPANDABLE_WALL_HORIZONTAL,
2773 EL_EXPANDABLE_WALL_VERTICAL,
2774 EL_EXPANDABLE_WALL_ANY,
2787 EL_QUICKSAND_FILLING,
2788 EL_QUICKSAND_EMPTYING,
2790 EL_MAGIC_WALL_ACTIVE,
2791 EL_MAGIC_WALL_EMPTYING,
2792 EL_MAGIC_WALL_FILLING,
2796 EL_BD_MAGIC_WALL_ACTIVE,
2797 EL_BD_MAGIC_WALL_EMPTYING,
2798 EL_BD_MAGIC_WALL_FULL,
2799 EL_BD_MAGIC_WALL_FILLING,
2800 EL_BD_MAGIC_WALL_DEAD,
2809 EL_SP_TERMINAL_ACTIVE,
2813 EL_INVISIBLE_WALL_ACTIVE,
2814 EL_SWITCHGATE_SWITCH_UP,
2815 EL_SWITCHGATE_SWITCH_DOWN,
2817 EL_TIMEGATE_SWITCH_ACTIVE,
2829 /* the following elements are a direct copy of "indestructible" elements,
2830 except "EL_ACID", which is "indestructible", but not "solid"! */
2835 EL_ACID_POOL_TOPLEFT,
2836 EL_ACID_POOL_TOPRIGHT,
2837 EL_ACID_POOL_BOTTOMLEFT,
2838 EL_ACID_POOL_BOTTOM,
2839 EL_ACID_POOL_BOTTOMRIGHT,
2840 EL_SP_HARDWARE_GRAY,
2841 EL_SP_HARDWARE_GREEN,
2842 EL_SP_HARDWARE_BLUE,
2844 EL_SP_HARDWARE_YELLOW,
2845 EL_SP_HARDWARE_BASE_1,
2846 EL_SP_HARDWARE_BASE_2,
2847 EL_SP_HARDWARE_BASE_3,
2848 EL_SP_HARDWARE_BASE_4,
2849 EL_SP_HARDWARE_BASE_5,
2850 EL_SP_HARDWARE_BASE_6,
2851 EL_INVISIBLE_STEELWALL,
2852 EL_INVISIBLE_STEELWALL_ACTIVE,
2853 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2854 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2855 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2856 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2857 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2858 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2859 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2860 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2861 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2862 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2863 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2864 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2866 EL_LIGHT_SWITCH_ACTIVE,
2867 EL_SIGN_EXCLAMATION,
2868 EL_SIGN_RADIOACTIVITY,
2879 EL_STEELWALL_SLIPPERY,
2902 EL_SWITCHGATE_OPENING,
2903 EL_SWITCHGATE_CLOSED,
2904 EL_SWITCHGATE_CLOSING,
2906 EL_TIMEGATE_OPENING,
2908 EL_TIMEGATE_CLOSING,
2912 EL_TUBE_VERTICAL_LEFT,
2913 EL_TUBE_VERTICAL_RIGHT,
2914 EL_TUBE_HORIZONTAL_UP,
2915 EL_TUBE_HORIZONTAL_DOWN,
2923 static int ep_classic_enemy[] =
2939 static int ep_belt[] =
2941 EL_CONVEYOR_BELT_1_LEFT,
2942 EL_CONVEYOR_BELT_1_MIDDLE,
2943 EL_CONVEYOR_BELT_1_RIGHT,
2944 EL_CONVEYOR_BELT_2_LEFT,
2945 EL_CONVEYOR_BELT_2_MIDDLE,
2946 EL_CONVEYOR_BELT_2_RIGHT,
2947 EL_CONVEYOR_BELT_3_LEFT,
2948 EL_CONVEYOR_BELT_3_MIDDLE,
2949 EL_CONVEYOR_BELT_3_RIGHT,
2950 EL_CONVEYOR_BELT_4_LEFT,
2951 EL_CONVEYOR_BELT_4_MIDDLE,
2952 EL_CONVEYOR_BELT_4_RIGHT,
2956 static int ep_belt_active[] =
2958 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2959 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2960 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2961 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2962 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2963 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2964 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2965 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2966 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2967 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2968 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2969 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2973 static int ep_belt_switch[] =
2975 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2976 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2977 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2978 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2979 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2980 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2981 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2982 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2983 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2984 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2985 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2986 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2990 static int ep_tube[] =
2997 EL_TUBE_HORIZONTAL_UP,
2998 EL_TUBE_HORIZONTAL_DOWN,
3000 EL_TUBE_VERTICAL_LEFT,
3001 EL_TUBE_VERTICAL_RIGHT,
3006 static int ep_keygate[] =
3035 static int ep_amoeboid[] =
3045 static int ep_amoebalive[] =
3054 static int ep_has_content[] =
3064 static int ep_can_turn_each_move[] =
3066 /* !!! do something with this one !!! */
3070 static int ep_can_grow[] =
3082 static int ep_active_bomb[] =
3085 EL_DYNABOMB_PLAYER_1_ACTIVE,
3086 EL_DYNABOMB_PLAYER_2_ACTIVE,
3087 EL_DYNABOMB_PLAYER_3_ACTIVE,
3088 EL_DYNABOMB_PLAYER_4_ACTIVE,
3089 EL_SP_DISK_RED_ACTIVE,
3093 static int ep_inactive[] =
3142 EL_INVISIBLE_STEELWALL,
3150 EL_WALL_EMERALD_YELLOW,
3151 EL_DYNABOMB_INCREASE_NUMBER,
3152 EL_DYNABOMB_INCREASE_SIZE,
3153 EL_DYNABOMB_INCREASE_POWER,
3157 EL_SOKOBAN_FIELD_EMPTY,
3158 EL_SOKOBAN_FIELD_FULL,
3159 EL_WALL_EMERALD_RED,
3160 EL_WALL_EMERALD_PURPLE,
3161 EL_ACID_POOL_TOPLEFT,
3162 EL_ACID_POOL_TOPRIGHT,
3163 EL_ACID_POOL_BOTTOMLEFT,
3164 EL_ACID_POOL_BOTTOM,
3165 EL_ACID_POOL_BOTTOMRIGHT,
3169 EL_BD_MAGIC_WALL_DEAD,
3170 EL_AMOEBA_TO_DIAMOND,
3178 EL_SP_GRAVITY_PORT_RIGHT,
3179 EL_SP_GRAVITY_PORT_DOWN,
3180 EL_SP_GRAVITY_PORT_LEFT,
3181 EL_SP_GRAVITY_PORT_UP,
3182 EL_SP_PORT_HORIZONTAL,
3183 EL_SP_PORT_VERTICAL,
3194 EL_SP_HARDWARE_GRAY,
3195 EL_SP_HARDWARE_GREEN,
3196 EL_SP_HARDWARE_BLUE,
3198 EL_SP_HARDWARE_YELLOW,
3199 EL_SP_HARDWARE_BASE_1,
3200 EL_SP_HARDWARE_BASE_2,
3201 EL_SP_HARDWARE_BASE_3,
3202 EL_SP_HARDWARE_BASE_4,
3203 EL_SP_HARDWARE_BASE_5,
3204 EL_SP_HARDWARE_BASE_6,
3205 EL_SP_GRAVITY_ON_PORT_LEFT,
3206 EL_SP_GRAVITY_ON_PORT_RIGHT,
3207 EL_SP_GRAVITY_ON_PORT_UP,
3208 EL_SP_GRAVITY_ON_PORT_DOWN,
3209 EL_SP_GRAVITY_OFF_PORT_LEFT,
3210 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3211 EL_SP_GRAVITY_OFF_PORT_UP,
3212 EL_SP_GRAVITY_OFF_PORT_DOWN,
3213 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3214 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3215 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3216 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3217 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3218 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3219 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3220 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3221 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3222 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3223 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3224 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3225 EL_SIGN_EXCLAMATION,
3226 EL_SIGN_RADIOACTIVITY,
3237 EL_STEELWALL_SLIPPERY,
3242 EL_EMC_WALL_SLIPPERY_1,
3243 EL_EMC_WALL_SLIPPERY_2,
3244 EL_EMC_WALL_SLIPPERY_3,
3245 EL_EMC_WALL_SLIPPERY_4,
3265 static int ep_em_slippery_wall[] =
3270 static int ep_gfx_crumbled[] =
3283 } element_properties[] =
3285 { ep_diggable, EP_DIGGABLE },
3286 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3287 { ep_dont_run_into, EP_DONT_RUN_INTO },
3288 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3289 { ep_dont_touch, EP_DONT_TOUCH },
3290 { ep_indestructible, EP_INDESTRUCTIBLE },
3291 { ep_slippery, EP_SLIPPERY },
3292 { ep_can_change, EP_CAN_CHANGE },
3293 { ep_can_move, EP_CAN_MOVE },
3294 { ep_can_fall, EP_CAN_FALL },
3295 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3296 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3297 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3298 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3299 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3300 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3301 { ep_walkable_over, EP_WALKABLE_OVER },
3302 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3303 { ep_walkable_under, EP_WALKABLE_UNDER },
3304 { ep_passable_over, EP_PASSABLE_OVER },
3305 { ep_passable_inside, EP_PASSABLE_INSIDE },
3306 { ep_passable_under, EP_PASSABLE_UNDER },
3307 { ep_droppable, EP_DROPPABLE },
3308 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3309 { ep_pushable, EP_PUSHABLE },
3310 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3311 { ep_protected, EP_PROTECTED },
3312 { ep_throwable, EP_THROWABLE },
3313 { ep_can_explode, EP_CAN_EXPLODE },
3314 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3316 { ep_player, EP_PLAYER },
3317 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3318 { ep_switchable, EP_SWITCHABLE },
3319 { ep_bd_element, EP_BD_ELEMENT },
3320 { ep_sp_element, EP_SP_ELEMENT },
3321 { ep_sb_element, EP_SB_ELEMENT },
3323 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3324 { ep_food_penguin, EP_FOOD_PENGUIN },
3325 { ep_food_pig, EP_FOOD_PIG },
3326 { ep_historic_wall, EP_HISTORIC_WALL },
3327 { ep_historic_solid, EP_HISTORIC_SOLID },
3328 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3329 { ep_belt, EP_BELT },
3330 { ep_belt_active, EP_BELT_ACTIVE },
3331 { ep_belt_switch, EP_BELT_SWITCH },
3332 { ep_tube, EP_TUBE },
3333 { ep_keygate, EP_KEYGATE },
3334 { ep_amoeboid, EP_AMOEBOID },
3335 { ep_amoebalive, EP_AMOEBALIVE },
3336 { ep_has_content, EP_HAS_CONTENT },
3337 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3338 { ep_can_grow, EP_CAN_GROW },
3339 { ep_active_bomb, EP_ACTIVE_BOMB },
3340 { ep_inactive, EP_INACTIVE },
3342 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3344 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3351 /* always start with reliable default values (element has no properties) */
3352 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3353 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3354 SET_PROPERTY(i, j, FALSE);
3356 /* set all base element properties from above array definitions */
3357 for (i = 0; element_properties[i].elements != NULL; i++)
3358 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3359 SET_PROPERTY((element_properties[i].elements)[j],
3360 element_properties[i].property, TRUE);
3362 /* copy properties to some elements that are only stored in level file */
3363 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3364 for (j = 0; copy_properties[j][0] != -1; j++)
3365 if (HAS_PROPERTY(copy_properties[j][0], i))
3366 for (k = 1; k <= 4; k++)
3367 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3370 void InitElementPropertiesEngine(int engine_version)
3372 static int no_wall_properties[] =
3375 EP_COLLECTIBLE_ONLY,
3377 EP_DONT_COLLIDE_WITH,
3380 EP_CAN_SMASH_PLAYER,
3381 EP_CAN_SMASH_ENEMIES,
3382 EP_CAN_SMASH_EVERYTHING,
3387 EP_FOOD_DARK_YAMYAM,
3403 /* important: after initialization in InitElementPropertiesStatic(), the
3404 elements are not again initialized to a default value; therefore all
3405 changes have to make sure that they leave the element with a defined
3406 property (which means that conditional property changes must be set to
3407 a reliable default value before) */
3409 /* set all special, combined or engine dependent element properties */
3410 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3412 /* ---------- INACTIVE ------------------------------------------------- */
3413 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3415 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3416 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3417 IS_WALKABLE_INSIDE(i) ||
3418 IS_WALKABLE_UNDER(i)));
3420 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3421 IS_PASSABLE_INSIDE(i) ||
3422 IS_PASSABLE_UNDER(i)));
3424 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3425 IS_PASSABLE_OVER(i)));
3427 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3428 IS_PASSABLE_INSIDE(i)));
3430 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3431 IS_PASSABLE_UNDER(i)));
3433 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3436 /* ---------- COLLECTIBLE ---------------------------------------------- */
3437 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3441 /* ---------- SNAPPABLE ------------------------------------------------ */
3442 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3443 IS_COLLECTIBLE(i) ||
3447 /* ---------- WALL ----------------------------------------------------- */
3448 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3450 for (j = 0; no_wall_properties[j] != -1; j++)
3451 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3452 i >= EL_FIRST_RUNTIME_UNREAL)
3453 SET_PROPERTY(i, EP_WALL, FALSE);
3455 if (IS_HISTORIC_WALL(i))
3456 SET_PROPERTY(i, EP_WALL, TRUE);
3458 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3459 if (engine_version < VERSION_IDENT(2,2,0,0))
3460 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3462 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3464 !IS_COLLECTIBLE(i)));
3466 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3468 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3469 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3471 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3472 IS_INDESTRUCTIBLE(i)));
3474 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3476 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3477 else if (engine_version < VERSION_IDENT(2,2,0,0))
3478 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3480 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3484 if (IS_CUSTOM_ELEMENT(i))
3486 /* these are additional properties which are initially false when set */
3488 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3490 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3491 if (DONT_COLLIDE_WITH(i))
3492 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3494 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3495 if (CAN_SMASH_EVERYTHING(i))
3496 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3497 if (CAN_SMASH_ENEMIES(i))
3498 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3501 /* ---------- CAN_SMASH ------------------------------------------------ */
3502 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3503 CAN_SMASH_ENEMIES(i) ||
3504 CAN_SMASH_EVERYTHING(i)));
3506 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3507 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3508 EXPLODES_BY_FIRE(i)));
3510 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3511 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3512 EXPLODES_SMASHED(i)));
3514 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3515 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3516 EXPLODES_IMPACT(i)));
3518 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3519 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3521 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3522 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3523 i == EL_BLACK_ORB));
3525 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3526 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3528 IS_CUSTOM_ELEMENT(i)));
3530 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3531 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3532 i == EL_SP_ELECTRON));
3534 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3535 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3536 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3537 getMoveIntoAcidProperty(&level, i));
3539 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3540 if (MAYBE_DONT_COLLIDE_WITH(i))
3541 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3542 getDontCollideWithProperty(&level, i));
3544 /* ---------- SP_PORT -------------------------------------------------- */
3545 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3546 IS_PASSABLE_INSIDE(i)));
3548 /* ---------- CAN_CHANGE ----------------------------------------------- */
3549 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3550 for (j = 0; j < element_info[i].num_change_pages; j++)
3551 if (element_info[i].change_page[j].can_change)
3552 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3554 /* ---------- HAS_ACTION ----------------------------------------------- */
3555 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3556 for (j = 0; j < element_info[i].num_change_pages; j++)
3557 if (element_info[i].change_page[j].has_action)
3558 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3560 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3561 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3564 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3566 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3567 element_info[i].crumbled[ACTION_DEFAULT] !=
3568 element_info[i].graphic[ACTION_DEFAULT]);
3570 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3571 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3572 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3576 /* dynamically adjust element properties according to game engine version */
3578 static int ep_em_slippery_wall[] =
3583 EL_EXPANDABLE_WALL_HORIZONTAL,
3584 EL_EXPANDABLE_WALL_VERTICAL,
3585 EL_EXPANDABLE_WALL_ANY,
3589 /* special EM style gems behaviour */
3590 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3591 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3592 level.em_slippery_gems);
3594 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3595 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3596 (level.em_slippery_gems &&
3597 engine_version > VERSION_IDENT(2,0,1,0)));
3600 /* set default push delay values (corrected since version 3.0.7-1) */
3601 if (engine_version < VERSION_IDENT(3,0,7,1))
3603 game.default_push_delay_fixed = 2;
3604 game.default_push_delay_random = 8;
3608 game.default_push_delay_fixed = 8;
3609 game.default_push_delay_random = 8;
3612 /* set uninitialized push delay values of custom elements in older levels */
3613 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3615 int element = EL_CUSTOM_START + i;
3617 if (element_info[element].push_delay_fixed == -1)
3618 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3619 if (element_info[element].push_delay_random == -1)
3620 element_info[element].push_delay_random = game.default_push_delay_random;
3623 /* set some other uninitialized values of custom elements in older levels */
3624 if (engine_version < VERSION_IDENT(3,1,0,0))
3626 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3628 int element = EL_CUSTOM_START + i;
3630 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3632 element_info[element].explosion_delay = 17;
3633 element_info[element].ignition_delay = 8;
3638 /* set element properties that were handled incorrectly in older levels */
3639 if (engine_version < VERSION_IDENT(3,1,0,0))
3641 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3642 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3646 /* this is needed because some graphics depend on element properties */
3647 if (game_status == GAME_MODE_PLAYING)
3648 InitElementGraphicInfo();
3651 static void InitGlobal()
3655 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3657 /* check if element_name_info entry defined for each element in "main.h" */
3658 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3659 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3661 element_info[i].token_name = element_name_info[i].token_name;
3662 element_info[i].class_name = element_name_info[i].class_name;
3663 element_info[i].editor_description=element_name_info[i].editor_description;
3666 global.autoplay_leveldir = NULL;
3667 global.convert_leveldir = NULL;
3669 global.frames_per_second = 0;
3670 global.fps_slowdown = FALSE;
3671 global.fps_slowdown_factor = 1;
3674 void Execute_Command(char *command)
3678 if (strcmp(command, "print graphicsinfo.conf") == 0)
3680 printf("# You can configure additional/alternative image files here.\n");
3681 printf("# (The entries below are default and therefore commented out.)\n");
3683 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3685 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3688 for (i = 0; image_config[i].token != NULL; i++)
3689 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3690 image_config[i].value));
3694 else if (strcmp(command, "print soundsinfo.conf") == 0)
3696 printf("# You can configure additional/alternative sound files here.\n");
3697 printf("# (The entries below are default and therefore commented out.)\n");
3699 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3701 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3704 for (i = 0; sound_config[i].token != NULL; i++)
3705 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3706 sound_config[i].value));
3710 else if (strcmp(command, "print musicinfo.conf") == 0)
3712 printf("# You can configure additional/alternative music files here.\n");
3713 printf("# (The entries below are default and therefore commented out.)\n");
3715 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3717 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3720 for (i = 0; music_config[i].token != NULL; i++)
3721 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3722 music_config[i].value));
3726 else if (strcmp(command, "print editorsetup.conf") == 0)
3728 printf("# You can configure your personal editor element list here.\n");
3729 printf("# (The entries below are default and therefore commented out.)\n");
3732 PrintEditorElementList();
3736 else if (strcmp(command, "print helpanim.conf") == 0)
3738 printf("# You can configure different element help animations here.\n");
3739 printf("# (The entries below are default and therefore commented out.)\n");
3742 for (i = 0; helpanim_config[i].token != NULL; i++)
3744 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3745 helpanim_config[i].value));
3747 if (strcmp(helpanim_config[i].token, "end") == 0)
3753 else if (strcmp(command, "print helptext.conf") == 0)
3755 printf("# You can configure different element help text here.\n");
3756 printf("# (The entries below are default and therefore commented out.)\n");
3759 for (i = 0; helptext_config[i].token != NULL; i++)
3760 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3761 helptext_config[i].value));
3765 else if (strncmp(command, "dump level ", 11) == 0)
3767 char *filename = &command[11];
3769 if (!fileExists(filename))
3770 Error(ERR_EXIT, "cannot open file '%s'", filename);
3772 LoadLevelFromFilename(&level, filename);
3777 else if (strncmp(command, "dump tape ", 10) == 0)
3779 char *filename = &command[10];
3781 if (!fileExists(filename))
3782 Error(ERR_EXIT, "cannot open file '%s'", filename);
3784 LoadTapeFromFilename(filename);
3789 else if (strncmp(command, "autoplay ", 9) == 0)
3791 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3793 while (*str_ptr != '\0') /* continue parsing string */
3795 /* cut leading whitespace from string, replace it by string terminator */
3796 while (*str_ptr == ' ' || *str_ptr == '\t')
3799 if (*str_ptr == '\0') /* end of string reached */
3802 if (global.autoplay_leveldir == NULL) /* read level set string */
3804 global.autoplay_leveldir = str_ptr;
3805 global.autoplay_all = TRUE; /* default: play all tapes */
3807 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3808 global.autoplay_level[i] = FALSE;
3810 else /* read level number string */
3812 int level_nr = atoi(str_ptr); /* get level_nr value */
3814 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3815 global.autoplay_level[level_nr] = TRUE;
3817 global.autoplay_all = FALSE;
3820 /* advance string pointer to the next whitespace (or end of string) */
3821 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3825 else if (strncmp(command, "convert ", 8) == 0)
3827 char *str_copy = getStringCopy(&command[8]);
3828 char *str_ptr = strchr(str_copy, ' ');
3830 global.convert_leveldir = str_copy;
3831 global.convert_level_nr = -1;
3833 if (str_ptr != NULL) /* level number follows */
3835 *str_ptr++ = '\0'; /* terminate leveldir string */
3836 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3841 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3845 static void InitSetup()
3847 LoadSetup(); /* global setup info */
3849 /* set some options from setup file */
3851 if (setup.options.verbose)
3852 options.verbose = TRUE;
3855 static void InitGameInfo()
3857 game.restart_level = FALSE;
3860 static void InitPlayerInfo()
3864 /* choose default local player */
3865 local_player = &stored_player[0];
3867 for (i = 0; i < MAX_PLAYERS; i++)
3868 stored_player[i].connected = FALSE;
3870 local_player->connected = TRUE;
3873 static void InitArtworkInfo()
3878 static char *get_string_in_brackets(char *string)
3880 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3882 sprintf(string_in_brackets, "[%s]", string);
3884 return string_in_brackets;
3887 static char *get_level_id_suffix(int id_nr)
3889 char *id_suffix = checked_malloc(1 + 3 + 1);
3891 if (id_nr < 0 || id_nr > 999)
3894 sprintf(id_suffix, ".%03d", id_nr);
3900 static char *get_element_class_token(int element)
3902 char *element_class_name = element_info[element].class_name;
3903 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3905 sprintf(element_class_token, "[%s]", element_class_name);
3907 return element_class_token;
3910 static char *get_action_class_token(int action)
3912 char *action_class_name = &element_action_info[action].suffix[1];
3913 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3915 sprintf(action_class_token, "[%s]", action_class_name);
3917 return action_class_token;
3921 static void InitArtworkConfig()
3923 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3924 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3925 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3926 static char *action_id_suffix[NUM_ACTIONS + 1];
3927 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3928 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3929 static char *level_id_suffix[MAX_LEVELS + 1];
3930 static char *dummy[1] = { NULL };
3931 static char *ignore_generic_tokens[] =
3937 static char **ignore_image_tokens;
3938 static char **ignore_sound_tokens;
3939 static char **ignore_music_tokens;
3940 int num_ignore_generic_tokens;
3941 int num_ignore_image_tokens;
3942 int num_ignore_sound_tokens;
3943 int num_ignore_music_tokens;
3946 /* dynamically determine list of generic tokens to be ignored */
3947 num_ignore_generic_tokens = 0;
3948 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3949 num_ignore_generic_tokens++;
3951 /* dynamically determine list of image tokens to be ignored */
3952 num_ignore_image_tokens = num_ignore_generic_tokens;
3953 for (i = 0; image_config_vars[i].token != NULL; i++)
3954 num_ignore_image_tokens++;
3955 ignore_image_tokens =
3956 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3957 for (i = 0; i < num_ignore_generic_tokens; i++)
3958 ignore_image_tokens[i] = ignore_generic_tokens[i];
3959 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3960 ignore_image_tokens[num_ignore_generic_tokens + i] =
3961 image_config_vars[i].token;
3962 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3964 /* dynamically determine list of sound tokens to be ignored */
3965 num_ignore_sound_tokens = num_ignore_generic_tokens;
3966 ignore_sound_tokens =
3967 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3968 for (i = 0; i < num_ignore_generic_tokens; i++)
3969 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3970 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3972 /* dynamically determine list of music tokens to be ignored */
3973 num_ignore_music_tokens = num_ignore_generic_tokens;
3974 ignore_music_tokens =
3975 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3976 for (i = 0; i < num_ignore_generic_tokens; i++)
3977 ignore_music_tokens[i] = ignore_generic_tokens[i];
3978 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3980 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3981 image_id_prefix[i] = element_info[i].token_name;
3982 for (i = 0; i < NUM_FONTS; i++)
3983 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3984 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3986 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3987 sound_id_prefix[i] = element_info[i].token_name;
3988 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3989 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3990 get_string_in_brackets(element_info[i].class_name);
3991 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3993 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3994 music_id_prefix[i] = music_prefix_info[i].prefix;
3995 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
3997 for (i = 0; i < NUM_ACTIONS; i++)
3998 action_id_suffix[i] = element_action_info[i].suffix;
3999 action_id_suffix[NUM_ACTIONS] = NULL;
4001 for (i = 0; i < NUM_DIRECTIONS; i++)
4002 direction_id_suffix[i] = element_direction_info[i].suffix;
4003 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4005 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4006 special_id_suffix[i] = special_suffix_info[i].suffix;
4007 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4009 for (i = 0; i < MAX_LEVELS; i++)
4010 level_id_suffix[i] = get_level_id_suffix(i);
4011 level_id_suffix[MAX_LEVELS] = NULL;
4013 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4014 image_id_prefix, action_id_suffix, direction_id_suffix,
4015 special_id_suffix, ignore_image_tokens);
4016 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4017 sound_id_prefix, action_id_suffix, dummy,
4018 special_id_suffix, ignore_sound_tokens);
4019 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4020 music_id_prefix, special_id_suffix, level_id_suffix,
4021 dummy, ignore_music_tokens);
4024 static void InitMixer()
4032 char *filename_font_initial = NULL;
4033 Bitmap *bitmap_font_initial = NULL;
4036 /* determine settings for initial font (for displaying startup messages) */
4037 for (i = 0; image_config[i].token != NULL; i++)
4039 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4041 char font_token[128];
4044 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4045 len_font_token = strlen(font_token);
4047 if (strcmp(image_config[i].token, font_token) == 0)
4048 filename_font_initial = image_config[i].value;
4049 else if (strlen(image_config[i].token) > len_font_token &&
4050 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4052 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4053 font_initial[j].src_x = atoi(image_config[i].value);
4054 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4055 font_initial[j].src_y = atoi(image_config[i].value);
4056 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4057 font_initial[j].width = atoi(image_config[i].value);
4058 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4059 font_initial[j].height = atoi(image_config[i].value);
4064 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4066 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4067 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4070 if (filename_font_initial == NULL) /* should not happen */
4071 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4073 /* create additional image buffers for double-buffering */
4074 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4075 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4077 /* initialize screen properties */
4078 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4079 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4081 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4082 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4083 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4085 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4087 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4088 font_initial[j].bitmap = bitmap_font_initial;
4090 InitFontGraphicInfo();
4092 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4093 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4095 DrawInitText("Loading graphics:", 120, FC_GREEN);
4098 void InitGfxBackground()
4102 drawto = backbuffer;
4103 fieldbuffer = bitmap_db_field;
4104 SetDrawtoField(DRAW_BACKBUFFER);
4106 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4107 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4108 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4109 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4111 for (x = 0; x < MAX_BUF_XSIZE; x++)
4112 for (y = 0; y < MAX_BUF_YSIZE; y++)
4115 redraw_mask = REDRAW_ALL;
4118 static void InitLevelInfo()
4120 LoadLevelInfo(); /* global level info */
4121 LoadLevelSetup_LastSeries(); /* last played series info */
4122 LoadLevelSetup_SeriesInfo(); /* last played level info */
4125 void InitLevelArtworkInfo()
4127 LoadLevelArtworkInfo();
4130 static void InitImages()
4132 setLevelArtworkDir(artwork.gfx_first);
4135 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4136 leveldir_current->identifier,
4137 artwork.gfx_current_identifier,
4138 artwork.gfx_current->identifier,
4139 leveldir_current->graphics_set,
4140 leveldir_current->graphics_path);
4143 ReloadCustomImages();
4145 LoadCustomElementDescriptions();
4146 LoadSpecialMenuDesignSettings();
4148 ReinitializeGraphics();
4151 static void InitSound(char *identifier)
4153 if (identifier == NULL)
4154 identifier = artwork.snd_current->identifier;
4156 /* set artwork path to send it to the sound server process */
4157 setLevelArtworkDir(artwork.snd_first);
4159 InitReloadCustomSounds(identifier);
4160 ReinitializeSounds();
4163 static void InitMusic(char *identifier)
4165 if (identifier == NULL)
4166 identifier = artwork.mus_current->identifier;
4168 /* set artwork path to send it to the sound server process */
4169 setLevelArtworkDir(artwork.mus_first);
4171 InitReloadCustomMusic(identifier);
4172 ReinitializeMusic();
4175 void InitNetworkServer()
4177 #if defined(NETWORK_AVALIABLE)
4181 if (!options.network)
4184 #if defined(NETWORK_AVALIABLE)
4185 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4187 if (!ConnectToServer(options.server_host, options.server_port))
4188 Error(ERR_EXIT, "cannot connect to network game server");
4190 SendToServer_PlayerName(setup.player_name);
4191 SendToServer_ProtocolVersion();
4194 SendToServer_NrWanted(nr_wanted);
4198 static char *getNewArtworkIdentifier(int type)
4200 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4201 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4202 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4203 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4204 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4205 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4206 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4207 char *leveldir_identifier = leveldir_current->identifier;
4209 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4210 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4212 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4214 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4215 char *artwork_current_identifier;
4216 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4218 /* leveldir_current may be invalid (level group, parent link) */
4219 if (!validLevelSeries(leveldir_current))
4222 /* 1st step: determine artwork set to be activated in descending order:
4223 --------------------------------------------------------------------
4224 1. setup artwork (when configured to override everything else)
4225 2. artwork set configured in "levelinfo.conf" of current level set
4226 (artwork in level directory will have priority when loading later)
4227 3. artwork in level directory (stored in artwork sub-directory)
4228 4. setup artwork (currently configured in setup menu) */
4230 if (setup_override_artwork)
4231 artwork_current_identifier = setup_artwork_set;
4232 else if (leveldir_artwork_set != NULL)
4233 artwork_current_identifier = leveldir_artwork_set;
4234 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4235 artwork_current_identifier = leveldir_identifier;
4237 artwork_current_identifier = setup_artwork_set;
4240 /* 2nd step: check if it is really needed to reload artwork set
4241 ------------------------------------------------------------ */
4244 if (type == ARTWORK_TYPE_GRAPHICS)
4245 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4246 artwork_new_identifier,
4247 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4248 artwork_current_identifier,
4249 leveldir_current->graphics_set,
4250 leveldir_current->identifier);
4253 /* ---------- reload if level set and also artwork set has changed ------- */
4254 if (leveldir_current_identifier[type] != leveldir_identifier &&
4255 (last_has_level_artwork_set[type] || has_level_artwork_set))
4256 artwork_new_identifier = artwork_current_identifier;
4258 leveldir_current_identifier[type] = leveldir_identifier;
4259 last_has_level_artwork_set[type] = has_level_artwork_set;
4262 if (type == ARTWORK_TYPE_GRAPHICS)
4263 printf("::: 1: '%s'\n", artwork_new_identifier);
4266 /* ---------- reload if "override artwork" setting has changed ----------- */
4267 if (last_override_level_artwork[type] != setup_override_artwork)
4268 artwork_new_identifier = artwork_current_identifier;
4270 last_override_level_artwork[type] = setup_override_artwork;
4273 if (type == ARTWORK_TYPE_GRAPHICS)
4274 printf("::: 2: '%s'\n", artwork_new_identifier);
4277 /* ---------- reload if current artwork identifier has changed ----------- */
4278 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4279 artwork_current_identifier) != 0)
4280 artwork_new_identifier = artwork_current_identifier;
4282 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4285 if (type == ARTWORK_TYPE_GRAPHICS)
4286 printf("::: 3: '%s'\n", artwork_new_identifier);
4289 /* ---------- do not reload directly after starting ---------------------- */
4290 if (!initialized[type])
4291 artwork_new_identifier = NULL;
4293 initialized[type] = TRUE;
4296 if (type == ARTWORK_TYPE_GRAPHICS)
4297 printf("::: 4: '%s'\n", artwork_new_identifier);
4301 if (type == ARTWORK_TYPE_GRAPHICS)
4302 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4303 artwork.gfx_current_identifier, artwork_current_identifier,
4304 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4305 artwork_new_identifier);
4308 return artwork_new_identifier;
4311 void ReloadCustomArtwork(int force_reload)
4313 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4314 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4315 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4316 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4317 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4318 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4319 boolean redraw_screen = FALSE;
4321 if (gfx_new_identifier != NULL || force_reload_gfx)
4324 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4325 artwork.gfx_current_identifier,
4327 artwork.gfx_current->identifier,
4328 leveldir_current->graphics_set);
4331 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4335 redraw_screen = TRUE;
4338 if (snd_new_identifier != NULL || force_reload_snd)
4340 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4342 InitSound(snd_new_identifier);
4344 redraw_screen = TRUE;
4347 if (mus_new_identifier != NULL || force_reload_mus)
4349 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4351 InitMusic(mus_new_identifier);
4353 redraw_screen = TRUE;
4358 InitGfxBackground();
4360 /* force redraw of (open or closed) door graphics */
4361 SetDoorState(DOOR_OPEN_ALL);
4362 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4366 void KeyboardAutoRepeatOffUnlessAutoplay()
4368 if (global.autoplay_leveldir == NULL)
4369 KeyboardAutoRepeatOff();
4373 /* ========================================================================= */
4375 /* ========================================================================= */
4379 InitGlobal(); /* initialize some global variables */
4381 if (options.execute_command)
4382 Execute_Command(options.execute_command);
4384 if (options.serveronly)
4386 #if defined(PLATFORM_UNIX)
4387 NetworkServer(options.server_port, options.serveronly);
4389 Error(ERR_WARN, "networking only supported in Unix version");
4392 exit(0); /* never reached, server loops forever */
4399 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4400 InitArtworkConfig(); /* needed before forking sound child process */
4405 InitRND(NEW_RANDOMIZE);
4406 InitSimpleRND(NEW_RANDOMIZE);
4411 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4414 InitEventFilter(FilterMouseMotionEvents);
4416 InitElementPropertiesStatic();
4417 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4422 InitLevelArtworkInfo();
4424 InitImages(); /* needs to know current level directory */
4425 InitSound(NULL); /* needs to know current level directory */
4426 InitMusic(NULL); /* needs to know current level directory */
4428 InitGfxBackground();
4430 if (global.autoplay_leveldir)
4435 else if (global.convert_leveldir)
4441 game_status = GAME_MODE_MAIN;
4449 InitNetworkServer();
4452 void CloseAllAndExit(int exit_value)
4457 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4465 #if defined(TARGET_SDL)
4466 if (network_server) /* terminate network server */
4467 SDL_KillThread(server_thread);
4470 CloseVideoDisplay();
4471 ClosePlatformDependentStuff();