1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
82 FreeLevelEditorGadgets();
91 static boolean gadgets_initialized = FALSE;
93 if (gadgets_initialized)
96 CreateLevelEditorGadgets();
100 CreateScreenGadgets();
102 gadgets_initialized = TRUE;
105 inline void InitElementSmallImagesScaledUp(int graphic)
107 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
110 void InitElementSmallImages()
112 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
113 int num_property_mappings = getImageListPropertyMappingSize();
116 /* initialize normal images from static configuration */
117 for (i = 0; element_to_graphic[i].element > -1; i++)
118 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
120 /* initialize special images from static configuration */
121 for (i = 0; element_to_special_graphic[i].element > -1; i++)
122 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
124 /* initialize images from dynamic configuration (may be elements or other) */
125 for (i = 0; i < num_property_mappings; i++)
126 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
130 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
131 void SetBitmaps_EM(Bitmap **em_bitmap)
133 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
134 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
138 static int getFontBitmapID(int font_nr)
142 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
143 special = game_status;
144 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
145 special = GFX_SPECIAL_ARG_MAIN;
146 else if (game_status == GAME_MODE_PLAYING)
147 special = GFX_SPECIAL_ARG_DOOR;
150 return font_info[font_nr].special_bitmap_id[special];
155 void InitFontGraphicInfo()
157 static struct FontBitmapInfo *font_bitmap_info = NULL;
158 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
159 int num_property_mappings = getImageListPropertyMappingSize();
160 int num_font_bitmaps = NUM_FONTS;
163 if (graphic_info == NULL) /* still at startup phase */
165 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
170 /* ---------- initialize font graphic definitions ---------- */
172 /* always start with reliable default values (normal font graphics) */
173 for (i = 0; i < NUM_FONTS; i++)
174 font_info[i].graphic = IMG_FONT_INITIAL_1;
176 /* initialize normal font/graphic mapping from static configuration */
177 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
179 int font_nr = font_to_graphic[i].font_nr;
180 int special = font_to_graphic[i].special;
181 int graphic = font_to_graphic[i].graphic;
186 font_info[font_nr].graphic = graphic;
189 /* always start with reliable default values (special font graphics) */
190 for (i = 0; i < NUM_FONTS; i++)
192 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
194 font_info[i].special_graphic[j] = font_info[i].graphic;
195 font_info[i].special_bitmap_id[j] = i;
199 /* initialize special font/graphic mapping from static configuration */
200 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
202 int font_nr = font_to_graphic[i].font_nr;
203 int special = font_to_graphic[i].special;
204 int graphic = font_to_graphic[i].graphic;
205 int base_graphic = font2baseimg(font_nr);
207 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
209 boolean base_redefined =
210 getImageListEntryFromImageID(base_graphic)->redefined;
211 boolean special_redefined =
212 getImageListEntryFromImageID(graphic)->redefined;
214 /* if the base font ("font.title_1", for example) has been redefined,
215 but not the special font ("font.title_1.LEVELS", for example), do not
216 use an existing (in this case considered obsolete) special font
217 anymore, but use the automatically determined default font */
218 if (base_redefined && !special_redefined)
221 font_info[font_nr].special_graphic[special] = graphic;
222 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
227 /* initialize special element/graphic mapping from dynamic configuration */
228 for (i = 0; i < num_property_mappings; i++)
230 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
231 int special = property_mapping[i].ext3_index;
232 int graphic = property_mapping[i].artwork_index;
237 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
239 font_info[font_nr].special_graphic[special] = graphic;
240 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
245 /* ---------- initialize font bitmap array ---------- */
247 if (font_bitmap_info != NULL)
248 FreeFontInfo(font_bitmap_info);
251 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
253 /* ---------- initialize font bitmap definitions ---------- */
255 for (i = 0; i < NUM_FONTS; i++)
257 if (i < NUM_INITIAL_FONTS)
259 font_bitmap_info[i] = font_initial[i];
263 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
265 int font_bitmap_id = font_info[i].special_bitmap_id[j];
266 int graphic = font_info[i].special_graphic[j];
268 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
269 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
271 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
272 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
275 /* copy font relevant information from graphics information */
276 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
277 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
278 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
279 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
280 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
281 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
282 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
284 font_bitmap_info[font_bitmap_id].num_chars =
285 graphic_info[graphic].anim_frames;
286 font_bitmap_info[font_bitmap_id].num_chars_per_line =
287 graphic_info[graphic].anim_frames_per_line;
291 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
294 void InitElementGraphicInfo()
296 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
297 int num_property_mappings = getImageListPropertyMappingSize();
300 if (graphic_info == NULL) /* still at startup phase */
303 /* set values to -1 to identify later as "uninitialized" values */
304 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
306 for (act = 0; act < NUM_ACTIONS; act++)
308 element_info[i].graphic[act] = -1;
309 element_info[i].crumbled[act] = -1;
311 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
313 element_info[i].direction_graphic[act][dir] = -1;
314 element_info[i].direction_crumbled[act][dir] = -1;
319 /* initialize normal element/graphic mapping from static configuration */
320 for (i = 0; element_to_graphic[i].element > -1; i++)
322 int element = element_to_graphic[i].element;
323 int action = element_to_graphic[i].action;
324 int direction = element_to_graphic[i].direction;
325 boolean crumbled = element_to_graphic[i].crumbled;
326 int graphic = element_to_graphic[i].graphic;
327 int base_graphic = el2baseimg(element);
329 if (graphic_info[graphic].bitmap == NULL)
332 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
335 boolean base_redefined =
336 getImageListEntryFromImageID(base_graphic)->redefined;
337 boolean act_dir_redefined =
338 getImageListEntryFromImageID(graphic)->redefined;
340 /* if the base graphic ("emerald", for example) has been redefined,
341 but not the action graphic ("emerald.falling", for example), do not
342 use an existing (in this case considered obsolete) action graphic
343 anymore, but use the automatically determined default graphic */
344 if (base_redefined && !act_dir_redefined)
349 action = ACTION_DEFAULT;
354 element_info[element].direction_crumbled[action][direction] = graphic;
356 element_info[element].crumbled[action] = graphic;
361 element_info[element].direction_graphic[action][direction] = graphic;
363 element_info[element].graphic[action] = graphic;
367 /* initialize normal element/graphic mapping from dynamic configuration */
368 for (i = 0; i < num_property_mappings; i++)
370 int element = property_mapping[i].base_index;
371 int action = property_mapping[i].ext1_index;
372 int direction = property_mapping[i].ext2_index;
373 int special = property_mapping[i].ext3_index;
374 int graphic = property_mapping[i].artwork_index;
375 boolean crumbled = FALSE;
377 if (special == GFX_SPECIAL_ARG_CRUMBLED)
383 if (graphic_info[graphic].bitmap == NULL)
386 if (element >= MAX_NUM_ELEMENTS || special != -1)
390 action = ACTION_DEFAULT;
395 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
396 element_info[element].direction_crumbled[action][dir] = -1;
399 element_info[element].direction_crumbled[action][direction] = graphic;
401 element_info[element].crumbled[action] = graphic;
406 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
407 element_info[element].direction_graphic[action][dir] = -1;
410 element_info[element].direction_graphic[action][direction] = graphic;
412 element_info[element].graphic[action] = graphic;
416 /* now copy all graphics that are defined to be cloned from other graphics */
417 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
419 int graphic = element_info[i].graphic[ACTION_DEFAULT];
420 int crumbled_like, diggable_like;
425 crumbled_like = graphic_info[graphic].crumbled_like;
426 diggable_like = graphic_info[graphic].diggable_like;
428 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
430 for (act = 0; act < NUM_ACTIONS; act++)
431 element_info[i].crumbled[act] =
432 element_info[crumbled_like].crumbled[act];
433 for (act = 0; act < NUM_ACTIONS; act++)
434 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
435 element_info[i].direction_crumbled[act][dir] =
436 element_info[crumbled_like].direction_crumbled[act][dir];
439 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
441 element_info[i].graphic[ACTION_DIGGING] =
442 element_info[diggable_like].graphic[ACTION_DIGGING];
443 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
444 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
445 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
450 /* set hardcoded definitions for some runtime elements without graphic */
451 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
454 /* now set all undefined/invalid graphics to -1 to set to default after it */
455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
457 for (act = 0; act < NUM_ACTIONS; act++)
461 graphic = element_info[i].graphic[act];
462 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
463 element_info[i].graphic[act] = -1;
465 graphic = element_info[i].crumbled[act];
466 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
467 element_info[i].crumbled[act] = -1;
469 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
471 graphic = element_info[i].direction_graphic[act][dir];
472 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
473 element_info[i].direction_graphic[act][dir] = -1;
475 graphic = element_info[i].direction_crumbled[act][dir];
476 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
477 element_info[i].direction_crumbled[act][dir] = -1;
482 /* adjust graphics with 2nd tile for movement according to direction
483 (do this before correcting '-1' values to minimize calculations) */
484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
486 for (act = 0; act < NUM_ACTIONS; act++)
488 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
490 int graphic = element_info[i].direction_graphic[act][dir];
491 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
493 if (act == ACTION_FALLING) /* special case */
494 graphic = element_info[i].graphic[act];
497 graphic_info[graphic].double_movement &&
498 graphic_info[graphic].swap_double_tiles != 0)
500 struct GraphicInfo *g = &graphic_info[graphic];
501 int src_x_front = g->src_x;
502 int src_y_front = g->src_y;
503 int src_x_back = g->src_x + g->offset2_x;
504 int src_y_back = g->src_y + g->offset2_y;
505 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
507 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
508 src_y_front < src_y_back);
509 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
510 boolean swap_movement_tiles_autodetected =
511 (!frames_are_ordered_diagonally &&
512 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
513 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
514 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
515 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
518 /* swap frontside and backside graphic tile coordinates, if needed */
519 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
521 /* get current (wrong) backside tile coordinates */
522 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
525 /* set frontside tile coordinates to backside tile coordinates */
526 g->src_x = src_x_back;
527 g->src_y = src_y_back;
529 /* invert tile offset to point to new backside tile coordinates */
533 /* do not swap front and backside tiles again after correction */
534 g->swap_double_tiles = 0;
541 /* now set all '-1' values to element specific default values */
542 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
544 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
545 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
546 int default_direction_graphic[NUM_DIRECTIONS];
547 int default_direction_crumbled[NUM_DIRECTIONS];
549 if (default_graphic == -1)
550 default_graphic = IMG_UNKNOWN;
552 if (default_crumbled == -1)
553 default_crumbled = default_graphic;
555 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
556 if (default_crumbled == -1)
557 default_crumbled = IMG_EMPTY;
560 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
562 default_direction_graphic[dir] =
563 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
564 default_direction_crumbled[dir] =
565 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
567 if (default_direction_graphic[dir] == -1)
568 default_direction_graphic[dir] = default_graphic;
570 if (default_direction_crumbled[dir] == -1)
571 default_direction_crumbled[dir] = default_direction_graphic[dir];
573 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
574 if (default_direction_crumbled[dir] == -1)
575 default_direction_crumbled[dir] = default_crumbled;
579 for (act = 0; act < NUM_ACTIONS; act++)
581 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
582 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
583 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
584 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
585 act == ACTION_TURNING_FROM_RIGHT ||
586 act == ACTION_TURNING_FROM_UP ||
587 act == ACTION_TURNING_FROM_DOWN);
589 /* generic default action graphic (defined by "[default]" directive) */
590 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
591 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
592 int default_remove_graphic = IMG_EMPTY;
594 if (act_remove && default_action_graphic != -1)
595 default_remove_graphic = default_action_graphic;
597 /* look for special default action graphic (classic game specific) */
598 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
599 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
600 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
601 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
602 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
603 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
605 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
606 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
607 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
608 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
609 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
610 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
613 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
614 /* !!! make this better !!! */
615 if (i == EL_EMPTY_SPACE)
617 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
618 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
622 if (default_action_graphic == -1)
623 default_action_graphic = default_graphic;
625 if (default_action_crumbled == -1)
626 default_action_crumbled = default_action_graphic;
628 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
629 if (default_action_crumbled == -1)
630 default_action_crumbled = default_crumbled;
633 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
635 /* use action graphic as the default direction graphic, if undefined */
636 int default_action_direction_graphic = element_info[i].graphic[act];
637 int default_action_direction_crumbled = element_info[i].crumbled[act];
639 /* no graphic for current action -- use default direction graphic */
640 if (default_action_direction_graphic == -1)
641 default_action_direction_graphic =
642 (act_remove ? default_remove_graphic :
644 element_info[i].direction_graphic[ACTION_TURNING][dir] :
645 default_action_graphic != default_graphic ?
646 default_action_graphic :
647 default_direction_graphic[dir]);
649 if (element_info[i].direction_graphic[act][dir] == -1)
650 element_info[i].direction_graphic[act][dir] =
651 default_action_direction_graphic;
654 if (default_action_direction_crumbled == -1)
655 default_action_direction_crumbled =
656 element_info[i].direction_graphic[act][dir];
658 if (default_action_direction_crumbled == -1)
659 default_action_direction_crumbled =
660 (act_remove ? default_remove_graphic :
662 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
663 default_action_crumbled != default_crumbled ?
664 default_action_crumbled :
665 default_direction_crumbled[dir]);
668 if (element_info[i].direction_crumbled[act][dir] == -1)
669 element_info[i].direction_crumbled[act][dir] =
670 default_action_direction_crumbled;
673 /* no graphic for this specific action -- use default action graphic */
674 if (element_info[i].graphic[act] == -1)
675 element_info[i].graphic[act] =
676 (act_remove ? default_remove_graphic :
677 act_turning ? element_info[i].graphic[ACTION_TURNING] :
678 default_action_graphic);
680 if (element_info[i].crumbled[act] == -1)
681 element_info[i].crumbled[act] = element_info[i].graphic[act];
683 if (element_info[i].crumbled[act] == -1)
684 element_info[i].crumbled[act] =
685 (act_remove ? default_remove_graphic :
686 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
687 default_action_crumbled);
692 /* set animation mode to "none" for each graphic with only 1 frame */
693 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
695 for (act = 0; act < NUM_ACTIONS; act++)
697 int graphic = element_info[i].graphic[act];
698 int crumbled = element_info[i].crumbled[act];
700 if (graphic_info[graphic].anim_frames == 1)
701 graphic_info[graphic].anim_mode = ANIM_NONE;
702 if (graphic_info[crumbled].anim_frames == 1)
703 graphic_info[crumbled].anim_mode = ANIM_NONE;
705 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
707 graphic = element_info[i].direction_graphic[act][dir];
708 crumbled = element_info[i].direction_crumbled[act][dir];
710 if (graphic_info[graphic].anim_frames == 1)
711 graphic_info[graphic].anim_mode = ANIM_NONE;
712 if (graphic_info[crumbled].anim_frames == 1)
713 graphic_info[crumbled].anim_mode = ANIM_NONE;
722 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
723 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
725 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
726 element_info[i].token_name, i);
732 void InitElementSpecialGraphicInfo()
734 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
735 int num_property_mappings = getImageListPropertyMappingSize();
738 /* always start with reliable default values */
739 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
740 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
741 element_info[i].special_graphic[j] =
742 element_info[i].graphic[ACTION_DEFAULT];
744 /* initialize special element/graphic mapping from static configuration */
745 for (i = 0; element_to_special_graphic[i].element > -1; i++)
747 int element = element_to_special_graphic[i].element;
748 int special = element_to_special_graphic[i].special;
749 int graphic = element_to_special_graphic[i].graphic;
750 int base_graphic = el2baseimg(element);
751 boolean base_redefined =
752 getImageListEntryFromImageID(base_graphic)->redefined;
753 boolean special_redefined =
754 getImageListEntryFromImageID(graphic)->redefined;
756 /* if the base graphic ("emerald", for example) has been redefined,
757 but not the special graphic ("emerald.EDITOR", for example), do not
758 use an existing (in this case considered obsolete) special graphic
759 anymore, but use the automatically created (down-scaled) graphic */
760 if (base_redefined && !special_redefined)
763 element_info[element].special_graphic[special] = graphic;
766 /* initialize special element/graphic mapping from dynamic configuration */
767 for (i = 0; i < num_property_mappings; i++)
769 int element = property_mapping[i].base_index;
770 int special = property_mapping[i].ext3_index;
771 int graphic = property_mapping[i].artwork_index;
773 if (element >= MAX_NUM_ELEMENTS)
776 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
777 element_info[element].special_graphic[special] = graphic;
780 /* now set all undefined/invalid graphics to default */
781 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
782 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
783 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
784 element_info[i].special_graphic[j] =
785 element_info[i].graphic[ACTION_DEFAULT];
788 static int get_element_from_token(char *token)
793 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
794 if (strcmp(element_info[i].token_name, token) == 0)
798 for (i = 0; image_config[i].token != NULL; i++)
800 int len_config_value = strlen(image_config[i].value);
802 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
803 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
804 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
807 if (strcmp(image_config[i].token, token) == 0)
817 static int get_scaled_graphic_width(int graphic)
819 int original_width = getOriginalImageWidthFromImageID(graphic);
820 int scale_up_factor = graphic_info[graphic].scale_up_factor;
822 return original_width * scale_up_factor;
825 static int get_scaled_graphic_height(int graphic)
827 int original_height = getOriginalImageHeightFromImageID(graphic);
828 int scale_up_factor = graphic_info[graphic].scale_up_factor;
830 return original_height * scale_up_factor;
833 static void set_graphic_parameters(int graphic, int graphic_copy_from)
835 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
836 char **parameter_raw = image->parameter;
837 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
838 int parameter[NUM_GFX_ARGS];
839 int anim_frames_per_row = 1, anim_frames_per_col = 1;
840 int anim_frames_per_line = 1;
844 if (graphic != graphic_copy_from)
846 graphic_info[graphic] = graphic_info[graphic_copy_from];
852 /* if fallback to default artwork is done, also use the default parameters */
853 if (image->fallback_to_default)
854 parameter_raw = image->default_parameter;
856 /* get integer values from string parameters */
857 for (i = 0; i < NUM_GFX_ARGS; i++)
860 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
861 image_config_suffix[i].type);
863 if (image_config_suffix[i].type == TYPE_TOKEN)
864 parameter[i] = get_element_from_token(parameter_raw[i]);
867 graphic_info[graphic].bitmap = src_bitmap;
869 /* start with reliable default values */
870 graphic_info[graphic].src_image_width = 0;
871 graphic_info[graphic].src_image_height = 0;
872 graphic_info[graphic].src_x = 0;
873 graphic_info[graphic].src_y = 0;
874 graphic_info[graphic].width = TILEX;
875 graphic_info[graphic].height = TILEY;
876 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
877 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
878 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
879 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
880 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
881 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
882 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
883 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
884 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
885 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
886 graphic_info[graphic].anim_delay_fixed = 0;
887 graphic_info[graphic].anim_delay_random = 0;
888 graphic_info[graphic].post_delay_fixed = 0;
889 graphic_info[graphic].post_delay_random = 0;
891 /* optional x and y tile position of animation frame sequence */
892 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
893 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
894 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
895 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
897 /* optional x and y pixel position of animation frame sequence */
898 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
899 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
900 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
901 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
903 /* optional width and height of each animation frame */
904 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
905 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
906 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
907 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
909 /* optional zoom factor for scaling up the image to a larger size */
910 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
911 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
912 if (graphic_info[graphic].scale_up_factor < 1)
913 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
917 /* get final bitmap size (with scaling, but without small images) */
918 int src_image_width = get_scaled_graphic_width(graphic);
919 int src_image_height = get_scaled_graphic_height(graphic);
921 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
922 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
924 graphic_info[graphic].src_image_width = src_image_width;
925 graphic_info[graphic].src_image_height = src_image_height;
928 /* correct x or y offset dependent of vertical or horizontal frame order */
929 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
931 graphic_info[graphic].offset_y =
932 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
933 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
934 anim_frames_per_line = anim_frames_per_col;
936 else /* frames are ordered horizontally */
938 graphic_info[graphic].offset_x =
939 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
940 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
941 anim_frames_per_line = anim_frames_per_row;
944 /* optionally, the x and y offset of frames can be specified directly */
945 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
947 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
948 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
950 /* optionally, moving animations may have separate start and end graphics */
951 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
953 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
954 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
956 /* correct x or y offset2 dependent of vertical or horizontal frame order */
957 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
958 graphic_info[graphic].offset2_y =
959 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
960 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
961 else /* frames are ordered horizontally */
962 graphic_info[graphic].offset2_x =
963 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
964 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
966 /* optionally, the x and y offset of 2nd graphic can be specified directly */
967 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
968 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
969 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
972 /* optionally, the second movement tile can be specified as start tile */
973 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
976 /* automatically determine correct number of frames, if not defined */
977 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
979 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
980 graphic_info[graphic].anim_frames = anim_frames_per_row;
981 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
982 graphic_info[graphic].anim_frames = anim_frames_per_col;
984 graphic_info[graphic].anim_frames = 1;
986 graphic_info[graphic].anim_frames_per_line =
987 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
988 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
990 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
991 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
992 graphic_info[graphic].anim_delay = 1;
994 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
996 if (graphic_info[graphic].anim_frames == 1)
997 graphic_info[graphic].anim_mode = ANIM_NONE;
1000 /* automatically determine correct start frame, if not defined */
1001 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].anim_start_frame = 0;
1003 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1004 graphic_info[graphic].anim_start_frame =
1005 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1007 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1009 /* animation synchronized with global frame counter, not move position */
1010 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1012 /* optional element for cloning crumble graphics */
1013 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1016 /* optional element for cloning digging graphics */
1017 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1018 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1020 /* optional border size for "crumbling" diggable graphics */
1021 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1022 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1024 /* this is only used for player "boring" and "sleeping" actions */
1025 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1026 graphic_info[graphic].anim_delay_fixed =
1027 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1028 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].anim_delay_random =
1030 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1031 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1032 graphic_info[graphic].post_delay_fixed =
1033 parameter[GFX_ARG_POST_DELAY_FIXED];
1034 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1035 graphic_info[graphic].post_delay_random =
1036 parameter[GFX_ARG_POST_DELAY_RANDOM];
1038 /* this is only used for toon animations */
1039 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1040 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1042 /* this is only used for drawing font characters */
1043 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1044 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1046 /* this is only used for drawing envelope graphics */
1047 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1050 /* optional graphic for cloning all graphics settings */
1051 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1054 /* optional graphic for cloning all graphics settings */
1055 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1057 if (parameter[GFX_ARG_CLONE_FROM] != -1)
1059 int clone_graphic = parameter[GFX_ARG_CLONE_FROM];
1061 graphic_info[graphic] = graphic_info[clone_graphic];
1062 graphic_info[graphic].clone_from = clone_graphic;
1064 printf("::: %d -> %d\n", graphic, clone_graphic);
1070 static void set_cloned_graphic_parameters(int graphic)
1072 int fallback_graphic = IMG_CHAR_EXCLAM;
1073 int max_num_images = getImageListSize();
1074 int clone_graphic = graphic_info[graphic].clone_from;
1075 int num_references_followed = 1;
1077 while (graphic_info[clone_graphic].clone_from != -1 &&
1078 num_references_followed < max_num_images)
1080 clone_graphic = graphic_info[clone_graphic].clone_from;
1082 num_references_followed++;
1085 if (num_references_followed >= max_num_images)
1087 Error(ERR_RETURN_LINE, "-");
1088 Error(ERR_RETURN, "warning: error found in config file:");
1089 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1090 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1091 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1092 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1094 if (graphic == fallback_graphic)
1095 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1097 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1098 Error(ERR_RETURN_LINE, "-");
1100 set_graphic_parameters(graphic, fallback_graphic);
1104 graphic_info[graphic] = graphic_info[clone_graphic];
1105 graphic_info[graphic].clone_from = clone_graphic;
1108 printf("::: graphic %d ['%s'] is cloned from %d ['%s']\n",
1109 i, getTokenFromImageID(i),
1110 clone_graphic, getTokenFromImageID(clone_graphic));
1115 static void InitGraphicInfo()
1117 int fallback_graphic = IMG_CHAR_EXCLAM;
1118 int num_images = getImageListSize();
1121 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1122 static boolean clipmasks_initialized = FALSE;
1124 XGCValues clip_gc_values;
1125 unsigned long clip_gc_valuemask;
1126 GC copy_clipmask_gc = None;
1129 checked_free(graphic_info);
1131 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1133 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1134 if (clipmasks_initialized)
1136 for (i = 0; i < num_images; i++)
1138 if (graphic_info[i].clip_mask)
1139 XFreePixmap(display, graphic_info[i].clip_mask);
1140 if (graphic_info[i].clip_gc)
1141 XFreeGC(display, graphic_info[i].clip_gc);
1143 graphic_info[i].clip_mask = None;
1144 graphic_info[i].clip_gc = None;
1149 /* first set all graphic paramaters ... */
1150 for (i = 0; i < num_images; i++)
1151 set_graphic_parameters(i, i);
1153 /* ... then copy these parameters for cloned graphics */
1154 for (i = 0; i < num_images; i++)
1155 if (graphic_info[i].clone_from != -1)
1156 set_cloned_graphic_parameters(i);
1158 for (i = 0; i < num_images; i++)
1162 int first_frame, last_frame;
1163 int src_bitmap_width, src_bitmap_height;
1166 printf("::: image # %d: '%s' ['%s']\n",
1167 i, image->token, getTokenFromImageID(i));
1171 set_graphic_parameters(i, i);
1174 /* now check if no animation frames are outside of the loaded image */
1177 if (graphic_info[i].bitmap == NULL)
1178 Error(ERR_WARN, "no bitmap for graphic %d ['%s']",
1179 i, getTokenFromImageID(i));
1182 if (graphic_info[i].bitmap == NULL)
1183 continue; /* skip check for optional images that are undefined */
1186 /* get final bitmap size (with scaling, but without small images) */
1187 src_bitmap_width = graphic_info[i].src_image_width;
1188 src_bitmap_height = graphic_info[i].src_image_height;
1190 /* get final bitmap size (with scaling, but without small images) */
1191 src_bitmap_width = get_scaled_graphic_width(i);
1192 src_bitmap_height = get_scaled_graphic_height(i);
1194 if (graphic_info[i].clone_from != -1)
1196 int clone_graphic = graphic_info[i].clone_from;
1198 src_bitmap_width = get_scaled_graphic_width(clone_graphic);
1199 src_bitmap_height = get_scaled_graphic_height(clone_graphic);
1204 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1205 if (src_x < 0 || src_y < 0 ||
1206 src_x + TILEX > src_bitmap_width ||
1207 src_y + TILEY > src_bitmap_height)
1209 Error(ERR_RETURN_LINE, "-");
1210 Error(ERR_RETURN, "warning: error found in config file:");
1211 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1212 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1213 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1215 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1216 src_x, src_y, src_bitmap_width, src_bitmap_height);
1217 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1219 if (i == fallback_graphic)
1220 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1222 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1223 Error(ERR_RETURN_LINE, "-");
1225 set_graphic_parameters(i, fallback_graphic);
1228 last_frame = graphic_info[i].anim_frames - 1;
1229 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1230 if (src_x < 0 || src_y < 0 ||
1231 src_x + TILEX > src_bitmap_width ||
1232 src_y + TILEY > src_bitmap_height)
1234 Error(ERR_RETURN_LINE, "-");
1235 Error(ERR_RETURN, "warning: error found in config file:");
1236 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1237 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1238 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1240 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1241 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1242 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1244 if (i == fallback_graphic)
1245 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1247 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1248 Error(ERR_RETURN_LINE, "-");
1250 set_graphic_parameters(i, fallback_graphic);
1253 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1254 /* currently we only need a tile clip mask from the first frame */
1255 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1257 if (copy_clipmask_gc == None)
1259 clip_gc_values.graphics_exposures = False;
1260 clip_gc_valuemask = GCGraphicsExposures;
1261 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1262 clip_gc_valuemask, &clip_gc_values);
1265 graphic_info[i].clip_mask =
1266 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1268 src_pixmap = src_bitmap->clip_mask;
1269 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1270 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1272 clip_gc_values.graphics_exposures = False;
1273 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1274 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1276 graphic_info[i].clip_gc =
1277 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1281 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1282 if (copy_clipmask_gc)
1283 XFreeGC(display, copy_clipmask_gc);
1285 clipmasks_initialized = TRUE;
1289 static void InitElementSoundInfo()
1291 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1292 int num_property_mappings = getSoundListPropertyMappingSize();
1295 /* set values to -1 to identify later as "uninitialized" values */
1296 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1297 for (act = 0; act < NUM_ACTIONS; act++)
1298 element_info[i].sound[act] = -1;
1300 /* initialize element/sound mapping from static configuration */
1301 for (i = 0; element_to_sound[i].element > -1; i++)
1303 int element = element_to_sound[i].element;
1304 int action = element_to_sound[i].action;
1305 int sound = element_to_sound[i].sound;
1306 boolean is_class = element_to_sound[i].is_class;
1309 action = ACTION_DEFAULT;
1312 element_info[element].sound[action] = sound;
1314 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1315 if (strcmp(element_info[j].class_name,
1316 element_info[element].class_name) == 0)
1317 element_info[j].sound[action] = sound;
1320 /* initialize element class/sound mapping from dynamic configuration */
1321 for (i = 0; i < num_property_mappings; i++)
1323 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1324 int action = property_mapping[i].ext1_index;
1325 int sound = property_mapping[i].artwork_index;
1327 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1331 action = ACTION_DEFAULT;
1333 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1334 if (strcmp(element_info[j].class_name,
1335 element_info[element_class].class_name) == 0)
1336 element_info[j].sound[action] = sound;
1339 /* initialize element/sound mapping from dynamic configuration */
1340 for (i = 0; i < num_property_mappings; i++)
1342 int element = property_mapping[i].base_index;
1343 int action = property_mapping[i].ext1_index;
1344 int sound = property_mapping[i].artwork_index;
1346 if (element >= MAX_NUM_ELEMENTS)
1350 action = ACTION_DEFAULT;
1352 element_info[element].sound[action] = sound;
1355 /* now set all '-1' values to element specific default values */
1356 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1358 for (act = 0; act < NUM_ACTIONS; act++)
1360 /* generic default action sound (defined by "[default]" directive) */
1361 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1363 /* look for special default action sound (classic game specific) */
1364 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1365 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1366 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1367 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1368 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1369 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1371 /* !!! there's no such thing as a "default action sound" !!! */
1373 /* look for element specific default sound (independent from action) */
1374 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1375 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1379 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1380 /* !!! make this better !!! */
1381 if (i == EL_EMPTY_SPACE)
1382 default_action_sound = element_info[EL_DEFAULT].sound[act];
1385 /* no sound for this specific action -- use default action sound */
1386 if (element_info[i].sound[act] == -1)
1387 element_info[i].sound[act] = default_action_sound;
1391 /* copy sound settings to some elements that are only stored in level file
1392 in native R'n'D levels, but are used by game engine in native EM levels */
1393 for (i = 0; copy_properties[i][0] != -1; i++)
1394 for (j = 1; j <= 4; j++)
1395 for (act = 0; act < NUM_ACTIONS; act++)
1396 element_info[copy_properties[i][j]].sound[act] =
1397 element_info[copy_properties[i][0]].sound[act];
1400 static void InitGameModeSoundInfo()
1404 /* set values to -1 to identify later as "uninitialized" values */
1405 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1408 /* initialize gamemode/sound mapping from static configuration */
1409 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1411 int gamemode = gamemode_to_sound[i].gamemode;
1412 int sound = gamemode_to_sound[i].sound;
1415 gamemode = GAME_MODE_DEFAULT;
1417 menu.sound[gamemode] = sound;
1420 /* now set all '-1' values to levelset specific default values */
1421 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1422 if (menu.sound[i] == -1)
1423 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1426 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1427 if (menu.sound[i] != -1)
1428 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1432 static void set_sound_parameters(int sound, char **parameter_raw)
1434 int parameter[NUM_SND_ARGS];
1437 /* get integer values from string parameters */
1438 for (i = 0; i < NUM_SND_ARGS; i++)
1440 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1441 sound_config_suffix[i].type);
1443 /* explicit loop mode setting in configuration overrides default value */
1444 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1445 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1447 /* sound volume to change the original volume when loading the sound file */
1448 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1450 /* sound priority to give certain sounds a higher or lower priority */
1451 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1454 static void InitSoundInfo()
1456 int *sound_effect_properties;
1457 int num_sounds = getSoundListSize();
1460 checked_free(sound_info);
1462 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1463 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1465 /* initialize sound effect for all elements to "no sound" */
1466 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1467 for (j = 0; j < NUM_ACTIONS; j++)
1468 element_info[i].sound[j] = SND_UNDEFINED;
1470 for (i = 0; i < num_sounds; i++)
1472 struct FileInfo *sound = getSoundListEntry(i);
1473 int len_effect_text = strlen(sound->token);
1475 sound_effect_properties[i] = ACTION_OTHER;
1476 sound_info[i].loop = FALSE; /* default: play sound only once */
1479 printf("::: sound %d: '%s'\n", i, sound->token);
1482 /* determine all loop sounds and identify certain sound classes */
1484 for (j = 0; element_action_info[j].suffix; j++)
1486 int len_action_text = strlen(element_action_info[j].suffix);
1488 if (len_action_text < len_effect_text &&
1489 strcmp(&sound->token[len_effect_text - len_action_text],
1490 element_action_info[j].suffix) == 0)
1492 sound_effect_properties[i] = element_action_info[j].value;
1493 sound_info[i].loop = element_action_info[j].is_loop_sound;
1499 /* associate elements and some selected sound actions */
1501 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1503 if (element_info[j].class_name)
1505 int len_class_text = strlen(element_info[j].class_name);
1507 if (len_class_text + 1 < len_effect_text &&
1508 strncmp(sound->token,
1509 element_info[j].class_name, len_class_text) == 0 &&
1510 sound->token[len_class_text] == '.')
1512 int sound_action_value = sound_effect_properties[i];
1514 element_info[j].sound[sound_action_value] = i;
1519 set_sound_parameters(i, sound->parameter);
1522 free(sound_effect_properties);
1525 static void InitGameModeMusicInfo()
1527 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1528 int num_property_mappings = getMusicListPropertyMappingSize();
1529 int default_levelset_music = -1;
1532 /* set values to -1 to identify later as "uninitialized" values */
1533 for (i = 0; i < MAX_LEVELS; i++)
1534 levelset.music[i] = -1;
1535 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1538 /* initialize gamemode/music mapping from static configuration */
1539 for (i = 0; gamemode_to_music[i].music > -1; i++)
1541 int gamemode = gamemode_to_music[i].gamemode;
1542 int music = gamemode_to_music[i].music;
1545 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1549 gamemode = GAME_MODE_DEFAULT;
1551 menu.music[gamemode] = music;
1554 /* initialize gamemode/music mapping from dynamic configuration */
1555 for (i = 0; i < num_property_mappings; i++)
1557 int prefix = property_mapping[i].base_index;
1558 int gamemode = property_mapping[i].ext1_index;
1559 int level = property_mapping[i].ext2_index;
1560 int music = property_mapping[i].artwork_index;
1563 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1564 prefix, gamemode, level, music);
1567 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1571 gamemode = GAME_MODE_DEFAULT;
1573 /* level specific music only allowed for in-game music */
1574 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1575 gamemode = GAME_MODE_PLAYING;
1580 default_levelset_music = music;
1583 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1584 levelset.music[level] = music;
1585 if (gamemode != GAME_MODE_PLAYING)
1586 menu.music[gamemode] = music;
1589 /* now set all '-1' values to menu specific default values */
1590 /* (undefined values of "levelset.music[]" might stay at "-1" to
1591 allow dynamic selection of music files from music directory!) */
1592 for (i = 0; i < MAX_LEVELS; i++)
1593 if (levelset.music[i] == -1)
1594 levelset.music[i] = default_levelset_music;
1595 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1596 if (menu.music[i] == -1)
1597 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1600 for (i = 0; i < MAX_LEVELS; i++)
1601 if (levelset.music[i] != -1)
1602 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1603 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1604 if (menu.music[i] != -1)
1605 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1609 static void set_music_parameters(int music, char **parameter_raw)
1611 int parameter[NUM_MUS_ARGS];
1614 /* get integer values from string parameters */
1615 for (i = 0; i < NUM_MUS_ARGS; i++)
1617 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1618 music_config_suffix[i].type);
1620 /* explicit loop mode setting in configuration overrides default value */
1621 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1622 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1625 static void InitMusicInfo()
1627 int num_music = getMusicListSize();
1630 checked_free(music_info);
1632 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1634 for (i = 0; i < num_music; i++)
1636 struct FileInfo *music = getMusicListEntry(i);
1637 int len_music_text = strlen(music->token);
1639 music_info[i].loop = TRUE; /* default: play music in loop mode */
1641 /* determine all loop music */
1643 for (j = 0; music_prefix_info[j].prefix; j++)
1645 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1647 if (len_prefix_text < len_music_text &&
1648 strncmp(music->token,
1649 music_prefix_info[j].prefix, len_prefix_text) == 0)
1651 music_info[i].loop = music_prefix_info[j].is_loop_music;
1657 set_music_parameters(i, music->parameter);
1661 static void ReinitializeGraphics()
1663 InitGraphicInfo(); /* graphic properties mapping */
1664 InitElementGraphicInfo(); /* element game graphic mapping */
1665 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1667 InitElementSmallImages(); /* scale images to all needed sizes */
1668 InitFontGraphicInfo(); /* initialize text drawing functions */
1670 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1672 SetMainBackgroundImage(IMG_BACKGROUND);
1673 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1679 static void ReinitializeSounds()
1681 InitSoundInfo(); /* sound properties mapping */
1682 InitElementSoundInfo(); /* element game sound mapping */
1683 InitGameModeSoundInfo(); /* game mode sound mapping */
1685 InitPlayLevelSound(); /* internal game sound settings */
1688 static void ReinitializeMusic()
1690 InitMusicInfo(); /* music properties mapping */
1691 InitGameModeMusicInfo(); /* game mode music mapping */
1694 static int get_special_property_bit(int element, int property_bit_nr)
1696 struct PropertyBitInfo
1702 static struct PropertyBitInfo pb_can_move_into_acid[] =
1704 /* the player may be able fall into acid when gravity is activated */
1709 { EL_SP_MURPHY, 0 },
1710 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1712 /* all element that can move may be able to also move into acid */
1715 { EL_BUG_RIGHT, 1 },
1718 { EL_SPACESHIP, 2 },
1719 { EL_SPACESHIP_LEFT, 2 },
1720 { EL_SPACESHIP_RIGHT, 2 },
1721 { EL_SPACESHIP_UP, 2 },
1722 { EL_SPACESHIP_DOWN, 2 },
1723 { EL_BD_BUTTERFLY, 3 },
1724 { EL_BD_BUTTERFLY_LEFT, 3 },
1725 { EL_BD_BUTTERFLY_RIGHT, 3 },
1726 { EL_BD_BUTTERFLY_UP, 3 },
1727 { EL_BD_BUTTERFLY_DOWN, 3 },
1728 { EL_BD_FIREFLY, 4 },
1729 { EL_BD_FIREFLY_LEFT, 4 },
1730 { EL_BD_FIREFLY_RIGHT, 4 },
1731 { EL_BD_FIREFLY_UP, 4 },
1732 { EL_BD_FIREFLY_DOWN, 4 },
1734 { EL_DARK_YAMYAM, 6 },
1737 { EL_PACMAN_LEFT, 8 },
1738 { EL_PACMAN_RIGHT, 8 },
1739 { EL_PACMAN_UP, 8 },
1740 { EL_PACMAN_DOWN, 8 },
1742 { EL_MOLE_LEFT, 9 },
1743 { EL_MOLE_RIGHT, 9 },
1745 { EL_MOLE_DOWN, 9 },
1749 { EL_SATELLITE, 13 },
1750 { EL_SP_SNIKSNAK, 14 },
1751 { EL_SP_ELECTRON, 15 },
1758 static struct PropertyBitInfo pb_dont_collide_with[] =
1760 { EL_SP_SNIKSNAK, 0 },
1761 { EL_SP_ELECTRON, 1 },
1769 struct PropertyBitInfo *pb_info;
1772 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1773 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1778 struct PropertyBitInfo *pb_info = NULL;
1781 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1782 if (pb_definition[i].bit_nr == property_bit_nr)
1783 pb_info = pb_definition[i].pb_info;
1785 if (pb_info == NULL)
1788 for (i = 0; pb_info[i].element != -1; i++)
1789 if (pb_info[i].element == element)
1790 return pb_info[i].bit_nr;
1795 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1796 boolean property_value)
1798 int bit_nr = get_special_property_bit(element, property_bit_nr);
1803 *bitfield |= (1 << bit_nr);
1805 *bitfield &= ~(1 << bit_nr);
1809 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1811 int bit_nr = get_special_property_bit(element, property_bit_nr);
1814 return ((*bitfield & (1 << bit_nr)) != 0);
1819 void InitElementPropertiesStatic()
1821 static int ep_diggable[] =
1826 EL_SP_BUGGY_BASE_ACTIVATING,
1829 EL_INVISIBLE_SAND_ACTIVE,
1832 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1833 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1837 EL_SP_BUGGY_BASE_ACTIVE,
1843 static int ep_collectible_only[] =
1864 EL_DYNABOMB_INCREASE_NUMBER,
1865 EL_DYNABOMB_INCREASE_SIZE,
1866 EL_DYNABOMB_INCREASE_POWER,
1885 static int ep_dont_run_into[] =
1887 /* same elements as in 'ep_dont_touch' */
1893 /* same elements as in 'ep_dont_collide_with' */
1905 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1909 EL_SP_BUGGY_BASE_ACTIVE,
1915 static int ep_dont_collide_with[] =
1917 /* same elements as in 'ep_dont_touch' */
1933 static int ep_dont_touch[] =
1942 static int ep_indestructible[] =
1946 EL_ACID_POOL_TOPLEFT,
1947 EL_ACID_POOL_TOPRIGHT,
1948 EL_ACID_POOL_BOTTOMLEFT,
1949 EL_ACID_POOL_BOTTOM,
1950 EL_ACID_POOL_BOTTOMRIGHT,
1951 EL_SP_HARDWARE_GRAY,
1952 EL_SP_HARDWARE_GREEN,
1953 EL_SP_HARDWARE_BLUE,
1955 EL_SP_HARDWARE_YELLOW,
1956 EL_SP_HARDWARE_BASE_1,
1957 EL_SP_HARDWARE_BASE_2,
1958 EL_SP_HARDWARE_BASE_3,
1959 EL_SP_HARDWARE_BASE_4,
1960 EL_SP_HARDWARE_BASE_5,
1961 EL_SP_HARDWARE_BASE_6,
1962 EL_INVISIBLE_STEELWALL,
1963 EL_INVISIBLE_STEELWALL_ACTIVE,
1964 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1965 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1966 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1967 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1968 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1969 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1970 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1971 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1972 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1973 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1974 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1975 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1977 EL_LIGHT_SWITCH_ACTIVE,
1978 EL_SIGN_EXCLAMATION,
1979 EL_SIGN_RADIOACTIVITY,
1990 EL_STEELWALL_SLIPPERY,
2021 EL_SWITCHGATE_OPENING,
2022 EL_SWITCHGATE_CLOSED,
2023 EL_SWITCHGATE_CLOSING,
2025 EL_SWITCHGATE_SWITCH_UP,
2026 EL_SWITCHGATE_SWITCH_DOWN,
2029 EL_TIMEGATE_OPENING,
2031 EL_TIMEGATE_CLOSING,
2034 EL_TIMEGATE_SWITCH_ACTIVE,
2039 EL_TUBE_VERTICAL_LEFT,
2040 EL_TUBE_VERTICAL_RIGHT,
2041 EL_TUBE_HORIZONTAL_UP,
2042 EL_TUBE_HORIZONTAL_DOWN,
2050 static int ep_slippery[] =
2064 EL_ROBOT_WHEEL_ACTIVE,
2070 EL_ACID_POOL_TOPLEFT,
2071 EL_ACID_POOL_TOPRIGHT,
2081 EL_STEELWALL_SLIPPERY,
2084 EL_EMC_WALL_SLIPPERY_1,
2085 EL_EMC_WALL_SLIPPERY_2,
2086 EL_EMC_WALL_SLIPPERY_3,
2087 EL_EMC_WALL_SLIPPERY_4,
2091 static int ep_can_change[] =
2096 static int ep_can_move[] =
2098 /* same elements as in 'pb_can_move_into_acid' */
2120 static int ep_can_fall[] =
2135 EL_BD_MAGIC_WALL_FULL,
2148 static int ep_can_smash_player[] =
2173 static int ep_can_smash_enemies[] =
2181 static int ep_can_smash_everything[] =
2189 static int ep_explodes_by_fire[] =
2191 /* same elements as in 'ep_explodes_impact' */
2196 /* same elements as in 'ep_explodes_smashed' */
2205 EL_DYNABOMB_PLAYER_1_ACTIVE,
2206 EL_DYNABOMB_PLAYER_2_ACTIVE,
2207 EL_DYNABOMB_PLAYER_3_ACTIVE,
2208 EL_DYNABOMB_PLAYER_4_ACTIVE,
2209 EL_DYNABOMB_INCREASE_NUMBER,
2210 EL_DYNABOMB_INCREASE_SIZE,
2211 EL_DYNABOMB_INCREASE_POWER,
2212 EL_SP_DISK_RED_ACTIVE,
2225 static int ep_explodes_smashed[] =
2227 /* same elements as in 'ep_explodes_impact' */
2240 static int ep_explodes_impact[] =
2248 static int ep_walkable_over[] =
2252 EL_SOKOBAN_FIELD_EMPTY,
2270 static int ep_walkable_inside[] =
2275 EL_TUBE_VERTICAL_LEFT,
2276 EL_TUBE_VERTICAL_RIGHT,
2277 EL_TUBE_HORIZONTAL_UP,
2278 EL_TUBE_HORIZONTAL_DOWN,
2286 static int ep_walkable_under[] =
2291 static int ep_passable_over[] =
2314 static int ep_passable_inside[] =
2320 EL_SP_PORT_HORIZONTAL,
2321 EL_SP_PORT_VERTICAL,
2323 EL_SP_GRAVITY_PORT_LEFT,
2324 EL_SP_GRAVITY_PORT_RIGHT,
2325 EL_SP_GRAVITY_PORT_UP,
2326 EL_SP_GRAVITY_PORT_DOWN,
2327 EL_SP_GRAVITY_ON_PORT_LEFT,
2328 EL_SP_GRAVITY_ON_PORT_RIGHT,
2329 EL_SP_GRAVITY_ON_PORT_UP,
2330 EL_SP_GRAVITY_ON_PORT_DOWN,
2331 EL_SP_GRAVITY_OFF_PORT_LEFT,
2332 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2333 EL_SP_GRAVITY_OFF_PORT_UP,
2334 EL_SP_GRAVITY_OFF_PORT_DOWN,
2338 static int ep_passable_under[] =
2343 static int ep_droppable[] =
2348 static int ep_explodes_1x1_old[] =
2353 static int ep_pushable[] =
2365 EL_SOKOBAN_FIELD_FULL,
2373 static int ep_explodes_cross_old[] =
2378 static int ep_protected[] =
2380 /* same elements as in 'ep_walkable_inside' */
2384 EL_TUBE_VERTICAL_LEFT,
2385 EL_TUBE_VERTICAL_RIGHT,
2386 EL_TUBE_HORIZONTAL_UP,
2387 EL_TUBE_HORIZONTAL_DOWN,
2393 /* same elements as in 'ep_passable_over' */
2413 /* same elements as in 'ep_passable_inside' */
2418 EL_SP_PORT_HORIZONTAL,
2419 EL_SP_PORT_VERTICAL,
2421 EL_SP_GRAVITY_PORT_LEFT,
2422 EL_SP_GRAVITY_PORT_RIGHT,
2423 EL_SP_GRAVITY_PORT_UP,
2424 EL_SP_GRAVITY_PORT_DOWN,
2425 EL_SP_GRAVITY_ON_PORT_LEFT,
2426 EL_SP_GRAVITY_ON_PORT_RIGHT,
2427 EL_SP_GRAVITY_ON_PORT_UP,
2428 EL_SP_GRAVITY_ON_PORT_DOWN,
2429 EL_SP_GRAVITY_OFF_PORT_LEFT,
2430 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2431 EL_SP_GRAVITY_OFF_PORT_UP,
2432 EL_SP_GRAVITY_OFF_PORT_DOWN,
2436 static int ep_throwable[] =
2441 static int ep_can_explode[] =
2443 /* same elements as in 'ep_explodes_impact' */
2448 /* same elements as in 'ep_explodes_smashed' */
2454 /* elements that can explode by explosion or by dragonfire */
2457 EL_DYNABOMB_PLAYER_1_ACTIVE,
2458 EL_DYNABOMB_PLAYER_2_ACTIVE,
2459 EL_DYNABOMB_PLAYER_3_ACTIVE,
2460 EL_DYNABOMB_PLAYER_4_ACTIVE,
2461 EL_DYNABOMB_INCREASE_NUMBER,
2462 EL_DYNABOMB_INCREASE_SIZE,
2463 EL_DYNABOMB_INCREASE_POWER,
2464 EL_SP_DISK_RED_ACTIVE,
2472 /* elements that can explode only by explosion */
2477 static int ep_gravity_reachable[] =
2483 EL_INVISIBLE_SAND_ACTIVE,
2488 EL_SP_PORT_HORIZONTAL,
2489 EL_SP_PORT_VERTICAL,
2491 EL_SP_GRAVITY_PORT_LEFT,
2492 EL_SP_GRAVITY_PORT_RIGHT,
2493 EL_SP_GRAVITY_PORT_UP,
2494 EL_SP_GRAVITY_PORT_DOWN,
2495 EL_SP_GRAVITY_ON_PORT_LEFT,
2496 EL_SP_GRAVITY_ON_PORT_RIGHT,
2497 EL_SP_GRAVITY_ON_PORT_UP,
2498 EL_SP_GRAVITY_ON_PORT_DOWN,
2499 EL_SP_GRAVITY_OFF_PORT_LEFT,
2500 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2501 EL_SP_GRAVITY_OFF_PORT_UP,
2502 EL_SP_GRAVITY_OFF_PORT_DOWN,
2507 static int ep_player[] =
2514 EL_SOKOBAN_FIELD_PLAYER,
2519 static int ep_can_pass_magic_wall[] =
2532 static int ep_switchable[] =
2536 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2537 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2538 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2539 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2540 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2541 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2542 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2543 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2544 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2545 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2546 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2547 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2548 EL_SWITCHGATE_SWITCH_UP,
2549 EL_SWITCHGATE_SWITCH_DOWN,
2551 EL_LIGHT_SWITCH_ACTIVE,
2553 EL_BALLOON_SWITCH_LEFT,
2554 EL_BALLOON_SWITCH_RIGHT,
2555 EL_BALLOON_SWITCH_UP,
2556 EL_BALLOON_SWITCH_DOWN,
2557 EL_BALLOON_SWITCH_ANY,
2560 EL_EMC_MAGIC_BALL_SWITCH,
2564 static int ep_bd_element[] =
2597 static int ep_sp_element[] =
2599 /* should always be valid */
2602 /* standard classic Supaplex elements */
2609 EL_SP_HARDWARE_GRAY,
2617 EL_SP_GRAVITY_PORT_RIGHT,
2618 EL_SP_GRAVITY_PORT_DOWN,
2619 EL_SP_GRAVITY_PORT_LEFT,
2620 EL_SP_GRAVITY_PORT_UP,
2625 EL_SP_PORT_VERTICAL,
2626 EL_SP_PORT_HORIZONTAL,
2632 EL_SP_HARDWARE_BASE_1,
2633 EL_SP_HARDWARE_GREEN,
2634 EL_SP_HARDWARE_BLUE,
2636 EL_SP_HARDWARE_YELLOW,
2637 EL_SP_HARDWARE_BASE_2,
2638 EL_SP_HARDWARE_BASE_3,
2639 EL_SP_HARDWARE_BASE_4,
2640 EL_SP_HARDWARE_BASE_5,
2641 EL_SP_HARDWARE_BASE_6,
2645 /* additional elements that appeared in newer Supaplex levels */
2648 /* additional gravity port elements (not switching, but setting gravity) */
2649 EL_SP_GRAVITY_ON_PORT_LEFT,
2650 EL_SP_GRAVITY_ON_PORT_RIGHT,
2651 EL_SP_GRAVITY_ON_PORT_UP,
2652 EL_SP_GRAVITY_ON_PORT_DOWN,
2653 EL_SP_GRAVITY_OFF_PORT_LEFT,
2654 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2655 EL_SP_GRAVITY_OFF_PORT_UP,
2656 EL_SP_GRAVITY_OFF_PORT_DOWN,
2658 /* more than one Murphy in a level results in an inactive clone */
2661 /* runtime Supaplex elements */
2662 EL_SP_DISK_RED_ACTIVE,
2663 EL_SP_TERMINAL_ACTIVE,
2664 EL_SP_BUGGY_BASE_ACTIVATING,
2665 EL_SP_BUGGY_BASE_ACTIVE,
2671 static int ep_sb_element[] =
2676 EL_SOKOBAN_FIELD_EMPTY,
2677 EL_SOKOBAN_FIELD_FULL,
2678 EL_SOKOBAN_FIELD_PLAYER,
2683 EL_INVISIBLE_STEELWALL,
2687 static int ep_gem[] =
2698 static int ep_food_dark_yamyam[] =
2725 static int ep_food_penguin[] =
2738 static int ep_food_pig[] =
2749 static int ep_historic_wall[] =
2774 EL_EXPANDABLE_WALL_HORIZONTAL,
2775 EL_EXPANDABLE_WALL_VERTICAL,
2776 EL_EXPANDABLE_WALL_ANY,
2777 EL_EXPANDABLE_WALL_GROWING,
2784 EL_SP_HARDWARE_GRAY,
2785 EL_SP_HARDWARE_GREEN,
2786 EL_SP_HARDWARE_BLUE,
2788 EL_SP_HARDWARE_YELLOW,
2789 EL_SP_HARDWARE_BASE_1,
2790 EL_SP_HARDWARE_BASE_2,
2791 EL_SP_HARDWARE_BASE_3,
2792 EL_SP_HARDWARE_BASE_4,
2793 EL_SP_HARDWARE_BASE_5,
2794 EL_SP_HARDWARE_BASE_6,
2796 EL_SP_TERMINAL_ACTIVE,
2799 EL_INVISIBLE_STEELWALL,
2800 EL_INVISIBLE_STEELWALL_ACTIVE,
2802 EL_INVISIBLE_WALL_ACTIVE,
2803 EL_STEELWALL_SLIPPERY,
2819 static int ep_historic_solid[] =
2823 EL_EXPANDABLE_WALL_HORIZONTAL,
2824 EL_EXPANDABLE_WALL_VERTICAL,
2825 EL_EXPANDABLE_WALL_ANY,
2838 EL_QUICKSAND_FILLING,
2839 EL_QUICKSAND_EMPTYING,
2841 EL_MAGIC_WALL_ACTIVE,
2842 EL_MAGIC_WALL_EMPTYING,
2843 EL_MAGIC_WALL_FILLING,
2847 EL_BD_MAGIC_WALL_ACTIVE,
2848 EL_BD_MAGIC_WALL_EMPTYING,
2849 EL_BD_MAGIC_WALL_FULL,
2850 EL_BD_MAGIC_WALL_FILLING,
2851 EL_BD_MAGIC_WALL_DEAD,
2860 EL_SP_TERMINAL_ACTIVE,
2864 EL_INVISIBLE_WALL_ACTIVE,
2865 EL_SWITCHGATE_SWITCH_UP,
2866 EL_SWITCHGATE_SWITCH_DOWN,
2868 EL_TIMEGATE_SWITCH_ACTIVE,
2880 /* the following elements are a direct copy of "indestructible" elements,
2881 except "EL_ACID", which is "indestructible", but not "solid"! */
2886 EL_ACID_POOL_TOPLEFT,
2887 EL_ACID_POOL_TOPRIGHT,
2888 EL_ACID_POOL_BOTTOMLEFT,
2889 EL_ACID_POOL_BOTTOM,
2890 EL_ACID_POOL_BOTTOMRIGHT,
2891 EL_SP_HARDWARE_GRAY,
2892 EL_SP_HARDWARE_GREEN,
2893 EL_SP_HARDWARE_BLUE,
2895 EL_SP_HARDWARE_YELLOW,
2896 EL_SP_HARDWARE_BASE_1,
2897 EL_SP_HARDWARE_BASE_2,
2898 EL_SP_HARDWARE_BASE_3,
2899 EL_SP_HARDWARE_BASE_4,
2900 EL_SP_HARDWARE_BASE_5,
2901 EL_SP_HARDWARE_BASE_6,
2902 EL_INVISIBLE_STEELWALL,
2903 EL_INVISIBLE_STEELWALL_ACTIVE,
2904 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2905 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2906 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2907 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2908 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2909 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2910 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2911 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2912 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2913 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2914 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2915 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2917 EL_LIGHT_SWITCH_ACTIVE,
2918 EL_SIGN_EXCLAMATION,
2919 EL_SIGN_RADIOACTIVITY,
2930 EL_STEELWALL_SLIPPERY,
2953 EL_SWITCHGATE_OPENING,
2954 EL_SWITCHGATE_CLOSED,
2955 EL_SWITCHGATE_CLOSING,
2957 EL_TIMEGATE_OPENING,
2959 EL_TIMEGATE_CLOSING,
2963 EL_TUBE_VERTICAL_LEFT,
2964 EL_TUBE_VERTICAL_RIGHT,
2965 EL_TUBE_HORIZONTAL_UP,
2966 EL_TUBE_HORIZONTAL_DOWN,
2974 static int ep_classic_enemy[] =
2990 static int ep_belt[] =
2992 EL_CONVEYOR_BELT_1_LEFT,
2993 EL_CONVEYOR_BELT_1_MIDDLE,
2994 EL_CONVEYOR_BELT_1_RIGHT,
2995 EL_CONVEYOR_BELT_2_LEFT,
2996 EL_CONVEYOR_BELT_2_MIDDLE,
2997 EL_CONVEYOR_BELT_2_RIGHT,
2998 EL_CONVEYOR_BELT_3_LEFT,
2999 EL_CONVEYOR_BELT_3_MIDDLE,
3000 EL_CONVEYOR_BELT_3_RIGHT,
3001 EL_CONVEYOR_BELT_4_LEFT,
3002 EL_CONVEYOR_BELT_4_MIDDLE,
3003 EL_CONVEYOR_BELT_4_RIGHT,
3007 static int ep_belt_active[] =
3009 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3010 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3011 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3012 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3013 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3014 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3015 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3016 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3017 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3018 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3019 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3020 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3024 static int ep_belt_switch[] =
3026 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3027 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3028 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3029 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3030 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3031 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3032 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3033 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3034 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3035 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3036 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3037 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3041 static int ep_tube[] =
3048 EL_TUBE_HORIZONTAL_UP,
3049 EL_TUBE_HORIZONTAL_DOWN,
3051 EL_TUBE_VERTICAL_LEFT,
3052 EL_TUBE_VERTICAL_RIGHT,
3057 static int ep_keygate[] =
3086 static int ep_amoeboid[] =
3096 static int ep_amoebalive[] =
3105 static int ep_has_content[] =
3115 static int ep_can_turn_each_move[] =
3117 /* !!! do something with this one !!! */
3121 static int ep_can_grow[] =
3133 static int ep_active_bomb[] =
3136 EL_DYNABOMB_PLAYER_1_ACTIVE,
3137 EL_DYNABOMB_PLAYER_2_ACTIVE,
3138 EL_DYNABOMB_PLAYER_3_ACTIVE,
3139 EL_DYNABOMB_PLAYER_4_ACTIVE,
3140 EL_SP_DISK_RED_ACTIVE,
3144 static int ep_inactive[] =
3193 EL_INVISIBLE_STEELWALL,
3201 EL_WALL_EMERALD_YELLOW,
3202 EL_DYNABOMB_INCREASE_NUMBER,
3203 EL_DYNABOMB_INCREASE_SIZE,
3204 EL_DYNABOMB_INCREASE_POWER,
3208 EL_SOKOBAN_FIELD_EMPTY,
3209 EL_SOKOBAN_FIELD_FULL,
3210 EL_WALL_EMERALD_RED,
3211 EL_WALL_EMERALD_PURPLE,
3212 EL_ACID_POOL_TOPLEFT,
3213 EL_ACID_POOL_TOPRIGHT,
3214 EL_ACID_POOL_BOTTOMLEFT,
3215 EL_ACID_POOL_BOTTOM,
3216 EL_ACID_POOL_BOTTOMRIGHT,
3220 EL_BD_MAGIC_WALL_DEAD,
3221 EL_AMOEBA_TO_DIAMOND,
3229 EL_SP_GRAVITY_PORT_RIGHT,
3230 EL_SP_GRAVITY_PORT_DOWN,
3231 EL_SP_GRAVITY_PORT_LEFT,
3232 EL_SP_GRAVITY_PORT_UP,
3233 EL_SP_PORT_HORIZONTAL,
3234 EL_SP_PORT_VERTICAL,
3245 EL_SP_HARDWARE_GRAY,
3246 EL_SP_HARDWARE_GREEN,
3247 EL_SP_HARDWARE_BLUE,
3249 EL_SP_HARDWARE_YELLOW,
3250 EL_SP_HARDWARE_BASE_1,
3251 EL_SP_HARDWARE_BASE_2,
3252 EL_SP_HARDWARE_BASE_3,
3253 EL_SP_HARDWARE_BASE_4,
3254 EL_SP_HARDWARE_BASE_5,
3255 EL_SP_HARDWARE_BASE_6,
3256 EL_SP_GRAVITY_ON_PORT_LEFT,
3257 EL_SP_GRAVITY_ON_PORT_RIGHT,
3258 EL_SP_GRAVITY_ON_PORT_UP,
3259 EL_SP_GRAVITY_ON_PORT_DOWN,
3260 EL_SP_GRAVITY_OFF_PORT_LEFT,
3261 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3262 EL_SP_GRAVITY_OFF_PORT_UP,
3263 EL_SP_GRAVITY_OFF_PORT_DOWN,
3264 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3265 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3266 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3267 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3268 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3269 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3270 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3271 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3272 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3273 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3274 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3275 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3276 EL_SIGN_EXCLAMATION,
3277 EL_SIGN_RADIOACTIVITY,
3288 EL_STEELWALL_SLIPPERY,
3293 EL_EMC_WALL_SLIPPERY_1,
3294 EL_EMC_WALL_SLIPPERY_2,
3295 EL_EMC_WALL_SLIPPERY_3,
3296 EL_EMC_WALL_SLIPPERY_4,
3316 static int ep_em_slippery_wall[] =
3321 static int ep_gfx_crumbled[] =
3334 } element_properties[] =
3336 { ep_diggable, EP_DIGGABLE },
3337 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3338 { ep_dont_run_into, EP_DONT_RUN_INTO },
3339 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3340 { ep_dont_touch, EP_DONT_TOUCH },
3341 { ep_indestructible, EP_INDESTRUCTIBLE },
3342 { ep_slippery, EP_SLIPPERY },
3343 { ep_can_change, EP_CAN_CHANGE },
3344 { ep_can_move, EP_CAN_MOVE },
3345 { ep_can_fall, EP_CAN_FALL },
3346 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3347 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3348 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3349 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3350 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3351 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3352 { ep_walkable_over, EP_WALKABLE_OVER },
3353 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3354 { ep_walkable_under, EP_WALKABLE_UNDER },
3355 { ep_passable_over, EP_PASSABLE_OVER },
3356 { ep_passable_inside, EP_PASSABLE_INSIDE },
3357 { ep_passable_under, EP_PASSABLE_UNDER },
3358 { ep_droppable, EP_DROPPABLE },
3359 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3360 { ep_pushable, EP_PUSHABLE },
3361 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3362 { ep_protected, EP_PROTECTED },
3363 { ep_throwable, EP_THROWABLE },
3364 { ep_can_explode, EP_CAN_EXPLODE },
3365 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3367 { ep_player, EP_PLAYER },
3368 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3369 { ep_switchable, EP_SWITCHABLE },
3370 { ep_bd_element, EP_BD_ELEMENT },
3371 { ep_sp_element, EP_SP_ELEMENT },
3372 { ep_sb_element, EP_SB_ELEMENT },
3374 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3375 { ep_food_penguin, EP_FOOD_PENGUIN },
3376 { ep_food_pig, EP_FOOD_PIG },
3377 { ep_historic_wall, EP_HISTORIC_WALL },
3378 { ep_historic_solid, EP_HISTORIC_SOLID },
3379 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3380 { ep_belt, EP_BELT },
3381 { ep_belt_active, EP_BELT_ACTIVE },
3382 { ep_belt_switch, EP_BELT_SWITCH },
3383 { ep_tube, EP_TUBE },
3384 { ep_keygate, EP_KEYGATE },
3385 { ep_amoeboid, EP_AMOEBOID },
3386 { ep_amoebalive, EP_AMOEBALIVE },
3387 { ep_has_content, EP_HAS_CONTENT },
3388 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3389 { ep_can_grow, EP_CAN_GROW },
3390 { ep_active_bomb, EP_ACTIVE_BOMB },
3391 { ep_inactive, EP_INACTIVE },
3393 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3395 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3402 /* always start with reliable default values (element has no properties) */
3403 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3404 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3405 SET_PROPERTY(i, j, FALSE);
3407 /* set all base element properties from above array definitions */
3408 for (i = 0; element_properties[i].elements != NULL; i++)
3409 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3410 SET_PROPERTY((element_properties[i].elements)[j],
3411 element_properties[i].property, TRUE);
3413 /* copy properties to some elements that are only stored in level file */
3414 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3415 for (j = 0; copy_properties[j][0] != -1; j++)
3416 if (HAS_PROPERTY(copy_properties[j][0], i))
3417 for (k = 1; k <= 4; k++)
3418 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3421 void InitElementPropertiesEngine(int engine_version)
3423 static int no_wall_properties[] =
3426 EP_COLLECTIBLE_ONLY,
3428 EP_DONT_COLLIDE_WITH,
3431 EP_CAN_SMASH_PLAYER,
3432 EP_CAN_SMASH_ENEMIES,
3433 EP_CAN_SMASH_EVERYTHING,
3438 EP_FOOD_DARK_YAMYAM,
3454 /* important: after initialization in InitElementPropertiesStatic(), the
3455 elements are not again initialized to a default value; therefore all
3456 changes have to make sure that they leave the element with a defined
3457 property (which means that conditional property changes must be set to
3458 a reliable default value before) */
3460 /* set all special, combined or engine dependent element properties */
3461 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3463 /* ---------- INACTIVE ------------------------------------------------- */
3464 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3466 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3467 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3468 IS_WALKABLE_INSIDE(i) ||
3469 IS_WALKABLE_UNDER(i)));
3471 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3472 IS_PASSABLE_INSIDE(i) ||
3473 IS_PASSABLE_UNDER(i)));
3475 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3476 IS_PASSABLE_OVER(i)));
3478 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3479 IS_PASSABLE_INSIDE(i)));
3481 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3482 IS_PASSABLE_UNDER(i)));
3484 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3487 /* ---------- COLLECTIBLE ---------------------------------------------- */
3488 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3492 /* ---------- SNAPPABLE ------------------------------------------------ */
3493 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3494 IS_COLLECTIBLE(i) ||
3498 /* ---------- WALL ----------------------------------------------------- */
3499 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3501 for (j = 0; no_wall_properties[j] != -1; j++)
3502 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3503 i >= EL_FIRST_RUNTIME_UNREAL)
3504 SET_PROPERTY(i, EP_WALL, FALSE);
3506 if (IS_HISTORIC_WALL(i))
3507 SET_PROPERTY(i, EP_WALL, TRUE);
3509 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3510 if (engine_version < VERSION_IDENT(2,2,0,0))
3511 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3513 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3515 !IS_COLLECTIBLE(i)));
3517 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3519 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3520 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3522 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3523 IS_INDESTRUCTIBLE(i)));
3525 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3527 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3528 else if (engine_version < VERSION_IDENT(2,2,0,0))
3529 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3531 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3535 if (IS_CUSTOM_ELEMENT(i))
3537 /* these are additional properties which are initially false when set */
3539 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3541 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3542 if (DONT_COLLIDE_WITH(i))
3543 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3545 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3546 if (CAN_SMASH_EVERYTHING(i))
3547 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3548 if (CAN_SMASH_ENEMIES(i))
3549 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3552 /* ---------- CAN_SMASH ------------------------------------------------ */
3553 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3554 CAN_SMASH_ENEMIES(i) ||
3555 CAN_SMASH_EVERYTHING(i)));
3557 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3558 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3559 EXPLODES_BY_FIRE(i)));
3561 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3562 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3563 EXPLODES_SMASHED(i)));
3565 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3566 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3567 EXPLODES_IMPACT(i)));
3569 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3570 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3572 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3573 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3574 i == EL_BLACK_ORB));
3576 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3577 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3579 IS_CUSTOM_ELEMENT(i)));
3581 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3582 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3583 i == EL_SP_ELECTRON));
3585 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3586 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3587 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3588 getMoveIntoAcidProperty(&level, i));
3590 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3591 if (MAYBE_DONT_COLLIDE_WITH(i))
3592 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3593 getDontCollideWithProperty(&level, i));
3595 /* ---------- SP_PORT -------------------------------------------------- */
3596 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3597 IS_PASSABLE_INSIDE(i)));
3599 /* ---------- CAN_CHANGE ----------------------------------------------- */
3600 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3601 for (j = 0; j < element_info[i].num_change_pages; j++)
3602 if (element_info[i].change_page[j].can_change)
3603 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3605 /* ---------- HAS_ACTION ----------------------------------------------- */
3606 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3607 for (j = 0; j < element_info[i].num_change_pages; j++)
3608 if (element_info[i].change_page[j].has_action)
3609 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3611 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3612 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3615 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3617 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3618 element_info[i].crumbled[ACTION_DEFAULT] !=
3619 element_info[i].graphic[ACTION_DEFAULT]);
3621 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3622 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3623 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3627 /* dynamically adjust element properties according to game engine version */
3629 static int ep_em_slippery_wall[] =
3634 EL_EXPANDABLE_WALL_HORIZONTAL,
3635 EL_EXPANDABLE_WALL_VERTICAL,
3636 EL_EXPANDABLE_WALL_ANY,
3640 /* special EM style gems behaviour */
3641 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3642 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3643 level.em_slippery_gems);
3645 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3646 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3647 (level.em_slippery_gems &&
3648 engine_version > VERSION_IDENT(2,0,1,0)));
3651 /* set default push delay values (corrected since version 3.0.7-1) */
3652 if (engine_version < VERSION_IDENT(3,0,7,1))
3654 game.default_push_delay_fixed = 2;
3655 game.default_push_delay_random = 8;
3659 game.default_push_delay_fixed = 8;
3660 game.default_push_delay_random = 8;
3663 /* set uninitialized push delay values of custom elements in older levels */
3664 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3666 int element = EL_CUSTOM_START + i;
3668 if (element_info[element].push_delay_fixed == -1)
3669 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3670 if (element_info[element].push_delay_random == -1)
3671 element_info[element].push_delay_random = game.default_push_delay_random;
3674 /* set some other uninitialized values of custom elements in older levels */
3675 if (engine_version < VERSION_IDENT(3,1,0,0))
3677 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3679 int element = EL_CUSTOM_START + i;
3681 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3683 element_info[element].explosion_delay = 17;
3684 element_info[element].ignition_delay = 8;
3689 /* set element properties that were handled incorrectly in older levels */
3690 if (engine_version < VERSION_IDENT(3,1,0,0))
3692 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3693 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3697 /* this is needed because some graphics depend on element properties */
3698 if (game_status == GAME_MODE_PLAYING)
3699 InitElementGraphicInfo();
3702 static void InitGlobal()
3706 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3708 /* check if element_name_info entry defined for each element in "main.h" */
3709 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3710 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3712 element_info[i].token_name = element_name_info[i].token_name;
3713 element_info[i].class_name = element_name_info[i].class_name;
3714 element_info[i].editor_description=element_name_info[i].editor_description;
3717 global.autoplay_leveldir = NULL;
3718 global.convert_leveldir = NULL;
3720 global.frames_per_second = 0;
3721 global.fps_slowdown = FALSE;
3722 global.fps_slowdown_factor = 1;
3725 void Execute_Command(char *command)
3729 if (strcmp(command, "print graphicsinfo.conf") == 0)
3731 printf("# You can configure additional/alternative image files here.\n");
3732 printf("# (The entries below are default and therefore commented out.)\n");
3734 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3736 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3739 for (i = 0; image_config[i].token != NULL; i++)
3740 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3741 image_config[i].value));
3745 else if (strcmp(command, "print soundsinfo.conf") == 0)
3747 printf("# You can configure additional/alternative sound files here.\n");
3748 printf("# (The entries below are default and therefore commented out.)\n");
3750 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3752 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3755 for (i = 0; sound_config[i].token != NULL; i++)
3756 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3757 sound_config[i].value));
3761 else if (strcmp(command, "print musicinfo.conf") == 0)
3763 printf("# You can configure additional/alternative music files here.\n");
3764 printf("# (The entries below are default and therefore commented out.)\n");
3766 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3768 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3771 for (i = 0; music_config[i].token != NULL; i++)
3772 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3773 music_config[i].value));
3777 else if (strcmp(command, "print editorsetup.conf") == 0)
3779 printf("# You can configure your personal editor element list here.\n");
3780 printf("# (The entries below are default and therefore commented out.)\n");
3783 PrintEditorElementList();
3787 else if (strcmp(command, "print helpanim.conf") == 0)
3789 printf("# You can configure different element help animations here.\n");
3790 printf("# (The entries below are default and therefore commented out.)\n");
3793 for (i = 0; helpanim_config[i].token != NULL; i++)
3795 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3796 helpanim_config[i].value));
3798 if (strcmp(helpanim_config[i].token, "end") == 0)
3804 else if (strcmp(command, "print helptext.conf") == 0)
3806 printf("# You can configure different element help text here.\n");
3807 printf("# (The entries below are default and therefore commented out.)\n");
3810 for (i = 0; helptext_config[i].token != NULL; i++)
3811 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3812 helptext_config[i].value));
3816 else if (strncmp(command, "dump level ", 11) == 0)
3818 char *filename = &command[11];
3820 if (!fileExists(filename))
3821 Error(ERR_EXIT, "cannot open file '%s'", filename);
3823 LoadLevelFromFilename(&level, filename);
3828 else if (strncmp(command, "dump tape ", 10) == 0)
3830 char *filename = &command[10];
3832 if (!fileExists(filename))
3833 Error(ERR_EXIT, "cannot open file '%s'", filename);
3835 LoadTapeFromFilename(filename);
3840 else if (strncmp(command, "autoplay ", 9) == 0)
3842 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3844 while (*str_ptr != '\0') /* continue parsing string */
3846 /* cut leading whitespace from string, replace it by string terminator */
3847 while (*str_ptr == ' ' || *str_ptr == '\t')
3850 if (*str_ptr == '\0') /* end of string reached */
3853 if (global.autoplay_leveldir == NULL) /* read level set string */
3855 global.autoplay_leveldir = str_ptr;
3856 global.autoplay_all = TRUE; /* default: play all tapes */
3858 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3859 global.autoplay_level[i] = FALSE;
3861 else /* read level number string */
3863 int level_nr = atoi(str_ptr); /* get level_nr value */
3865 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3866 global.autoplay_level[level_nr] = TRUE;
3868 global.autoplay_all = FALSE;
3871 /* advance string pointer to the next whitespace (or end of string) */
3872 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3876 else if (strncmp(command, "convert ", 8) == 0)
3878 char *str_copy = getStringCopy(&command[8]);
3879 char *str_ptr = strchr(str_copy, ' ');
3881 global.convert_leveldir = str_copy;
3882 global.convert_level_nr = -1;
3884 if (str_ptr != NULL) /* level number follows */
3886 *str_ptr++ = '\0'; /* terminate leveldir string */
3887 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3892 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3896 static void InitSetup()
3898 LoadSetup(); /* global setup info */
3900 /* set some options from setup file */
3902 if (setup.options.verbose)
3903 options.verbose = TRUE;
3906 static void InitGameInfo()
3908 game.restart_level = FALSE;
3911 static void InitPlayerInfo()
3915 /* choose default local player */
3916 local_player = &stored_player[0];
3918 for (i = 0; i < MAX_PLAYERS; i++)
3919 stored_player[i].connected = FALSE;
3921 local_player->connected = TRUE;
3924 static void InitArtworkInfo()
3929 static char *get_string_in_brackets(char *string)
3931 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3933 sprintf(string_in_brackets, "[%s]", string);
3935 return string_in_brackets;
3938 static char *get_level_id_suffix(int id_nr)
3940 char *id_suffix = checked_malloc(1 + 3 + 1);
3942 if (id_nr < 0 || id_nr > 999)
3945 sprintf(id_suffix, ".%03d", id_nr);
3951 static char *get_element_class_token(int element)
3953 char *element_class_name = element_info[element].class_name;
3954 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3956 sprintf(element_class_token, "[%s]", element_class_name);
3958 return element_class_token;
3961 static char *get_action_class_token(int action)
3963 char *action_class_name = &element_action_info[action].suffix[1];
3964 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3966 sprintf(action_class_token, "[%s]", action_class_name);
3968 return action_class_token;
3972 static void InitArtworkConfig()
3974 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3975 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3976 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3977 static char *action_id_suffix[NUM_ACTIONS + 1];
3978 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3979 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3980 static char *level_id_suffix[MAX_LEVELS + 1];
3981 static char *dummy[1] = { NULL };
3982 static char *ignore_generic_tokens[] =
3988 static char **ignore_image_tokens;
3989 static char **ignore_sound_tokens;
3990 static char **ignore_music_tokens;
3991 int num_ignore_generic_tokens;
3992 int num_ignore_image_tokens;
3993 int num_ignore_sound_tokens;
3994 int num_ignore_music_tokens;
3997 /* dynamically determine list of generic tokens to be ignored */
3998 num_ignore_generic_tokens = 0;
3999 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4000 num_ignore_generic_tokens++;
4002 /* dynamically determine list of image tokens to be ignored */
4003 num_ignore_image_tokens = num_ignore_generic_tokens;
4004 for (i = 0; image_config_vars[i].token != NULL; i++)
4005 num_ignore_image_tokens++;
4006 ignore_image_tokens =
4007 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4008 for (i = 0; i < num_ignore_generic_tokens; i++)
4009 ignore_image_tokens[i] = ignore_generic_tokens[i];
4010 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4011 ignore_image_tokens[num_ignore_generic_tokens + i] =
4012 image_config_vars[i].token;
4013 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4015 /* dynamically determine list of sound tokens to be ignored */
4016 num_ignore_sound_tokens = num_ignore_generic_tokens;
4017 ignore_sound_tokens =
4018 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4019 for (i = 0; i < num_ignore_generic_tokens; i++)
4020 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4021 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4023 /* dynamically determine list of music tokens to be ignored */
4024 num_ignore_music_tokens = num_ignore_generic_tokens;
4025 ignore_music_tokens =
4026 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4027 for (i = 0; i < num_ignore_generic_tokens; i++)
4028 ignore_music_tokens[i] = ignore_generic_tokens[i];
4029 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4032 image_id_prefix[i] = element_info[i].token_name;
4033 for (i = 0; i < NUM_FONTS; i++)
4034 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4035 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4037 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4038 sound_id_prefix[i] = element_info[i].token_name;
4039 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4040 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4041 get_string_in_brackets(element_info[i].class_name);
4042 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4044 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4045 music_id_prefix[i] = music_prefix_info[i].prefix;
4046 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4048 for (i = 0; i < NUM_ACTIONS; i++)
4049 action_id_suffix[i] = element_action_info[i].suffix;
4050 action_id_suffix[NUM_ACTIONS] = NULL;
4052 for (i = 0; i < NUM_DIRECTIONS; i++)
4053 direction_id_suffix[i] = element_direction_info[i].suffix;
4054 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4056 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4057 special_id_suffix[i] = special_suffix_info[i].suffix;
4058 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4060 for (i = 0; i < MAX_LEVELS; i++)
4061 level_id_suffix[i] = get_level_id_suffix(i);
4062 level_id_suffix[MAX_LEVELS] = NULL;
4064 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4065 image_id_prefix, action_id_suffix, direction_id_suffix,
4066 special_id_suffix, ignore_image_tokens);
4067 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4068 sound_id_prefix, action_id_suffix, dummy,
4069 special_id_suffix, ignore_sound_tokens);
4070 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4071 music_id_prefix, special_id_suffix, level_id_suffix,
4072 dummy, ignore_music_tokens);
4075 static void InitMixer()
4083 char *filename_font_initial = NULL;
4084 Bitmap *bitmap_font_initial = NULL;
4087 /* determine settings for initial font (for displaying startup messages) */
4088 for (i = 0; image_config[i].token != NULL; i++)
4090 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4092 char font_token[128];
4095 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4096 len_font_token = strlen(font_token);
4098 if (strcmp(image_config[i].token, font_token) == 0)
4099 filename_font_initial = image_config[i].value;
4100 else if (strlen(image_config[i].token) > len_font_token &&
4101 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4103 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4104 font_initial[j].src_x = atoi(image_config[i].value);
4105 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4106 font_initial[j].src_y = atoi(image_config[i].value);
4107 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4108 font_initial[j].width = atoi(image_config[i].value);
4109 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4110 font_initial[j].height = atoi(image_config[i].value);
4115 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4117 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4118 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4121 if (filename_font_initial == NULL) /* should not happen */
4122 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4124 /* create additional image buffers for double-buffering */
4125 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4126 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4128 /* initialize screen properties */
4129 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4130 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4132 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4133 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4134 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4136 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4138 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4139 font_initial[j].bitmap = bitmap_font_initial;
4141 InitFontGraphicInfo();
4143 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4144 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4146 DrawInitText("Loading graphics:", 120, FC_GREEN);
4149 void InitGfxBackground()
4153 drawto = backbuffer;
4154 fieldbuffer = bitmap_db_field;
4155 SetDrawtoField(DRAW_BACKBUFFER);
4157 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4158 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4159 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4160 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4162 for (x = 0; x < MAX_BUF_XSIZE; x++)
4163 for (y = 0; y < MAX_BUF_YSIZE; y++)
4166 redraw_mask = REDRAW_ALL;
4169 static void InitLevelInfo()
4171 LoadLevelInfo(); /* global level info */
4172 LoadLevelSetup_LastSeries(); /* last played series info */
4173 LoadLevelSetup_SeriesInfo(); /* last played level info */
4176 void InitLevelArtworkInfo()
4178 LoadLevelArtworkInfo();
4181 static void InitImages()
4183 setLevelArtworkDir(artwork.gfx_first);
4186 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4187 leveldir_current->identifier,
4188 artwork.gfx_current_identifier,
4189 artwork.gfx_current->identifier,
4190 leveldir_current->graphics_set,
4191 leveldir_current->graphics_path);
4194 ReloadCustomImages();
4196 LoadCustomElementDescriptions();
4197 LoadSpecialMenuDesignSettings();
4199 ReinitializeGraphics();
4202 static void InitSound(char *identifier)
4204 if (identifier == NULL)
4205 identifier = artwork.snd_current->identifier;
4207 /* set artwork path to send it to the sound server process */
4208 setLevelArtworkDir(artwork.snd_first);
4210 InitReloadCustomSounds(identifier);
4211 ReinitializeSounds();
4214 static void InitMusic(char *identifier)
4216 if (identifier == NULL)
4217 identifier = artwork.mus_current->identifier;
4219 /* set artwork path to send it to the sound server process */
4220 setLevelArtworkDir(artwork.mus_first);
4222 InitReloadCustomMusic(identifier);
4223 ReinitializeMusic();
4226 void InitNetworkServer()
4228 #if defined(NETWORK_AVALIABLE)
4232 if (!options.network)
4235 #if defined(NETWORK_AVALIABLE)
4236 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4238 if (!ConnectToServer(options.server_host, options.server_port))
4239 Error(ERR_EXIT, "cannot connect to network game server");
4241 SendToServer_PlayerName(setup.player_name);
4242 SendToServer_ProtocolVersion();
4245 SendToServer_NrWanted(nr_wanted);
4249 static char *getNewArtworkIdentifier(int type)
4251 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4252 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4253 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4254 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4255 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4256 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4257 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4258 char *leveldir_identifier = leveldir_current->identifier;
4260 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4261 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4263 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4265 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4266 char *artwork_current_identifier;
4267 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4269 /* leveldir_current may be invalid (level group, parent link) */
4270 if (!validLevelSeries(leveldir_current))
4273 /* 1st step: determine artwork set to be activated in descending order:
4274 --------------------------------------------------------------------
4275 1. setup artwork (when configured to override everything else)
4276 2. artwork set configured in "levelinfo.conf" of current level set
4277 (artwork in level directory will have priority when loading later)
4278 3. artwork in level directory (stored in artwork sub-directory)
4279 4. setup artwork (currently configured in setup menu) */
4281 if (setup_override_artwork)
4282 artwork_current_identifier = setup_artwork_set;
4283 else if (leveldir_artwork_set != NULL)
4284 artwork_current_identifier = leveldir_artwork_set;
4285 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4286 artwork_current_identifier = leveldir_identifier;
4288 artwork_current_identifier = setup_artwork_set;
4291 /* 2nd step: check if it is really needed to reload artwork set
4292 ------------------------------------------------------------ */
4295 if (type == ARTWORK_TYPE_GRAPHICS)
4296 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4297 artwork_new_identifier,
4298 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4299 artwork_current_identifier,
4300 leveldir_current->graphics_set,
4301 leveldir_current->identifier);
4304 /* ---------- reload if level set and also artwork set has changed ------- */
4305 if (leveldir_current_identifier[type] != leveldir_identifier &&
4306 (last_has_level_artwork_set[type] || has_level_artwork_set))
4307 artwork_new_identifier = artwork_current_identifier;
4309 leveldir_current_identifier[type] = leveldir_identifier;
4310 last_has_level_artwork_set[type] = has_level_artwork_set;
4313 if (type == ARTWORK_TYPE_GRAPHICS)
4314 printf("::: 1: '%s'\n", artwork_new_identifier);
4317 /* ---------- reload if "override artwork" setting has changed ----------- */
4318 if (last_override_level_artwork[type] != setup_override_artwork)
4319 artwork_new_identifier = artwork_current_identifier;
4321 last_override_level_artwork[type] = setup_override_artwork;
4324 if (type == ARTWORK_TYPE_GRAPHICS)
4325 printf("::: 2: '%s'\n", artwork_new_identifier);
4328 /* ---------- reload if current artwork identifier has changed ----------- */
4329 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4330 artwork_current_identifier) != 0)
4331 artwork_new_identifier = artwork_current_identifier;
4333 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4336 if (type == ARTWORK_TYPE_GRAPHICS)
4337 printf("::: 3: '%s'\n", artwork_new_identifier);
4340 /* ---------- do not reload directly after starting ---------------------- */
4341 if (!initialized[type])
4342 artwork_new_identifier = NULL;
4344 initialized[type] = TRUE;
4347 if (type == ARTWORK_TYPE_GRAPHICS)
4348 printf("::: 4: '%s'\n", artwork_new_identifier);
4352 if (type == ARTWORK_TYPE_GRAPHICS)
4353 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4354 artwork.gfx_current_identifier, artwork_current_identifier,
4355 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4356 artwork_new_identifier);
4359 return artwork_new_identifier;
4362 void ReloadCustomArtwork(int force_reload)
4364 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4365 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4366 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4367 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4368 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4369 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4370 boolean redraw_screen = FALSE;
4372 if (gfx_new_identifier != NULL || force_reload_gfx)
4375 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4376 artwork.gfx_current_identifier,
4378 artwork.gfx_current->identifier,
4379 leveldir_current->graphics_set);
4382 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4386 redraw_screen = TRUE;
4389 if (snd_new_identifier != NULL || force_reload_snd)
4391 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4393 InitSound(snd_new_identifier);
4395 redraw_screen = TRUE;
4398 if (mus_new_identifier != NULL || force_reload_mus)
4400 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4402 InitMusic(mus_new_identifier);
4404 redraw_screen = TRUE;
4409 InitGfxBackground();
4411 /* force redraw of (open or closed) door graphics */
4412 SetDoorState(DOOR_OPEN_ALL);
4413 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4417 void KeyboardAutoRepeatOffUnlessAutoplay()
4419 if (global.autoplay_leveldir == NULL)
4420 KeyboardAutoRepeatOff();
4424 /* ========================================================================= */
4426 /* ========================================================================= */
4430 InitGlobal(); /* initialize some global variables */
4432 if (options.execute_command)
4433 Execute_Command(options.execute_command);
4435 if (options.serveronly)
4437 #if defined(PLATFORM_UNIX)
4438 NetworkServer(options.server_port, options.serveronly);
4440 Error(ERR_WARN, "networking only supported in Unix version");
4443 exit(0); /* never reached, server loops forever */
4450 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4451 InitArtworkConfig(); /* needed before forking sound child process */
4456 InitRND(NEW_RANDOMIZE);
4457 InitSimpleRND(NEW_RANDOMIZE);
4462 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4465 InitEventFilter(FilterMouseMotionEvents);
4467 InitElementPropertiesStatic();
4468 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4473 InitLevelArtworkInfo();
4475 InitImages(); /* needs to know current level directory */
4476 InitSound(NULL); /* needs to know current level directory */
4477 InitMusic(NULL); /* needs to know current level directory */
4479 InitGfxBackground();
4481 if (global.autoplay_leveldir)
4486 else if (global.convert_leveldir)
4492 game_status = GAME_MODE_MAIN;
4500 InitNetworkServer();
4503 void CloseAllAndExit(int exit_value)
4508 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4516 #if defined(TARGET_SDL)
4517 if (network_server) /* terminate network server */
4518 SDL_KillThread(server_thread);
4521 CloseVideoDisplay();
4522 ClosePlatformDependentStuff();