1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
82 FreeLevelEditorGadgets();
91 static boolean gadgets_initialized = FALSE;
93 if (gadgets_initialized)
96 CreateLevelEditorGadgets();
100 CreateScreenGadgets();
102 gadgets_initialized = TRUE;
105 inline void InitElementSmallImagesScaledUp(int graphic)
107 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
110 void InitElementSmallImages()
112 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
113 int num_property_mappings = getImageListPropertyMappingSize();
116 /* initialize normal images from static configuration */
117 for (i = 0; element_to_graphic[i].element > -1; i++)
118 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
120 /* initialize special images from static configuration */
121 for (i = 0; element_to_special_graphic[i].element > -1; i++)
122 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
124 /* initialize images from dynamic configuration (may be elements or other) */
125 for (i = 0; i < num_property_mappings; i++)
126 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
130 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
131 void SetBitmaps_EM(Bitmap **em_bitmap)
133 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
134 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
138 static int getFontBitmapID(int font_nr)
142 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
143 special = game_status;
144 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
145 special = GFX_SPECIAL_ARG_MAIN;
146 else if (game_status == GAME_MODE_PLAYING)
147 special = GFX_SPECIAL_ARG_DOOR;
150 return font_info[font_nr].special_bitmap_id[special];
155 void InitFontGraphicInfo()
157 static struct FontBitmapInfo *font_bitmap_info = NULL;
158 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
159 int num_property_mappings = getImageListPropertyMappingSize();
160 int num_font_bitmaps = NUM_FONTS;
163 if (graphic_info == NULL) /* still at startup phase */
165 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
170 /* ---------- initialize font graphic definitions ---------- */
172 /* always start with reliable default values (normal font graphics) */
173 for (i = 0; i < NUM_FONTS; i++)
174 font_info[i].graphic = IMG_FONT_INITIAL_1;
176 /* initialize normal font/graphic mapping from static configuration */
177 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
179 int font_nr = font_to_graphic[i].font_nr;
180 int special = font_to_graphic[i].special;
181 int graphic = font_to_graphic[i].graphic;
186 font_info[font_nr].graphic = graphic;
189 /* always start with reliable default values (special font graphics) */
190 for (i = 0; i < NUM_FONTS; i++)
192 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
194 font_info[i].special_graphic[j] = font_info[i].graphic;
195 font_info[i].special_bitmap_id[j] = i;
199 /* initialize special font/graphic mapping from static configuration */
200 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
202 int font_nr = font_to_graphic[i].font_nr;
203 int special = font_to_graphic[i].special;
204 int graphic = font_to_graphic[i].graphic;
205 int base_graphic = font2baseimg(font_nr);
207 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
209 boolean base_redefined =
210 getImageListEntryFromImageID(base_graphic)->redefined;
211 boolean special_redefined =
212 getImageListEntryFromImageID(graphic)->redefined;
214 /* if the base font ("font.title_1", for example) has been redefined,
215 but not the special font ("font.title_1.LEVELS", for example), do not
216 use an existing (in this case considered obsolete) special font
217 anymore, but use the automatically determined default font */
218 if (base_redefined && !special_redefined)
221 font_info[font_nr].special_graphic[special] = graphic;
222 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
227 /* initialize special element/graphic mapping from dynamic configuration */
228 for (i = 0; i < num_property_mappings; i++)
230 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
231 int special = property_mapping[i].ext3_index;
232 int graphic = property_mapping[i].artwork_index;
237 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
239 font_info[font_nr].special_graphic[special] = graphic;
240 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
245 /* ---------- initialize font bitmap array ---------- */
247 if (font_bitmap_info != NULL)
248 FreeFontInfo(font_bitmap_info);
251 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
253 /* ---------- initialize font bitmap definitions ---------- */
255 for (i = 0; i < NUM_FONTS; i++)
257 if (i < NUM_INITIAL_FONTS)
259 font_bitmap_info[i] = font_initial[i];
263 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
265 int font_bitmap_id = font_info[i].special_bitmap_id[j];
266 int graphic = font_info[i].special_graphic[j];
268 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
269 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
271 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
272 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
275 /* copy font relevant information from graphics information */
276 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
277 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
278 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
279 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
280 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
281 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
282 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
284 font_bitmap_info[font_bitmap_id].num_chars =
285 graphic_info[graphic].anim_frames;
286 font_bitmap_info[font_bitmap_id].num_chars_per_line =
287 graphic_info[graphic].anim_frames_per_line;
291 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
294 void InitElementGraphicInfo()
296 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
297 int num_property_mappings = getImageListPropertyMappingSize();
300 if (graphic_info == NULL) /* still at startup phase */
303 /* set values to -1 to identify later as "uninitialized" values */
304 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
306 for (act = 0; act < NUM_ACTIONS; act++)
308 element_info[i].graphic[act] = -1;
309 element_info[i].crumbled[act] = -1;
311 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
313 element_info[i].direction_graphic[act][dir] = -1;
314 element_info[i].direction_crumbled[act][dir] = -1;
319 /* initialize normal element/graphic mapping from static configuration */
320 for (i = 0; element_to_graphic[i].element > -1; i++)
322 int element = element_to_graphic[i].element;
323 int action = element_to_graphic[i].action;
324 int direction = element_to_graphic[i].direction;
325 boolean crumbled = element_to_graphic[i].crumbled;
326 int graphic = element_to_graphic[i].graphic;
327 int base_graphic = el2baseimg(element);
329 if (graphic_info[graphic].bitmap == NULL)
332 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
335 boolean base_redefined =
336 getImageListEntryFromImageID(base_graphic)->redefined;
337 boolean act_dir_redefined =
338 getImageListEntryFromImageID(graphic)->redefined;
340 /* if the base graphic ("emerald", for example) has been redefined,
341 but not the action graphic ("emerald.falling", for example), do not
342 use an existing (in this case considered obsolete) action graphic
343 anymore, but use the automatically determined default graphic */
344 if (base_redefined && !act_dir_redefined)
349 action = ACTION_DEFAULT;
354 element_info[element].direction_crumbled[action][direction] = graphic;
356 element_info[element].crumbled[action] = graphic;
361 element_info[element].direction_graphic[action][direction] = graphic;
363 element_info[element].graphic[action] = graphic;
367 /* initialize normal element/graphic mapping from dynamic configuration */
368 for (i = 0; i < num_property_mappings; i++)
370 int element = property_mapping[i].base_index;
371 int action = property_mapping[i].ext1_index;
372 int direction = property_mapping[i].ext2_index;
373 int special = property_mapping[i].ext3_index;
374 int graphic = property_mapping[i].artwork_index;
375 boolean crumbled = FALSE;
377 if (special == GFX_SPECIAL_ARG_CRUMBLED)
383 if (graphic_info[graphic].bitmap == NULL)
386 if (element >= MAX_NUM_ELEMENTS || special != -1)
390 action = ACTION_DEFAULT;
395 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
396 element_info[element].direction_crumbled[action][dir] = -1;
399 element_info[element].direction_crumbled[action][direction] = graphic;
401 element_info[element].crumbled[action] = graphic;
406 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
407 element_info[element].direction_graphic[action][dir] = -1;
410 element_info[element].direction_graphic[action][direction] = graphic;
412 element_info[element].graphic[action] = graphic;
416 /* now copy all graphics that are defined to be cloned from other graphics */
417 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
419 int graphic = element_info[i].graphic[ACTION_DEFAULT];
420 int crumbled_like, diggable_like;
425 crumbled_like = graphic_info[graphic].crumbled_like;
426 diggable_like = graphic_info[graphic].diggable_like;
428 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
430 for (act = 0; act < NUM_ACTIONS; act++)
431 element_info[i].crumbled[act] =
432 element_info[crumbled_like].crumbled[act];
433 for (act = 0; act < NUM_ACTIONS; act++)
434 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
435 element_info[i].direction_crumbled[act][dir] =
436 element_info[crumbled_like].direction_crumbled[act][dir];
439 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
441 element_info[i].graphic[ACTION_DIGGING] =
442 element_info[diggable_like].graphic[ACTION_DIGGING];
443 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
444 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
445 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
450 /* set hardcoded definitions for some runtime elements without graphic */
451 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
454 /* now set all undefined/invalid graphics to -1 to set to default after it */
455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
457 for (act = 0; act < NUM_ACTIONS; act++)
461 graphic = element_info[i].graphic[act];
462 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
463 element_info[i].graphic[act] = -1;
465 graphic = element_info[i].crumbled[act];
466 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
467 element_info[i].crumbled[act] = -1;
469 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
471 graphic = element_info[i].direction_graphic[act][dir];
472 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
473 element_info[i].direction_graphic[act][dir] = -1;
475 graphic = element_info[i].direction_crumbled[act][dir];
476 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
477 element_info[i].direction_crumbled[act][dir] = -1;
482 /* adjust graphics with 2nd tile for movement according to direction
483 (do this before correcting '-1' values to minimize calculations) */
484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
486 for (act = 0; act < NUM_ACTIONS; act++)
488 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
490 int graphic = element_info[i].direction_graphic[act][dir];
491 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
493 if (act == ACTION_FALLING) /* special case */
494 graphic = element_info[i].graphic[act];
497 graphic_info[graphic].double_movement &&
498 graphic_info[graphic].swap_double_tiles != 0)
500 struct GraphicInfo *g = &graphic_info[graphic];
501 int src_x_front = g->src_x;
502 int src_y_front = g->src_y;
503 int src_x_back = g->src_x + g->offset2_x;
504 int src_y_back = g->src_y + g->offset2_y;
505 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
507 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
508 src_y_front < src_y_back);
509 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
510 boolean swap_movement_tiles_autodetected =
511 (!frames_are_ordered_diagonally &&
512 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
513 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
514 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
515 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
518 /* swap frontside and backside graphic tile coordinates, if needed */
519 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
521 /* get current (wrong) backside tile coordinates */
522 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
525 /* set frontside tile coordinates to backside tile coordinates */
526 g->src_x = src_x_back;
527 g->src_y = src_y_back;
529 /* invert tile offset to point to new backside tile coordinates */
533 /* do not swap front and backside tiles again after correction */
534 g->swap_double_tiles = 0;
541 /* now set all '-1' values to element specific default values */
542 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
544 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
545 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
546 int default_direction_graphic[NUM_DIRECTIONS];
547 int default_direction_crumbled[NUM_DIRECTIONS];
549 if (default_graphic == -1)
550 default_graphic = IMG_UNKNOWN;
552 if (default_crumbled == -1)
553 default_crumbled = default_graphic;
555 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
556 if (default_crumbled == -1)
557 default_crumbled = IMG_EMPTY;
560 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
562 default_direction_graphic[dir] =
563 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
564 default_direction_crumbled[dir] =
565 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
567 if (default_direction_graphic[dir] == -1)
568 default_direction_graphic[dir] = default_graphic;
570 if (default_direction_crumbled[dir] == -1)
571 default_direction_crumbled[dir] = default_direction_graphic[dir];
573 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
574 if (default_direction_crumbled[dir] == -1)
575 default_direction_crumbled[dir] = default_crumbled;
579 for (act = 0; act < NUM_ACTIONS; act++)
581 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
582 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
583 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
584 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
585 act == ACTION_TURNING_FROM_RIGHT ||
586 act == ACTION_TURNING_FROM_UP ||
587 act == ACTION_TURNING_FROM_DOWN);
589 /* generic default action graphic (defined by "[default]" directive) */
590 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
591 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
592 int default_remove_graphic = IMG_EMPTY;
594 if (act_remove && default_action_graphic != -1)
595 default_remove_graphic = default_action_graphic;
597 /* look for special default action graphic (classic game specific) */
598 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
599 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
600 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
601 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
602 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
603 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
605 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
606 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
607 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
608 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
609 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
610 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
613 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
614 /* !!! make this better !!! */
615 if (i == EL_EMPTY_SPACE)
617 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
618 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
622 if (default_action_graphic == -1)
623 default_action_graphic = default_graphic;
625 if (default_action_crumbled == -1)
626 default_action_crumbled = default_action_graphic;
628 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
629 if (default_action_crumbled == -1)
630 default_action_crumbled = default_crumbled;
633 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
635 /* use action graphic as the default direction graphic, if undefined */
636 int default_action_direction_graphic = element_info[i].graphic[act];
637 int default_action_direction_crumbled = element_info[i].crumbled[act];
639 /* no graphic for current action -- use default direction graphic */
640 if (default_action_direction_graphic == -1)
641 default_action_direction_graphic =
642 (act_remove ? default_remove_graphic :
644 element_info[i].direction_graphic[ACTION_TURNING][dir] :
645 default_action_graphic != default_graphic ?
646 default_action_graphic :
647 default_direction_graphic[dir]);
649 if (element_info[i].direction_graphic[act][dir] == -1)
650 element_info[i].direction_graphic[act][dir] =
651 default_action_direction_graphic;
654 if (default_action_direction_crumbled == -1)
655 default_action_direction_crumbled =
656 element_info[i].direction_graphic[act][dir];
658 if (default_action_direction_crumbled == -1)
659 default_action_direction_crumbled =
660 (act_remove ? default_remove_graphic :
662 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
663 default_action_crumbled != default_crumbled ?
664 default_action_crumbled :
665 default_direction_crumbled[dir]);
668 if (element_info[i].direction_crumbled[act][dir] == -1)
669 element_info[i].direction_crumbled[act][dir] =
670 default_action_direction_crumbled;
673 /* no graphic for this specific action -- use default action graphic */
674 if (element_info[i].graphic[act] == -1)
675 element_info[i].graphic[act] =
676 (act_remove ? default_remove_graphic :
677 act_turning ? element_info[i].graphic[ACTION_TURNING] :
678 default_action_graphic);
680 if (element_info[i].crumbled[act] == -1)
681 element_info[i].crumbled[act] = element_info[i].graphic[act];
683 if (element_info[i].crumbled[act] == -1)
684 element_info[i].crumbled[act] =
685 (act_remove ? default_remove_graphic :
686 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
687 default_action_crumbled);
692 /* set animation mode to "none" for each graphic with only 1 frame */
693 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
695 for (act = 0; act < NUM_ACTIONS; act++)
697 int graphic = element_info[i].graphic[act];
698 int crumbled = element_info[i].crumbled[act];
700 if (graphic_info[graphic].anim_frames == 1)
701 graphic_info[graphic].anim_mode = ANIM_NONE;
702 if (graphic_info[crumbled].anim_frames == 1)
703 graphic_info[crumbled].anim_mode = ANIM_NONE;
705 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
707 graphic = element_info[i].direction_graphic[act][dir];
708 crumbled = element_info[i].direction_crumbled[act][dir];
710 if (graphic_info[graphic].anim_frames == 1)
711 graphic_info[graphic].anim_mode = ANIM_NONE;
712 if (graphic_info[crumbled].anim_frames == 1)
713 graphic_info[crumbled].anim_mode = ANIM_NONE;
722 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
723 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
725 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
726 element_info[i].token_name, i);
732 void InitElementSpecialGraphicInfo()
734 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
735 int num_property_mappings = getImageListPropertyMappingSize();
738 /* always start with reliable default values */
739 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
740 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
741 element_info[i].special_graphic[j] =
742 element_info[i].graphic[ACTION_DEFAULT];
744 /* initialize special element/graphic mapping from static configuration */
745 for (i = 0; element_to_special_graphic[i].element > -1; i++)
747 int element = element_to_special_graphic[i].element;
748 int special = element_to_special_graphic[i].special;
749 int graphic = element_to_special_graphic[i].graphic;
750 int base_graphic = el2baseimg(element);
751 boolean base_redefined =
752 getImageListEntryFromImageID(base_graphic)->redefined;
753 boolean special_redefined =
754 getImageListEntryFromImageID(graphic)->redefined;
756 /* if the base graphic ("emerald", for example) has been redefined,
757 but not the special graphic ("emerald.EDITOR", for example), do not
758 use an existing (in this case considered obsolete) special graphic
759 anymore, but use the automatically created (down-scaled) graphic */
760 if (base_redefined && !special_redefined)
763 element_info[element].special_graphic[special] = graphic;
766 /* initialize special element/graphic mapping from dynamic configuration */
767 for (i = 0; i < num_property_mappings; i++)
769 int element = property_mapping[i].base_index;
770 int special = property_mapping[i].ext3_index;
771 int graphic = property_mapping[i].artwork_index;
773 if (element >= MAX_NUM_ELEMENTS)
776 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
777 element_info[element].special_graphic[special] = graphic;
780 /* now set all undefined/invalid graphics to default */
781 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
782 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
783 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
784 element_info[i].special_graphic[j] =
785 element_info[i].graphic[ACTION_DEFAULT];
788 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
793 if (type != TYPE_TOKEN)
794 return get_parameter_value(value_raw, suffix, type);
796 if (strcmp(value_raw, ARG_UNDEFINED) == 0)
797 return ARG_UNDEFINED_VALUE;
799 /* !!! OPTIMIZE THIS BY USING HASH !!! */
800 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
801 if (strcmp(element_info[i].token_name, value_raw) == 0)
804 /* !!! OPTIMIZE THIS BY USING HASH !!! */
805 for (i = 0; image_config[i].token != NULL; i++)
807 int len_config_value = strlen(image_config[i].value);
809 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
810 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
811 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
814 if (strcmp(image_config[i].token, value_raw) == 0)
823 static int get_scaled_graphic_width(int graphic)
825 int original_width = getOriginalImageWidthFromImageID(graphic);
826 int scale_up_factor = graphic_info[graphic].scale_up_factor;
828 return original_width * scale_up_factor;
831 static int get_scaled_graphic_height(int graphic)
833 int original_height = getOriginalImageHeightFromImageID(graphic);
834 int scale_up_factor = graphic_info[graphic].scale_up_factor;
836 return original_height * scale_up_factor;
839 static void set_graphic_parameters(int graphic)
841 struct FileInfo *image = getImageListEntryFromImageID(graphic);
842 char **parameter_raw = image->parameter;
843 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
844 int parameter[NUM_GFX_ARGS];
845 int anim_frames_per_row = 1, anim_frames_per_col = 1;
846 int anim_frames_per_line = 1;
849 /* if fallback to default artwork is done, also use the default parameters */
850 if (image->fallback_to_default)
851 parameter_raw = image->default_parameter;
853 /* get integer values from string parameters */
854 for (i = 0; i < NUM_GFX_ARGS; i++)
855 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
856 image_config_suffix[i].token,
857 image_config_suffix[i].type);
859 graphic_info[graphic].bitmap = src_bitmap;
861 /* start with reliable default values */
862 graphic_info[graphic].src_image_width = 0;
863 graphic_info[graphic].src_image_height = 0;
864 graphic_info[graphic].src_x = 0;
865 graphic_info[graphic].src_y = 0;
866 graphic_info[graphic].width = TILEX;
867 graphic_info[graphic].height = TILEY;
868 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
869 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
870 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
871 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
872 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
873 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
874 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
875 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
876 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
877 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
878 graphic_info[graphic].anim_delay_fixed = 0;
879 graphic_info[graphic].anim_delay_random = 0;
880 graphic_info[graphic].post_delay_fixed = 0;
881 graphic_info[graphic].post_delay_random = 0;
883 /* optional x and y tile position of animation frame sequence */
884 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
885 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
886 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
887 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
889 /* optional x and y pixel position of animation frame sequence */
890 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
891 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
892 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
893 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
895 /* optional width and height of each animation frame */
896 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
897 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
898 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
899 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
901 /* optional zoom factor for scaling up the image to a larger size */
902 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
903 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
904 if (graphic_info[graphic].scale_up_factor < 1)
905 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
909 /* get final bitmap size (with scaling, but without small images) */
910 int src_image_width = get_scaled_graphic_width(graphic);
911 int src_image_height = get_scaled_graphic_height(graphic);
913 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
914 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
916 graphic_info[graphic].src_image_width = src_image_width;
917 graphic_info[graphic].src_image_height = src_image_height;
920 /* correct x or y offset dependent of vertical or horizontal frame order */
921 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
923 graphic_info[graphic].offset_y =
924 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
925 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
926 anim_frames_per_line = anim_frames_per_col;
928 else /* frames are ordered horizontally */
930 graphic_info[graphic].offset_x =
931 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
932 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
933 anim_frames_per_line = anim_frames_per_row;
936 /* optionally, the x and y offset of frames can be specified directly */
937 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
938 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
939 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
940 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
942 /* optionally, moving animations may have separate start and end graphics */
943 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
945 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
946 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
948 /* correct x or y offset2 dependent of vertical or horizontal frame order */
949 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
950 graphic_info[graphic].offset2_y =
951 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
952 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
953 else /* frames are ordered horizontally */
954 graphic_info[graphic].offset2_x =
955 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
956 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
958 /* optionally, the x and y offset of 2nd graphic can be specified directly */
959 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
960 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
961 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
962 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
964 /* optionally, the second movement tile can be specified as start tile */
965 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
966 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
968 /* automatically determine correct number of frames, if not defined */
969 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
970 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
971 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
972 graphic_info[graphic].anim_frames = anim_frames_per_row;
973 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
974 graphic_info[graphic].anim_frames = anim_frames_per_col;
976 graphic_info[graphic].anim_frames = 1;
978 graphic_info[graphic].anim_frames_per_line =
979 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
980 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
982 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
983 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
984 graphic_info[graphic].anim_delay = 1;
986 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
988 if (graphic_info[graphic].anim_frames == 1)
989 graphic_info[graphic].anim_mode = ANIM_NONE;
992 /* automatically determine correct start frame, if not defined */
993 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].anim_start_frame = 0;
995 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
996 graphic_info[graphic].anim_start_frame =
997 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
999 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1001 /* animation synchronized with global frame counter, not move position */
1002 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1004 /* optional element for cloning crumble graphics */
1005 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1008 /* optional element for cloning digging graphics */
1009 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1012 /* optional border size for "crumbling" diggable graphics */
1013 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1016 /* this is only used for player "boring" and "sleeping" actions */
1017 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1018 graphic_info[graphic].anim_delay_fixed =
1019 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1020 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1021 graphic_info[graphic].anim_delay_random =
1022 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1023 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1024 graphic_info[graphic].post_delay_fixed =
1025 parameter[GFX_ARG_POST_DELAY_FIXED];
1026 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1027 graphic_info[graphic].post_delay_random =
1028 parameter[GFX_ARG_POST_DELAY_RANDOM];
1030 /* this is only used for toon animations */
1031 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1032 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1034 /* this is only used for drawing font characters */
1035 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1036 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1038 /* this is only used for drawing envelope graphics */
1039 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1041 /* optional graphic for cloning all graphics settings */
1042 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1043 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1046 static void set_cloned_graphic_parameters(int graphic)
1048 int fallback_graphic = IMG_CHAR_EXCLAM;
1049 int max_num_images = getImageListSize();
1050 int clone_graphic = graphic_info[graphic].clone_from;
1051 int num_references_followed = 1;
1053 while (graphic_info[clone_graphic].clone_from != -1 &&
1054 num_references_followed < max_num_images)
1056 clone_graphic = graphic_info[clone_graphic].clone_from;
1058 num_references_followed++;
1061 if (num_references_followed >= max_num_images)
1063 Error(ERR_RETURN_LINE, "-");
1064 Error(ERR_RETURN, "warning: error found in config file:");
1065 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1066 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1067 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1068 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1070 if (graphic == fallback_graphic)
1071 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1073 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1074 Error(ERR_RETURN_LINE, "-");
1076 graphic_info[graphic] = graphic_info[fallback_graphic];
1080 graphic_info[graphic] = graphic_info[clone_graphic];
1081 graphic_info[graphic].clone_from = clone_graphic;
1085 static void InitGraphicInfo()
1087 int fallback_graphic = IMG_CHAR_EXCLAM;
1088 int num_images = getImageListSize();
1091 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1092 static boolean clipmasks_initialized = FALSE;
1094 XGCValues clip_gc_values;
1095 unsigned long clip_gc_valuemask;
1096 GC copy_clipmask_gc = None;
1099 checked_free(graphic_info);
1101 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1103 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1104 if (clipmasks_initialized)
1106 for (i = 0; i < num_images; i++)
1108 if (graphic_info[i].clip_mask)
1109 XFreePixmap(display, graphic_info[i].clip_mask);
1110 if (graphic_info[i].clip_gc)
1111 XFreeGC(display, graphic_info[i].clip_gc);
1113 graphic_info[i].clip_mask = None;
1114 graphic_info[i].clip_gc = None;
1119 /* first set all graphic paramaters ... */
1120 for (i = 0; i < num_images; i++)
1121 set_graphic_parameters(i);
1123 /* ... then copy these parameters for cloned graphics */
1124 for (i = 0; i < num_images; i++)
1125 if (graphic_info[i].clone_from != -1)
1126 set_cloned_graphic_parameters(i);
1128 for (i = 0; i < num_images; i++)
1132 int first_frame, last_frame;
1133 int src_bitmap_width, src_bitmap_height;
1135 /* now check if no animation frames are outside of the loaded image */
1137 if (graphic_info[i].bitmap == NULL)
1138 continue; /* skip check for optional images that are undefined */
1140 /* get final bitmap size (with scaling, but without small images) */
1141 src_bitmap_width = graphic_info[i].src_image_width;
1142 src_bitmap_height = graphic_info[i].src_image_height;
1144 /* check if first animation frame is inside specified bitmap */
1147 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1149 if (src_x < 0 || src_y < 0 ||
1150 src_x + TILEX > src_bitmap_width ||
1151 src_y + TILEY > src_bitmap_height)
1153 Error(ERR_RETURN_LINE, "-");
1154 Error(ERR_RETURN, "warning: error found in config file:");
1155 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1156 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1157 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1159 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1160 src_x, src_y, src_bitmap_width, src_bitmap_height);
1161 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1163 if (i == fallback_graphic)
1164 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1166 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1167 Error(ERR_RETURN_LINE, "-");
1169 graphic_info[i] = graphic_info[fallback_graphic];
1172 /* check if last animation frame is inside specified bitmap */
1174 last_frame = graphic_info[i].anim_frames - 1;
1175 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1177 if (src_x < 0 || src_y < 0 ||
1178 src_x + TILEX > src_bitmap_width ||
1179 src_y + TILEY > src_bitmap_height)
1181 Error(ERR_RETURN_LINE, "-");
1182 Error(ERR_RETURN, "warning: error found in config file:");
1183 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1184 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1185 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1187 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1188 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1189 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1191 if (i == fallback_graphic)
1192 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1194 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1195 Error(ERR_RETURN_LINE, "-");
1197 graphic_info[i] = graphic_info[fallback_graphic];
1200 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1201 /* currently we only need a tile clip mask from the first frame */
1202 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1204 if (copy_clipmask_gc == None)
1206 clip_gc_values.graphics_exposures = False;
1207 clip_gc_valuemask = GCGraphicsExposures;
1208 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1209 clip_gc_valuemask, &clip_gc_values);
1212 graphic_info[i].clip_mask =
1213 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1215 src_pixmap = src_bitmap->clip_mask;
1216 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1217 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1219 clip_gc_values.graphics_exposures = False;
1220 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1221 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1223 graphic_info[i].clip_gc =
1224 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1228 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1229 if (copy_clipmask_gc)
1230 XFreeGC(display, copy_clipmask_gc);
1232 clipmasks_initialized = TRUE;
1236 static void InitElementSoundInfo()
1238 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1239 int num_property_mappings = getSoundListPropertyMappingSize();
1242 /* set values to -1 to identify later as "uninitialized" values */
1243 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1244 for (act = 0; act < NUM_ACTIONS; act++)
1245 element_info[i].sound[act] = -1;
1247 /* initialize element/sound mapping from static configuration */
1248 for (i = 0; element_to_sound[i].element > -1; i++)
1250 int element = element_to_sound[i].element;
1251 int action = element_to_sound[i].action;
1252 int sound = element_to_sound[i].sound;
1253 boolean is_class = element_to_sound[i].is_class;
1256 action = ACTION_DEFAULT;
1259 element_info[element].sound[action] = sound;
1261 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1262 if (strcmp(element_info[j].class_name,
1263 element_info[element].class_name) == 0)
1264 element_info[j].sound[action] = sound;
1267 /* initialize element class/sound mapping from dynamic configuration */
1268 for (i = 0; i < num_property_mappings; i++)
1270 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1271 int action = property_mapping[i].ext1_index;
1272 int sound = property_mapping[i].artwork_index;
1274 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1278 action = ACTION_DEFAULT;
1280 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1281 if (strcmp(element_info[j].class_name,
1282 element_info[element_class].class_name) == 0)
1283 element_info[j].sound[action] = sound;
1286 /* initialize element/sound mapping from dynamic configuration */
1287 for (i = 0; i < num_property_mappings; i++)
1289 int element = property_mapping[i].base_index;
1290 int action = property_mapping[i].ext1_index;
1291 int sound = property_mapping[i].artwork_index;
1293 if (element >= MAX_NUM_ELEMENTS)
1297 action = ACTION_DEFAULT;
1299 element_info[element].sound[action] = sound;
1302 /* now set all '-1' values to element specific default values */
1303 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1305 for (act = 0; act < NUM_ACTIONS; act++)
1307 /* generic default action sound (defined by "[default]" directive) */
1308 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1310 /* look for special default action sound (classic game specific) */
1311 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1312 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1313 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1314 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1315 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1316 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1318 /* !!! there's no such thing as a "default action sound" !!! */
1320 /* look for element specific default sound (independent from action) */
1321 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1322 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1326 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1327 /* !!! make this better !!! */
1328 if (i == EL_EMPTY_SPACE)
1329 default_action_sound = element_info[EL_DEFAULT].sound[act];
1332 /* no sound for this specific action -- use default action sound */
1333 if (element_info[i].sound[act] == -1)
1334 element_info[i].sound[act] = default_action_sound;
1338 /* copy sound settings to some elements that are only stored in level file
1339 in native R'n'D levels, but are used by game engine in native EM levels */
1340 for (i = 0; copy_properties[i][0] != -1; i++)
1341 for (j = 1; j <= 4; j++)
1342 for (act = 0; act < NUM_ACTIONS; act++)
1343 element_info[copy_properties[i][j]].sound[act] =
1344 element_info[copy_properties[i][0]].sound[act];
1347 static void InitGameModeSoundInfo()
1351 /* set values to -1 to identify later as "uninitialized" values */
1352 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1355 /* initialize gamemode/sound mapping from static configuration */
1356 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1358 int gamemode = gamemode_to_sound[i].gamemode;
1359 int sound = gamemode_to_sound[i].sound;
1362 gamemode = GAME_MODE_DEFAULT;
1364 menu.sound[gamemode] = sound;
1367 /* now set all '-1' values to levelset specific default values */
1368 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1369 if (menu.sound[i] == -1)
1370 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1373 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1374 if (menu.sound[i] != -1)
1375 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1379 static void set_sound_parameters(int sound, char **parameter_raw)
1381 int parameter[NUM_SND_ARGS];
1384 /* get integer values from string parameters */
1385 for (i = 0; i < NUM_SND_ARGS; i++)
1387 get_parameter_value(parameter_raw[i],
1388 sound_config_suffix[i].token,
1389 sound_config_suffix[i].type);
1391 /* explicit loop mode setting in configuration overrides default value */
1392 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1393 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1395 /* sound volume to change the original volume when loading the sound file */
1396 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1398 /* sound priority to give certain sounds a higher or lower priority */
1399 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1402 static void InitSoundInfo()
1404 int *sound_effect_properties;
1405 int num_sounds = getSoundListSize();
1408 checked_free(sound_info);
1410 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1411 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1413 /* initialize sound effect for all elements to "no sound" */
1414 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1415 for (j = 0; j < NUM_ACTIONS; j++)
1416 element_info[i].sound[j] = SND_UNDEFINED;
1418 for (i = 0; i < num_sounds; i++)
1420 struct FileInfo *sound = getSoundListEntry(i);
1421 int len_effect_text = strlen(sound->token);
1423 sound_effect_properties[i] = ACTION_OTHER;
1424 sound_info[i].loop = FALSE; /* default: play sound only once */
1427 printf("::: sound %d: '%s'\n", i, sound->token);
1430 /* determine all loop sounds and identify certain sound classes */
1432 for (j = 0; element_action_info[j].suffix; j++)
1434 int len_action_text = strlen(element_action_info[j].suffix);
1436 if (len_action_text < len_effect_text &&
1437 strcmp(&sound->token[len_effect_text - len_action_text],
1438 element_action_info[j].suffix) == 0)
1440 sound_effect_properties[i] = element_action_info[j].value;
1441 sound_info[i].loop = element_action_info[j].is_loop_sound;
1447 /* associate elements and some selected sound actions */
1449 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1451 if (element_info[j].class_name)
1453 int len_class_text = strlen(element_info[j].class_name);
1455 if (len_class_text + 1 < len_effect_text &&
1456 strncmp(sound->token,
1457 element_info[j].class_name, len_class_text) == 0 &&
1458 sound->token[len_class_text] == '.')
1460 int sound_action_value = sound_effect_properties[i];
1462 element_info[j].sound[sound_action_value] = i;
1467 set_sound_parameters(i, sound->parameter);
1470 free(sound_effect_properties);
1473 static void InitGameModeMusicInfo()
1475 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1476 int num_property_mappings = getMusicListPropertyMappingSize();
1477 int default_levelset_music = -1;
1480 /* set values to -1 to identify later as "uninitialized" values */
1481 for (i = 0; i < MAX_LEVELS; i++)
1482 levelset.music[i] = -1;
1483 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1486 /* initialize gamemode/music mapping from static configuration */
1487 for (i = 0; gamemode_to_music[i].music > -1; i++)
1489 int gamemode = gamemode_to_music[i].gamemode;
1490 int music = gamemode_to_music[i].music;
1493 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1497 gamemode = GAME_MODE_DEFAULT;
1499 menu.music[gamemode] = music;
1502 /* initialize gamemode/music mapping from dynamic configuration */
1503 for (i = 0; i < num_property_mappings; i++)
1505 int prefix = property_mapping[i].base_index;
1506 int gamemode = property_mapping[i].ext1_index;
1507 int level = property_mapping[i].ext2_index;
1508 int music = property_mapping[i].artwork_index;
1511 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1512 prefix, gamemode, level, music);
1515 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1519 gamemode = GAME_MODE_DEFAULT;
1521 /* level specific music only allowed for in-game music */
1522 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1523 gamemode = GAME_MODE_PLAYING;
1528 default_levelset_music = music;
1531 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1532 levelset.music[level] = music;
1533 if (gamemode != GAME_MODE_PLAYING)
1534 menu.music[gamemode] = music;
1537 /* now set all '-1' values to menu specific default values */
1538 /* (undefined values of "levelset.music[]" might stay at "-1" to
1539 allow dynamic selection of music files from music directory!) */
1540 for (i = 0; i < MAX_LEVELS; i++)
1541 if (levelset.music[i] == -1)
1542 levelset.music[i] = default_levelset_music;
1543 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1544 if (menu.music[i] == -1)
1545 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1548 for (i = 0; i < MAX_LEVELS; i++)
1549 if (levelset.music[i] != -1)
1550 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1551 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1552 if (menu.music[i] != -1)
1553 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1557 static void set_music_parameters(int music, char **parameter_raw)
1559 int parameter[NUM_MUS_ARGS];
1562 /* get integer values from string parameters */
1563 for (i = 0; i < NUM_MUS_ARGS; i++)
1565 get_parameter_value(parameter_raw[i],
1566 music_config_suffix[i].token,
1567 music_config_suffix[i].type);
1569 /* explicit loop mode setting in configuration overrides default value */
1570 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1571 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1574 static void InitMusicInfo()
1576 int num_music = getMusicListSize();
1579 checked_free(music_info);
1581 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1583 for (i = 0; i < num_music; i++)
1585 struct FileInfo *music = getMusicListEntry(i);
1586 int len_music_text = strlen(music->token);
1588 music_info[i].loop = TRUE; /* default: play music in loop mode */
1590 /* determine all loop music */
1592 for (j = 0; music_prefix_info[j].prefix; j++)
1594 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1596 if (len_prefix_text < len_music_text &&
1597 strncmp(music->token,
1598 music_prefix_info[j].prefix, len_prefix_text) == 0)
1600 music_info[i].loop = music_prefix_info[j].is_loop_music;
1606 set_music_parameters(i, music->parameter);
1610 static void ReinitializeGraphics()
1612 InitGraphicInfo(); /* graphic properties mapping */
1613 InitElementGraphicInfo(); /* element game graphic mapping */
1614 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1616 InitElementSmallImages(); /* scale images to all needed sizes */
1617 InitFontGraphicInfo(); /* initialize text drawing functions */
1619 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1621 SetMainBackgroundImage(IMG_BACKGROUND);
1622 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1628 static void ReinitializeSounds()
1630 InitSoundInfo(); /* sound properties mapping */
1631 InitElementSoundInfo(); /* element game sound mapping */
1632 InitGameModeSoundInfo(); /* game mode sound mapping */
1634 InitPlayLevelSound(); /* internal game sound settings */
1637 static void ReinitializeMusic()
1639 InitMusicInfo(); /* music properties mapping */
1640 InitGameModeMusicInfo(); /* game mode music mapping */
1643 static int get_special_property_bit(int element, int property_bit_nr)
1645 struct PropertyBitInfo
1651 static struct PropertyBitInfo pb_can_move_into_acid[] =
1653 /* the player may be able fall into acid when gravity is activated */
1658 { EL_SP_MURPHY, 0 },
1659 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1661 /* all element that can move may be able to also move into acid */
1664 { EL_BUG_RIGHT, 1 },
1667 { EL_SPACESHIP, 2 },
1668 { EL_SPACESHIP_LEFT, 2 },
1669 { EL_SPACESHIP_RIGHT, 2 },
1670 { EL_SPACESHIP_UP, 2 },
1671 { EL_SPACESHIP_DOWN, 2 },
1672 { EL_BD_BUTTERFLY, 3 },
1673 { EL_BD_BUTTERFLY_LEFT, 3 },
1674 { EL_BD_BUTTERFLY_RIGHT, 3 },
1675 { EL_BD_BUTTERFLY_UP, 3 },
1676 { EL_BD_BUTTERFLY_DOWN, 3 },
1677 { EL_BD_FIREFLY, 4 },
1678 { EL_BD_FIREFLY_LEFT, 4 },
1679 { EL_BD_FIREFLY_RIGHT, 4 },
1680 { EL_BD_FIREFLY_UP, 4 },
1681 { EL_BD_FIREFLY_DOWN, 4 },
1683 { EL_DARK_YAMYAM, 6 },
1686 { EL_PACMAN_LEFT, 8 },
1687 { EL_PACMAN_RIGHT, 8 },
1688 { EL_PACMAN_UP, 8 },
1689 { EL_PACMAN_DOWN, 8 },
1691 { EL_MOLE_LEFT, 9 },
1692 { EL_MOLE_RIGHT, 9 },
1694 { EL_MOLE_DOWN, 9 },
1698 { EL_SATELLITE, 13 },
1699 { EL_SP_SNIKSNAK, 14 },
1700 { EL_SP_ELECTRON, 15 },
1707 static struct PropertyBitInfo pb_dont_collide_with[] =
1709 { EL_SP_SNIKSNAK, 0 },
1710 { EL_SP_ELECTRON, 1 },
1718 struct PropertyBitInfo *pb_info;
1721 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1722 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1727 struct PropertyBitInfo *pb_info = NULL;
1730 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1731 if (pb_definition[i].bit_nr == property_bit_nr)
1732 pb_info = pb_definition[i].pb_info;
1734 if (pb_info == NULL)
1737 for (i = 0; pb_info[i].element != -1; i++)
1738 if (pb_info[i].element == element)
1739 return pb_info[i].bit_nr;
1744 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1745 boolean property_value)
1747 int bit_nr = get_special_property_bit(element, property_bit_nr);
1752 *bitfield |= (1 << bit_nr);
1754 *bitfield &= ~(1 << bit_nr);
1758 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1760 int bit_nr = get_special_property_bit(element, property_bit_nr);
1763 return ((*bitfield & (1 << bit_nr)) != 0);
1768 void InitElementPropertiesStatic()
1770 static int ep_diggable[] =
1775 EL_SP_BUGGY_BASE_ACTIVATING,
1778 EL_INVISIBLE_SAND_ACTIVE,
1781 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1782 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1786 EL_SP_BUGGY_BASE_ACTIVE,
1792 static int ep_collectible_only[] =
1813 EL_DYNABOMB_INCREASE_NUMBER,
1814 EL_DYNABOMB_INCREASE_SIZE,
1815 EL_DYNABOMB_INCREASE_POWER,
1834 static int ep_dont_run_into[] =
1836 /* same elements as in 'ep_dont_touch' */
1842 /* same elements as in 'ep_dont_collide_with' */
1854 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1858 EL_SP_BUGGY_BASE_ACTIVE,
1864 static int ep_dont_collide_with[] =
1866 /* same elements as in 'ep_dont_touch' */
1882 static int ep_dont_touch[] =
1891 static int ep_indestructible[] =
1895 EL_ACID_POOL_TOPLEFT,
1896 EL_ACID_POOL_TOPRIGHT,
1897 EL_ACID_POOL_BOTTOMLEFT,
1898 EL_ACID_POOL_BOTTOM,
1899 EL_ACID_POOL_BOTTOMRIGHT,
1900 EL_SP_HARDWARE_GRAY,
1901 EL_SP_HARDWARE_GREEN,
1902 EL_SP_HARDWARE_BLUE,
1904 EL_SP_HARDWARE_YELLOW,
1905 EL_SP_HARDWARE_BASE_1,
1906 EL_SP_HARDWARE_BASE_2,
1907 EL_SP_HARDWARE_BASE_3,
1908 EL_SP_HARDWARE_BASE_4,
1909 EL_SP_HARDWARE_BASE_5,
1910 EL_SP_HARDWARE_BASE_6,
1911 EL_INVISIBLE_STEELWALL,
1912 EL_INVISIBLE_STEELWALL_ACTIVE,
1913 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1914 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1915 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1916 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1917 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1918 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1919 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1920 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1921 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1922 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1923 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1924 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1926 EL_LIGHT_SWITCH_ACTIVE,
1927 EL_SIGN_EXCLAMATION,
1928 EL_SIGN_RADIOACTIVITY,
1939 EL_STEELWALL_SLIPPERY,
1953 EL_GATE_1_GRAY_ACTIVE,
1954 EL_GATE_2_GRAY_ACTIVE,
1955 EL_GATE_3_GRAY_ACTIVE,
1956 EL_GATE_4_GRAY_ACTIVE,
1965 EL_EM_GATE_1_GRAY_ACTIVE,
1966 EL_EM_GATE_2_GRAY_ACTIVE,
1967 EL_EM_GATE_3_GRAY_ACTIVE,
1968 EL_EM_GATE_4_GRAY_ACTIVE,
1977 EL_EMC_GATE_5_GRAY_ACTIVE,
1978 EL_EMC_GATE_6_GRAY_ACTIVE,
1979 EL_EMC_GATE_7_GRAY_ACTIVE,
1980 EL_EMC_GATE_8_GRAY_ACTIVE,
1982 EL_SWITCHGATE_OPENING,
1983 EL_SWITCHGATE_CLOSED,
1984 EL_SWITCHGATE_CLOSING,
1986 EL_SWITCHGATE_SWITCH_UP,
1987 EL_SWITCHGATE_SWITCH_DOWN,
1990 EL_TIMEGATE_OPENING,
1992 EL_TIMEGATE_CLOSING,
1995 EL_TIMEGATE_SWITCH_ACTIVE,
2000 EL_TUBE_VERTICAL_LEFT,
2001 EL_TUBE_VERTICAL_RIGHT,
2002 EL_TUBE_HORIZONTAL_UP,
2003 EL_TUBE_HORIZONTAL_DOWN,
2011 static int ep_slippery[] =
2025 EL_ROBOT_WHEEL_ACTIVE,
2031 EL_ACID_POOL_TOPLEFT,
2032 EL_ACID_POOL_TOPRIGHT,
2042 EL_STEELWALL_SLIPPERY,
2045 EL_EMC_WALL_SLIPPERY_1,
2046 EL_EMC_WALL_SLIPPERY_2,
2047 EL_EMC_WALL_SLIPPERY_3,
2048 EL_EMC_WALL_SLIPPERY_4,
2052 static int ep_can_change[] =
2057 static int ep_can_move[] =
2059 /* same elements as in 'pb_can_move_into_acid' */
2081 static int ep_can_fall[] =
2096 EL_BD_MAGIC_WALL_FULL,
2109 static int ep_can_smash_player[] =
2134 static int ep_can_smash_enemies[] =
2142 static int ep_can_smash_everything[] =
2150 static int ep_explodes_by_fire[] =
2152 /* same elements as in 'ep_explodes_impact' */
2157 /* same elements as in 'ep_explodes_smashed' */
2166 EL_DYNABOMB_PLAYER_1_ACTIVE,
2167 EL_DYNABOMB_PLAYER_2_ACTIVE,
2168 EL_DYNABOMB_PLAYER_3_ACTIVE,
2169 EL_DYNABOMB_PLAYER_4_ACTIVE,
2170 EL_DYNABOMB_INCREASE_NUMBER,
2171 EL_DYNABOMB_INCREASE_SIZE,
2172 EL_DYNABOMB_INCREASE_POWER,
2173 EL_SP_DISK_RED_ACTIVE,
2186 static int ep_explodes_smashed[] =
2188 /* same elements as in 'ep_explodes_impact' */
2201 static int ep_explodes_impact[] =
2209 static int ep_walkable_over[] =
2213 EL_SOKOBAN_FIELD_EMPTY,
2225 EL_GATE_1_GRAY_ACTIVE,
2226 EL_GATE_2_GRAY_ACTIVE,
2227 EL_GATE_3_GRAY_ACTIVE,
2228 EL_GATE_4_GRAY_ACTIVE,
2235 static int ep_walkable_inside[] =
2240 EL_TUBE_VERTICAL_LEFT,
2241 EL_TUBE_VERTICAL_RIGHT,
2242 EL_TUBE_HORIZONTAL_UP,
2243 EL_TUBE_HORIZONTAL_DOWN,
2251 static int ep_walkable_under[] =
2256 static int ep_passable_over[] =
2266 EL_EM_GATE_1_GRAY_ACTIVE,
2267 EL_EM_GATE_2_GRAY_ACTIVE,
2268 EL_EM_GATE_3_GRAY_ACTIVE,
2269 EL_EM_GATE_4_GRAY_ACTIVE,
2278 EL_EMC_GATE_5_GRAY_ACTIVE,
2279 EL_EMC_GATE_6_GRAY_ACTIVE,
2280 EL_EMC_GATE_7_GRAY_ACTIVE,
2281 EL_EMC_GATE_8_GRAY_ACTIVE,
2287 static int ep_passable_inside[] =
2293 EL_SP_PORT_HORIZONTAL,
2294 EL_SP_PORT_VERTICAL,
2296 EL_SP_GRAVITY_PORT_LEFT,
2297 EL_SP_GRAVITY_PORT_RIGHT,
2298 EL_SP_GRAVITY_PORT_UP,
2299 EL_SP_GRAVITY_PORT_DOWN,
2300 EL_SP_GRAVITY_ON_PORT_LEFT,
2301 EL_SP_GRAVITY_ON_PORT_RIGHT,
2302 EL_SP_GRAVITY_ON_PORT_UP,
2303 EL_SP_GRAVITY_ON_PORT_DOWN,
2304 EL_SP_GRAVITY_OFF_PORT_LEFT,
2305 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2306 EL_SP_GRAVITY_OFF_PORT_UP,
2307 EL_SP_GRAVITY_OFF_PORT_DOWN,
2311 static int ep_passable_under[] =
2316 static int ep_droppable[] =
2321 static int ep_explodes_1x1_old[] =
2326 static int ep_pushable[] =
2338 EL_SOKOBAN_FIELD_FULL,
2346 static int ep_explodes_cross_old[] =
2351 static int ep_protected[] =
2353 /* same elements as in 'ep_walkable_inside' */
2357 EL_TUBE_VERTICAL_LEFT,
2358 EL_TUBE_VERTICAL_RIGHT,
2359 EL_TUBE_HORIZONTAL_UP,
2360 EL_TUBE_HORIZONTAL_DOWN,
2366 /* same elements as in 'ep_passable_over' */
2375 EL_EM_GATE_1_GRAY_ACTIVE,
2376 EL_EM_GATE_2_GRAY_ACTIVE,
2377 EL_EM_GATE_3_GRAY_ACTIVE,
2378 EL_EM_GATE_4_GRAY_ACTIVE,
2387 EL_EMC_GATE_5_GRAY_ACTIVE,
2388 EL_EMC_GATE_6_GRAY_ACTIVE,
2389 EL_EMC_GATE_7_GRAY_ACTIVE,
2390 EL_EMC_GATE_8_GRAY_ACTIVE,
2394 /* same elements as in 'ep_passable_inside' */
2399 EL_SP_PORT_HORIZONTAL,
2400 EL_SP_PORT_VERTICAL,
2402 EL_SP_GRAVITY_PORT_LEFT,
2403 EL_SP_GRAVITY_PORT_RIGHT,
2404 EL_SP_GRAVITY_PORT_UP,
2405 EL_SP_GRAVITY_PORT_DOWN,
2406 EL_SP_GRAVITY_ON_PORT_LEFT,
2407 EL_SP_GRAVITY_ON_PORT_RIGHT,
2408 EL_SP_GRAVITY_ON_PORT_UP,
2409 EL_SP_GRAVITY_ON_PORT_DOWN,
2410 EL_SP_GRAVITY_OFF_PORT_LEFT,
2411 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2412 EL_SP_GRAVITY_OFF_PORT_UP,
2413 EL_SP_GRAVITY_OFF_PORT_DOWN,
2417 static int ep_throwable[] =
2422 static int ep_can_explode[] =
2424 /* same elements as in 'ep_explodes_impact' */
2429 /* same elements as in 'ep_explodes_smashed' */
2435 /* elements that can explode by explosion or by dragonfire */
2438 EL_DYNABOMB_PLAYER_1_ACTIVE,
2439 EL_DYNABOMB_PLAYER_2_ACTIVE,
2440 EL_DYNABOMB_PLAYER_3_ACTIVE,
2441 EL_DYNABOMB_PLAYER_4_ACTIVE,
2442 EL_DYNABOMB_INCREASE_NUMBER,
2443 EL_DYNABOMB_INCREASE_SIZE,
2444 EL_DYNABOMB_INCREASE_POWER,
2445 EL_SP_DISK_RED_ACTIVE,
2453 /* elements that can explode only by explosion */
2458 static int ep_gravity_reachable[] =
2464 EL_INVISIBLE_SAND_ACTIVE,
2469 EL_SP_PORT_HORIZONTAL,
2470 EL_SP_PORT_VERTICAL,
2472 EL_SP_GRAVITY_PORT_LEFT,
2473 EL_SP_GRAVITY_PORT_RIGHT,
2474 EL_SP_GRAVITY_PORT_UP,
2475 EL_SP_GRAVITY_PORT_DOWN,
2476 EL_SP_GRAVITY_ON_PORT_LEFT,
2477 EL_SP_GRAVITY_ON_PORT_RIGHT,
2478 EL_SP_GRAVITY_ON_PORT_UP,
2479 EL_SP_GRAVITY_ON_PORT_DOWN,
2480 EL_SP_GRAVITY_OFF_PORT_LEFT,
2481 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2482 EL_SP_GRAVITY_OFF_PORT_UP,
2483 EL_SP_GRAVITY_OFF_PORT_DOWN,
2488 static int ep_player[] =
2495 EL_SOKOBAN_FIELD_PLAYER,
2500 static int ep_can_pass_magic_wall[] =
2513 static int ep_switchable[] =
2517 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2518 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2519 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2520 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2521 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2522 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2523 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2524 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2525 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2526 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2527 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2528 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2529 EL_SWITCHGATE_SWITCH_UP,
2530 EL_SWITCHGATE_SWITCH_DOWN,
2532 EL_LIGHT_SWITCH_ACTIVE,
2534 EL_BALLOON_SWITCH_LEFT,
2535 EL_BALLOON_SWITCH_RIGHT,
2536 EL_BALLOON_SWITCH_UP,
2537 EL_BALLOON_SWITCH_DOWN,
2538 EL_BALLOON_SWITCH_ANY,
2539 EL_BALLOON_SWITCH_NONE,
2542 EL_EMC_MAGIC_BALL_SWITCH,
2546 static int ep_bd_element[] =
2579 static int ep_sp_element[] =
2581 /* should always be valid */
2584 /* standard classic Supaplex elements */
2591 EL_SP_HARDWARE_GRAY,
2599 EL_SP_GRAVITY_PORT_RIGHT,
2600 EL_SP_GRAVITY_PORT_DOWN,
2601 EL_SP_GRAVITY_PORT_LEFT,
2602 EL_SP_GRAVITY_PORT_UP,
2607 EL_SP_PORT_VERTICAL,
2608 EL_SP_PORT_HORIZONTAL,
2614 EL_SP_HARDWARE_BASE_1,
2615 EL_SP_HARDWARE_GREEN,
2616 EL_SP_HARDWARE_BLUE,
2618 EL_SP_HARDWARE_YELLOW,
2619 EL_SP_HARDWARE_BASE_2,
2620 EL_SP_HARDWARE_BASE_3,
2621 EL_SP_HARDWARE_BASE_4,
2622 EL_SP_HARDWARE_BASE_5,
2623 EL_SP_HARDWARE_BASE_6,
2627 /* additional elements that appeared in newer Supaplex levels */
2630 /* additional gravity port elements (not switching, but setting gravity) */
2631 EL_SP_GRAVITY_ON_PORT_LEFT,
2632 EL_SP_GRAVITY_ON_PORT_RIGHT,
2633 EL_SP_GRAVITY_ON_PORT_UP,
2634 EL_SP_GRAVITY_ON_PORT_DOWN,
2635 EL_SP_GRAVITY_OFF_PORT_LEFT,
2636 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2637 EL_SP_GRAVITY_OFF_PORT_UP,
2638 EL_SP_GRAVITY_OFF_PORT_DOWN,
2640 /* more than one Murphy in a level results in an inactive clone */
2643 /* runtime Supaplex elements */
2644 EL_SP_DISK_RED_ACTIVE,
2645 EL_SP_TERMINAL_ACTIVE,
2646 EL_SP_BUGGY_BASE_ACTIVATING,
2647 EL_SP_BUGGY_BASE_ACTIVE,
2653 static int ep_sb_element[] =
2658 EL_SOKOBAN_FIELD_EMPTY,
2659 EL_SOKOBAN_FIELD_FULL,
2660 EL_SOKOBAN_FIELD_PLAYER,
2665 EL_INVISIBLE_STEELWALL,
2669 static int ep_gem[] =
2680 static int ep_food_dark_yamyam[] =
2707 static int ep_food_penguin[] =
2720 static int ep_food_pig[] =
2731 static int ep_historic_wall[] =
2742 EL_GATE_1_GRAY_ACTIVE,
2743 EL_GATE_2_GRAY_ACTIVE,
2744 EL_GATE_3_GRAY_ACTIVE,
2745 EL_GATE_4_GRAY_ACTIVE,
2754 EL_EM_GATE_1_GRAY_ACTIVE,
2755 EL_EM_GATE_2_GRAY_ACTIVE,
2756 EL_EM_GATE_3_GRAY_ACTIVE,
2757 EL_EM_GATE_4_GRAY_ACTIVE,
2764 EL_EXPANDABLE_WALL_HORIZONTAL,
2765 EL_EXPANDABLE_WALL_VERTICAL,
2766 EL_EXPANDABLE_WALL_ANY,
2767 EL_EXPANDABLE_WALL_GROWING,
2774 EL_SP_HARDWARE_GRAY,
2775 EL_SP_HARDWARE_GREEN,
2776 EL_SP_HARDWARE_BLUE,
2778 EL_SP_HARDWARE_YELLOW,
2779 EL_SP_HARDWARE_BASE_1,
2780 EL_SP_HARDWARE_BASE_2,
2781 EL_SP_HARDWARE_BASE_3,
2782 EL_SP_HARDWARE_BASE_4,
2783 EL_SP_HARDWARE_BASE_5,
2784 EL_SP_HARDWARE_BASE_6,
2786 EL_SP_TERMINAL_ACTIVE,
2789 EL_INVISIBLE_STEELWALL,
2790 EL_INVISIBLE_STEELWALL_ACTIVE,
2792 EL_INVISIBLE_WALL_ACTIVE,
2793 EL_STEELWALL_SLIPPERY,
2809 static int ep_historic_solid[] =
2813 EL_EXPANDABLE_WALL_HORIZONTAL,
2814 EL_EXPANDABLE_WALL_VERTICAL,
2815 EL_EXPANDABLE_WALL_ANY,
2828 EL_QUICKSAND_FILLING,
2829 EL_QUICKSAND_EMPTYING,
2831 EL_MAGIC_WALL_ACTIVE,
2832 EL_MAGIC_WALL_EMPTYING,
2833 EL_MAGIC_WALL_FILLING,
2837 EL_BD_MAGIC_WALL_ACTIVE,
2838 EL_BD_MAGIC_WALL_EMPTYING,
2839 EL_BD_MAGIC_WALL_FULL,
2840 EL_BD_MAGIC_WALL_FILLING,
2841 EL_BD_MAGIC_WALL_DEAD,
2850 EL_SP_TERMINAL_ACTIVE,
2854 EL_INVISIBLE_WALL_ACTIVE,
2855 EL_SWITCHGATE_SWITCH_UP,
2856 EL_SWITCHGATE_SWITCH_DOWN,
2858 EL_TIMEGATE_SWITCH_ACTIVE,
2870 /* the following elements are a direct copy of "indestructible" elements,
2871 except "EL_ACID", which is "indestructible", but not "solid"! */
2876 EL_ACID_POOL_TOPLEFT,
2877 EL_ACID_POOL_TOPRIGHT,
2878 EL_ACID_POOL_BOTTOMLEFT,
2879 EL_ACID_POOL_BOTTOM,
2880 EL_ACID_POOL_BOTTOMRIGHT,
2881 EL_SP_HARDWARE_GRAY,
2882 EL_SP_HARDWARE_GREEN,
2883 EL_SP_HARDWARE_BLUE,
2885 EL_SP_HARDWARE_YELLOW,
2886 EL_SP_HARDWARE_BASE_1,
2887 EL_SP_HARDWARE_BASE_2,
2888 EL_SP_HARDWARE_BASE_3,
2889 EL_SP_HARDWARE_BASE_4,
2890 EL_SP_HARDWARE_BASE_5,
2891 EL_SP_HARDWARE_BASE_6,
2892 EL_INVISIBLE_STEELWALL,
2893 EL_INVISIBLE_STEELWALL_ACTIVE,
2894 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2895 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2896 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2897 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2898 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2899 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2900 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2901 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2902 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2903 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2904 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2905 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2907 EL_LIGHT_SWITCH_ACTIVE,
2908 EL_SIGN_EXCLAMATION,
2909 EL_SIGN_RADIOACTIVITY,
2920 EL_STEELWALL_SLIPPERY,
2934 EL_GATE_1_GRAY_ACTIVE,
2935 EL_GATE_2_GRAY_ACTIVE,
2936 EL_GATE_3_GRAY_ACTIVE,
2937 EL_GATE_4_GRAY_ACTIVE,
2946 EL_EM_GATE_1_GRAY_ACTIVE,
2947 EL_EM_GATE_2_GRAY_ACTIVE,
2948 EL_EM_GATE_3_GRAY_ACTIVE,
2949 EL_EM_GATE_4_GRAY_ACTIVE,
2951 EL_SWITCHGATE_OPENING,
2952 EL_SWITCHGATE_CLOSED,
2953 EL_SWITCHGATE_CLOSING,
2955 EL_TIMEGATE_OPENING,
2957 EL_TIMEGATE_CLOSING,
2961 EL_TUBE_VERTICAL_LEFT,
2962 EL_TUBE_VERTICAL_RIGHT,
2963 EL_TUBE_HORIZONTAL_UP,
2964 EL_TUBE_HORIZONTAL_DOWN,
2972 static int ep_classic_enemy[] =
2988 static int ep_belt[] =
2990 EL_CONVEYOR_BELT_1_LEFT,
2991 EL_CONVEYOR_BELT_1_MIDDLE,
2992 EL_CONVEYOR_BELT_1_RIGHT,
2993 EL_CONVEYOR_BELT_2_LEFT,
2994 EL_CONVEYOR_BELT_2_MIDDLE,
2995 EL_CONVEYOR_BELT_2_RIGHT,
2996 EL_CONVEYOR_BELT_3_LEFT,
2997 EL_CONVEYOR_BELT_3_MIDDLE,
2998 EL_CONVEYOR_BELT_3_RIGHT,
2999 EL_CONVEYOR_BELT_4_LEFT,
3000 EL_CONVEYOR_BELT_4_MIDDLE,
3001 EL_CONVEYOR_BELT_4_RIGHT,
3005 static int ep_belt_active[] =
3007 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3008 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3009 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3010 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3011 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3012 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3013 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3014 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3015 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3016 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3017 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3018 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3022 static int ep_belt_switch[] =
3024 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3025 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3026 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3027 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3028 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3029 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3030 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3031 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3032 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3033 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3034 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3035 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3039 static int ep_tube[] =
3046 EL_TUBE_HORIZONTAL_UP,
3047 EL_TUBE_HORIZONTAL_DOWN,
3049 EL_TUBE_VERTICAL_LEFT,
3050 EL_TUBE_VERTICAL_RIGHT,
3055 static int ep_keygate[] =
3065 EL_GATE_1_GRAY_ACTIVE,
3066 EL_GATE_2_GRAY_ACTIVE,
3067 EL_GATE_3_GRAY_ACTIVE,
3068 EL_GATE_4_GRAY_ACTIVE,
3077 EL_EM_GATE_1_GRAY_ACTIVE,
3078 EL_EM_GATE_2_GRAY_ACTIVE,
3079 EL_EM_GATE_3_GRAY_ACTIVE,
3080 EL_EM_GATE_4_GRAY_ACTIVE,
3089 EL_EMC_GATE_5_GRAY_ACTIVE,
3090 EL_EMC_GATE_6_GRAY_ACTIVE,
3091 EL_EMC_GATE_7_GRAY_ACTIVE,
3092 EL_EMC_GATE_8_GRAY_ACTIVE,
3096 static int ep_amoeboid[] =
3106 static int ep_amoebalive[] =
3115 static int ep_has_content[] =
3125 static int ep_can_turn_each_move[] =
3127 /* !!! do something with this one !!! */
3131 static int ep_can_grow[] =
3143 static int ep_active_bomb[] =
3146 EL_DYNABOMB_PLAYER_1_ACTIVE,
3147 EL_DYNABOMB_PLAYER_2_ACTIVE,
3148 EL_DYNABOMB_PLAYER_3_ACTIVE,
3149 EL_DYNABOMB_PLAYER_4_ACTIVE,
3150 EL_SP_DISK_RED_ACTIVE,
3154 static int ep_inactive[] =
3186 EL_GATE_1_GRAY_ACTIVE,
3187 EL_GATE_2_GRAY_ACTIVE,
3188 EL_GATE_3_GRAY_ACTIVE,
3189 EL_GATE_4_GRAY_ACTIVE,
3198 EL_EM_GATE_1_GRAY_ACTIVE,
3199 EL_EM_GATE_2_GRAY_ACTIVE,
3200 EL_EM_GATE_3_GRAY_ACTIVE,
3201 EL_EM_GATE_4_GRAY_ACTIVE,
3210 EL_EMC_GATE_5_GRAY_ACTIVE,
3211 EL_EMC_GATE_6_GRAY_ACTIVE,
3212 EL_EMC_GATE_7_GRAY_ACTIVE,
3213 EL_EMC_GATE_8_GRAY_ACTIVE,
3215 EL_INVISIBLE_STEELWALL,
3223 EL_WALL_EMERALD_YELLOW,
3224 EL_DYNABOMB_INCREASE_NUMBER,
3225 EL_DYNABOMB_INCREASE_SIZE,
3226 EL_DYNABOMB_INCREASE_POWER,
3230 EL_SOKOBAN_FIELD_EMPTY,
3231 EL_SOKOBAN_FIELD_FULL,
3232 EL_WALL_EMERALD_RED,
3233 EL_WALL_EMERALD_PURPLE,
3234 EL_ACID_POOL_TOPLEFT,
3235 EL_ACID_POOL_TOPRIGHT,
3236 EL_ACID_POOL_BOTTOMLEFT,
3237 EL_ACID_POOL_BOTTOM,
3238 EL_ACID_POOL_BOTTOMRIGHT,
3242 EL_BD_MAGIC_WALL_DEAD,
3243 EL_AMOEBA_TO_DIAMOND,
3251 EL_SP_GRAVITY_PORT_RIGHT,
3252 EL_SP_GRAVITY_PORT_DOWN,
3253 EL_SP_GRAVITY_PORT_LEFT,
3254 EL_SP_GRAVITY_PORT_UP,
3255 EL_SP_PORT_HORIZONTAL,
3256 EL_SP_PORT_VERTICAL,
3267 EL_SP_HARDWARE_GRAY,
3268 EL_SP_HARDWARE_GREEN,
3269 EL_SP_HARDWARE_BLUE,
3271 EL_SP_HARDWARE_YELLOW,
3272 EL_SP_HARDWARE_BASE_1,
3273 EL_SP_HARDWARE_BASE_2,
3274 EL_SP_HARDWARE_BASE_3,
3275 EL_SP_HARDWARE_BASE_4,
3276 EL_SP_HARDWARE_BASE_5,
3277 EL_SP_HARDWARE_BASE_6,
3278 EL_SP_GRAVITY_ON_PORT_LEFT,
3279 EL_SP_GRAVITY_ON_PORT_RIGHT,
3280 EL_SP_GRAVITY_ON_PORT_UP,
3281 EL_SP_GRAVITY_ON_PORT_DOWN,
3282 EL_SP_GRAVITY_OFF_PORT_LEFT,
3283 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3284 EL_SP_GRAVITY_OFF_PORT_UP,
3285 EL_SP_GRAVITY_OFF_PORT_DOWN,
3286 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3287 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3288 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3289 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3290 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3291 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3292 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3293 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3294 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3295 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3296 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3297 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3298 EL_SIGN_EXCLAMATION,
3299 EL_SIGN_RADIOACTIVITY,
3310 EL_STEELWALL_SLIPPERY,
3315 EL_EMC_WALL_SLIPPERY_1,
3316 EL_EMC_WALL_SLIPPERY_2,
3317 EL_EMC_WALL_SLIPPERY_3,
3318 EL_EMC_WALL_SLIPPERY_4,
3338 static int ep_em_slippery_wall[] =
3343 static int ep_gfx_crumbled[] =
3356 } element_properties[] =
3358 { ep_diggable, EP_DIGGABLE },
3359 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3360 { ep_dont_run_into, EP_DONT_RUN_INTO },
3361 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3362 { ep_dont_touch, EP_DONT_TOUCH },
3363 { ep_indestructible, EP_INDESTRUCTIBLE },
3364 { ep_slippery, EP_SLIPPERY },
3365 { ep_can_change, EP_CAN_CHANGE },
3366 { ep_can_move, EP_CAN_MOVE },
3367 { ep_can_fall, EP_CAN_FALL },
3368 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3369 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3370 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3371 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3372 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3373 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3374 { ep_walkable_over, EP_WALKABLE_OVER },
3375 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3376 { ep_walkable_under, EP_WALKABLE_UNDER },
3377 { ep_passable_over, EP_PASSABLE_OVER },
3378 { ep_passable_inside, EP_PASSABLE_INSIDE },
3379 { ep_passable_under, EP_PASSABLE_UNDER },
3380 { ep_droppable, EP_DROPPABLE },
3381 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3382 { ep_pushable, EP_PUSHABLE },
3383 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3384 { ep_protected, EP_PROTECTED },
3385 { ep_throwable, EP_THROWABLE },
3386 { ep_can_explode, EP_CAN_EXPLODE },
3387 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3389 { ep_player, EP_PLAYER },
3390 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3391 { ep_switchable, EP_SWITCHABLE },
3392 { ep_bd_element, EP_BD_ELEMENT },
3393 { ep_sp_element, EP_SP_ELEMENT },
3394 { ep_sb_element, EP_SB_ELEMENT },
3396 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3397 { ep_food_penguin, EP_FOOD_PENGUIN },
3398 { ep_food_pig, EP_FOOD_PIG },
3399 { ep_historic_wall, EP_HISTORIC_WALL },
3400 { ep_historic_solid, EP_HISTORIC_SOLID },
3401 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3402 { ep_belt, EP_BELT },
3403 { ep_belt_active, EP_BELT_ACTIVE },
3404 { ep_belt_switch, EP_BELT_SWITCH },
3405 { ep_tube, EP_TUBE },
3406 { ep_keygate, EP_KEYGATE },
3407 { ep_amoeboid, EP_AMOEBOID },
3408 { ep_amoebalive, EP_AMOEBALIVE },
3409 { ep_has_content, EP_HAS_CONTENT },
3410 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3411 { ep_can_grow, EP_CAN_GROW },
3412 { ep_active_bomb, EP_ACTIVE_BOMB },
3413 { ep_inactive, EP_INACTIVE },
3415 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3417 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3424 /* always start with reliable default values (element has no properties) */
3425 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3426 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3427 SET_PROPERTY(i, j, FALSE);
3429 /* set all base element properties from above array definitions */
3430 for (i = 0; element_properties[i].elements != NULL; i++)
3431 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3432 SET_PROPERTY((element_properties[i].elements)[j],
3433 element_properties[i].property, TRUE);
3435 /* copy properties to some elements that are only stored in level file */
3436 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3437 for (j = 0; copy_properties[j][0] != -1; j++)
3438 if (HAS_PROPERTY(copy_properties[j][0], i))
3439 for (k = 1; k <= 4; k++)
3440 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3443 void InitElementPropertiesEngine(int engine_version)
3445 static int no_wall_properties[] =
3448 EP_COLLECTIBLE_ONLY,
3450 EP_DONT_COLLIDE_WITH,
3453 EP_CAN_SMASH_PLAYER,
3454 EP_CAN_SMASH_ENEMIES,
3455 EP_CAN_SMASH_EVERYTHING,
3460 EP_FOOD_DARK_YAMYAM,
3476 /* important: after initialization in InitElementPropertiesStatic(), the
3477 elements are not again initialized to a default value; therefore all
3478 changes have to make sure that they leave the element with a defined
3479 property (which means that conditional property changes must be set to
3480 a reliable default value before) */
3482 /* set all special, combined or engine dependent element properties */
3483 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3485 /* ---------- INACTIVE ------------------------------------------------- */
3486 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3488 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3489 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3490 IS_WALKABLE_INSIDE(i) ||
3491 IS_WALKABLE_UNDER(i)));
3493 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3494 IS_PASSABLE_INSIDE(i) ||
3495 IS_PASSABLE_UNDER(i)));
3497 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3498 IS_PASSABLE_OVER(i)));
3500 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3501 IS_PASSABLE_INSIDE(i)));
3503 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3504 IS_PASSABLE_UNDER(i)));
3506 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3509 /* ---------- COLLECTIBLE ---------------------------------------------- */
3510 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3514 /* ---------- SNAPPABLE ------------------------------------------------ */
3515 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3516 IS_COLLECTIBLE(i) ||
3520 /* ---------- WALL ----------------------------------------------------- */
3521 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3523 for (j = 0; no_wall_properties[j] != -1; j++)
3524 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3525 i >= EL_FIRST_RUNTIME_UNREAL)
3526 SET_PROPERTY(i, EP_WALL, FALSE);
3528 if (IS_HISTORIC_WALL(i))
3529 SET_PROPERTY(i, EP_WALL, TRUE);
3531 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3532 if (engine_version < VERSION_IDENT(2,2,0,0))
3533 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3535 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3537 !IS_COLLECTIBLE(i)));
3539 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3541 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3542 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3544 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3545 IS_INDESTRUCTIBLE(i)));
3547 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3549 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3550 else if (engine_version < VERSION_IDENT(2,2,0,0))
3551 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3553 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3557 if (IS_CUSTOM_ELEMENT(i))
3559 /* these are additional properties which are initially false when set */
3561 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3563 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3564 if (DONT_COLLIDE_WITH(i))
3565 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3567 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3568 if (CAN_SMASH_EVERYTHING(i))
3569 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3570 if (CAN_SMASH_ENEMIES(i))
3571 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3574 /* ---------- CAN_SMASH ------------------------------------------------ */
3575 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3576 CAN_SMASH_ENEMIES(i) ||
3577 CAN_SMASH_EVERYTHING(i)));
3579 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3580 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3581 EXPLODES_BY_FIRE(i)));
3583 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3584 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3585 EXPLODES_SMASHED(i)));
3587 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3588 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3589 EXPLODES_IMPACT(i)));
3591 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3592 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3594 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3595 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3596 i == EL_BLACK_ORB));
3598 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3599 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3601 IS_CUSTOM_ELEMENT(i)));
3603 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3604 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3605 i == EL_SP_ELECTRON));
3607 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3608 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3609 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3610 getMoveIntoAcidProperty(&level, i));
3612 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3613 if (MAYBE_DONT_COLLIDE_WITH(i))
3614 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3615 getDontCollideWithProperty(&level, i));
3617 /* ---------- SP_PORT -------------------------------------------------- */
3618 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3619 IS_PASSABLE_INSIDE(i)));
3621 /* ---------- CAN_CHANGE ----------------------------------------------- */
3622 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3623 for (j = 0; j < element_info[i].num_change_pages; j++)
3624 if (element_info[i].change_page[j].can_change)
3625 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3627 /* ---------- HAS_ACTION ----------------------------------------------- */
3628 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3629 for (j = 0; j < element_info[i].num_change_pages; j++)
3630 if (element_info[i].change_page[j].has_action)
3631 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3633 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3634 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3637 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3639 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3640 element_info[i].crumbled[ACTION_DEFAULT] !=
3641 element_info[i].graphic[ACTION_DEFAULT]);
3643 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3644 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3645 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3649 /* dynamically adjust element properties according to game engine version */
3651 static int ep_em_slippery_wall[] =
3656 EL_EXPANDABLE_WALL_HORIZONTAL,
3657 EL_EXPANDABLE_WALL_VERTICAL,
3658 EL_EXPANDABLE_WALL_ANY,
3662 /* special EM style gems behaviour */
3663 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3664 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3665 level.em_slippery_gems);
3667 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3668 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3669 (level.em_slippery_gems &&
3670 engine_version > VERSION_IDENT(2,0,1,0)));
3673 /* set default push delay values (corrected since version 3.0.7-1) */
3674 if (engine_version < VERSION_IDENT(3,0,7,1))
3676 game.default_push_delay_fixed = 2;
3677 game.default_push_delay_random = 8;
3681 game.default_push_delay_fixed = 8;
3682 game.default_push_delay_random = 8;
3685 /* set uninitialized push delay values of custom elements in older levels */
3686 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3688 int element = EL_CUSTOM_START + i;
3690 if (element_info[element].push_delay_fixed == -1)
3691 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3692 if (element_info[element].push_delay_random == -1)
3693 element_info[element].push_delay_random = game.default_push_delay_random;
3696 /* set some other uninitialized values of custom elements in older levels */
3697 if (engine_version < VERSION_IDENT(3,1,0,0))
3699 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3701 int element = EL_CUSTOM_START + i;
3703 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3705 element_info[element].explosion_delay = 17;
3706 element_info[element].ignition_delay = 8;
3711 /* set element properties that were handled incorrectly in older levels */
3712 if (engine_version < VERSION_IDENT(3,1,0,0))
3714 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3715 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3719 /* this is needed because some graphics depend on element properties */
3720 if (game_status == GAME_MODE_PLAYING)
3721 InitElementGraphicInfo();
3724 static void InitGlobal()
3728 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3730 /* check if element_name_info entry defined for each element in "main.h" */
3731 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3732 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3734 element_info[i].token_name = element_name_info[i].token_name;
3735 element_info[i].class_name = element_name_info[i].class_name;
3736 element_info[i].editor_description=element_name_info[i].editor_description;
3739 global.autoplay_leveldir = NULL;
3740 global.convert_leveldir = NULL;
3742 global.frames_per_second = 0;
3743 global.fps_slowdown = FALSE;
3744 global.fps_slowdown_factor = 1;
3747 void Execute_Command(char *command)
3751 if (strcmp(command, "print graphicsinfo.conf") == 0)
3753 printf("# You can configure additional/alternative image files here.\n");
3754 printf("# (The entries below are default and therefore commented out.)\n");
3756 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3758 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3761 for (i = 0; image_config[i].token != NULL; i++)
3762 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3763 image_config[i].value));
3767 else if (strcmp(command, "print soundsinfo.conf") == 0)
3769 printf("# You can configure additional/alternative sound files here.\n");
3770 printf("# (The entries below are default and therefore commented out.)\n");
3772 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3774 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3777 for (i = 0; sound_config[i].token != NULL; i++)
3778 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3779 sound_config[i].value));
3783 else if (strcmp(command, "print musicinfo.conf") == 0)
3785 printf("# You can configure additional/alternative music files here.\n");
3786 printf("# (The entries below are default and therefore commented out.)\n");
3788 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3790 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3793 for (i = 0; music_config[i].token != NULL; i++)
3794 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3795 music_config[i].value));
3799 else if (strcmp(command, "print editorsetup.conf") == 0)
3801 printf("# You can configure your personal editor element list here.\n");
3802 printf("# (The entries below are default and therefore commented out.)\n");
3805 PrintEditorElementList();
3809 else if (strcmp(command, "print helpanim.conf") == 0)
3811 printf("# You can configure different element help animations here.\n");
3812 printf("# (The entries below are default and therefore commented out.)\n");
3815 for (i = 0; helpanim_config[i].token != NULL; i++)
3817 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3818 helpanim_config[i].value));
3820 if (strcmp(helpanim_config[i].token, "end") == 0)
3826 else if (strcmp(command, "print helptext.conf") == 0)
3828 printf("# You can configure different element help text here.\n");
3829 printf("# (The entries below are default and therefore commented out.)\n");
3832 for (i = 0; helptext_config[i].token != NULL; i++)
3833 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3834 helptext_config[i].value));
3838 else if (strncmp(command, "dump level ", 11) == 0)
3840 char *filename = &command[11];
3842 if (!fileExists(filename))
3843 Error(ERR_EXIT, "cannot open file '%s'", filename);
3845 LoadLevelFromFilename(&level, filename);
3850 else if (strncmp(command, "dump tape ", 10) == 0)
3852 char *filename = &command[10];
3854 if (!fileExists(filename))
3855 Error(ERR_EXIT, "cannot open file '%s'", filename);
3857 LoadTapeFromFilename(filename);
3862 else if (strncmp(command, "autoplay ", 9) == 0)
3864 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3866 while (*str_ptr != '\0') /* continue parsing string */
3868 /* cut leading whitespace from string, replace it by string terminator */
3869 while (*str_ptr == ' ' || *str_ptr == '\t')
3872 if (*str_ptr == '\0') /* end of string reached */
3875 if (global.autoplay_leveldir == NULL) /* read level set string */
3877 global.autoplay_leveldir = str_ptr;
3878 global.autoplay_all = TRUE; /* default: play all tapes */
3880 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3881 global.autoplay_level[i] = FALSE;
3883 else /* read level number string */
3885 int level_nr = atoi(str_ptr); /* get level_nr value */
3887 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3888 global.autoplay_level[level_nr] = TRUE;
3890 global.autoplay_all = FALSE;
3893 /* advance string pointer to the next whitespace (or end of string) */
3894 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3898 else if (strncmp(command, "convert ", 8) == 0)
3900 char *str_copy = getStringCopy(&command[8]);
3901 char *str_ptr = strchr(str_copy, ' ');
3903 global.convert_leveldir = str_copy;
3904 global.convert_level_nr = -1;
3906 if (str_ptr != NULL) /* level number follows */
3908 *str_ptr++ = '\0'; /* terminate leveldir string */
3909 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3914 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3918 static void InitSetup()
3920 LoadSetup(); /* global setup info */
3922 /* set some options from setup file */
3924 if (setup.options.verbose)
3925 options.verbose = TRUE;
3928 static void InitGameInfo()
3930 game.restart_level = FALSE;
3933 static void InitPlayerInfo()
3937 /* choose default local player */
3938 local_player = &stored_player[0];
3940 for (i = 0; i < MAX_PLAYERS; i++)
3941 stored_player[i].connected = FALSE;
3943 local_player->connected = TRUE;
3946 static void InitArtworkInfo()
3951 static char *get_string_in_brackets(char *string)
3953 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3955 sprintf(string_in_brackets, "[%s]", string);
3957 return string_in_brackets;
3960 static char *get_level_id_suffix(int id_nr)
3962 char *id_suffix = checked_malloc(1 + 3 + 1);
3964 if (id_nr < 0 || id_nr > 999)
3967 sprintf(id_suffix, ".%03d", id_nr);
3973 static char *get_element_class_token(int element)
3975 char *element_class_name = element_info[element].class_name;
3976 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3978 sprintf(element_class_token, "[%s]", element_class_name);
3980 return element_class_token;
3983 static char *get_action_class_token(int action)
3985 char *action_class_name = &element_action_info[action].suffix[1];
3986 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3988 sprintf(action_class_token, "[%s]", action_class_name);
3990 return action_class_token;
3994 static void InitArtworkConfig()
3996 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3997 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3998 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3999 static char *action_id_suffix[NUM_ACTIONS + 1];
4000 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4001 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4002 static char *level_id_suffix[MAX_LEVELS + 1];
4003 static char *dummy[1] = { NULL };
4004 static char *ignore_generic_tokens[] =
4010 static char **ignore_image_tokens;
4011 static char **ignore_sound_tokens;
4012 static char **ignore_music_tokens;
4013 int num_ignore_generic_tokens;
4014 int num_ignore_image_tokens;
4015 int num_ignore_sound_tokens;
4016 int num_ignore_music_tokens;
4019 /* dynamically determine list of generic tokens to be ignored */
4020 num_ignore_generic_tokens = 0;
4021 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4022 num_ignore_generic_tokens++;
4024 /* dynamically determine list of image tokens to be ignored */
4025 num_ignore_image_tokens = num_ignore_generic_tokens;
4026 for (i = 0; image_config_vars[i].token != NULL; i++)
4027 num_ignore_image_tokens++;
4028 ignore_image_tokens =
4029 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4030 for (i = 0; i < num_ignore_generic_tokens; i++)
4031 ignore_image_tokens[i] = ignore_generic_tokens[i];
4032 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4033 ignore_image_tokens[num_ignore_generic_tokens + i] =
4034 image_config_vars[i].token;
4035 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4037 /* dynamically determine list of sound tokens to be ignored */
4038 num_ignore_sound_tokens = num_ignore_generic_tokens;
4039 ignore_sound_tokens =
4040 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4041 for (i = 0; i < num_ignore_generic_tokens; i++)
4042 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4043 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4045 /* dynamically determine list of music tokens to be ignored */
4046 num_ignore_music_tokens = num_ignore_generic_tokens;
4047 ignore_music_tokens =
4048 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4049 for (i = 0; i < num_ignore_generic_tokens; i++)
4050 ignore_music_tokens[i] = ignore_generic_tokens[i];
4051 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4054 image_id_prefix[i] = element_info[i].token_name;
4055 for (i = 0; i < NUM_FONTS; i++)
4056 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4057 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4059 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4060 sound_id_prefix[i] = element_info[i].token_name;
4061 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4062 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4063 get_string_in_brackets(element_info[i].class_name);
4064 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4066 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4067 music_id_prefix[i] = music_prefix_info[i].prefix;
4068 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4070 for (i = 0; i < NUM_ACTIONS; i++)
4071 action_id_suffix[i] = element_action_info[i].suffix;
4072 action_id_suffix[NUM_ACTIONS] = NULL;
4074 for (i = 0; i < NUM_DIRECTIONS; i++)
4075 direction_id_suffix[i] = element_direction_info[i].suffix;
4076 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4078 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4079 special_id_suffix[i] = special_suffix_info[i].suffix;
4080 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4082 for (i = 0; i < MAX_LEVELS; i++)
4083 level_id_suffix[i] = get_level_id_suffix(i);
4084 level_id_suffix[MAX_LEVELS] = NULL;
4086 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4087 image_id_prefix, action_id_suffix, direction_id_suffix,
4088 special_id_suffix, ignore_image_tokens);
4089 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4090 sound_id_prefix, action_id_suffix, dummy,
4091 special_id_suffix, ignore_sound_tokens);
4092 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4093 music_id_prefix, special_id_suffix, level_id_suffix,
4094 dummy, ignore_music_tokens);
4097 static void InitMixer()
4105 char *filename_font_initial = NULL;
4106 Bitmap *bitmap_font_initial = NULL;
4109 /* determine settings for initial font (for displaying startup messages) */
4110 for (i = 0; image_config[i].token != NULL; i++)
4112 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4114 char font_token[128];
4117 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4118 len_font_token = strlen(font_token);
4120 if (strcmp(image_config[i].token, font_token) == 0)
4121 filename_font_initial = image_config[i].value;
4122 else if (strlen(image_config[i].token) > len_font_token &&
4123 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4125 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4126 font_initial[j].src_x = atoi(image_config[i].value);
4127 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4128 font_initial[j].src_y = atoi(image_config[i].value);
4129 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4130 font_initial[j].width = atoi(image_config[i].value);
4131 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4132 font_initial[j].height = atoi(image_config[i].value);
4137 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4139 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4140 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4143 if (filename_font_initial == NULL) /* should not happen */
4144 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4146 /* create additional image buffers for double-buffering */
4147 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4148 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4150 /* initialize screen properties */
4151 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4152 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4154 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4155 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4156 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4158 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4160 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4161 font_initial[j].bitmap = bitmap_font_initial;
4163 InitFontGraphicInfo();
4165 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4166 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4168 DrawInitText("Loading graphics:", 120, FC_GREEN);
4171 void InitGfxBackground()
4175 drawto = backbuffer;
4176 fieldbuffer = bitmap_db_field;
4177 SetDrawtoField(DRAW_BACKBUFFER);
4179 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4180 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4181 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4182 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4184 for (x = 0; x < MAX_BUF_XSIZE; x++)
4185 for (y = 0; y < MAX_BUF_YSIZE; y++)
4188 redraw_mask = REDRAW_ALL;
4191 static void InitLevelInfo()
4193 LoadLevelInfo(); /* global level info */
4194 LoadLevelSetup_LastSeries(); /* last played series info */
4195 LoadLevelSetup_SeriesInfo(); /* last played level info */
4198 void InitLevelArtworkInfo()
4200 LoadLevelArtworkInfo();
4203 static void InitImages()
4205 setLevelArtworkDir(artwork.gfx_first);
4208 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4209 leveldir_current->identifier,
4210 artwork.gfx_current_identifier,
4211 artwork.gfx_current->identifier,
4212 leveldir_current->graphics_set,
4213 leveldir_current->graphics_path);
4216 ReloadCustomImages();
4218 LoadCustomElementDescriptions();
4219 LoadSpecialMenuDesignSettings();
4221 ReinitializeGraphics();
4224 static void InitSound(char *identifier)
4226 if (identifier == NULL)
4227 identifier = artwork.snd_current->identifier;
4229 /* set artwork path to send it to the sound server process */
4230 setLevelArtworkDir(artwork.snd_first);
4232 InitReloadCustomSounds(identifier);
4233 ReinitializeSounds();
4236 static void InitMusic(char *identifier)
4238 if (identifier == NULL)
4239 identifier = artwork.mus_current->identifier;
4241 /* set artwork path to send it to the sound server process */
4242 setLevelArtworkDir(artwork.mus_first);
4244 InitReloadCustomMusic(identifier);
4245 ReinitializeMusic();
4248 void InitNetworkServer()
4250 #if defined(NETWORK_AVALIABLE)
4254 if (!options.network)
4257 #if defined(NETWORK_AVALIABLE)
4258 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4260 if (!ConnectToServer(options.server_host, options.server_port))
4261 Error(ERR_EXIT, "cannot connect to network game server");
4263 SendToServer_PlayerName(setup.player_name);
4264 SendToServer_ProtocolVersion();
4267 SendToServer_NrWanted(nr_wanted);
4271 static char *getNewArtworkIdentifier(int type)
4273 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4274 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4275 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4276 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4277 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4278 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4279 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4280 char *leveldir_identifier = leveldir_current->identifier;
4282 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4283 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4285 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4287 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4288 char *artwork_current_identifier;
4289 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4291 /* leveldir_current may be invalid (level group, parent link) */
4292 if (!validLevelSeries(leveldir_current))
4295 /* 1st step: determine artwork set to be activated in descending order:
4296 --------------------------------------------------------------------
4297 1. setup artwork (when configured to override everything else)
4298 2. artwork set configured in "levelinfo.conf" of current level set
4299 (artwork in level directory will have priority when loading later)
4300 3. artwork in level directory (stored in artwork sub-directory)
4301 4. setup artwork (currently configured in setup menu) */
4303 if (setup_override_artwork)
4304 artwork_current_identifier = setup_artwork_set;
4305 else if (leveldir_artwork_set != NULL)
4306 artwork_current_identifier = leveldir_artwork_set;
4307 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4308 artwork_current_identifier = leveldir_identifier;
4310 artwork_current_identifier = setup_artwork_set;
4313 /* 2nd step: check if it is really needed to reload artwork set
4314 ------------------------------------------------------------ */
4317 if (type == ARTWORK_TYPE_GRAPHICS)
4318 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4319 artwork_new_identifier,
4320 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4321 artwork_current_identifier,
4322 leveldir_current->graphics_set,
4323 leveldir_current->identifier);
4326 /* ---------- reload if level set and also artwork set has changed ------- */
4327 if (leveldir_current_identifier[type] != leveldir_identifier &&
4328 (last_has_level_artwork_set[type] || has_level_artwork_set))
4329 artwork_new_identifier = artwork_current_identifier;
4331 leveldir_current_identifier[type] = leveldir_identifier;
4332 last_has_level_artwork_set[type] = has_level_artwork_set;
4335 if (type == ARTWORK_TYPE_GRAPHICS)
4336 printf("::: 1: '%s'\n", artwork_new_identifier);
4339 /* ---------- reload if "override artwork" setting has changed ----------- */
4340 if (last_override_level_artwork[type] != setup_override_artwork)
4341 artwork_new_identifier = artwork_current_identifier;
4343 last_override_level_artwork[type] = setup_override_artwork;
4346 if (type == ARTWORK_TYPE_GRAPHICS)
4347 printf("::: 2: '%s'\n", artwork_new_identifier);
4350 /* ---------- reload if current artwork identifier has changed ----------- */
4351 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4352 artwork_current_identifier) != 0)
4353 artwork_new_identifier = artwork_current_identifier;
4355 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4358 if (type == ARTWORK_TYPE_GRAPHICS)
4359 printf("::: 3: '%s'\n", artwork_new_identifier);
4362 /* ---------- do not reload directly after starting ---------------------- */
4363 if (!initialized[type])
4364 artwork_new_identifier = NULL;
4366 initialized[type] = TRUE;
4369 if (type == ARTWORK_TYPE_GRAPHICS)
4370 printf("::: 4: '%s'\n", artwork_new_identifier);
4374 if (type == ARTWORK_TYPE_GRAPHICS)
4375 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4376 artwork.gfx_current_identifier, artwork_current_identifier,
4377 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4378 artwork_new_identifier);
4381 return artwork_new_identifier;
4384 void ReloadCustomArtwork(int force_reload)
4386 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4387 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4388 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4389 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4390 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4391 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4392 boolean redraw_screen = FALSE;
4394 if (gfx_new_identifier != NULL || force_reload_gfx)
4397 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4398 artwork.gfx_current_identifier,
4400 artwork.gfx_current->identifier,
4401 leveldir_current->graphics_set);
4404 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4408 redraw_screen = TRUE;
4411 if (snd_new_identifier != NULL || force_reload_snd)
4413 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4415 InitSound(snd_new_identifier);
4417 redraw_screen = TRUE;
4420 if (mus_new_identifier != NULL || force_reload_mus)
4422 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4424 InitMusic(mus_new_identifier);
4426 redraw_screen = TRUE;
4431 InitGfxBackground();
4433 /* force redraw of (open or closed) door graphics */
4434 SetDoorState(DOOR_OPEN_ALL);
4435 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4439 void KeyboardAutoRepeatOffUnlessAutoplay()
4441 if (global.autoplay_leveldir == NULL)
4442 KeyboardAutoRepeatOff();
4446 /* ========================================================================= */
4448 /* ========================================================================= */
4452 InitGlobal(); /* initialize some global variables */
4454 if (options.execute_command)
4455 Execute_Command(options.execute_command);
4457 if (options.serveronly)
4459 #if defined(PLATFORM_UNIX)
4460 NetworkServer(options.server_port, options.serveronly);
4462 Error(ERR_WARN, "networking only supported in Unix version");
4465 exit(0); /* never reached, server loops forever */
4472 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4473 InitArtworkConfig(); /* needed before forking sound child process */
4478 InitRND(NEW_RANDOMIZE);
4479 InitSimpleRND(NEW_RANDOMIZE);
4484 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4487 InitEventFilter(FilterMouseMotionEvents);
4489 InitElementPropertiesStatic();
4490 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4495 InitLevelArtworkInfo();
4497 InitImages(); /* needs to know current level directory */
4498 InitSound(NULL); /* needs to know current level directory */
4499 InitMusic(NULL); /* needs to know current level directory */
4501 InitGfxBackground();
4503 if (global.autoplay_leveldir)
4508 else if (global.convert_leveldir)
4514 game_status = GAME_MODE_MAIN;
4522 InitNetworkServer();
4525 void CloseAllAndExit(int exit_value)
4530 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4538 #if defined(TARGET_SDL)
4539 if (network_server) /* terminate network server */
4540 SDL_KillThread(server_thread);
4543 CloseVideoDisplay();
4544 ClosePlatformDependentStuff();