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,
2507 EL_BALLOON_SWITCH_NONE,
2510 EL_EMC_MAGIC_BALL_SWITCH,
2514 static int ep_bd_element[] =
2547 static int ep_sp_element[] =
2549 /* should always be valid */
2552 /* standard classic Supaplex elements */
2559 EL_SP_HARDWARE_GRAY,
2567 EL_SP_GRAVITY_PORT_RIGHT,
2568 EL_SP_GRAVITY_PORT_DOWN,
2569 EL_SP_GRAVITY_PORT_LEFT,
2570 EL_SP_GRAVITY_PORT_UP,
2575 EL_SP_PORT_VERTICAL,
2576 EL_SP_PORT_HORIZONTAL,
2582 EL_SP_HARDWARE_BASE_1,
2583 EL_SP_HARDWARE_GREEN,
2584 EL_SP_HARDWARE_BLUE,
2586 EL_SP_HARDWARE_YELLOW,
2587 EL_SP_HARDWARE_BASE_2,
2588 EL_SP_HARDWARE_BASE_3,
2589 EL_SP_HARDWARE_BASE_4,
2590 EL_SP_HARDWARE_BASE_5,
2591 EL_SP_HARDWARE_BASE_6,
2595 /* additional elements that appeared in newer Supaplex levels */
2598 /* additional gravity port elements (not switching, but setting gravity) */
2599 EL_SP_GRAVITY_ON_PORT_LEFT,
2600 EL_SP_GRAVITY_ON_PORT_RIGHT,
2601 EL_SP_GRAVITY_ON_PORT_UP,
2602 EL_SP_GRAVITY_ON_PORT_DOWN,
2603 EL_SP_GRAVITY_OFF_PORT_LEFT,
2604 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2605 EL_SP_GRAVITY_OFF_PORT_UP,
2606 EL_SP_GRAVITY_OFF_PORT_DOWN,
2608 /* more than one Murphy in a level results in an inactive clone */
2611 /* runtime Supaplex elements */
2612 EL_SP_DISK_RED_ACTIVE,
2613 EL_SP_TERMINAL_ACTIVE,
2614 EL_SP_BUGGY_BASE_ACTIVATING,
2615 EL_SP_BUGGY_BASE_ACTIVE,
2621 static int ep_sb_element[] =
2626 EL_SOKOBAN_FIELD_EMPTY,
2627 EL_SOKOBAN_FIELD_FULL,
2628 EL_SOKOBAN_FIELD_PLAYER,
2633 EL_INVISIBLE_STEELWALL,
2637 static int ep_gem[] =
2648 static int ep_food_dark_yamyam[] =
2675 static int ep_food_penguin[] =
2688 static int ep_food_pig[] =
2699 static int ep_historic_wall[] =
2724 EL_EXPANDABLE_WALL_HORIZONTAL,
2725 EL_EXPANDABLE_WALL_VERTICAL,
2726 EL_EXPANDABLE_WALL_ANY,
2727 EL_EXPANDABLE_WALL_GROWING,
2734 EL_SP_HARDWARE_GRAY,
2735 EL_SP_HARDWARE_GREEN,
2736 EL_SP_HARDWARE_BLUE,
2738 EL_SP_HARDWARE_YELLOW,
2739 EL_SP_HARDWARE_BASE_1,
2740 EL_SP_HARDWARE_BASE_2,
2741 EL_SP_HARDWARE_BASE_3,
2742 EL_SP_HARDWARE_BASE_4,
2743 EL_SP_HARDWARE_BASE_5,
2744 EL_SP_HARDWARE_BASE_6,
2746 EL_SP_TERMINAL_ACTIVE,
2749 EL_INVISIBLE_STEELWALL,
2750 EL_INVISIBLE_STEELWALL_ACTIVE,
2752 EL_INVISIBLE_WALL_ACTIVE,
2753 EL_STEELWALL_SLIPPERY,
2769 static int ep_historic_solid[] =
2773 EL_EXPANDABLE_WALL_HORIZONTAL,
2774 EL_EXPANDABLE_WALL_VERTICAL,
2775 EL_EXPANDABLE_WALL_ANY,
2788 EL_QUICKSAND_FILLING,
2789 EL_QUICKSAND_EMPTYING,
2791 EL_MAGIC_WALL_ACTIVE,
2792 EL_MAGIC_WALL_EMPTYING,
2793 EL_MAGIC_WALL_FILLING,
2797 EL_BD_MAGIC_WALL_ACTIVE,
2798 EL_BD_MAGIC_WALL_EMPTYING,
2799 EL_BD_MAGIC_WALL_FULL,
2800 EL_BD_MAGIC_WALL_FILLING,
2801 EL_BD_MAGIC_WALL_DEAD,
2810 EL_SP_TERMINAL_ACTIVE,
2814 EL_INVISIBLE_WALL_ACTIVE,
2815 EL_SWITCHGATE_SWITCH_UP,
2816 EL_SWITCHGATE_SWITCH_DOWN,
2818 EL_TIMEGATE_SWITCH_ACTIVE,
2830 /* the following elements are a direct copy of "indestructible" elements,
2831 except "EL_ACID", which is "indestructible", but not "solid"! */
2836 EL_ACID_POOL_TOPLEFT,
2837 EL_ACID_POOL_TOPRIGHT,
2838 EL_ACID_POOL_BOTTOMLEFT,
2839 EL_ACID_POOL_BOTTOM,
2840 EL_ACID_POOL_BOTTOMRIGHT,
2841 EL_SP_HARDWARE_GRAY,
2842 EL_SP_HARDWARE_GREEN,
2843 EL_SP_HARDWARE_BLUE,
2845 EL_SP_HARDWARE_YELLOW,
2846 EL_SP_HARDWARE_BASE_1,
2847 EL_SP_HARDWARE_BASE_2,
2848 EL_SP_HARDWARE_BASE_3,
2849 EL_SP_HARDWARE_BASE_4,
2850 EL_SP_HARDWARE_BASE_5,
2851 EL_SP_HARDWARE_BASE_6,
2852 EL_INVISIBLE_STEELWALL,
2853 EL_INVISIBLE_STEELWALL_ACTIVE,
2854 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2855 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2856 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2857 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2858 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2859 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2860 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2861 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2862 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2863 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2864 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2865 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2867 EL_LIGHT_SWITCH_ACTIVE,
2868 EL_SIGN_EXCLAMATION,
2869 EL_SIGN_RADIOACTIVITY,
2880 EL_STEELWALL_SLIPPERY,
2903 EL_SWITCHGATE_OPENING,
2904 EL_SWITCHGATE_CLOSED,
2905 EL_SWITCHGATE_CLOSING,
2907 EL_TIMEGATE_OPENING,
2909 EL_TIMEGATE_CLOSING,
2913 EL_TUBE_VERTICAL_LEFT,
2914 EL_TUBE_VERTICAL_RIGHT,
2915 EL_TUBE_HORIZONTAL_UP,
2916 EL_TUBE_HORIZONTAL_DOWN,
2924 static int ep_classic_enemy[] =
2940 static int ep_belt[] =
2942 EL_CONVEYOR_BELT_1_LEFT,
2943 EL_CONVEYOR_BELT_1_MIDDLE,
2944 EL_CONVEYOR_BELT_1_RIGHT,
2945 EL_CONVEYOR_BELT_2_LEFT,
2946 EL_CONVEYOR_BELT_2_MIDDLE,
2947 EL_CONVEYOR_BELT_2_RIGHT,
2948 EL_CONVEYOR_BELT_3_LEFT,
2949 EL_CONVEYOR_BELT_3_MIDDLE,
2950 EL_CONVEYOR_BELT_3_RIGHT,
2951 EL_CONVEYOR_BELT_4_LEFT,
2952 EL_CONVEYOR_BELT_4_MIDDLE,
2953 EL_CONVEYOR_BELT_4_RIGHT,
2957 static int ep_belt_active[] =
2959 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2960 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2961 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2962 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2963 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2964 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2965 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2966 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2967 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2968 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2969 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2970 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2974 static int ep_belt_switch[] =
2976 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2977 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2978 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2979 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2980 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2981 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2982 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2983 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2984 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2985 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2986 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2987 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2991 static int ep_tube[] =
2998 EL_TUBE_HORIZONTAL_UP,
2999 EL_TUBE_HORIZONTAL_DOWN,
3001 EL_TUBE_VERTICAL_LEFT,
3002 EL_TUBE_VERTICAL_RIGHT,
3007 static int ep_keygate[] =
3036 static int ep_amoeboid[] =
3046 static int ep_amoebalive[] =
3055 static int ep_has_content[] =
3065 static int ep_can_turn_each_move[] =
3067 /* !!! do something with this one !!! */
3071 static int ep_can_grow[] =
3083 static int ep_active_bomb[] =
3086 EL_DYNABOMB_PLAYER_1_ACTIVE,
3087 EL_DYNABOMB_PLAYER_2_ACTIVE,
3088 EL_DYNABOMB_PLAYER_3_ACTIVE,
3089 EL_DYNABOMB_PLAYER_4_ACTIVE,
3090 EL_SP_DISK_RED_ACTIVE,
3094 static int ep_inactive[] =
3143 EL_INVISIBLE_STEELWALL,
3151 EL_WALL_EMERALD_YELLOW,
3152 EL_DYNABOMB_INCREASE_NUMBER,
3153 EL_DYNABOMB_INCREASE_SIZE,
3154 EL_DYNABOMB_INCREASE_POWER,
3158 EL_SOKOBAN_FIELD_EMPTY,
3159 EL_SOKOBAN_FIELD_FULL,
3160 EL_WALL_EMERALD_RED,
3161 EL_WALL_EMERALD_PURPLE,
3162 EL_ACID_POOL_TOPLEFT,
3163 EL_ACID_POOL_TOPRIGHT,
3164 EL_ACID_POOL_BOTTOMLEFT,
3165 EL_ACID_POOL_BOTTOM,
3166 EL_ACID_POOL_BOTTOMRIGHT,
3170 EL_BD_MAGIC_WALL_DEAD,
3171 EL_AMOEBA_TO_DIAMOND,
3179 EL_SP_GRAVITY_PORT_RIGHT,
3180 EL_SP_GRAVITY_PORT_DOWN,
3181 EL_SP_GRAVITY_PORT_LEFT,
3182 EL_SP_GRAVITY_PORT_UP,
3183 EL_SP_PORT_HORIZONTAL,
3184 EL_SP_PORT_VERTICAL,
3195 EL_SP_HARDWARE_GRAY,
3196 EL_SP_HARDWARE_GREEN,
3197 EL_SP_HARDWARE_BLUE,
3199 EL_SP_HARDWARE_YELLOW,
3200 EL_SP_HARDWARE_BASE_1,
3201 EL_SP_HARDWARE_BASE_2,
3202 EL_SP_HARDWARE_BASE_3,
3203 EL_SP_HARDWARE_BASE_4,
3204 EL_SP_HARDWARE_BASE_5,
3205 EL_SP_HARDWARE_BASE_6,
3206 EL_SP_GRAVITY_ON_PORT_LEFT,
3207 EL_SP_GRAVITY_ON_PORT_RIGHT,
3208 EL_SP_GRAVITY_ON_PORT_UP,
3209 EL_SP_GRAVITY_ON_PORT_DOWN,
3210 EL_SP_GRAVITY_OFF_PORT_LEFT,
3211 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3212 EL_SP_GRAVITY_OFF_PORT_UP,
3213 EL_SP_GRAVITY_OFF_PORT_DOWN,
3214 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3215 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3216 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3217 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3218 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3219 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3220 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3221 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3222 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3223 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3224 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3225 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3226 EL_SIGN_EXCLAMATION,
3227 EL_SIGN_RADIOACTIVITY,
3238 EL_STEELWALL_SLIPPERY,
3243 EL_EMC_WALL_SLIPPERY_1,
3244 EL_EMC_WALL_SLIPPERY_2,
3245 EL_EMC_WALL_SLIPPERY_3,
3246 EL_EMC_WALL_SLIPPERY_4,
3266 static int ep_em_slippery_wall[] =
3271 static int ep_gfx_crumbled[] =
3284 } element_properties[] =
3286 { ep_diggable, EP_DIGGABLE },
3287 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3288 { ep_dont_run_into, EP_DONT_RUN_INTO },
3289 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3290 { ep_dont_touch, EP_DONT_TOUCH },
3291 { ep_indestructible, EP_INDESTRUCTIBLE },
3292 { ep_slippery, EP_SLIPPERY },
3293 { ep_can_change, EP_CAN_CHANGE },
3294 { ep_can_move, EP_CAN_MOVE },
3295 { ep_can_fall, EP_CAN_FALL },
3296 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3297 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3298 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3299 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3300 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3301 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3302 { ep_walkable_over, EP_WALKABLE_OVER },
3303 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3304 { ep_walkable_under, EP_WALKABLE_UNDER },
3305 { ep_passable_over, EP_PASSABLE_OVER },
3306 { ep_passable_inside, EP_PASSABLE_INSIDE },
3307 { ep_passable_under, EP_PASSABLE_UNDER },
3308 { ep_droppable, EP_DROPPABLE },
3309 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3310 { ep_pushable, EP_PUSHABLE },
3311 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3312 { ep_protected, EP_PROTECTED },
3313 { ep_throwable, EP_THROWABLE },
3314 { ep_can_explode, EP_CAN_EXPLODE },
3315 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3317 { ep_player, EP_PLAYER },
3318 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3319 { ep_switchable, EP_SWITCHABLE },
3320 { ep_bd_element, EP_BD_ELEMENT },
3321 { ep_sp_element, EP_SP_ELEMENT },
3322 { ep_sb_element, EP_SB_ELEMENT },
3324 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3325 { ep_food_penguin, EP_FOOD_PENGUIN },
3326 { ep_food_pig, EP_FOOD_PIG },
3327 { ep_historic_wall, EP_HISTORIC_WALL },
3328 { ep_historic_solid, EP_HISTORIC_SOLID },
3329 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3330 { ep_belt, EP_BELT },
3331 { ep_belt_active, EP_BELT_ACTIVE },
3332 { ep_belt_switch, EP_BELT_SWITCH },
3333 { ep_tube, EP_TUBE },
3334 { ep_keygate, EP_KEYGATE },
3335 { ep_amoeboid, EP_AMOEBOID },
3336 { ep_amoebalive, EP_AMOEBALIVE },
3337 { ep_has_content, EP_HAS_CONTENT },
3338 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3339 { ep_can_grow, EP_CAN_GROW },
3340 { ep_active_bomb, EP_ACTIVE_BOMB },
3341 { ep_inactive, EP_INACTIVE },
3343 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3345 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3352 /* always start with reliable default values (element has no properties) */
3353 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3354 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3355 SET_PROPERTY(i, j, FALSE);
3357 /* set all base element properties from above array definitions */
3358 for (i = 0; element_properties[i].elements != NULL; i++)
3359 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3360 SET_PROPERTY((element_properties[i].elements)[j],
3361 element_properties[i].property, TRUE);
3363 /* copy properties to some elements that are only stored in level file */
3364 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3365 for (j = 0; copy_properties[j][0] != -1; j++)
3366 if (HAS_PROPERTY(copy_properties[j][0], i))
3367 for (k = 1; k <= 4; k++)
3368 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3371 void InitElementPropertiesEngine(int engine_version)
3373 static int no_wall_properties[] =
3376 EP_COLLECTIBLE_ONLY,
3378 EP_DONT_COLLIDE_WITH,
3381 EP_CAN_SMASH_PLAYER,
3382 EP_CAN_SMASH_ENEMIES,
3383 EP_CAN_SMASH_EVERYTHING,
3388 EP_FOOD_DARK_YAMYAM,
3404 /* important: after initialization in InitElementPropertiesStatic(), the
3405 elements are not again initialized to a default value; therefore all
3406 changes have to make sure that they leave the element with a defined
3407 property (which means that conditional property changes must be set to
3408 a reliable default value before) */
3410 /* set all special, combined or engine dependent element properties */
3411 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3413 /* ---------- INACTIVE ------------------------------------------------- */
3414 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3416 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3417 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3418 IS_WALKABLE_INSIDE(i) ||
3419 IS_WALKABLE_UNDER(i)));
3421 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3422 IS_PASSABLE_INSIDE(i) ||
3423 IS_PASSABLE_UNDER(i)));
3425 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3426 IS_PASSABLE_OVER(i)));
3428 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3429 IS_PASSABLE_INSIDE(i)));
3431 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3432 IS_PASSABLE_UNDER(i)));
3434 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3437 /* ---------- COLLECTIBLE ---------------------------------------------- */
3438 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3442 /* ---------- SNAPPABLE ------------------------------------------------ */
3443 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3444 IS_COLLECTIBLE(i) ||
3448 /* ---------- WALL ----------------------------------------------------- */
3449 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3451 for (j = 0; no_wall_properties[j] != -1; j++)
3452 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3453 i >= EL_FIRST_RUNTIME_UNREAL)
3454 SET_PROPERTY(i, EP_WALL, FALSE);
3456 if (IS_HISTORIC_WALL(i))
3457 SET_PROPERTY(i, EP_WALL, TRUE);
3459 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3460 if (engine_version < VERSION_IDENT(2,2,0,0))
3461 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3463 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3465 !IS_COLLECTIBLE(i)));
3467 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3469 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3470 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3472 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3473 IS_INDESTRUCTIBLE(i)));
3475 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3477 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3478 else if (engine_version < VERSION_IDENT(2,2,0,0))
3479 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3481 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3485 if (IS_CUSTOM_ELEMENT(i))
3487 /* these are additional properties which are initially false when set */
3489 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3491 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3492 if (DONT_COLLIDE_WITH(i))
3493 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3495 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3496 if (CAN_SMASH_EVERYTHING(i))
3497 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3498 if (CAN_SMASH_ENEMIES(i))
3499 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3502 /* ---------- CAN_SMASH ------------------------------------------------ */
3503 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3504 CAN_SMASH_ENEMIES(i) ||
3505 CAN_SMASH_EVERYTHING(i)));
3507 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3508 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3509 EXPLODES_BY_FIRE(i)));
3511 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3512 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3513 EXPLODES_SMASHED(i)));
3515 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3516 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3517 EXPLODES_IMPACT(i)));
3519 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3520 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3522 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3523 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3524 i == EL_BLACK_ORB));
3526 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3527 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3529 IS_CUSTOM_ELEMENT(i)));
3531 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3532 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3533 i == EL_SP_ELECTRON));
3535 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3536 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3537 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3538 getMoveIntoAcidProperty(&level, i));
3540 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3541 if (MAYBE_DONT_COLLIDE_WITH(i))
3542 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3543 getDontCollideWithProperty(&level, i));
3545 /* ---------- SP_PORT -------------------------------------------------- */
3546 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3547 IS_PASSABLE_INSIDE(i)));
3549 /* ---------- CAN_CHANGE ----------------------------------------------- */
3550 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3551 for (j = 0; j < element_info[i].num_change_pages; j++)
3552 if (element_info[i].change_page[j].can_change)
3553 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3555 /* ---------- HAS_ACTION ----------------------------------------------- */
3556 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3557 for (j = 0; j < element_info[i].num_change_pages; j++)
3558 if (element_info[i].change_page[j].has_action)
3559 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3561 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3562 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3565 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3567 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3568 element_info[i].crumbled[ACTION_DEFAULT] !=
3569 element_info[i].graphic[ACTION_DEFAULT]);
3571 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3572 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3573 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3577 /* dynamically adjust element properties according to game engine version */
3579 static int ep_em_slippery_wall[] =
3584 EL_EXPANDABLE_WALL_HORIZONTAL,
3585 EL_EXPANDABLE_WALL_VERTICAL,
3586 EL_EXPANDABLE_WALL_ANY,
3590 /* special EM style gems behaviour */
3591 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3592 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3593 level.em_slippery_gems);
3595 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3596 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3597 (level.em_slippery_gems &&
3598 engine_version > VERSION_IDENT(2,0,1,0)));
3601 /* set default push delay values (corrected since version 3.0.7-1) */
3602 if (engine_version < VERSION_IDENT(3,0,7,1))
3604 game.default_push_delay_fixed = 2;
3605 game.default_push_delay_random = 8;
3609 game.default_push_delay_fixed = 8;
3610 game.default_push_delay_random = 8;
3613 /* set uninitialized push delay values of custom elements in older levels */
3614 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3616 int element = EL_CUSTOM_START + i;
3618 if (element_info[element].push_delay_fixed == -1)
3619 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3620 if (element_info[element].push_delay_random == -1)
3621 element_info[element].push_delay_random = game.default_push_delay_random;
3624 /* set some other uninitialized values of custom elements in older levels */
3625 if (engine_version < VERSION_IDENT(3,1,0,0))
3627 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3629 int element = EL_CUSTOM_START + i;
3631 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3633 element_info[element].explosion_delay = 17;
3634 element_info[element].ignition_delay = 8;
3639 /* set element properties that were handled incorrectly in older levels */
3640 if (engine_version < VERSION_IDENT(3,1,0,0))
3642 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3643 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3647 /* this is needed because some graphics depend on element properties */
3648 if (game_status == GAME_MODE_PLAYING)
3649 InitElementGraphicInfo();
3652 static void InitGlobal()
3656 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3658 /* check if element_name_info entry defined for each element in "main.h" */
3659 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3660 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3662 element_info[i].token_name = element_name_info[i].token_name;
3663 element_info[i].class_name = element_name_info[i].class_name;
3664 element_info[i].editor_description=element_name_info[i].editor_description;
3667 global.autoplay_leveldir = NULL;
3668 global.convert_leveldir = NULL;
3670 global.frames_per_second = 0;
3671 global.fps_slowdown = FALSE;
3672 global.fps_slowdown_factor = 1;
3675 void Execute_Command(char *command)
3679 if (strcmp(command, "print graphicsinfo.conf") == 0)
3681 printf("# You can configure additional/alternative image files here.\n");
3682 printf("# (The entries below are default and therefore commented out.)\n");
3684 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3686 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3689 for (i = 0; image_config[i].token != NULL; i++)
3690 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3691 image_config[i].value));
3695 else if (strcmp(command, "print soundsinfo.conf") == 0)
3697 printf("# You can configure additional/alternative sound files here.\n");
3698 printf("# (The entries below are default and therefore commented out.)\n");
3700 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3702 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3705 for (i = 0; sound_config[i].token != NULL; i++)
3706 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3707 sound_config[i].value));
3711 else if (strcmp(command, "print musicinfo.conf") == 0)
3713 printf("# You can configure additional/alternative music files here.\n");
3714 printf("# (The entries below are default and therefore commented out.)\n");
3716 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3718 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3721 for (i = 0; music_config[i].token != NULL; i++)
3722 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3723 music_config[i].value));
3727 else if (strcmp(command, "print editorsetup.conf") == 0)
3729 printf("# You can configure your personal editor element list here.\n");
3730 printf("# (The entries below are default and therefore commented out.)\n");
3733 PrintEditorElementList();
3737 else if (strcmp(command, "print helpanim.conf") == 0)
3739 printf("# You can configure different element help animations here.\n");
3740 printf("# (The entries below are default and therefore commented out.)\n");
3743 for (i = 0; helpanim_config[i].token != NULL; i++)
3745 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3746 helpanim_config[i].value));
3748 if (strcmp(helpanim_config[i].token, "end") == 0)
3754 else if (strcmp(command, "print helptext.conf") == 0)
3756 printf("# You can configure different element help text here.\n");
3757 printf("# (The entries below are default and therefore commented out.)\n");
3760 for (i = 0; helptext_config[i].token != NULL; i++)
3761 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3762 helptext_config[i].value));
3766 else if (strncmp(command, "dump level ", 11) == 0)
3768 char *filename = &command[11];
3770 if (!fileExists(filename))
3771 Error(ERR_EXIT, "cannot open file '%s'", filename);
3773 LoadLevelFromFilename(&level, filename);
3778 else if (strncmp(command, "dump tape ", 10) == 0)
3780 char *filename = &command[10];
3782 if (!fileExists(filename))
3783 Error(ERR_EXIT, "cannot open file '%s'", filename);
3785 LoadTapeFromFilename(filename);
3790 else if (strncmp(command, "autoplay ", 9) == 0)
3792 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3794 while (*str_ptr != '\0') /* continue parsing string */
3796 /* cut leading whitespace from string, replace it by string terminator */
3797 while (*str_ptr == ' ' || *str_ptr == '\t')
3800 if (*str_ptr == '\0') /* end of string reached */
3803 if (global.autoplay_leveldir == NULL) /* read level set string */
3805 global.autoplay_leveldir = str_ptr;
3806 global.autoplay_all = TRUE; /* default: play all tapes */
3808 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3809 global.autoplay_level[i] = FALSE;
3811 else /* read level number string */
3813 int level_nr = atoi(str_ptr); /* get level_nr value */
3815 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3816 global.autoplay_level[level_nr] = TRUE;
3818 global.autoplay_all = FALSE;
3821 /* advance string pointer to the next whitespace (or end of string) */
3822 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3826 else if (strncmp(command, "convert ", 8) == 0)
3828 char *str_copy = getStringCopy(&command[8]);
3829 char *str_ptr = strchr(str_copy, ' ');
3831 global.convert_leveldir = str_copy;
3832 global.convert_level_nr = -1;
3834 if (str_ptr != NULL) /* level number follows */
3836 *str_ptr++ = '\0'; /* terminate leveldir string */
3837 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3842 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3846 static void InitSetup()
3848 LoadSetup(); /* global setup info */
3850 /* set some options from setup file */
3852 if (setup.options.verbose)
3853 options.verbose = TRUE;
3856 static void InitGameInfo()
3858 game.restart_level = FALSE;
3861 static void InitPlayerInfo()
3865 /* choose default local player */
3866 local_player = &stored_player[0];
3868 for (i = 0; i < MAX_PLAYERS; i++)
3869 stored_player[i].connected = FALSE;
3871 local_player->connected = TRUE;
3874 static void InitArtworkInfo()
3879 static char *get_string_in_brackets(char *string)
3881 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3883 sprintf(string_in_brackets, "[%s]", string);
3885 return string_in_brackets;
3888 static char *get_level_id_suffix(int id_nr)
3890 char *id_suffix = checked_malloc(1 + 3 + 1);
3892 if (id_nr < 0 || id_nr > 999)
3895 sprintf(id_suffix, ".%03d", id_nr);
3901 static char *get_element_class_token(int element)
3903 char *element_class_name = element_info[element].class_name;
3904 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3906 sprintf(element_class_token, "[%s]", element_class_name);
3908 return element_class_token;
3911 static char *get_action_class_token(int action)
3913 char *action_class_name = &element_action_info[action].suffix[1];
3914 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3916 sprintf(action_class_token, "[%s]", action_class_name);
3918 return action_class_token;
3922 static void InitArtworkConfig()
3924 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3925 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3926 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3927 static char *action_id_suffix[NUM_ACTIONS + 1];
3928 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3929 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3930 static char *level_id_suffix[MAX_LEVELS + 1];
3931 static char *dummy[1] = { NULL };
3932 static char *ignore_generic_tokens[] =
3938 static char **ignore_image_tokens;
3939 static char **ignore_sound_tokens;
3940 static char **ignore_music_tokens;
3941 int num_ignore_generic_tokens;
3942 int num_ignore_image_tokens;
3943 int num_ignore_sound_tokens;
3944 int num_ignore_music_tokens;
3947 /* dynamically determine list of generic tokens to be ignored */
3948 num_ignore_generic_tokens = 0;
3949 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3950 num_ignore_generic_tokens++;
3952 /* dynamically determine list of image tokens to be ignored */
3953 num_ignore_image_tokens = num_ignore_generic_tokens;
3954 for (i = 0; image_config_vars[i].token != NULL; i++)
3955 num_ignore_image_tokens++;
3956 ignore_image_tokens =
3957 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3958 for (i = 0; i < num_ignore_generic_tokens; i++)
3959 ignore_image_tokens[i] = ignore_generic_tokens[i];
3960 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3961 ignore_image_tokens[num_ignore_generic_tokens + i] =
3962 image_config_vars[i].token;
3963 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3965 /* dynamically determine list of sound tokens to be ignored */
3966 num_ignore_sound_tokens = num_ignore_generic_tokens;
3967 ignore_sound_tokens =
3968 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3969 for (i = 0; i < num_ignore_generic_tokens; i++)
3970 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3971 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3973 /* dynamically determine list of music tokens to be ignored */
3974 num_ignore_music_tokens = num_ignore_generic_tokens;
3975 ignore_music_tokens =
3976 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3977 for (i = 0; i < num_ignore_generic_tokens; i++)
3978 ignore_music_tokens[i] = ignore_generic_tokens[i];
3979 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3981 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3982 image_id_prefix[i] = element_info[i].token_name;
3983 for (i = 0; i < NUM_FONTS; i++)
3984 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3985 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3987 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3988 sound_id_prefix[i] = element_info[i].token_name;
3989 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3990 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3991 get_string_in_brackets(element_info[i].class_name);
3992 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3994 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3995 music_id_prefix[i] = music_prefix_info[i].prefix;
3996 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
3998 for (i = 0; i < NUM_ACTIONS; i++)
3999 action_id_suffix[i] = element_action_info[i].suffix;
4000 action_id_suffix[NUM_ACTIONS] = NULL;
4002 for (i = 0; i < NUM_DIRECTIONS; i++)
4003 direction_id_suffix[i] = element_direction_info[i].suffix;
4004 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4006 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4007 special_id_suffix[i] = special_suffix_info[i].suffix;
4008 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4010 for (i = 0; i < MAX_LEVELS; i++)
4011 level_id_suffix[i] = get_level_id_suffix(i);
4012 level_id_suffix[MAX_LEVELS] = NULL;
4014 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4015 image_id_prefix, action_id_suffix, direction_id_suffix,
4016 special_id_suffix, ignore_image_tokens);
4017 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4018 sound_id_prefix, action_id_suffix, dummy,
4019 special_id_suffix, ignore_sound_tokens);
4020 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4021 music_id_prefix, special_id_suffix, level_id_suffix,
4022 dummy, ignore_music_tokens);
4025 static void InitMixer()
4033 char *filename_font_initial = NULL;
4034 Bitmap *bitmap_font_initial = NULL;
4037 /* determine settings for initial font (for displaying startup messages) */
4038 for (i = 0; image_config[i].token != NULL; i++)
4040 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4042 char font_token[128];
4045 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4046 len_font_token = strlen(font_token);
4048 if (strcmp(image_config[i].token, font_token) == 0)
4049 filename_font_initial = image_config[i].value;
4050 else if (strlen(image_config[i].token) > len_font_token &&
4051 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4053 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4054 font_initial[j].src_x = atoi(image_config[i].value);
4055 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4056 font_initial[j].src_y = atoi(image_config[i].value);
4057 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4058 font_initial[j].width = atoi(image_config[i].value);
4059 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4060 font_initial[j].height = atoi(image_config[i].value);
4065 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4067 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4068 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4071 if (filename_font_initial == NULL) /* should not happen */
4072 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4074 /* create additional image buffers for double-buffering */
4075 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4076 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4078 /* initialize screen properties */
4079 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4080 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4082 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4083 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4084 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4086 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4088 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4089 font_initial[j].bitmap = bitmap_font_initial;
4091 InitFontGraphicInfo();
4093 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4094 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4096 DrawInitText("Loading graphics:", 120, FC_GREEN);
4099 void InitGfxBackground()
4103 drawto = backbuffer;
4104 fieldbuffer = bitmap_db_field;
4105 SetDrawtoField(DRAW_BACKBUFFER);
4107 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4108 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4109 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4110 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4112 for (x = 0; x < MAX_BUF_XSIZE; x++)
4113 for (y = 0; y < MAX_BUF_YSIZE; y++)
4116 redraw_mask = REDRAW_ALL;
4119 static void InitLevelInfo()
4121 LoadLevelInfo(); /* global level info */
4122 LoadLevelSetup_LastSeries(); /* last played series info */
4123 LoadLevelSetup_SeriesInfo(); /* last played level info */
4126 void InitLevelArtworkInfo()
4128 LoadLevelArtworkInfo();
4131 static void InitImages()
4133 setLevelArtworkDir(artwork.gfx_first);
4136 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4137 leveldir_current->identifier,
4138 artwork.gfx_current_identifier,
4139 artwork.gfx_current->identifier,
4140 leveldir_current->graphics_set,
4141 leveldir_current->graphics_path);
4144 ReloadCustomImages();
4146 LoadCustomElementDescriptions();
4147 LoadSpecialMenuDesignSettings();
4149 ReinitializeGraphics();
4152 static void InitSound(char *identifier)
4154 if (identifier == NULL)
4155 identifier = artwork.snd_current->identifier;
4157 /* set artwork path to send it to the sound server process */
4158 setLevelArtworkDir(artwork.snd_first);
4160 InitReloadCustomSounds(identifier);
4161 ReinitializeSounds();
4164 static void InitMusic(char *identifier)
4166 if (identifier == NULL)
4167 identifier = artwork.mus_current->identifier;
4169 /* set artwork path to send it to the sound server process */
4170 setLevelArtworkDir(artwork.mus_first);
4172 InitReloadCustomMusic(identifier);
4173 ReinitializeMusic();
4176 void InitNetworkServer()
4178 #if defined(NETWORK_AVALIABLE)
4182 if (!options.network)
4185 #if defined(NETWORK_AVALIABLE)
4186 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4188 if (!ConnectToServer(options.server_host, options.server_port))
4189 Error(ERR_EXIT, "cannot connect to network game server");
4191 SendToServer_PlayerName(setup.player_name);
4192 SendToServer_ProtocolVersion();
4195 SendToServer_NrWanted(nr_wanted);
4199 static char *getNewArtworkIdentifier(int type)
4201 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4202 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4203 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4204 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4205 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4206 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4207 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4208 char *leveldir_identifier = leveldir_current->identifier;
4210 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4211 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4213 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4215 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4216 char *artwork_current_identifier;
4217 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4219 /* leveldir_current may be invalid (level group, parent link) */
4220 if (!validLevelSeries(leveldir_current))
4223 /* 1st step: determine artwork set to be activated in descending order:
4224 --------------------------------------------------------------------
4225 1. setup artwork (when configured to override everything else)
4226 2. artwork set configured in "levelinfo.conf" of current level set
4227 (artwork in level directory will have priority when loading later)
4228 3. artwork in level directory (stored in artwork sub-directory)
4229 4. setup artwork (currently configured in setup menu) */
4231 if (setup_override_artwork)
4232 artwork_current_identifier = setup_artwork_set;
4233 else if (leveldir_artwork_set != NULL)
4234 artwork_current_identifier = leveldir_artwork_set;
4235 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4236 artwork_current_identifier = leveldir_identifier;
4238 artwork_current_identifier = setup_artwork_set;
4241 /* 2nd step: check if it is really needed to reload artwork set
4242 ------------------------------------------------------------ */
4245 if (type == ARTWORK_TYPE_GRAPHICS)
4246 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4247 artwork_new_identifier,
4248 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4249 artwork_current_identifier,
4250 leveldir_current->graphics_set,
4251 leveldir_current->identifier);
4254 /* ---------- reload if level set and also artwork set has changed ------- */
4255 if (leveldir_current_identifier[type] != leveldir_identifier &&
4256 (last_has_level_artwork_set[type] || has_level_artwork_set))
4257 artwork_new_identifier = artwork_current_identifier;
4259 leveldir_current_identifier[type] = leveldir_identifier;
4260 last_has_level_artwork_set[type] = has_level_artwork_set;
4263 if (type == ARTWORK_TYPE_GRAPHICS)
4264 printf("::: 1: '%s'\n", artwork_new_identifier);
4267 /* ---------- reload if "override artwork" setting has changed ----------- */
4268 if (last_override_level_artwork[type] != setup_override_artwork)
4269 artwork_new_identifier = artwork_current_identifier;
4271 last_override_level_artwork[type] = setup_override_artwork;
4274 if (type == ARTWORK_TYPE_GRAPHICS)
4275 printf("::: 2: '%s'\n", artwork_new_identifier);
4278 /* ---------- reload if current artwork identifier has changed ----------- */
4279 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4280 artwork_current_identifier) != 0)
4281 artwork_new_identifier = artwork_current_identifier;
4283 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4286 if (type == ARTWORK_TYPE_GRAPHICS)
4287 printf("::: 3: '%s'\n", artwork_new_identifier);
4290 /* ---------- do not reload directly after starting ---------------------- */
4291 if (!initialized[type])
4292 artwork_new_identifier = NULL;
4294 initialized[type] = TRUE;
4297 if (type == ARTWORK_TYPE_GRAPHICS)
4298 printf("::: 4: '%s'\n", artwork_new_identifier);
4302 if (type == ARTWORK_TYPE_GRAPHICS)
4303 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4304 artwork.gfx_current_identifier, artwork_current_identifier,
4305 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4306 artwork_new_identifier);
4309 return artwork_new_identifier;
4312 void ReloadCustomArtwork(int force_reload)
4314 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4315 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4316 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4317 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4318 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4319 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4320 boolean redraw_screen = FALSE;
4322 if (gfx_new_identifier != NULL || force_reload_gfx)
4325 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4326 artwork.gfx_current_identifier,
4328 artwork.gfx_current->identifier,
4329 leveldir_current->graphics_set);
4332 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4336 redraw_screen = TRUE;
4339 if (snd_new_identifier != NULL || force_reload_snd)
4341 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4343 InitSound(snd_new_identifier);
4345 redraw_screen = TRUE;
4348 if (mus_new_identifier != NULL || force_reload_mus)
4350 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4352 InitMusic(mus_new_identifier);
4354 redraw_screen = TRUE;
4359 InitGfxBackground();
4361 /* force redraw of (open or closed) door graphics */
4362 SetDoorState(DOOR_OPEN_ALL);
4363 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4367 void KeyboardAutoRepeatOffUnlessAutoplay()
4369 if (global.autoplay_leveldir == NULL)
4370 KeyboardAutoRepeatOff();
4374 /* ========================================================================= */
4376 /* ========================================================================= */
4380 InitGlobal(); /* initialize some global variables */
4382 if (options.execute_command)
4383 Execute_Command(options.execute_command);
4385 if (options.serveronly)
4387 #if defined(PLATFORM_UNIX)
4388 NetworkServer(options.server_port, options.serveronly);
4390 Error(ERR_WARN, "networking only supported in Unix version");
4393 exit(0); /* never reached, server loops forever */
4400 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4401 InitArtworkConfig(); /* needed before forking sound child process */
4406 InitRND(NEW_RANDOMIZE);
4407 InitSimpleRND(NEW_RANDOMIZE);
4412 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4415 InitEventFilter(FilterMouseMotionEvents);
4417 InitElementPropertiesStatic();
4418 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4423 InitLevelArtworkInfo();
4425 InitImages(); /* needs to know current level directory */
4426 InitSound(NULL); /* needs to know current level directory */
4427 InitMusic(NULL); /* needs to know current level directory */
4429 InitGfxBackground();
4431 if (global.autoplay_leveldir)
4436 else if (global.convert_leveldir)
4442 game_status = GAME_MODE_MAIN;
4450 InitNetworkServer();
4453 void CloseAllAndExit(int exit_value)
4458 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4466 #if defined(TARGET_SDL)
4467 if (network_server) /* terminate network server */
4468 SDL_KillThread(server_thread);
4471 CloseVideoDisplay();
4472 ClosePlatformDependentStuff();