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;
207 font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
210 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
213 boolean base_redefined =
214 getImageListEntryFromImageID(base_graphic)->redefined;
215 boolean special_redefined =
216 getImageListEntryFromImageID(graphic)->redefined;
218 /* if the base font ("font.title_1", for example) has been redefined,
219 but not the special font ("font.title_1.LEVELS", for example), do not
220 use an existing (in this case considered obsolete) special font
221 anymore, but use the automatically determined default font */
222 if (base_redefined && !special_redefined)
226 font_info[font_nr].special_graphic[special] = graphic;
227 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
232 /* initialize special element/graphic mapping from dynamic configuration */
233 for (i = 0; i < num_property_mappings; i++)
235 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
236 int special = property_mapping[i].ext3_index;
237 int graphic = property_mapping[i].artwork_index;
242 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
244 font_info[font_nr].special_graphic[special] = graphic;
245 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
250 /* ---------- initialize font bitmap array ---------- */
252 if (font_bitmap_info != NULL)
253 FreeFontInfo(font_bitmap_info);
256 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
258 /* ---------- initialize font bitmap definitions ---------- */
260 for (i = 0; i < NUM_FONTS; i++)
262 if (i < NUM_INITIAL_FONTS)
264 font_bitmap_info[i] = font_initial[i];
268 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
270 int font_bitmap_id = font_info[i].special_bitmap_id[j];
271 int graphic = font_info[i].special_graphic[j];
273 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
274 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
276 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
277 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
280 /* copy font relevant information from graphics information */
281 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
282 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
283 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
284 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
285 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
286 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
287 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
289 font_bitmap_info[font_bitmap_id].num_chars =
290 graphic_info[graphic].anim_frames;
291 font_bitmap_info[font_bitmap_id].num_chars_per_line =
292 graphic_info[graphic].anim_frames_per_line;
296 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
299 void InitElementGraphicInfo()
301 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
302 int num_property_mappings = getImageListPropertyMappingSize();
305 if (graphic_info == NULL) /* still at startup phase */
308 /* set values to -1 to identify later as "uninitialized" values */
309 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
311 for (act = 0; act < NUM_ACTIONS; act++)
313 element_info[i].graphic[act] = -1;
314 element_info[i].crumbled[act] = -1;
316 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
318 element_info[i].direction_graphic[act][dir] = -1;
319 element_info[i].direction_crumbled[act][dir] = -1;
324 /* initialize normal element/graphic mapping from static configuration */
325 for (i = 0; element_to_graphic[i].element > -1; i++)
327 int element = element_to_graphic[i].element;
328 int action = element_to_graphic[i].action;
329 int direction = element_to_graphic[i].direction;
330 boolean crumbled = element_to_graphic[i].crumbled;
331 int graphic = element_to_graphic[i].graphic;
332 int base_graphic = el2baseimg(element);
334 if (graphic_info[graphic].bitmap == NULL)
337 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
340 boolean base_redefined =
341 getImageListEntryFromImageID(base_graphic)->redefined;
342 boolean act_dir_redefined =
343 getImageListEntryFromImageID(graphic)->redefined;
345 /* if the base graphic ("emerald", for example) has been redefined,
346 but not the action graphic ("emerald.falling", for example), do not
347 use an existing (in this case considered obsolete) action graphic
348 anymore, but use the automatically determined default graphic */
349 if (base_redefined && !act_dir_redefined)
354 action = ACTION_DEFAULT;
359 element_info[element].direction_crumbled[action][direction] = graphic;
361 element_info[element].crumbled[action] = graphic;
366 element_info[element].direction_graphic[action][direction] = graphic;
368 element_info[element].graphic[action] = graphic;
372 /* initialize normal element/graphic mapping from dynamic configuration */
373 for (i = 0; i < num_property_mappings; i++)
375 int element = property_mapping[i].base_index;
376 int action = property_mapping[i].ext1_index;
377 int direction = property_mapping[i].ext2_index;
378 int special = property_mapping[i].ext3_index;
379 int graphic = property_mapping[i].artwork_index;
380 boolean crumbled = FALSE;
382 if (special == GFX_SPECIAL_ARG_CRUMBLED)
388 if (graphic_info[graphic].bitmap == NULL)
391 if (element >= MAX_NUM_ELEMENTS || special != -1)
395 action = ACTION_DEFAULT;
400 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
401 element_info[element].direction_crumbled[action][dir] = -1;
404 element_info[element].direction_crumbled[action][direction] = graphic;
406 element_info[element].crumbled[action] = graphic;
411 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
412 element_info[element].direction_graphic[action][dir] = -1;
415 element_info[element].direction_graphic[action][direction] = graphic;
417 element_info[element].graphic[action] = graphic;
421 /* now copy all graphics that are defined to be cloned from other graphics */
422 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
424 int graphic = element_info[i].graphic[ACTION_DEFAULT];
425 int crumbled_like, diggable_like;
430 crumbled_like = graphic_info[graphic].crumbled_like;
431 diggable_like = graphic_info[graphic].diggable_like;
433 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
435 for (act = 0; act < NUM_ACTIONS; act++)
436 element_info[i].crumbled[act] =
437 element_info[crumbled_like].crumbled[act];
438 for (act = 0; act < NUM_ACTIONS; act++)
439 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
440 element_info[i].direction_crumbled[act][dir] =
441 element_info[crumbled_like].direction_crumbled[act][dir];
444 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
446 element_info[i].graphic[ACTION_DIGGING] =
447 element_info[diggable_like].graphic[ACTION_DIGGING];
448 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
449 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
450 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
455 /* set hardcoded definitions for some runtime elements without graphic */
456 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
459 /* now set all undefined/invalid graphics to -1 to set to default after it */
460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
462 for (act = 0; act < NUM_ACTIONS; act++)
466 graphic = element_info[i].graphic[act];
467 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
468 element_info[i].graphic[act] = -1;
470 graphic = element_info[i].crumbled[act];
471 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
472 element_info[i].crumbled[act] = -1;
474 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
476 graphic = element_info[i].direction_graphic[act][dir];
477 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
478 element_info[i].direction_graphic[act][dir] = -1;
480 graphic = element_info[i].direction_crumbled[act][dir];
481 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
482 element_info[i].direction_crumbled[act][dir] = -1;
487 /* adjust graphics with 2nd tile for movement according to direction
488 (do this before correcting '-1' values to minimize calculations) */
489 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
491 for (act = 0; act < NUM_ACTIONS; act++)
493 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
495 int graphic = element_info[i].direction_graphic[act][dir];
496 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
498 if (act == ACTION_FALLING) /* special case */
499 graphic = element_info[i].graphic[act];
502 graphic_info[graphic].double_movement &&
503 graphic_info[graphic].swap_double_tiles != 0)
505 struct GraphicInfo *g = &graphic_info[graphic];
506 int src_x_front = g->src_x;
507 int src_y_front = g->src_y;
508 int src_x_back = g->src_x + g->offset2_x;
509 int src_y_back = g->src_y + g->offset2_y;
510 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
512 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
513 src_y_front < src_y_back);
514 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
515 boolean swap_movement_tiles_autodetected =
516 (!frames_are_ordered_diagonally &&
517 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
518 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
519 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
520 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
523 /* swap frontside and backside graphic tile coordinates, if needed */
524 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
526 /* get current (wrong) backside tile coordinates */
527 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
530 /* set frontside tile coordinates to backside tile coordinates */
531 g->src_x = src_x_back;
532 g->src_y = src_y_back;
534 /* invert tile offset to point to new backside tile coordinates */
538 /* do not swap front and backside tiles again after correction */
539 g->swap_double_tiles = 0;
546 /* now set all '-1' values to element specific default values */
547 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
549 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
550 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
551 int default_direction_graphic[NUM_DIRECTIONS];
552 int default_direction_crumbled[NUM_DIRECTIONS];
554 if (default_graphic == -1)
555 default_graphic = IMG_UNKNOWN;
557 if (default_crumbled == -1)
558 default_crumbled = default_graphic;
560 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
561 if (default_crumbled == -1)
562 default_crumbled = IMG_EMPTY;
565 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
567 default_direction_graphic[dir] =
568 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
569 default_direction_crumbled[dir] =
570 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
572 if (default_direction_graphic[dir] == -1)
573 default_direction_graphic[dir] = default_graphic;
575 if (default_direction_crumbled[dir] == -1)
576 default_direction_crumbled[dir] = default_direction_graphic[dir];
578 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
579 if (default_direction_crumbled[dir] == -1)
580 default_direction_crumbled[dir] = default_crumbled;
584 for (act = 0; act < NUM_ACTIONS; act++)
586 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
587 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
588 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
589 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
590 act == ACTION_TURNING_FROM_RIGHT ||
591 act == ACTION_TURNING_FROM_UP ||
592 act == ACTION_TURNING_FROM_DOWN);
594 /* generic default action graphic (defined by "[default]" directive) */
595 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
596 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
597 int default_remove_graphic = IMG_EMPTY;
599 if (act_remove && default_action_graphic != -1)
600 default_remove_graphic = default_action_graphic;
602 /* look for special default action graphic (classic game specific) */
603 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
604 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
605 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
606 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
607 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
608 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
610 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
611 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
612 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
613 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
614 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
615 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
618 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
619 /* !!! make this better !!! */
620 if (i == EL_EMPTY_SPACE)
622 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
623 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
627 if (default_action_graphic == -1)
628 default_action_graphic = default_graphic;
630 if (default_action_crumbled == -1)
631 default_action_crumbled = default_action_graphic;
633 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
634 if (default_action_crumbled == -1)
635 default_action_crumbled = default_crumbled;
638 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
640 /* use action graphic as the default direction graphic, if undefined */
641 int default_action_direction_graphic = element_info[i].graphic[act];
642 int default_action_direction_crumbled = element_info[i].crumbled[act];
644 /* no graphic for current action -- use default direction graphic */
645 if (default_action_direction_graphic == -1)
646 default_action_direction_graphic =
647 (act_remove ? default_remove_graphic :
649 element_info[i].direction_graphic[ACTION_TURNING][dir] :
650 default_action_graphic != default_graphic ?
651 default_action_graphic :
652 default_direction_graphic[dir]);
654 if (element_info[i].direction_graphic[act][dir] == -1)
655 element_info[i].direction_graphic[act][dir] =
656 default_action_direction_graphic;
659 if (default_action_direction_crumbled == -1)
660 default_action_direction_crumbled =
661 element_info[i].direction_graphic[act][dir];
663 if (default_action_direction_crumbled == -1)
664 default_action_direction_crumbled =
665 (act_remove ? default_remove_graphic :
667 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
668 default_action_crumbled != default_crumbled ?
669 default_action_crumbled :
670 default_direction_crumbled[dir]);
673 if (element_info[i].direction_crumbled[act][dir] == -1)
674 element_info[i].direction_crumbled[act][dir] =
675 default_action_direction_crumbled;
678 /* no graphic for this specific action -- use default action graphic */
679 if (element_info[i].graphic[act] == -1)
680 element_info[i].graphic[act] =
681 (act_remove ? default_remove_graphic :
682 act_turning ? element_info[i].graphic[ACTION_TURNING] :
683 default_action_graphic);
685 if (element_info[i].crumbled[act] == -1)
686 element_info[i].crumbled[act] = element_info[i].graphic[act];
688 if (element_info[i].crumbled[act] == -1)
689 element_info[i].crumbled[act] =
690 (act_remove ? default_remove_graphic :
691 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
692 default_action_crumbled);
697 /* set animation mode to "none" for each graphic with only 1 frame */
698 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
700 for (act = 0; act < NUM_ACTIONS; act++)
702 int graphic = element_info[i].graphic[act];
703 int crumbled = element_info[i].crumbled[act];
705 if (graphic_info[graphic].anim_frames == 1)
706 graphic_info[graphic].anim_mode = ANIM_NONE;
707 if (graphic_info[crumbled].anim_frames == 1)
708 graphic_info[crumbled].anim_mode = ANIM_NONE;
710 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
712 graphic = element_info[i].direction_graphic[act][dir];
713 crumbled = element_info[i].direction_crumbled[act][dir];
715 if (graphic_info[graphic].anim_frames == 1)
716 graphic_info[graphic].anim_mode = ANIM_NONE;
717 if (graphic_info[crumbled].anim_frames == 1)
718 graphic_info[crumbled].anim_mode = ANIM_NONE;
727 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
728 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
730 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
731 element_info[i].token_name, i);
737 void InitElementSpecialGraphicInfo()
739 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
740 int num_property_mappings = getImageListPropertyMappingSize();
743 /* always start with reliable default values */
744 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
745 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
746 element_info[i].special_graphic[j] =
747 element_info[i].graphic[ACTION_DEFAULT];
749 /* initialize special element/graphic mapping from static configuration */
750 for (i = 0; element_to_special_graphic[i].element > -1; i++)
752 int element = element_to_special_graphic[i].element;
753 int special = element_to_special_graphic[i].special;
754 int graphic = element_to_special_graphic[i].graphic;
755 int base_graphic = el2baseimg(element);
756 boolean base_redefined =
757 getImageListEntryFromImageID(base_graphic)->redefined;
758 boolean special_redefined =
759 getImageListEntryFromImageID(graphic)->redefined;
761 /* if the base graphic ("emerald", for example) has been redefined,
762 but not the special graphic ("emerald.EDITOR", for example), do not
763 use an existing (in this case considered obsolete) special graphic
764 anymore, but use the automatically created (down-scaled) graphic */
765 if (base_redefined && !special_redefined)
768 element_info[element].special_graphic[special] = graphic;
771 /* initialize special element/graphic mapping from dynamic configuration */
772 for (i = 0; i < num_property_mappings; i++)
774 int element = property_mapping[i].base_index;
775 int special = property_mapping[i].ext3_index;
776 int graphic = property_mapping[i].artwork_index;
778 if (element >= MAX_NUM_ELEMENTS)
781 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
782 element_info[element].special_graphic[special] = graphic;
785 /* now set all undefined/invalid graphics to default */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
787 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
788 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
789 element_info[i].special_graphic[j] =
790 element_info[i].graphic[ACTION_DEFAULT];
793 static int get_element_from_token(char *token)
797 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
798 if (strcmp(element_info[i].token_name, token) == 0)
804 static int get_scaled_graphic_width(int graphic)
806 int original_width = getOriginalImageWidthFromImageID(graphic);
807 int scale_up_factor = graphic_info[graphic].scale_up_factor;
809 return original_width * scale_up_factor;
812 static int get_scaled_graphic_height(int graphic)
814 int original_height = getOriginalImageHeightFromImageID(graphic);
815 int scale_up_factor = graphic_info[graphic].scale_up_factor;
817 return original_height * scale_up_factor;
820 static void set_graphic_parameters(int graphic, int graphic_copy_from)
822 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
823 char **parameter_raw = image->parameter;
824 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
825 int parameter[NUM_GFX_ARGS];
826 int anim_frames_per_row = 1, anim_frames_per_col = 1;
827 int anim_frames_per_line = 1;
830 /* if fallback to default artwork is done, also use the default parameters */
831 if (image->fallback_to_default)
832 parameter_raw = image->default_parameter;
834 /* get integer values from string parameters */
835 for (i = 0; i < NUM_GFX_ARGS; i++)
838 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
839 image_config_suffix[i].type);
841 if (image_config_suffix[i].type == TYPE_TOKEN)
842 parameter[i] = get_element_from_token(parameter_raw[i]);
845 graphic_info[graphic].bitmap = src_bitmap;
847 /* start with reliable default values */
848 graphic_info[graphic].src_x = 0;
849 graphic_info[graphic].src_y = 0;
850 graphic_info[graphic].width = TILEX;
851 graphic_info[graphic].height = TILEY;
852 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
853 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
854 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
855 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
856 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
857 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
858 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
859 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
860 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
861 graphic_info[graphic].anim_delay_fixed = 0;
862 graphic_info[graphic].anim_delay_random = 0;
863 graphic_info[graphic].post_delay_fixed = 0;
864 graphic_info[graphic].post_delay_random = 0;
866 /* optional x and y tile position of animation frame sequence */
867 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
868 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
869 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
870 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
872 /* optional x and y pixel position of animation frame sequence */
873 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
874 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
875 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
876 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
878 /* optional width and height of each animation frame */
879 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
880 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
881 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
882 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
884 /* optional zoom factor for scaling up the image to a larger size */
885 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
886 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
887 if (graphic_info[graphic].scale_up_factor < 1)
888 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
892 /* get final bitmap size (with scaling, but without small images) */
893 int src_bitmap_width = get_scaled_graphic_width(graphic);
894 int src_bitmap_height = get_scaled_graphic_height(graphic);
896 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
897 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
900 /* correct x or y offset dependent of vertical or horizontal frame order */
901 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
903 graphic_info[graphic].offset_y =
904 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
905 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
906 anim_frames_per_line = anim_frames_per_col;
908 else /* frames are ordered horizontally */
910 graphic_info[graphic].offset_x =
911 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
912 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
913 anim_frames_per_line = anim_frames_per_row;
916 /* optionally, the x and y offset of frames can be specified directly */
917 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
918 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
919 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
920 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
922 /* optionally, moving animations may have separate start and end graphics */
923 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
925 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
926 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
928 /* correct x or y offset2 dependent of vertical or horizontal frame order */
929 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
930 graphic_info[graphic].offset2_y =
931 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
932 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
933 else /* frames are ordered horizontally */
934 graphic_info[graphic].offset2_x =
935 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
936 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
938 /* optionally, the x and y offset of 2nd graphic can be specified directly */
939 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
940 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
941 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
942 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
944 /* optionally, the second movement tile can be specified as start tile */
945 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
948 /* automatically determine correct number of frames, if not defined */
949 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
950 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
951 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
952 graphic_info[graphic].anim_frames = anim_frames_per_row;
953 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
954 graphic_info[graphic].anim_frames = anim_frames_per_col;
956 graphic_info[graphic].anim_frames = 1;
958 graphic_info[graphic].anim_frames_per_line =
959 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
960 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
962 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
963 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
964 graphic_info[graphic].anim_delay = 1;
966 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
968 if (graphic_info[graphic].anim_frames == 1)
969 graphic_info[graphic].anim_mode = ANIM_NONE;
972 /* automatically determine correct start frame, if not defined */
973 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].anim_start_frame = 0;
975 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
976 graphic_info[graphic].anim_start_frame =
977 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
979 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
981 /* animation synchronized with global frame counter, not move position */
982 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
984 /* optional element for cloning crumble graphics */
985 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
986 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
988 /* optional element for cloning digging graphics */
989 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
992 /* optional border size for "crumbling" diggable graphics */
993 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
996 /* this is only used for player "boring" and "sleeping" actions */
997 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
998 graphic_info[graphic].anim_delay_fixed =
999 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1000 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1001 graphic_info[graphic].anim_delay_random =
1002 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1003 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].post_delay_fixed =
1005 parameter[GFX_ARG_POST_DELAY_FIXED];
1006 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1007 graphic_info[graphic].post_delay_random =
1008 parameter[GFX_ARG_POST_DELAY_RANDOM];
1010 /* this is only used for toon animations */
1011 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1012 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1014 /* this is only used for drawing font characters */
1015 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1016 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1018 /* this is only used for drawing envelope graphics */
1019 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1022 static void InitGraphicInfo()
1024 int fallback_graphic = IMG_CHAR_EXCLAM;
1025 int num_images = getImageListSize();
1028 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1029 static boolean clipmasks_initialized = FALSE;
1031 XGCValues clip_gc_values;
1032 unsigned long clip_gc_valuemask;
1033 GC copy_clipmask_gc = None;
1036 checked_free(graphic_info);
1038 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1040 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1041 if (clipmasks_initialized)
1043 for (i = 0; i < num_images; i++)
1045 if (graphic_info[i].clip_mask)
1046 XFreePixmap(display, graphic_info[i].clip_mask);
1047 if (graphic_info[i].clip_gc)
1048 XFreeGC(display, graphic_info[i].clip_gc);
1050 graphic_info[i].clip_mask = None;
1051 graphic_info[i].clip_gc = None;
1056 for (i = 0; i < num_images; i++)
1060 int first_frame, last_frame;
1061 int src_bitmap_width, src_bitmap_height;
1064 printf("::: image # %d: '%s' ['%s']\n",
1065 i, image->token, getTokenFromImageID(i));
1068 set_graphic_parameters(i, i);
1070 /* now check if no animation frames are outside of the loaded image */
1072 if (graphic_info[i].bitmap == NULL)
1073 continue; /* skip check for optional images that are undefined */
1075 /* get final bitmap size (with scaling, but without small images) */
1076 src_bitmap_width = get_scaled_graphic_width(i);
1077 src_bitmap_height = get_scaled_graphic_height(i);
1080 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1081 if (src_x < 0 || src_y < 0 ||
1082 src_x + TILEX > src_bitmap_width ||
1083 src_y + TILEY > src_bitmap_height)
1085 Error(ERR_RETURN_LINE, "-");
1086 Error(ERR_RETURN, "warning: error found in config file:");
1087 Error(ERR_RETURN, "- config file: '%s'",
1088 getImageConfigFilename());
1089 Error(ERR_RETURN, "- config token: '%s'",
1090 getTokenFromImageID(i));
1091 Error(ERR_RETURN, "- image file: '%s'",
1092 src_bitmap->source_filename);
1094 "error: first animation frame out of bounds (%d, %d)",
1096 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1098 if (i == fallback_graphic)
1099 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1101 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1102 Error(ERR_RETURN_LINE, "-");
1104 set_graphic_parameters(i, fallback_graphic);
1107 last_frame = graphic_info[i].anim_frames - 1;
1108 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1109 if (src_x < 0 || src_y < 0 ||
1110 src_x + TILEX > src_bitmap_width ||
1111 src_y + TILEY > src_bitmap_height)
1113 Error(ERR_RETURN_LINE, "-");
1114 Error(ERR_RETURN, "warning: error found in config file:");
1115 Error(ERR_RETURN, "- config file: '%s'",
1116 getImageConfigFilename());
1117 Error(ERR_RETURN, "- config token: '%s'",
1118 getTokenFromImageID(i));
1119 Error(ERR_RETURN, "- image file: '%s'",
1120 src_bitmap->source_filename);
1122 "error: last animation frame (%d) out of bounds (%d, %d)",
1123 last_frame, src_x, src_y);
1124 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1126 if (i == fallback_graphic)
1127 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1129 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1130 Error(ERR_RETURN_LINE, "-");
1132 set_graphic_parameters(i, fallback_graphic);
1135 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1136 /* currently we only need a tile clip mask from the first frame */
1137 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1139 if (copy_clipmask_gc == None)
1141 clip_gc_values.graphics_exposures = False;
1142 clip_gc_valuemask = GCGraphicsExposures;
1143 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1144 clip_gc_valuemask, &clip_gc_values);
1147 graphic_info[i].clip_mask =
1148 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1150 src_pixmap = src_bitmap->clip_mask;
1151 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1152 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1154 clip_gc_values.graphics_exposures = False;
1155 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1156 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1158 graphic_info[i].clip_gc =
1159 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1163 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1164 if (copy_clipmask_gc)
1165 XFreeGC(display, copy_clipmask_gc);
1167 clipmasks_initialized = TRUE;
1171 static void InitElementSoundInfo()
1173 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1174 int num_property_mappings = getSoundListPropertyMappingSize();
1177 /* set values to -1 to identify later as "uninitialized" values */
1178 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1179 for (act = 0; act < NUM_ACTIONS; act++)
1180 element_info[i].sound[act] = -1;
1182 /* initialize element/sound mapping from static configuration */
1183 for (i = 0; element_to_sound[i].element > -1; i++)
1185 int element = element_to_sound[i].element;
1186 int action = element_to_sound[i].action;
1187 int sound = element_to_sound[i].sound;
1188 boolean is_class = element_to_sound[i].is_class;
1191 action = ACTION_DEFAULT;
1194 element_info[element].sound[action] = sound;
1196 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1197 if (strcmp(element_info[j].class_name,
1198 element_info[element].class_name) == 0)
1199 element_info[j].sound[action] = sound;
1202 /* initialize element class/sound mapping from dynamic configuration */
1203 for (i = 0; i < num_property_mappings; i++)
1205 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1206 int action = property_mapping[i].ext1_index;
1207 int sound = property_mapping[i].artwork_index;
1209 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1213 action = ACTION_DEFAULT;
1215 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1216 if (strcmp(element_info[j].class_name,
1217 element_info[element_class].class_name) == 0)
1218 element_info[j].sound[action] = sound;
1221 /* initialize element/sound mapping from dynamic configuration */
1222 for (i = 0; i < num_property_mappings; i++)
1224 int element = property_mapping[i].base_index;
1225 int action = property_mapping[i].ext1_index;
1226 int sound = property_mapping[i].artwork_index;
1228 if (element >= MAX_NUM_ELEMENTS)
1232 action = ACTION_DEFAULT;
1234 element_info[element].sound[action] = sound;
1237 /* now set all '-1' values to element specific default values */
1238 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1240 for (act = 0; act < NUM_ACTIONS; act++)
1242 /* generic default action sound (defined by "[default]" directive) */
1243 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1245 /* look for special default action sound (classic game specific) */
1246 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1247 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1248 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1249 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1250 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1251 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1253 /* !!! there's no such thing as a "default action sound" !!! */
1255 /* look for element specific default sound (independent from action) */
1256 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1257 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1261 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1262 /* !!! make this better !!! */
1263 if (i == EL_EMPTY_SPACE)
1264 default_action_sound = element_info[EL_DEFAULT].sound[act];
1267 /* no sound for this specific action -- use default action sound */
1268 if (element_info[i].sound[act] == -1)
1269 element_info[i].sound[act] = default_action_sound;
1273 /* copy sound settings to some elements that are only stored in level file
1274 in native R'n'D levels, but are used by game engine in native EM levels */
1275 for (i = 0; copy_properties[i][0] != -1; i++)
1276 for (j = 1; j <= 4; j++)
1277 for (act = 0; act < NUM_ACTIONS; act++)
1278 element_info[copy_properties[i][j]].sound[act] =
1279 element_info[copy_properties[i][0]].sound[act];
1282 static void InitGameModeSoundInfo()
1286 /* set values to -1 to identify later as "uninitialized" values */
1287 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1290 /* initialize gamemode/sound mapping from static configuration */
1291 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1293 int gamemode = gamemode_to_sound[i].gamemode;
1294 int sound = gamemode_to_sound[i].sound;
1297 gamemode = GAME_MODE_DEFAULT;
1299 menu.sound[gamemode] = sound;
1302 /* now set all '-1' values to levelset specific default values */
1303 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1304 if (menu.sound[i] == -1)
1305 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1308 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1309 if (menu.sound[i] != -1)
1310 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1314 static void set_sound_parameters(int sound, char **parameter_raw)
1316 int parameter[NUM_SND_ARGS];
1319 /* get integer values from string parameters */
1320 for (i = 0; i < NUM_SND_ARGS; i++)
1322 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1323 sound_config_suffix[i].type);
1325 /* explicit loop mode setting in configuration overrides default value */
1326 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1327 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1329 /* sound volume to change the original volume when loading the sound file */
1330 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1332 /* sound priority to give certain sounds a higher or lower priority */
1333 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1336 static void InitSoundInfo()
1338 int *sound_effect_properties;
1339 int num_sounds = getSoundListSize();
1342 checked_free(sound_info);
1344 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1345 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1347 /* initialize sound effect for all elements to "no sound" */
1348 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1349 for (j = 0; j < NUM_ACTIONS; j++)
1350 element_info[i].sound[j] = SND_UNDEFINED;
1352 for (i = 0; i < num_sounds; i++)
1354 struct FileInfo *sound = getSoundListEntry(i);
1355 int len_effect_text = strlen(sound->token);
1357 sound_effect_properties[i] = ACTION_OTHER;
1358 sound_info[i].loop = FALSE; /* default: play sound only once */
1361 printf("::: sound %d: '%s'\n", i, sound->token);
1364 /* determine all loop sounds and identify certain sound classes */
1366 for (j = 0; element_action_info[j].suffix; j++)
1368 int len_action_text = strlen(element_action_info[j].suffix);
1370 if (len_action_text < len_effect_text &&
1371 strcmp(&sound->token[len_effect_text - len_action_text],
1372 element_action_info[j].suffix) == 0)
1374 sound_effect_properties[i] = element_action_info[j].value;
1375 sound_info[i].loop = element_action_info[j].is_loop_sound;
1381 /* associate elements and some selected sound actions */
1383 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1385 if (element_info[j].class_name)
1387 int len_class_text = strlen(element_info[j].class_name);
1389 if (len_class_text + 1 < len_effect_text &&
1390 strncmp(sound->token,
1391 element_info[j].class_name, len_class_text) == 0 &&
1392 sound->token[len_class_text] == '.')
1394 int sound_action_value = sound_effect_properties[i];
1396 element_info[j].sound[sound_action_value] = i;
1401 set_sound_parameters(i, sound->parameter);
1404 free(sound_effect_properties);
1407 static void InitGameModeMusicInfo()
1409 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1410 int num_property_mappings = getMusicListPropertyMappingSize();
1411 int default_levelset_music = -1;
1414 /* set values to -1 to identify later as "uninitialized" values */
1415 for (i = 0; i < MAX_LEVELS; i++)
1416 levelset.music[i] = -1;
1417 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1420 /* initialize gamemode/music mapping from static configuration */
1421 for (i = 0; gamemode_to_music[i].music > -1; i++)
1423 int gamemode = gamemode_to_music[i].gamemode;
1424 int music = gamemode_to_music[i].music;
1427 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1431 gamemode = GAME_MODE_DEFAULT;
1433 menu.music[gamemode] = music;
1436 /* initialize gamemode/music mapping from dynamic configuration */
1437 for (i = 0; i < num_property_mappings; i++)
1439 int prefix = property_mapping[i].base_index;
1440 int gamemode = property_mapping[i].ext1_index;
1441 int level = property_mapping[i].ext2_index;
1442 int music = property_mapping[i].artwork_index;
1445 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1446 prefix, gamemode, level, music);
1449 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1453 gamemode = GAME_MODE_DEFAULT;
1455 /* level specific music only allowed for in-game music */
1456 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1457 gamemode = GAME_MODE_PLAYING;
1462 default_levelset_music = music;
1465 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1466 levelset.music[level] = music;
1467 if (gamemode != GAME_MODE_PLAYING)
1468 menu.music[gamemode] = music;
1471 /* now set all '-1' values to menu specific default values */
1472 /* (undefined values of "levelset.music[]" might stay at "-1" to
1473 allow dynamic selection of music files from music directory!) */
1474 for (i = 0; i < MAX_LEVELS; i++)
1475 if (levelset.music[i] == -1)
1476 levelset.music[i] = default_levelset_music;
1477 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1478 if (menu.music[i] == -1)
1479 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1482 for (i = 0; i < MAX_LEVELS; i++)
1483 if (levelset.music[i] != -1)
1484 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1485 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1486 if (menu.music[i] != -1)
1487 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1491 static void set_music_parameters(int music, char **parameter_raw)
1493 int parameter[NUM_MUS_ARGS];
1496 /* get integer values from string parameters */
1497 for (i = 0; i < NUM_MUS_ARGS; i++)
1499 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1500 music_config_suffix[i].type);
1502 /* explicit loop mode setting in configuration overrides default value */
1503 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1504 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1507 static void InitMusicInfo()
1509 int num_music = getMusicListSize();
1512 checked_free(music_info);
1514 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1516 for (i = 0; i < num_music; i++)
1518 struct FileInfo *music = getMusicListEntry(i);
1519 int len_music_text = strlen(music->token);
1521 music_info[i].loop = TRUE; /* default: play music in loop mode */
1523 /* determine all loop music */
1525 for (j = 0; music_prefix_info[j].prefix; j++)
1527 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1529 if (len_prefix_text < len_music_text &&
1530 strncmp(music->token,
1531 music_prefix_info[j].prefix, len_prefix_text) == 0)
1533 music_info[i].loop = music_prefix_info[j].is_loop_music;
1539 set_music_parameters(i, music->parameter);
1543 static void ReinitializeGraphics()
1545 InitGraphicInfo(); /* graphic properties mapping */
1546 InitElementGraphicInfo(); /* element game graphic mapping */
1547 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1549 InitElementSmallImages(); /* scale images to all needed sizes */
1550 InitFontGraphicInfo(); /* initialize text drawing functions */
1552 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1554 SetMainBackgroundImage(IMG_BACKGROUND);
1555 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1561 static void ReinitializeSounds()
1563 InitSoundInfo(); /* sound properties mapping */
1564 InitElementSoundInfo(); /* element game sound mapping */
1565 InitGameModeSoundInfo(); /* game mode sound mapping */
1567 InitPlayLevelSound(); /* internal game sound settings */
1570 static void ReinitializeMusic()
1572 InitMusicInfo(); /* music properties mapping */
1573 InitGameModeMusicInfo(); /* game mode music mapping */
1576 static int get_special_property_bit(int element, int property_bit_nr)
1578 struct PropertyBitInfo
1584 static struct PropertyBitInfo pb_can_move_into_acid[] =
1586 /* the player may be able fall into acid when gravity is activated */
1591 { EL_SP_MURPHY, 0 },
1592 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1594 /* all element that can move may be able to also move into acid */
1597 { EL_BUG_RIGHT, 1 },
1600 { EL_SPACESHIP, 2 },
1601 { EL_SPACESHIP_LEFT, 2 },
1602 { EL_SPACESHIP_RIGHT, 2 },
1603 { EL_SPACESHIP_UP, 2 },
1604 { EL_SPACESHIP_DOWN, 2 },
1605 { EL_BD_BUTTERFLY, 3 },
1606 { EL_BD_BUTTERFLY_LEFT, 3 },
1607 { EL_BD_BUTTERFLY_RIGHT, 3 },
1608 { EL_BD_BUTTERFLY_UP, 3 },
1609 { EL_BD_BUTTERFLY_DOWN, 3 },
1610 { EL_BD_FIREFLY, 4 },
1611 { EL_BD_FIREFLY_LEFT, 4 },
1612 { EL_BD_FIREFLY_RIGHT, 4 },
1613 { EL_BD_FIREFLY_UP, 4 },
1614 { EL_BD_FIREFLY_DOWN, 4 },
1616 { EL_DARK_YAMYAM, 6 },
1619 { EL_PACMAN_LEFT, 8 },
1620 { EL_PACMAN_RIGHT, 8 },
1621 { EL_PACMAN_UP, 8 },
1622 { EL_PACMAN_DOWN, 8 },
1624 { EL_MOLE_LEFT, 9 },
1625 { EL_MOLE_RIGHT, 9 },
1627 { EL_MOLE_DOWN, 9 },
1631 { EL_SATELLITE, 13 },
1632 { EL_SP_SNIKSNAK, 14 },
1633 { EL_SP_ELECTRON, 15 },
1640 static struct PropertyBitInfo pb_dont_collide_with[] =
1642 { EL_SP_SNIKSNAK, 0 },
1643 { EL_SP_ELECTRON, 1 },
1651 struct PropertyBitInfo *pb_info;
1654 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1655 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1660 struct PropertyBitInfo *pb_info = NULL;
1663 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1664 if (pb_definition[i].bit_nr == property_bit_nr)
1665 pb_info = pb_definition[i].pb_info;
1667 if (pb_info == NULL)
1670 for (i = 0; pb_info[i].element != -1; i++)
1671 if (pb_info[i].element == element)
1672 return pb_info[i].bit_nr;
1677 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1678 boolean property_value)
1680 int bit_nr = get_special_property_bit(element, property_bit_nr);
1685 *bitfield |= (1 << bit_nr);
1687 *bitfield &= ~(1 << bit_nr);
1691 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1693 int bit_nr = get_special_property_bit(element, property_bit_nr);
1696 return ((*bitfield & (1 << bit_nr)) != 0);
1701 void InitElementPropertiesStatic()
1703 static int ep_diggable[] =
1708 EL_SP_BUGGY_BASE_ACTIVATING,
1711 EL_INVISIBLE_SAND_ACTIVE,
1714 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1715 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1719 EL_SP_BUGGY_BASE_ACTIVE,
1725 static int ep_collectible_only[] =
1746 EL_DYNABOMB_INCREASE_NUMBER,
1747 EL_DYNABOMB_INCREASE_SIZE,
1748 EL_DYNABOMB_INCREASE_POWER,
1767 static int ep_dont_run_into[] =
1769 /* same elements as in 'ep_dont_touch' */
1775 /* same elements as in 'ep_dont_collide_with' */
1787 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1791 EL_SP_BUGGY_BASE_ACTIVE,
1797 static int ep_dont_collide_with[] =
1799 /* same elements as in 'ep_dont_touch' */
1815 static int ep_dont_touch[] =
1824 static int ep_indestructible[] =
1828 EL_ACID_POOL_TOPLEFT,
1829 EL_ACID_POOL_TOPRIGHT,
1830 EL_ACID_POOL_BOTTOMLEFT,
1831 EL_ACID_POOL_BOTTOM,
1832 EL_ACID_POOL_BOTTOMRIGHT,
1833 EL_SP_HARDWARE_GRAY,
1834 EL_SP_HARDWARE_GREEN,
1835 EL_SP_HARDWARE_BLUE,
1837 EL_SP_HARDWARE_YELLOW,
1838 EL_SP_HARDWARE_BASE_1,
1839 EL_SP_HARDWARE_BASE_2,
1840 EL_SP_HARDWARE_BASE_3,
1841 EL_SP_HARDWARE_BASE_4,
1842 EL_SP_HARDWARE_BASE_5,
1843 EL_SP_HARDWARE_BASE_6,
1844 EL_INVISIBLE_STEELWALL,
1845 EL_INVISIBLE_STEELWALL_ACTIVE,
1846 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1847 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1848 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1849 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1850 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1851 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1852 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1853 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1854 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1855 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1856 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1857 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1859 EL_LIGHT_SWITCH_ACTIVE,
1860 EL_SIGN_EXCLAMATION,
1861 EL_SIGN_RADIOACTIVITY,
1872 EL_STEELWALL_SLIPPERY,
1903 EL_SWITCHGATE_OPENING,
1904 EL_SWITCHGATE_CLOSED,
1905 EL_SWITCHGATE_CLOSING,
1907 EL_SWITCHGATE_SWITCH_UP,
1908 EL_SWITCHGATE_SWITCH_DOWN,
1911 EL_TIMEGATE_OPENING,
1913 EL_TIMEGATE_CLOSING,
1916 EL_TIMEGATE_SWITCH_ACTIVE,
1921 EL_TUBE_VERTICAL_LEFT,
1922 EL_TUBE_VERTICAL_RIGHT,
1923 EL_TUBE_HORIZONTAL_UP,
1924 EL_TUBE_HORIZONTAL_DOWN,
1932 static int ep_slippery[] =
1946 EL_ROBOT_WHEEL_ACTIVE,
1952 EL_ACID_POOL_TOPLEFT,
1953 EL_ACID_POOL_TOPRIGHT,
1963 EL_STEELWALL_SLIPPERY,
1966 EL_EMC_WALL_SLIPPERY_1,
1967 EL_EMC_WALL_SLIPPERY_2,
1968 EL_EMC_WALL_SLIPPERY_3,
1969 EL_EMC_WALL_SLIPPERY_4,
1973 static int ep_can_change[] =
1978 static int ep_can_move[] =
1980 /* same elements as in 'pb_can_move_into_acid' */
2002 static int ep_can_fall[] =
2017 EL_BD_MAGIC_WALL_FULL,
2030 static int ep_can_smash_player[] =
2055 static int ep_can_smash_enemies[] =
2063 static int ep_can_smash_everything[] =
2071 static int ep_explodes_by_fire[] =
2073 /* same elements as in 'ep_explodes_impact' */
2078 /* same elements as in 'ep_explodes_smashed' */
2087 EL_DYNABOMB_PLAYER_1_ACTIVE,
2088 EL_DYNABOMB_PLAYER_2_ACTIVE,
2089 EL_DYNABOMB_PLAYER_3_ACTIVE,
2090 EL_DYNABOMB_PLAYER_4_ACTIVE,
2091 EL_DYNABOMB_INCREASE_NUMBER,
2092 EL_DYNABOMB_INCREASE_SIZE,
2093 EL_DYNABOMB_INCREASE_POWER,
2094 EL_SP_DISK_RED_ACTIVE,
2107 static int ep_explodes_smashed[] =
2109 /* same elements as in 'ep_explodes_impact' */
2122 static int ep_explodes_impact[] =
2130 static int ep_walkable_over[] =
2134 EL_SOKOBAN_FIELD_EMPTY,
2152 static int ep_walkable_inside[] =
2157 EL_TUBE_VERTICAL_LEFT,
2158 EL_TUBE_VERTICAL_RIGHT,
2159 EL_TUBE_HORIZONTAL_UP,
2160 EL_TUBE_HORIZONTAL_DOWN,
2168 static int ep_walkable_under[] =
2173 static int ep_passable_over[] =
2196 static int ep_passable_inside[] =
2202 EL_SP_PORT_HORIZONTAL,
2203 EL_SP_PORT_VERTICAL,
2205 EL_SP_GRAVITY_PORT_LEFT,
2206 EL_SP_GRAVITY_PORT_RIGHT,
2207 EL_SP_GRAVITY_PORT_UP,
2208 EL_SP_GRAVITY_PORT_DOWN,
2209 EL_SP_GRAVITY_ON_PORT_LEFT,
2210 EL_SP_GRAVITY_ON_PORT_RIGHT,
2211 EL_SP_GRAVITY_ON_PORT_UP,
2212 EL_SP_GRAVITY_ON_PORT_DOWN,
2213 EL_SP_GRAVITY_OFF_PORT_LEFT,
2214 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2215 EL_SP_GRAVITY_OFF_PORT_UP,
2216 EL_SP_GRAVITY_OFF_PORT_DOWN,
2220 static int ep_passable_under[] =
2225 static int ep_droppable[] =
2230 static int ep_explodes_1x1_old[] =
2235 static int ep_pushable[] =
2247 EL_SOKOBAN_FIELD_FULL,
2255 static int ep_explodes_cross_old[] =
2260 static int ep_protected[] =
2262 /* same elements as in 'ep_walkable_inside' */
2266 EL_TUBE_VERTICAL_LEFT,
2267 EL_TUBE_VERTICAL_RIGHT,
2268 EL_TUBE_HORIZONTAL_UP,
2269 EL_TUBE_HORIZONTAL_DOWN,
2275 /* same elements as in 'ep_passable_over' */
2295 /* same elements as in 'ep_passable_inside' */
2300 EL_SP_PORT_HORIZONTAL,
2301 EL_SP_PORT_VERTICAL,
2303 EL_SP_GRAVITY_PORT_LEFT,
2304 EL_SP_GRAVITY_PORT_RIGHT,
2305 EL_SP_GRAVITY_PORT_UP,
2306 EL_SP_GRAVITY_PORT_DOWN,
2307 EL_SP_GRAVITY_ON_PORT_LEFT,
2308 EL_SP_GRAVITY_ON_PORT_RIGHT,
2309 EL_SP_GRAVITY_ON_PORT_UP,
2310 EL_SP_GRAVITY_ON_PORT_DOWN,
2311 EL_SP_GRAVITY_OFF_PORT_LEFT,
2312 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2313 EL_SP_GRAVITY_OFF_PORT_UP,
2314 EL_SP_GRAVITY_OFF_PORT_DOWN,
2318 static int ep_throwable[] =
2323 static int ep_can_explode[] =
2325 /* same elements as in 'ep_explodes_impact' */
2330 /* same elements as in 'ep_explodes_smashed' */
2336 /* elements that can explode by explosion or by dragonfire */
2339 EL_DYNABOMB_PLAYER_1_ACTIVE,
2340 EL_DYNABOMB_PLAYER_2_ACTIVE,
2341 EL_DYNABOMB_PLAYER_3_ACTIVE,
2342 EL_DYNABOMB_PLAYER_4_ACTIVE,
2343 EL_DYNABOMB_INCREASE_NUMBER,
2344 EL_DYNABOMB_INCREASE_SIZE,
2345 EL_DYNABOMB_INCREASE_POWER,
2346 EL_SP_DISK_RED_ACTIVE,
2354 /* elements that can explode only by explosion */
2359 static int ep_gravity_reachable[] =
2365 EL_INVISIBLE_SAND_ACTIVE,
2370 EL_SP_PORT_HORIZONTAL,
2371 EL_SP_PORT_VERTICAL,
2373 EL_SP_GRAVITY_PORT_LEFT,
2374 EL_SP_GRAVITY_PORT_RIGHT,
2375 EL_SP_GRAVITY_PORT_UP,
2376 EL_SP_GRAVITY_PORT_DOWN,
2377 EL_SP_GRAVITY_ON_PORT_LEFT,
2378 EL_SP_GRAVITY_ON_PORT_RIGHT,
2379 EL_SP_GRAVITY_ON_PORT_UP,
2380 EL_SP_GRAVITY_ON_PORT_DOWN,
2381 EL_SP_GRAVITY_OFF_PORT_LEFT,
2382 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2383 EL_SP_GRAVITY_OFF_PORT_UP,
2384 EL_SP_GRAVITY_OFF_PORT_DOWN,
2389 static int ep_player[] =
2396 EL_SOKOBAN_FIELD_PLAYER,
2401 static int ep_can_pass_magic_wall[] =
2414 static int ep_switchable[] =
2418 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2419 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2420 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2421 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2422 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2423 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2424 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2425 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2426 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2427 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2428 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2429 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2430 EL_SWITCHGATE_SWITCH_UP,
2431 EL_SWITCHGATE_SWITCH_DOWN,
2433 EL_LIGHT_SWITCH_ACTIVE,
2435 EL_BALLOON_SWITCH_LEFT,
2436 EL_BALLOON_SWITCH_RIGHT,
2437 EL_BALLOON_SWITCH_UP,
2438 EL_BALLOON_SWITCH_DOWN,
2439 EL_BALLOON_SWITCH_ANY,
2442 EL_EMC_MAGIC_BALL_SWITCH,
2446 static int ep_bd_element[] =
2479 static int ep_sp_element[] =
2481 /* should always be valid */
2484 /* standard classic Supaplex elements */
2491 EL_SP_HARDWARE_GRAY,
2499 EL_SP_GRAVITY_PORT_RIGHT,
2500 EL_SP_GRAVITY_PORT_DOWN,
2501 EL_SP_GRAVITY_PORT_LEFT,
2502 EL_SP_GRAVITY_PORT_UP,
2507 EL_SP_PORT_VERTICAL,
2508 EL_SP_PORT_HORIZONTAL,
2514 EL_SP_HARDWARE_BASE_1,
2515 EL_SP_HARDWARE_GREEN,
2516 EL_SP_HARDWARE_BLUE,
2518 EL_SP_HARDWARE_YELLOW,
2519 EL_SP_HARDWARE_BASE_2,
2520 EL_SP_HARDWARE_BASE_3,
2521 EL_SP_HARDWARE_BASE_4,
2522 EL_SP_HARDWARE_BASE_5,
2523 EL_SP_HARDWARE_BASE_6,
2527 /* additional elements that appeared in newer Supaplex levels */
2530 /* additional gravity port elements (not switching, but setting gravity) */
2531 EL_SP_GRAVITY_ON_PORT_LEFT,
2532 EL_SP_GRAVITY_ON_PORT_RIGHT,
2533 EL_SP_GRAVITY_ON_PORT_UP,
2534 EL_SP_GRAVITY_ON_PORT_DOWN,
2535 EL_SP_GRAVITY_OFF_PORT_LEFT,
2536 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2537 EL_SP_GRAVITY_OFF_PORT_UP,
2538 EL_SP_GRAVITY_OFF_PORT_DOWN,
2540 /* more than one Murphy in a level results in an inactive clone */
2543 /* runtime Supaplex elements */
2544 EL_SP_DISK_RED_ACTIVE,
2545 EL_SP_TERMINAL_ACTIVE,
2546 EL_SP_BUGGY_BASE_ACTIVATING,
2547 EL_SP_BUGGY_BASE_ACTIVE,
2553 static int ep_sb_element[] =
2558 EL_SOKOBAN_FIELD_EMPTY,
2559 EL_SOKOBAN_FIELD_FULL,
2560 EL_SOKOBAN_FIELD_PLAYER,
2565 EL_INVISIBLE_STEELWALL,
2569 static int ep_gem[] =
2580 static int ep_food_dark_yamyam[] =
2607 static int ep_food_penguin[] =
2620 static int ep_food_pig[] =
2631 static int ep_historic_wall[] =
2656 EL_EXPANDABLE_WALL_HORIZONTAL,
2657 EL_EXPANDABLE_WALL_VERTICAL,
2658 EL_EXPANDABLE_WALL_ANY,
2659 EL_EXPANDABLE_WALL_GROWING,
2666 EL_SP_HARDWARE_GRAY,
2667 EL_SP_HARDWARE_GREEN,
2668 EL_SP_HARDWARE_BLUE,
2670 EL_SP_HARDWARE_YELLOW,
2671 EL_SP_HARDWARE_BASE_1,
2672 EL_SP_HARDWARE_BASE_2,
2673 EL_SP_HARDWARE_BASE_3,
2674 EL_SP_HARDWARE_BASE_4,
2675 EL_SP_HARDWARE_BASE_5,
2676 EL_SP_HARDWARE_BASE_6,
2678 EL_SP_TERMINAL_ACTIVE,
2681 EL_INVISIBLE_STEELWALL,
2682 EL_INVISIBLE_STEELWALL_ACTIVE,
2684 EL_INVISIBLE_WALL_ACTIVE,
2685 EL_STEELWALL_SLIPPERY,
2701 static int ep_historic_solid[] =
2705 EL_EXPANDABLE_WALL_HORIZONTAL,
2706 EL_EXPANDABLE_WALL_VERTICAL,
2707 EL_EXPANDABLE_WALL_ANY,
2720 EL_QUICKSAND_FILLING,
2721 EL_QUICKSAND_EMPTYING,
2723 EL_MAGIC_WALL_ACTIVE,
2724 EL_MAGIC_WALL_EMPTYING,
2725 EL_MAGIC_WALL_FILLING,
2729 EL_BD_MAGIC_WALL_ACTIVE,
2730 EL_BD_MAGIC_WALL_EMPTYING,
2731 EL_BD_MAGIC_WALL_FULL,
2732 EL_BD_MAGIC_WALL_FILLING,
2733 EL_BD_MAGIC_WALL_DEAD,
2742 EL_SP_TERMINAL_ACTIVE,
2746 EL_INVISIBLE_WALL_ACTIVE,
2747 EL_SWITCHGATE_SWITCH_UP,
2748 EL_SWITCHGATE_SWITCH_DOWN,
2750 EL_TIMEGATE_SWITCH_ACTIVE,
2762 /* the following elements are a direct copy of "indestructible" elements,
2763 except "EL_ACID", which is "indestructible", but not "solid"! */
2768 EL_ACID_POOL_TOPLEFT,
2769 EL_ACID_POOL_TOPRIGHT,
2770 EL_ACID_POOL_BOTTOMLEFT,
2771 EL_ACID_POOL_BOTTOM,
2772 EL_ACID_POOL_BOTTOMRIGHT,
2773 EL_SP_HARDWARE_GRAY,
2774 EL_SP_HARDWARE_GREEN,
2775 EL_SP_HARDWARE_BLUE,
2777 EL_SP_HARDWARE_YELLOW,
2778 EL_SP_HARDWARE_BASE_1,
2779 EL_SP_HARDWARE_BASE_2,
2780 EL_SP_HARDWARE_BASE_3,
2781 EL_SP_HARDWARE_BASE_4,
2782 EL_SP_HARDWARE_BASE_5,
2783 EL_SP_HARDWARE_BASE_6,
2784 EL_INVISIBLE_STEELWALL,
2785 EL_INVISIBLE_STEELWALL_ACTIVE,
2786 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2787 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2788 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2789 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2790 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2791 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2792 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2793 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2794 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2795 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2796 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2797 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2799 EL_LIGHT_SWITCH_ACTIVE,
2800 EL_SIGN_EXCLAMATION,
2801 EL_SIGN_RADIOACTIVITY,
2812 EL_STEELWALL_SLIPPERY,
2835 EL_SWITCHGATE_OPENING,
2836 EL_SWITCHGATE_CLOSED,
2837 EL_SWITCHGATE_CLOSING,
2839 EL_TIMEGATE_OPENING,
2841 EL_TIMEGATE_CLOSING,
2845 EL_TUBE_VERTICAL_LEFT,
2846 EL_TUBE_VERTICAL_RIGHT,
2847 EL_TUBE_HORIZONTAL_UP,
2848 EL_TUBE_HORIZONTAL_DOWN,
2856 static int ep_classic_enemy[] =
2872 static int ep_belt[] =
2874 EL_CONVEYOR_BELT_1_LEFT,
2875 EL_CONVEYOR_BELT_1_MIDDLE,
2876 EL_CONVEYOR_BELT_1_RIGHT,
2877 EL_CONVEYOR_BELT_2_LEFT,
2878 EL_CONVEYOR_BELT_2_MIDDLE,
2879 EL_CONVEYOR_BELT_2_RIGHT,
2880 EL_CONVEYOR_BELT_3_LEFT,
2881 EL_CONVEYOR_BELT_3_MIDDLE,
2882 EL_CONVEYOR_BELT_3_RIGHT,
2883 EL_CONVEYOR_BELT_4_LEFT,
2884 EL_CONVEYOR_BELT_4_MIDDLE,
2885 EL_CONVEYOR_BELT_4_RIGHT,
2889 static int ep_belt_active[] =
2891 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2892 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2893 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2894 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2895 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2896 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2897 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2898 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2899 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2900 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2901 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2902 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2906 static int ep_belt_switch[] =
2908 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2909 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2910 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2911 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2912 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2913 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2914 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2915 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2916 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2917 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2918 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2919 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2923 static int ep_tube[] =
2930 EL_TUBE_HORIZONTAL_UP,
2931 EL_TUBE_HORIZONTAL_DOWN,
2933 EL_TUBE_VERTICAL_LEFT,
2934 EL_TUBE_VERTICAL_RIGHT,
2939 static int ep_keygate[] =
2968 static int ep_amoeboid[] =
2978 static int ep_amoebalive[] =
2987 static int ep_has_content[] =
2997 static int ep_can_turn_each_move[] =
2999 /* !!! do something with this one !!! */
3003 static int ep_can_grow[] =
3015 static int ep_active_bomb[] =
3018 EL_DYNABOMB_PLAYER_1_ACTIVE,
3019 EL_DYNABOMB_PLAYER_2_ACTIVE,
3020 EL_DYNABOMB_PLAYER_3_ACTIVE,
3021 EL_DYNABOMB_PLAYER_4_ACTIVE,
3022 EL_SP_DISK_RED_ACTIVE,
3026 static int ep_inactive[] =
3075 EL_INVISIBLE_STEELWALL,
3083 EL_WALL_EMERALD_YELLOW,
3084 EL_DYNABOMB_INCREASE_NUMBER,
3085 EL_DYNABOMB_INCREASE_SIZE,
3086 EL_DYNABOMB_INCREASE_POWER,
3090 EL_SOKOBAN_FIELD_EMPTY,
3091 EL_SOKOBAN_FIELD_FULL,
3092 EL_WALL_EMERALD_RED,
3093 EL_WALL_EMERALD_PURPLE,
3094 EL_ACID_POOL_TOPLEFT,
3095 EL_ACID_POOL_TOPRIGHT,
3096 EL_ACID_POOL_BOTTOMLEFT,
3097 EL_ACID_POOL_BOTTOM,
3098 EL_ACID_POOL_BOTTOMRIGHT,
3102 EL_BD_MAGIC_WALL_DEAD,
3103 EL_AMOEBA_TO_DIAMOND,
3111 EL_SP_GRAVITY_PORT_RIGHT,
3112 EL_SP_GRAVITY_PORT_DOWN,
3113 EL_SP_GRAVITY_PORT_LEFT,
3114 EL_SP_GRAVITY_PORT_UP,
3115 EL_SP_PORT_HORIZONTAL,
3116 EL_SP_PORT_VERTICAL,
3127 EL_SP_HARDWARE_GRAY,
3128 EL_SP_HARDWARE_GREEN,
3129 EL_SP_HARDWARE_BLUE,
3131 EL_SP_HARDWARE_YELLOW,
3132 EL_SP_HARDWARE_BASE_1,
3133 EL_SP_HARDWARE_BASE_2,
3134 EL_SP_HARDWARE_BASE_3,
3135 EL_SP_HARDWARE_BASE_4,
3136 EL_SP_HARDWARE_BASE_5,
3137 EL_SP_HARDWARE_BASE_6,
3138 EL_SP_GRAVITY_ON_PORT_LEFT,
3139 EL_SP_GRAVITY_ON_PORT_RIGHT,
3140 EL_SP_GRAVITY_ON_PORT_UP,
3141 EL_SP_GRAVITY_ON_PORT_DOWN,
3142 EL_SP_GRAVITY_OFF_PORT_LEFT,
3143 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3144 EL_SP_GRAVITY_OFF_PORT_UP,
3145 EL_SP_GRAVITY_OFF_PORT_DOWN,
3146 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3147 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3148 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3149 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3150 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3151 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3152 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3153 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3154 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3155 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3156 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3157 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3158 EL_SIGN_EXCLAMATION,
3159 EL_SIGN_RADIOACTIVITY,
3170 EL_STEELWALL_SLIPPERY,
3175 EL_EMC_WALL_SLIPPERY_1,
3176 EL_EMC_WALL_SLIPPERY_2,
3177 EL_EMC_WALL_SLIPPERY_3,
3178 EL_EMC_WALL_SLIPPERY_4,
3198 static int ep_em_slippery_wall[] =
3203 static int ep_gfx_crumbled[] =
3216 } element_properties[] =
3218 { ep_diggable, EP_DIGGABLE },
3219 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3220 { ep_dont_run_into, EP_DONT_RUN_INTO },
3221 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3222 { ep_dont_touch, EP_DONT_TOUCH },
3223 { ep_indestructible, EP_INDESTRUCTIBLE },
3224 { ep_slippery, EP_SLIPPERY },
3225 { ep_can_change, EP_CAN_CHANGE },
3226 { ep_can_move, EP_CAN_MOVE },
3227 { ep_can_fall, EP_CAN_FALL },
3228 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3229 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3230 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3231 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3232 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3233 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3234 { ep_walkable_over, EP_WALKABLE_OVER },
3235 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3236 { ep_walkable_under, EP_WALKABLE_UNDER },
3237 { ep_passable_over, EP_PASSABLE_OVER },
3238 { ep_passable_inside, EP_PASSABLE_INSIDE },
3239 { ep_passable_under, EP_PASSABLE_UNDER },
3240 { ep_droppable, EP_DROPPABLE },
3241 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3242 { ep_pushable, EP_PUSHABLE },
3243 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3244 { ep_protected, EP_PROTECTED },
3245 { ep_throwable, EP_THROWABLE },
3246 { ep_can_explode, EP_CAN_EXPLODE },
3247 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3249 { ep_player, EP_PLAYER },
3250 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3251 { ep_switchable, EP_SWITCHABLE },
3252 { ep_bd_element, EP_BD_ELEMENT },
3253 { ep_sp_element, EP_SP_ELEMENT },
3254 { ep_sb_element, EP_SB_ELEMENT },
3256 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3257 { ep_food_penguin, EP_FOOD_PENGUIN },
3258 { ep_food_pig, EP_FOOD_PIG },
3259 { ep_historic_wall, EP_HISTORIC_WALL },
3260 { ep_historic_solid, EP_HISTORIC_SOLID },
3261 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3262 { ep_belt, EP_BELT },
3263 { ep_belt_active, EP_BELT_ACTIVE },
3264 { ep_belt_switch, EP_BELT_SWITCH },
3265 { ep_tube, EP_TUBE },
3266 { ep_keygate, EP_KEYGATE },
3267 { ep_amoeboid, EP_AMOEBOID },
3268 { ep_amoebalive, EP_AMOEBALIVE },
3269 { ep_has_content, EP_HAS_CONTENT },
3270 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3271 { ep_can_grow, EP_CAN_GROW },
3272 { ep_active_bomb, EP_ACTIVE_BOMB },
3273 { ep_inactive, EP_INACTIVE },
3275 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3277 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3284 /* always start with reliable default values (element has no properties) */
3285 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3286 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3287 SET_PROPERTY(i, j, FALSE);
3289 /* set all base element properties from above array definitions */
3290 for (i = 0; element_properties[i].elements != NULL; i++)
3291 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3292 SET_PROPERTY((element_properties[i].elements)[j],
3293 element_properties[i].property, TRUE);
3295 /* copy properties to some elements that are only stored in level file */
3296 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3297 for (j = 0; copy_properties[j][0] != -1; j++)
3298 if (HAS_PROPERTY(copy_properties[j][0], i))
3299 for (k = 1; k <= 4; k++)
3300 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3303 void InitElementPropertiesEngine(int engine_version)
3305 static int no_wall_properties[] =
3308 EP_COLLECTIBLE_ONLY,
3310 EP_DONT_COLLIDE_WITH,
3313 EP_CAN_SMASH_PLAYER,
3314 EP_CAN_SMASH_ENEMIES,
3315 EP_CAN_SMASH_EVERYTHING,
3320 EP_FOOD_DARK_YAMYAM,
3336 /* important: after initialization in InitElementPropertiesStatic(), the
3337 elements are not again initialized to a default value; therefore all
3338 changes have to make sure that they leave the element with a defined
3339 property (which means that conditional property changes must be set to
3340 a reliable default value before) */
3342 /* set all special, combined or engine dependent element properties */
3343 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3345 /* ---------- INACTIVE ------------------------------------------------- */
3346 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3348 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3349 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3350 IS_WALKABLE_INSIDE(i) ||
3351 IS_WALKABLE_UNDER(i)));
3353 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3354 IS_PASSABLE_INSIDE(i) ||
3355 IS_PASSABLE_UNDER(i)));
3357 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3358 IS_PASSABLE_OVER(i)));
3360 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3361 IS_PASSABLE_INSIDE(i)));
3363 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3364 IS_PASSABLE_UNDER(i)));
3366 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3369 /* ---------- COLLECTIBLE ---------------------------------------------- */
3370 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3374 /* ---------- SNAPPABLE ------------------------------------------------ */
3375 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3376 IS_COLLECTIBLE(i) ||
3380 /* ---------- WALL ----------------------------------------------------- */
3381 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3383 for (j = 0; no_wall_properties[j] != -1; j++)
3384 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3385 i >= EL_FIRST_RUNTIME_UNREAL)
3386 SET_PROPERTY(i, EP_WALL, FALSE);
3388 if (IS_HISTORIC_WALL(i))
3389 SET_PROPERTY(i, EP_WALL, TRUE);
3391 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3392 if (engine_version < VERSION_IDENT(2,2,0,0))
3393 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3395 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3397 !IS_COLLECTIBLE(i)));
3399 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3401 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3402 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3404 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3405 IS_INDESTRUCTIBLE(i)));
3407 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3409 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3410 else if (engine_version < VERSION_IDENT(2,2,0,0))
3411 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3413 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3417 if (IS_CUSTOM_ELEMENT(i))
3419 /* these are additional properties which are initially false when set */
3421 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3423 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3424 if (DONT_COLLIDE_WITH(i))
3425 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3427 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3428 if (CAN_SMASH_EVERYTHING(i))
3429 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3430 if (CAN_SMASH_ENEMIES(i))
3431 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3434 /* ---------- CAN_SMASH ------------------------------------------------ */
3435 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3436 CAN_SMASH_ENEMIES(i) ||
3437 CAN_SMASH_EVERYTHING(i)));
3439 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3440 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3441 EXPLODES_BY_FIRE(i)));
3443 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3444 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3445 EXPLODES_SMASHED(i)));
3447 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3448 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3449 EXPLODES_IMPACT(i)));
3451 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3452 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3454 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3455 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3456 i == EL_BLACK_ORB));
3458 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3459 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3461 IS_CUSTOM_ELEMENT(i)));
3463 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3464 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3465 i == EL_SP_ELECTRON));
3467 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3468 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3469 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3470 getMoveIntoAcidProperty(&level, i));
3472 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3473 if (MAYBE_DONT_COLLIDE_WITH(i))
3474 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3475 getDontCollideWithProperty(&level, i));
3477 /* ---------- SP_PORT -------------------------------------------------- */
3478 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3479 IS_PASSABLE_INSIDE(i)));
3481 /* ---------- CAN_CHANGE ----------------------------------------------- */
3482 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3483 for (j = 0; j < element_info[i].num_change_pages; j++)
3484 if (element_info[i].change_page[j].can_change)
3485 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3487 /* ---------- HAS_ACTION ----------------------------------------------- */
3488 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3489 for (j = 0; j < element_info[i].num_change_pages; j++)
3490 if (element_info[i].change_page[j].has_action)
3491 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3493 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3494 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3497 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3499 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3500 element_info[i].crumbled[ACTION_DEFAULT] !=
3501 element_info[i].graphic[ACTION_DEFAULT]);
3503 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3504 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3505 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3509 /* dynamically adjust element properties according to game engine version */
3511 static int ep_em_slippery_wall[] =
3516 EL_EXPANDABLE_WALL_HORIZONTAL,
3517 EL_EXPANDABLE_WALL_VERTICAL,
3518 EL_EXPANDABLE_WALL_ANY,
3522 /* special EM style gems behaviour */
3523 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3524 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3525 level.em_slippery_gems);
3527 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3528 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3529 (level.em_slippery_gems &&
3530 engine_version > VERSION_IDENT(2,0,1,0)));
3533 /* set default push delay values (corrected since version 3.0.7-1) */
3534 if (engine_version < VERSION_IDENT(3,0,7,1))
3536 game.default_push_delay_fixed = 2;
3537 game.default_push_delay_random = 8;
3541 game.default_push_delay_fixed = 8;
3542 game.default_push_delay_random = 8;
3545 /* set uninitialized push delay values of custom elements in older levels */
3546 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3548 int element = EL_CUSTOM_START + i;
3550 if (element_info[element].push_delay_fixed == -1)
3551 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3552 if (element_info[element].push_delay_random == -1)
3553 element_info[element].push_delay_random = game.default_push_delay_random;
3556 /* set some other uninitialized values of custom elements in older levels */
3557 if (engine_version < VERSION_IDENT(3,1,0,0))
3559 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3561 int element = EL_CUSTOM_START + i;
3563 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3565 element_info[element].explosion_delay = 17;
3566 element_info[element].ignition_delay = 8;
3571 /* set element properties that were handled incorrectly in older levels */
3572 if (engine_version < VERSION_IDENT(3,1,0,0))
3574 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3575 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3579 /* this is needed because some graphics depend on element properties */
3580 if (game_status == GAME_MODE_PLAYING)
3581 InitElementGraphicInfo();
3584 static void InitGlobal()
3588 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3590 /* check if element_name_info entry defined for each element in "main.h" */
3591 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3592 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3594 element_info[i].token_name = element_name_info[i].token_name;
3595 element_info[i].class_name = element_name_info[i].class_name;
3596 element_info[i].editor_description=element_name_info[i].editor_description;
3599 global.autoplay_leveldir = NULL;
3600 global.convert_leveldir = NULL;
3602 global.frames_per_second = 0;
3603 global.fps_slowdown = FALSE;
3604 global.fps_slowdown_factor = 1;
3607 void Execute_Command(char *command)
3611 if (strcmp(command, "print graphicsinfo.conf") == 0)
3613 printf("# You can configure additional/alternative image files here.\n");
3614 printf("# (The entries below are default and therefore commented out.)\n");
3616 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3618 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3621 for (i = 0; image_config[i].token != NULL; i++)
3622 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3623 image_config[i].value));
3627 else if (strcmp(command, "print soundsinfo.conf") == 0)
3629 printf("# You can configure additional/alternative sound files here.\n");
3630 printf("# (The entries below are default and therefore commented out.)\n");
3632 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3634 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3637 for (i = 0; sound_config[i].token != NULL; i++)
3638 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3639 sound_config[i].value));
3643 else if (strcmp(command, "print musicinfo.conf") == 0)
3645 printf("# You can configure additional/alternative music files here.\n");
3646 printf("# (The entries below are default and therefore commented out.)\n");
3648 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3650 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3653 for (i = 0; music_config[i].token != NULL; i++)
3654 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3655 music_config[i].value));
3659 else if (strcmp(command, "print editorsetup.conf") == 0)
3661 printf("# You can configure your personal editor element list here.\n");
3662 printf("# (The entries below are default and therefore commented out.)\n");
3665 PrintEditorElementList();
3669 else if (strcmp(command, "print helpanim.conf") == 0)
3671 printf("# You can configure different element help animations here.\n");
3672 printf("# (The entries below are default and therefore commented out.)\n");
3675 for (i = 0; helpanim_config[i].token != NULL; i++)
3677 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3678 helpanim_config[i].value));
3680 if (strcmp(helpanim_config[i].token, "end") == 0)
3686 else if (strcmp(command, "print helptext.conf") == 0)
3688 printf("# You can configure different element help text here.\n");
3689 printf("# (The entries below are default and therefore commented out.)\n");
3692 for (i = 0; helptext_config[i].token != NULL; i++)
3693 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3694 helptext_config[i].value));
3698 else if (strncmp(command, "dump level ", 11) == 0)
3700 char *filename = &command[11];
3702 if (!fileExists(filename))
3703 Error(ERR_EXIT, "cannot open file '%s'", filename);
3705 LoadLevelFromFilename(&level, filename);
3710 else if (strncmp(command, "dump tape ", 10) == 0)
3712 char *filename = &command[10];
3714 if (!fileExists(filename))
3715 Error(ERR_EXIT, "cannot open file '%s'", filename);
3717 LoadTapeFromFilename(filename);
3722 else if (strncmp(command, "autoplay ", 9) == 0)
3724 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3726 while (*str_ptr != '\0') /* continue parsing string */
3728 /* cut leading whitespace from string, replace it by string terminator */
3729 while (*str_ptr == ' ' || *str_ptr == '\t')
3732 if (*str_ptr == '\0') /* end of string reached */
3735 if (global.autoplay_leveldir == NULL) /* read level set string */
3737 global.autoplay_leveldir = str_ptr;
3738 global.autoplay_all = TRUE; /* default: play all tapes */
3740 for (i = 0; i < MAX_TAPES_PER_SET; i++)
3741 global.autoplay_level[i] = FALSE;
3743 else /* read level number string */
3745 int level_nr = atoi(str_ptr); /* get level_nr value */
3747 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3748 global.autoplay_level[level_nr] = TRUE;
3750 global.autoplay_all = FALSE;
3753 /* advance string pointer to the next whitespace (or end of string) */
3754 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3758 else if (strncmp(command, "convert ", 8) == 0)
3760 char *str_copy = getStringCopy(&command[8]);
3761 char *str_ptr = strchr(str_copy, ' ');
3763 global.convert_leveldir = str_copy;
3764 global.convert_level_nr = -1;
3766 if (str_ptr != NULL) /* level number follows */
3768 *str_ptr++ = '\0'; /* terminate leveldir string */
3769 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
3774 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3778 static void InitSetup()
3780 LoadSetup(); /* global setup info */
3782 /* set some options from setup file */
3784 if (setup.options.verbose)
3785 options.verbose = TRUE;
3788 static void InitGameInfo()
3790 game.restart_level = FALSE;
3793 static void InitPlayerInfo()
3797 /* choose default local player */
3798 local_player = &stored_player[0];
3800 for (i = 0; i < MAX_PLAYERS; i++)
3801 stored_player[i].connected = FALSE;
3803 local_player->connected = TRUE;
3806 static void InitArtworkInfo()
3811 static char *get_string_in_brackets(char *string)
3813 char *string_in_brackets = checked_malloc(strlen(string) + 3);
3815 sprintf(string_in_brackets, "[%s]", string);
3817 return string_in_brackets;
3820 static char *get_level_id_suffix(int id_nr)
3822 char *id_suffix = checked_malloc(1 + 3 + 1);
3824 if (id_nr < 0 || id_nr > 999)
3827 sprintf(id_suffix, ".%03d", id_nr);
3833 static char *get_element_class_token(int element)
3835 char *element_class_name = element_info[element].class_name;
3836 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3838 sprintf(element_class_token, "[%s]", element_class_name);
3840 return element_class_token;
3843 static char *get_action_class_token(int action)
3845 char *action_class_name = &element_action_info[action].suffix[1];
3846 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3848 sprintf(action_class_token, "[%s]", action_class_name);
3850 return action_class_token;
3854 static void InitArtworkConfig()
3856 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3857 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3858 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3859 static char *action_id_suffix[NUM_ACTIONS + 1];
3860 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3861 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3862 static char *level_id_suffix[MAX_LEVELS + 1];
3863 static char *dummy[1] = { NULL };
3864 static char *ignore_generic_tokens[] =
3870 static char **ignore_image_tokens;
3871 static char **ignore_sound_tokens;
3872 static char **ignore_music_tokens;
3873 int num_ignore_generic_tokens;
3874 int num_ignore_image_tokens;
3875 int num_ignore_sound_tokens;
3876 int num_ignore_music_tokens;
3879 /* dynamically determine list of generic tokens to be ignored */
3880 num_ignore_generic_tokens = 0;
3881 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3882 num_ignore_generic_tokens++;
3884 /* dynamically determine list of image tokens to be ignored */
3885 num_ignore_image_tokens = num_ignore_generic_tokens;
3886 for (i = 0; image_config_vars[i].token != NULL; i++)
3887 num_ignore_image_tokens++;
3888 ignore_image_tokens =
3889 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3890 for (i = 0; i < num_ignore_generic_tokens; i++)
3891 ignore_image_tokens[i] = ignore_generic_tokens[i];
3892 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3893 ignore_image_tokens[num_ignore_generic_tokens + i] =
3894 image_config_vars[i].token;
3895 ignore_image_tokens[num_ignore_image_tokens] = NULL;
3897 /* dynamically determine list of sound tokens to be ignored */
3898 num_ignore_sound_tokens = num_ignore_generic_tokens;
3899 ignore_sound_tokens =
3900 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3901 for (i = 0; i < num_ignore_generic_tokens; i++)
3902 ignore_sound_tokens[i] = ignore_generic_tokens[i];
3903 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3905 /* dynamically determine list of music tokens to be ignored */
3906 num_ignore_music_tokens = num_ignore_generic_tokens;
3907 ignore_music_tokens =
3908 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3909 for (i = 0; i < num_ignore_generic_tokens; i++)
3910 ignore_music_tokens[i] = ignore_generic_tokens[i];
3911 ignore_music_tokens[num_ignore_music_tokens] = NULL;
3913 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3914 image_id_prefix[i] = element_info[i].token_name;
3915 for (i = 0; i < NUM_FONTS; i++)
3916 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3917 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3919 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3920 sound_id_prefix[i] = element_info[i].token_name;
3921 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3922 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3923 get_string_in_brackets(element_info[i].class_name);
3924 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3926 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3927 music_id_prefix[i] = music_prefix_info[i].prefix;
3928 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
3930 for (i = 0; i < NUM_ACTIONS; i++)
3931 action_id_suffix[i] = element_action_info[i].suffix;
3932 action_id_suffix[NUM_ACTIONS] = NULL;
3934 for (i = 0; i < NUM_DIRECTIONS; i++)
3935 direction_id_suffix[i] = element_direction_info[i].suffix;
3936 direction_id_suffix[NUM_DIRECTIONS] = NULL;
3938 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3939 special_id_suffix[i] = special_suffix_info[i].suffix;
3940 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3942 for (i = 0; i < MAX_LEVELS; i++)
3943 level_id_suffix[i] = get_level_id_suffix(i);
3944 level_id_suffix[MAX_LEVELS] = NULL;
3946 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3947 image_id_prefix, action_id_suffix, direction_id_suffix,
3948 special_id_suffix, ignore_image_tokens);
3949 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3950 sound_id_prefix, action_id_suffix, dummy,
3951 special_id_suffix, ignore_sound_tokens);
3952 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3953 music_id_prefix, special_id_suffix, level_id_suffix,
3954 dummy, ignore_music_tokens);
3957 static void InitMixer()
3965 char *filename_font_initial = NULL;
3966 Bitmap *bitmap_font_initial = NULL;
3969 /* determine settings for initial font (for displaying startup messages) */
3970 for (i = 0; image_config[i].token != NULL; i++)
3972 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3974 char font_token[128];
3977 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3978 len_font_token = strlen(font_token);
3980 if (strcmp(image_config[i].token, font_token) == 0)
3981 filename_font_initial = image_config[i].value;
3982 else if (strlen(image_config[i].token) > len_font_token &&
3983 strncmp(image_config[i].token, font_token, len_font_token) == 0)
3985 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3986 font_initial[j].src_x = atoi(image_config[i].value);
3987 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3988 font_initial[j].src_y = atoi(image_config[i].value);
3989 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3990 font_initial[j].width = atoi(image_config[i].value);
3991 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3992 font_initial[j].height = atoi(image_config[i].value);
3997 for (j = 0; j < NUM_INITIAL_FONTS; j++)
3999 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4000 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4003 if (filename_font_initial == NULL) /* should not happen */
4004 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4006 /* create additional image buffers for double-buffering */
4007 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4008 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4010 /* initialize screen properties */
4011 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4012 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4014 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4015 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4016 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4018 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4020 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4021 font_initial[j].bitmap = bitmap_font_initial;
4023 InitFontGraphicInfo();
4025 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4026 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4028 DrawInitText("Loading graphics:", 120, FC_GREEN);
4031 void InitGfxBackground()
4035 drawto = backbuffer;
4036 fieldbuffer = bitmap_db_field;
4037 SetDrawtoField(DRAW_BACKBUFFER);
4039 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4040 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4041 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4042 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4044 for (x = 0; x < MAX_BUF_XSIZE; x++)
4045 for (y = 0; y < MAX_BUF_YSIZE; y++)
4048 redraw_mask = REDRAW_ALL;
4051 static void InitLevelInfo()
4053 LoadLevelInfo(); /* global level info */
4054 LoadLevelSetup_LastSeries(); /* last played series info */
4055 LoadLevelSetup_SeriesInfo(); /* last played level info */
4058 void InitLevelArtworkInfo()
4060 LoadLevelArtworkInfo();
4063 static void InitImages()
4065 setLevelArtworkDir(artwork.gfx_first);
4068 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4069 leveldir_current->identifier,
4070 artwork.gfx_current_identifier,
4071 artwork.gfx_current->identifier,
4072 leveldir_current->graphics_set,
4073 leveldir_current->graphics_path);
4076 ReloadCustomImages();
4078 LoadCustomElementDescriptions();
4079 LoadSpecialMenuDesignSettings();
4081 ReinitializeGraphics();
4084 static void InitSound(char *identifier)
4086 if (identifier == NULL)
4087 identifier = artwork.snd_current->identifier;
4089 /* set artwork path to send it to the sound server process */
4090 setLevelArtworkDir(artwork.snd_first);
4092 InitReloadCustomSounds(identifier);
4093 ReinitializeSounds();
4096 static void InitMusic(char *identifier)
4098 if (identifier == NULL)
4099 identifier = artwork.mus_current->identifier;
4101 /* set artwork path to send it to the sound server process */
4102 setLevelArtworkDir(artwork.mus_first);
4104 InitReloadCustomMusic(identifier);
4105 ReinitializeMusic();
4108 void InitNetworkServer()
4110 #if defined(NETWORK_AVALIABLE)
4114 if (!options.network)
4117 #if defined(NETWORK_AVALIABLE)
4118 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4120 if (!ConnectToServer(options.server_host, options.server_port))
4121 Error(ERR_EXIT, "cannot connect to network game server");
4123 SendToServer_PlayerName(setup.player_name);
4124 SendToServer_ProtocolVersion();
4127 SendToServer_NrWanted(nr_wanted);
4131 static char *getNewArtworkIdentifier(int type)
4133 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4134 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4135 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4136 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4137 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4138 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4139 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4140 char *leveldir_identifier = leveldir_current->identifier;
4142 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4143 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4145 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4147 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4148 char *artwork_current_identifier;
4149 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4151 /* leveldir_current may be invalid (level group, parent link) */
4152 if (!validLevelSeries(leveldir_current))
4155 /* 1st step: determine artwork set to be activated in descending order:
4156 --------------------------------------------------------------------
4157 1. setup artwork (when configured to override everything else)
4158 2. artwork set configured in "levelinfo.conf" of current level set
4159 (artwork in level directory will have priority when loading later)
4160 3. artwork in level directory (stored in artwork sub-directory)
4161 4. setup artwork (currently configured in setup menu) */
4163 if (setup_override_artwork)
4164 artwork_current_identifier = setup_artwork_set;
4165 else if (leveldir_artwork_set != NULL)
4166 artwork_current_identifier = leveldir_artwork_set;
4167 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4168 artwork_current_identifier = leveldir_identifier;
4170 artwork_current_identifier = setup_artwork_set;
4173 /* 2nd step: check if it is really needed to reload artwork set
4174 ------------------------------------------------------------ */
4177 if (type == ARTWORK_TYPE_GRAPHICS)
4178 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4179 artwork_new_identifier,
4180 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4181 artwork_current_identifier,
4182 leveldir_current->graphics_set,
4183 leveldir_current->identifier);
4186 /* ---------- reload if level set and also artwork set has changed ------- */
4187 if (leveldir_current_identifier[type] != leveldir_identifier &&
4188 (last_has_level_artwork_set[type] || has_level_artwork_set))
4189 artwork_new_identifier = artwork_current_identifier;
4191 leveldir_current_identifier[type] = leveldir_identifier;
4192 last_has_level_artwork_set[type] = has_level_artwork_set;
4195 if (type == ARTWORK_TYPE_GRAPHICS)
4196 printf("::: 1: '%s'\n", artwork_new_identifier);
4199 /* ---------- reload if "override artwork" setting has changed ----------- */
4200 if (last_override_level_artwork[type] != setup_override_artwork)
4201 artwork_new_identifier = artwork_current_identifier;
4203 last_override_level_artwork[type] = setup_override_artwork;
4206 if (type == ARTWORK_TYPE_GRAPHICS)
4207 printf("::: 2: '%s'\n", artwork_new_identifier);
4210 /* ---------- reload if current artwork identifier has changed ----------- */
4211 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4212 artwork_current_identifier) != 0)
4213 artwork_new_identifier = artwork_current_identifier;
4215 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4218 if (type == ARTWORK_TYPE_GRAPHICS)
4219 printf("::: 3: '%s'\n", artwork_new_identifier);
4222 /* ---------- do not reload directly after starting ---------------------- */
4223 if (!initialized[type])
4224 artwork_new_identifier = NULL;
4226 initialized[type] = TRUE;
4229 if (type == ARTWORK_TYPE_GRAPHICS)
4230 printf("::: 4: '%s'\n", artwork_new_identifier);
4234 if (type == ARTWORK_TYPE_GRAPHICS)
4235 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4236 artwork.gfx_current_identifier, artwork_current_identifier,
4237 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4238 artwork_new_identifier);
4241 return artwork_new_identifier;
4244 void ReloadCustomArtwork(int force_reload)
4246 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4247 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4248 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4249 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4250 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4251 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4252 boolean redraw_screen = FALSE;
4254 if (gfx_new_identifier != NULL || force_reload_gfx)
4257 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4258 artwork.gfx_current_identifier,
4260 artwork.gfx_current->identifier,
4261 leveldir_current->graphics_set);
4264 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4268 redraw_screen = TRUE;
4271 if (snd_new_identifier != NULL || force_reload_snd)
4273 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4275 InitSound(snd_new_identifier);
4277 redraw_screen = TRUE;
4280 if (mus_new_identifier != NULL || force_reload_mus)
4282 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4284 InitMusic(mus_new_identifier);
4286 redraw_screen = TRUE;
4291 InitGfxBackground();
4293 /* force redraw of (open or closed) door graphics */
4294 SetDoorState(DOOR_OPEN_ALL);
4295 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4299 void KeyboardAutoRepeatOffUnlessAutoplay()
4301 if (global.autoplay_leveldir == NULL)
4302 KeyboardAutoRepeatOff();
4306 /* ========================================================================= */
4308 /* ========================================================================= */
4312 InitGlobal(); /* initialize some global variables */
4314 if (options.execute_command)
4315 Execute_Command(options.execute_command);
4317 if (options.serveronly)
4319 #if defined(PLATFORM_UNIX)
4320 NetworkServer(options.server_port, options.serveronly);
4322 Error(ERR_WARN, "networking only supported in Unix version");
4325 exit(0); /* never reached, server loops forever */
4332 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4333 InitArtworkConfig(); /* needed before forking sound child process */
4338 InitRND(NEW_RANDOMIZE);
4339 InitSimpleRND(NEW_RANDOMIZE);
4344 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4347 InitEventFilter(FilterMouseMotionEvents);
4349 InitElementPropertiesStatic();
4350 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4355 InitLevelArtworkInfo();
4357 InitImages(); /* needs to know current level directory */
4358 InitSound(NULL); /* needs to know current level directory */
4359 InitMusic(NULL); /* needs to know current level directory */
4361 InitGfxBackground();
4363 if (global.autoplay_leveldir)
4368 else if (global.convert_leveldir)
4374 game_status = GAME_MODE_MAIN;
4382 InitNetworkServer();
4385 void CloseAllAndExit(int exit_value)
4390 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4398 #if defined(TARGET_SDL)
4399 if (network_server) /* terminate network server */
4400 SDL_KillThread(server_thread);
4403 CloseVideoDisplay();
4404 ClosePlatformDependentStuff();