1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
109 gadgets_initialized = TRUE;
112 inline void InitElementSmallImagesScaledUp(int graphic)
114 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
117 void InitElementSmallImages()
119 static int special_graphics[] =
121 IMG_EDITOR_ELEMENT_BORDER,
122 IMG_EDITOR_ELEMENT_BORDER_INPUT,
123 IMG_EDITOR_CASCADE_LIST,
124 IMG_EDITOR_CASCADE_LIST_ACTIVE,
127 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
128 int num_property_mappings = getImageListPropertyMappingSize();
131 /* initialize normal images from static configuration */
132 for (i = 0; element_to_graphic[i].element > -1; i++)
133 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
135 /* initialize special images from static configuration */
136 for (i = 0; element_to_special_graphic[i].element > -1; i++)
137 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
139 /* initialize images from dynamic configuration (may be elements or other) */
140 for (i = 0; i < num_property_mappings; i++)
141 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
143 /* initialize special images from above list (non-element images) */
144 for (i = 0; special_graphics[i] > -1; i++)
145 InitElementSmallImagesScaledUp(special_graphics[i]);
148 void InitScaledImages()
152 /* scale normal images from static configuration, if not already scaled */
153 for (i = 0; i < NUM_IMAGE_FILES; i++)
154 ScaleImage(i, graphic_info[i].scale_up_factor);
158 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
159 void SetBitmaps_EM(Bitmap **em_bitmap)
161 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
162 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
166 static int getFontBitmapID(int font_nr)
170 if (game_status >= GAME_MODE_TITLE && game_status <= GAME_MODE_PSEUDO_PREVIEW)
171 special = game_status;
172 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
173 special = GFX_SPECIAL_ARG_MAIN;
174 else if (game_status == GAME_MODE_PLAYING)
175 special = GFX_SPECIAL_ARG_DOOR;
178 return font_info[font_nr].special_bitmap_id[special];
183 void InitFontGraphicInfo()
185 static struct FontBitmapInfo *font_bitmap_info = NULL;
186 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
187 int num_property_mappings = getImageListPropertyMappingSize();
188 int num_font_bitmaps = NUM_FONTS;
191 if (graphic_info == NULL) /* still at startup phase */
193 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
198 /* ---------- initialize font graphic definitions ---------- */
200 /* always start with reliable default values (normal font graphics) */
201 for (i = 0; i < NUM_FONTS; i++)
202 font_info[i].graphic = IMG_FONT_INITIAL_1;
204 /* initialize normal font/graphic mapping from static configuration */
205 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
207 int font_nr = font_to_graphic[i].font_nr;
208 int special = font_to_graphic[i].special;
209 int graphic = font_to_graphic[i].graphic;
214 font_info[font_nr].graphic = graphic;
217 /* always start with reliable default values (special font graphics) */
218 for (i = 0; i < NUM_FONTS; i++)
220 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
222 font_info[i].special_graphic[j] = font_info[i].graphic;
223 font_info[i].special_bitmap_id[j] = i;
227 /* initialize special font/graphic mapping from static configuration */
228 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
230 int font_nr = font_to_graphic[i].font_nr;
231 int special = font_to_graphic[i].special;
232 int graphic = font_to_graphic[i].graphic;
233 int base_graphic = font2baseimg(font_nr);
235 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
237 boolean base_redefined =
238 getImageListEntryFromImageID(base_graphic)->redefined;
239 boolean special_redefined =
240 getImageListEntryFromImageID(graphic)->redefined;
242 /* if the base font ("font.title_1", for example) has been redefined,
243 but not the special font ("font.title_1.LEVELS", for example), do not
244 use an existing (in this case considered obsolete) special font
245 anymore, but use the automatically determined default font */
246 if (base_redefined && !special_redefined)
249 font_info[font_nr].special_graphic[special] = graphic;
250 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
255 /* initialize special font/graphic mapping from dynamic configuration */
256 for (i = 0; i < num_property_mappings; i++)
258 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
259 int special = property_mapping[i].ext3_index;
260 int graphic = property_mapping[i].artwork_index;
265 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
267 font_info[font_nr].special_graphic[special] = graphic;
268 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
273 /* reset non-redefined ".active" font graphics if normal font is redefined */
274 /* (this different treatment is needed because normal and active fonts are
275 independently defined ("active" is not a property of font definitions!) */
276 for (i = 0; i < NUM_FONTS; i++)
278 int font_nr_base = i;
279 int font_nr_active = FONT_ACTIVE(font_nr_base);
281 /* check only those fonts with exist as normal and ".active" variant */
282 if (font_nr_base != font_nr_active)
284 int base_graphic = font_info[font_nr_base].graphic;
285 int active_graphic = font_info[font_nr_active].graphic;
286 boolean base_redefined =
287 getImageListEntryFromImageID(base_graphic)->redefined;
288 boolean active_redefined =
289 getImageListEntryFromImageID(active_graphic)->redefined;
291 /* if the base font ("font.menu_1", for example) has been redefined,
292 but not the active font ("font.menu_1.active", for example), do not
293 use an existing (in this case considered obsolete) active font
294 anymore, but use the automatically determined default font */
295 if (base_redefined && !active_redefined)
296 font_info[font_nr_active].graphic = base_graphic;
298 /* now also check each "special" font (which may be the same as above) */
299 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
301 int base_graphic = font_info[font_nr_base].special_graphic[j];
302 int active_graphic = font_info[font_nr_active].special_graphic[j];
303 boolean base_redefined =
304 getImageListEntryFromImageID(base_graphic)->redefined;
305 boolean active_redefined =
306 getImageListEntryFromImageID(active_graphic)->redefined;
308 /* same as above, but check special graphic definitions, for example:
309 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
310 if (base_redefined && !active_redefined)
312 font_info[font_nr_active].special_graphic[j] =
313 font_info[font_nr_base].special_graphic[j];
314 font_info[font_nr_active].special_bitmap_id[j] =
315 font_info[font_nr_base].special_bitmap_id[j];
321 /* ---------- initialize font bitmap array ---------- */
323 if (font_bitmap_info != NULL)
324 FreeFontInfo(font_bitmap_info);
327 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
329 /* ---------- initialize font bitmap definitions ---------- */
331 for (i = 0; i < NUM_FONTS; i++)
333 if (i < NUM_INITIAL_FONTS)
335 font_bitmap_info[i] = font_initial[i];
339 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
341 int font_bitmap_id = font_info[i].special_bitmap_id[j];
342 int graphic = font_info[i].special_graphic[j];
344 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
345 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
347 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
348 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
351 /* copy font relevant information from graphics information */
352 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
353 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
354 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
355 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
356 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
358 font_bitmap_info[font_bitmap_id].draw_xoffset =
359 graphic_info[graphic].draw_xoffset;
360 font_bitmap_info[font_bitmap_id].draw_yoffset =
361 graphic_info[graphic].draw_yoffset;
363 font_bitmap_info[font_bitmap_id].num_chars =
364 graphic_info[graphic].anim_frames;
365 font_bitmap_info[font_bitmap_id].num_chars_per_line =
366 graphic_info[graphic].anim_frames_per_line;
370 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
373 void InitElementGraphicInfo()
375 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
376 int num_property_mappings = getImageListPropertyMappingSize();
379 if (graphic_info == NULL) /* still at startup phase */
382 /* set values to -1 to identify later as "uninitialized" values */
383 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
385 for (act = 0; act < NUM_ACTIONS; act++)
387 element_info[i].graphic[act] = -1;
388 element_info[i].crumbled[act] = -1;
390 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
392 element_info[i].direction_graphic[act][dir] = -1;
393 element_info[i].direction_crumbled[act][dir] = -1;
398 /* initialize normal element/graphic mapping from static configuration */
399 for (i = 0; element_to_graphic[i].element > -1; i++)
401 int element = element_to_graphic[i].element;
402 int action = element_to_graphic[i].action;
403 int direction = element_to_graphic[i].direction;
404 boolean crumbled = element_to_graphic[i].crumbled;
405 int graphic = element_to_graphic[i].graphic;
406 int base_graphic = el2baseimg(element);
408 if (graphic_info[graphic].bitmap == NULL)
411 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
414 boolean base_redefined =
415 getImageListEntryFromImageID(base_graphic)->redefined;
416 boolean act_dir_redefined =
417 getImageListEntryFromImageID(graphic)->redefined;
419 /* if the base graphic ("emerald", for example) has been redefined,
420 but not the action graphic ("emerald.falling", for example), do not
421 use an existing (in this case considered obsolete) action graphic
422 anymore, but use the automatically determined default graphic */
423 if (base_redefined && !act_dir_redefined)
428 action = ACTION_DEFAULT;
433 element_info[element].direction_crumbled[action][direction] = graphic;
435 element_info[element].crumbled[action] = graphic;
440 element_info[element].direction_graphic[action][direction] = graphic;
442 element_info[element].graphic[action] = graphic;
446 /* initialize normal element/graphic mapping from dynamic configuration */
447 for (i = 0; i < num_property_mappings; i++)
449 int element = property_mapping[i].base_index;
450 int action = property_mapping[i].ext1_index;
451 int direction = property_mapping[i].ext2_index;
452 int special = property_mapping[i].ext3_index;
453 int graphic = property_mapping[i].artwork_index;
454 boolean crumbled = FALSE;
456 if (special == GFX_SPECIAL_ARG_CRUMBLED)
462 if (graphic_info[graphic].bitmap == NULL)
465 if (element >= MAX_NUM_ELEMENTS || special != -1)
469 action = ACTION_DEFAULT;
474 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
475 element_info[element].direction_crumbled[action][dir] = -1;
478 element_info[element].direction_crumbled[action][direction] = graphic;
480 element_info[element].crumbled[action] = graphic;
485 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
486 element_info[element].direction_graphic[action][dir] = -1;
489 element_info[element].direction_graphic[action][direction] = graphic;
491 element_info[element].graphic[action] = graphic;
495 /* now copy all graphics that are defined to be cloned from other graphics */
496 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
498 int graphic = element_info[i].graphic[ACTION_DEFAULT];
499 int crumbled_like, diggable_like;
504 crumbled_like = graphic_info[graphic].crumbled_like;
505 diggable_like = graphic_info[graphic].diggable_like;
507 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
509 for (act = 0; act < NUM_ACTIONS; act++)
510 element_info[i].crumbled[act] =
511 element_info[crumbled_like].crumbled[act];
512 for (act = 0; act < NUM_ACTIONS; act++)
513 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
514 element_info[i].direction_crumbled[act][dir] =
515 element_info[crumbled_like].direction_crumbled[act][dir];
518 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
520 element_info[i].graphic[ACTION_DIGGING] =
521 element_info[diggable_like].graphic[ACTION_DIGGING];
522 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
523 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
524 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
529 /* set hardcoded definitions for some runtime elements without graphic */
530 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
534 /* set hardcoded definitions for some internal elements without graphic */
535 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
537 if (IS_EDITOR_CASCADE_INACTIVE(i))
538 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
539 else if (IS_EDITOR_CASCADE_ACTIVE(i))
540 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
544 /* now set all undefined/invalid graphics to -1 to set to default after it */
545 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
547 for (act = 0; act < NUM_ACTIONS; act++)
551 graphic = element_info[i].graphic[act];
552 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
553 element_info[i].graphic[act] = -1;
555 graphic = element_info[i].crumbled[act];
556 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
557 element_info[i].crumbled[act] = -1;
559 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
561 graphic = element_info[i].direction_graphic[act][dir];
562 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
563 element_info[i].direction_graphic[act][dir] = -1;
565 graphic = element_info[i].direction_crumbled[act][dir];
566 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
567 element_info[i].direction_crumbled[act][dir] = -1;
572 /* adjust graphics with 2nd tile for movement according to direction
573 (do this before correcting '-1' values to minimize calculations) */
574 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
576 for (act = 0; act < NUM_ACTIONS; act++)
578 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
580 int graphic = element_info[i].direction_graphic[act][dir];
581 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
583 if (act == ACTION_FALLING) /* special case */
584 graphic = element_info[i].graphic[act];
587 graphic_info[graphic].double_movement &&
588 graphic_info[graphic].swap_double_tiles != 0)
590 struct GraphicInfo *g = &graphic_info[graphic];
591 int src_x_front = g->src_x;
592 int src_y_front = g->src_y;
593 int src_x_back = g->src_x + g->offset2_x;
594 int src_y_back = g->src_y + g->offset2_y;
595 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
597 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
598 src_y_front < src_y_back);
599 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
600 boolean swap_movement_tiles_autodetected =
601 (!frames_are_ordered_diagonally &&
602 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
603 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
604 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
605 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
608 /* swap frontside and backside graphic tile coordinates, if needed */
609 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
611 /* get current (wrong) backside tile coordinates */
612 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
615 /* set frontside tile coordinates to backside tile coordinates */
616 g->src_x = src_x_back;
617 g->src_y = src_y_back;
619 /* invert tile offset to point to new backside tile coordinates */
623 /* do not swap front and backside tiles again after correction */
624 g->swap_double_tiles = 0;
631 /* now set all '-1' values to element specific default values */
632 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
634 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
635 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
636 int default_direction_graphic[NUM_DIRECTIONS_FULL];
637 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
639 if (default_graphic == -1)
640 default_graphic = IMG_UNKNOWN;
642 if (default_crumbled == -1)
643 default_crumbled = default_graphic;
645 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
646 if (default_crumbled == -1)
647 default_crumbled = IMG_EMPTY;
650 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
652 default_direction_graphic[dir] =
653 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
654 default_direction_crumbled[dir] =
655 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
657 if (default_direction_graphic[dir] == -1)
658 default_direction_graphic[dir] = default_graphic;
660 if (default_direction_crumbled[dir] == -1)
661 default_direction_crumbled[dir] = default_direction_graphic[dir];
663 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
664 if (default_direction_crumbled[dir] == -1)
665 default_direction_crumbled[dir] = default_crumbled;
669 for (act = 0; act < NUM_ACTIONS; act++)
671 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
672 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
673 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
674 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
675 act == ACTION_TURNING_FROM_RIGHT ||
676 act == ACTION_TURNING_FROM_UP ||
677 act == ACTION_TURNING_FROM_DOWN);
679 /* generic default action graphic (defined by "[default]" directive) */
680 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
681 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
682 int default_remove_graphic = IMG_EMPTY;
684 if (act_remove && default_action_graphic != -1)
685 default_remove_graphic = default_action_graphic;
687 /* look for special default action graphic (classic game specific) */
688 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
689 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
690 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
691 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
692 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
693 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
695 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
696 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
697 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
698 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
699 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
700 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
703 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
704 /* !!! make this better !!! */
705 if (i == EL_EMPTY_SPACE)
707 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
708 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
712 if (default_action_graphic == -1)
713 default_action_graphic = default_graphic;
715 if (default_action_crumbled == -1)
716 default_action_crumbled = default_action_graphic;
718 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
719 if (default_action_crumbled == -1)
720 default_action_crumbled = default_crumbled;
723 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
725 /* use action graphic as the default direction graphic, if undefined */
726 int default_action_direction_graphic = element_info[i].graphic[act];
727 int default_action_direction_crumbled = element_info[i].crumbled[act];
729 /* no graphic for current action -- use default direction graphic */
730 if (default_action_direction_graphic == -1)
731 default_action_direction_graphic =
732 (act_remove ? default_remove_graphic :
734 element_info[i].direction_graphic[ACTION_TURNING][dir] :
735 default_action_graphic != default_graphic ?
736 default_action_graphic :
737 default_direction_graphic[dir]);
739 if (element_info[i].direction_graphic[act][dir] == -1)
740 element_info[i].direction_graphic[act][dir] =
741 default_action_direction_graphic;
744 if (default_action_direction_crumbled == -1)
745 default_action_direction_crumbled =
746 element_info[i].direction_graphic[act][dir];
748 if (default_action_direction_crumbled == -1)
749 default_action_direction_crumbled =
750 (act_remove ? default_remove_graphic :
752 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
753 default_action_crumbled != default_crumbled ?
754 default_action_crumbled :
755 default_direction_crumbled[dir]);
758 if (element_info[i].direction_crumbled[act][dir] == -1)
759 element_info[i].direction_crumbled[act][dir] =
760 default_action_direction_crumbled;
763 /* no graphic for this specific action -- use default action graphic */
764 if (element_info[i].graphic[act] == -1)
765 element_info[i].graphic[act] =
766 (act_remove ? default_remove_graphic :
767 act_turning ? element_info[i].graphic[ACTION_TURNING] :
768 default_action_graphic);
770 if (element_info[i].crumbled[act] == -1)
771 element_info[i].crumbled[act] = element_info[i].graphic[act];
773 if (element_info[i].crumbled[act] == -1)
774 element_info[i].crumbled[act] =
775 (act_remove ? default_remove_graphic :
776 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
777 default_action_crumbled);
783 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
784 /* set animation mode to "none" for each graphic with only 1 frame */
785 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
787 for (act = 0; act < NUM_ACTIONS; act++)
789 int graphic = element_info[i].graphic[act];
790 int crumbled = element_info[i].crumbled[act];
792 if (graphic_info[graphic].anim_frames == 1)
793 graphic_info[graphic].anim_mode = ANIM_NONE;
794 if (graphic_info[crumbled].anim_frames == 1)
795 graphic_info[crumbled].anim_mode = ANIM_NONE;
797 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
799 graphic = element_info[i].direction_graphic[act][dir];
800 crumbled = element_info[i].direction_crumbled[act][dir];
802 if (graphic_info[graphic].anim_frames == 1)
803 graphic_info[graphic].anim_mode = ANIM_NONE;
804 if (graphic_info[crumbled].anim_frames == 1)
805 graphic_info[crumbled].anim_mode = ANIM_NONE;
815 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
816 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
818 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
819 element_info[i].token_name, i);
825 void InitElementSpecialGraphicInfo()
827 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
828 int num_property_mappings = getImageListPropertyMappingSize();
831 /* always start with reliable default values */
832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
833 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
834 element_info[i].special_graphic[j] =
835 element_info[i].graphic[ACTION_DEFAULT];
837 /* initialize special element/graphic mapping from static configuration */
838 for (i = 0; element_to_special_graphic[i].element > -1; i++)
840 int element = element_to_special_graphic[i].element;
841 int special = element_to_special_graphic[i].special;
842 int graphic = element_to_special_graphic[i].graphic;
843 int base_graphic = el2baseimg(element);
844 boolean base_redefined =
845 getImageListEntryFromImageID(base_graphic)->redefined;
846 boolean special_redefined =
847 getImageListEntryFromImageID(graphic)->redefined;
849 /* if the base graphic ("emerald", for example) has been redefined,
850 but not the special graphic ("emerald.EDITOR", for example), do not
851 use an existing (in this case considered obsolete) special graphic
852 anymore, but use the automatically created (down-scaled) graphic */
853 if (base_redefined && !special_redefined)
856 element_info[element].special_graphic[special] = graphic;
859 /* initialize special element/graphic mapping from dynamic configuration */
860 for (i = 0; i < num_property_mappings; i++)
862 int element = property_mapping[i].base_index;
863 int special = property_mapping[i].ext3_index;
864 int graphic = property_mapping[i].artwork_index;
866 if (element >= MAX_NUM_ELEMENTS)
869 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
870 element_info[element].special_graphic[special] = graphic;
873 /* now set all undefined/invalid graphics to default */
874 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
875 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
876 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
877 element_info[i].special_graphic[j] =
878 element_info[i].graphic[ACTION_DEFAULT];
881 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
886 if (type != TYPE_TOKEN)
887 return get_parameter_value(value_raw, suffix, type);
889 if (strEqual(value_raw, ARG_UNDEFINED))
890 return ARG_UNDEFINED_VALUE;
892 /* !!! OPTIMIZE THIS BY USING HASH !!! */
893 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
894 if (strEqual(element_info[i].token_name, value_raw))
897 /* !!! OPTIMIZE THIS BY USING HASH !!! */
898 for (i = 0; image_config[i].token != NULL; i++)
900 int len_config_value = strlen(image_config[i].value);
902 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
903 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
904 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
907 if (strEqual(image_config[i].token, value_raw))
916 static int get_scaled_graphic_width(int graphic)
918 int original_width = getOriginalImageWidthFromImageID(graphic);
919 int scale_up_factor = graphic_info[graphic].scale_up_factor;
921 return original_width * scale_up_factor;
924 static int get_scaled_graphic_height(int graphic)
926 int original_height = getOriginalImageHeightFromImageID(graphic);
927 int scale_up_factor = graphic_info[graphic].scale_up_factor;
929 return original_height * scale_up_factor;
932 static void set_graphic_parameters(int graphic)
934 struct FileInfo *image = getImageListEntryFromImageID(graphic);
935 char **parameter_raw = image->parameter;
936 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
937 int parameter[NUM_GFX_ARGS];
938 int anim_frames_per_row = 1, anim_frames_per_col = 1;
939 int anim_frames_per_line = 1;
942 /* if fallback to default artwork is done, also use the default parameters */
943 if (image->fallback_to_default)
944 parameter_raw = image->default_parameter;
946 /* get integer values from string parameters */
947 for (i = 0; i < NUM_GFX_ARGS; i++)
948 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
949 image_config_suffix[i].token,
950 image_config_suffix[i].type);
952 graphic_info[graphic].bitmap = src_bitmap;
954 /* always start with reliable default values */
955 graphic_info[graphic].src_image_width = 0;
956 graphic_info[graphic].src_image_height = 0;
957 graphic_info[graphic].src_x = 0;
958 graphic_info[graphic].src_y = 0;
959 graphic_info[graphic].width = TILEX; /* default for element graphics */
960 graphic_info[graphic].height = TILEY; /* default for element graphics */
961 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
962 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
963 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
964 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
965 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
966 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
967 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
968 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
969 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
970 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
971 graphic_info[graphic].anim_delay_fixed = 0;
972 graphic_info[graphic].anim_delay_random = 0;
973 graphic_info[graphic].post_delay_fixed = 0;
974 graphic_info[graphic].post_delay_random = 0;
975 graphic_info[graphic].fade_delay = -1;
976 graphic_info[graphic].post_delay = -1;
977 graphic_info[graphic].auto_delay = -1;
980 /* optional zoom factor for scaling up the image to a larger size */
981 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
983 if (graphic_info[graphic].scale_up_factor < 1)
984 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
988 if (graphic_info[graphic].use_image_size)
990 /* set new default bitmap size (with scaling, but without small images) */
991 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
992 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
996 /* optional x and y tile position of animation frame sequence */
997 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
998 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
999 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1000 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1002 /* optional x and y pixel position of animation frame sequence */
1003 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1005 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1008 /* optional width and height of each animation frame */
1009 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1011 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1012 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1015 /* optional zoom factor for scaling up the image to a larger size */
1016 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1017 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1018 if (graphic_info[graphic].scale_up_factor < 1)
1019 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1024 /* get final bitmap size (with scaling, but without small images) */
1025 int src_image_width = get_scaled_graphic_width(graphic);
1026 int src_image_height = get_scaled_graphic_height(graphic);
1028 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1029 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1031 graphic_info[graphic].src_image_width = src_image_width;
1032 graphic_info[graphic].src_image_height = src_image_height;
1035 /* correct x or y offset dependent of vertical or horizontal frame order */
1036 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1038 graphic_info[graphic].offset_y =
1039 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1040 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1041 anim_frames_per_line = anim_frames_per_col;
1043 else /* frames are ordered horizontally */
1045 graphic_info[graphic].offset_x =
1046 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1047 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1048 anim_frames_per_line = anim_frames_per_row;
1051 /* optionally, the x and y offset of frames can be specified directly */
1052 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1054 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1057 /* optionally, moving animations may have separate start and end graphics */
1058 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1060 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1061 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1063 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1064 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1065 graphic_info[graphic].offset2_y =
1066 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1067 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1068 else /* frames are ordered horizontally */
1069 graphic_info[graphic].offset2_x =
1070 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1071 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1073 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1074 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1075 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1076 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1077 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1079 /* optionally, the second movement tile can be specified as start tile */
1080 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1081 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1083 /* automatically determine correct number of frames, if not defined */
1084 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1085 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1086 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1087 graphic_info[graphic].anim_frames = anim_frames_per_row;
1088 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1089 graphic_info[graphic].anim_frames = anim_frames_per_col;
1091 graphic_info[graphic].anim_frames = 1;
1093 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1094 graphic_info[graphic].anim_frames = 1;
1096 graphic_info[graphic].anim_frames_per_line =
1097 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1098 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1100 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1101 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1102 graphic_info[graphic].anim_delay = 1;
1104 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1106 if (graphic_info[graphic].anim_frames == 1)
1107 graphic_info[graphic].anim_mode = ANIM_NONE;
1110 /* automatically determine correct start frame, if not defined */
1111 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1112 graphic_info[graphic].anim_start_frame = 0;
1113 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1114 graphic_info[graphic].anim_start_frame =
1115 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1117 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1119 /* animation synchronized with global frame counter, not move position */
1120 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1122 /* optional element for cloning crumble graphics */
1123 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1126 /* optional element for cloning digging graphics */
1127 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1130 /* optional border size for "crumbling" diggable graphics */
1131 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1134 /* this is only used for player "boring" and "sleeping" actions */
1135 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1136 graphic_info[graphic].anim_delay_fixed =
1137 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1138 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1139 graphic_info[graphic].anim_delay_random =
1140 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1141 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1142 graphic_info[graphic].post_delay_fixed =
1143 parameter[GFX_ARG_POST_DELAY_FIXED];
1144 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1145 graphic_info[graphic].post_delay_random =
1146 parameter[GFX_ARG_POST_DELAY_RANDOM];
1148 /* this is only used for toon animations */
1149 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1150 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1152 /* this is only used for drawing font characters */
1153 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1154 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1156 /* this is only used for drawing envelope graphics */
1157 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1159 /* optional graphic for cloning all graphics settings */
1160 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1161 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1163 /* optional settings for drawing title screens */
1164 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1165 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1166 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1167 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1168 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1169 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1172 static void set_cloned_graphic_parameters(int graphic)
1174 int fallback_graphic = IMG_CHAR_EXCLAM;
1175 int max_num_images = getImageListSize();
1176 int clone_graphic = graphic_info[graphic].clone_from;
1177 int num_references_followed = 1;
1179 while (graphic_info[clone_graphic].clone_from != -1 &&
1180 num_references_followed < max_num_images)
1182 clone_graphic = graphic_info[clone_graphic].clone_from;
1184 num_references_followed++;
1187 if (num_references_followed >= max_num_images)
1189 Error(ERR_RETURN_LINE, "-");
1190 Error(ERR_RETURN, "warning: error found in config file:");
1191 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1192 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1193 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1194 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1196 if (graphic == fallback_graphic)
1197 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1199 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1200 Error(ERR_RETURN_LINE, "-");
1202 graphic_info[graphic] = graphic_info[fallback_graphic];
1206 graphic_info[graphic] = graphic_info[clone_graphic];
1207 graphic_info[graphic].clone_from = clone_graphic;
1211 static void InitGraphicInfo()
1213 int fallback_graphic = IMG_CHAR_EXCLAM;
1214 int num_images = getImageListSize();
1217 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1218 static boolean clipmasks_initialized = FALSE;
1220 XGCValues clip_gc_values;
1221 unsigned long clip_gc_valuemask;
1222 GC copy_clipmask_gc = None;
1225 /* use image size as default values for width and height for these images */
1226 static int full_size_graphics[] =
1231 IMG_BACKGROUND_ENVELOPE_1,
1232 IMG_BACKGROUND_ENVELOPE_2,
1233 IMG_BACKGROUND_ENVELOPE_3,
1234 IMG_BACKGROUND_ENVELOPE_4,
1237 IMG_BACKGROUND_TITLE,
1238 IMG_BACKGROUND_MESSAGE,
1239 IMG_BACKGROUND_MAIN,
1240 IMG_BACKGROUND_LEVELS,
1241 IMG_BACKGROUND_SCORES,
1242 IMG_BACKGROUND_EDITOR,
1243 IMG_BACKGROUND_INFO,
1244 IMG_BACKGROUND_INFO_ELEMENTS,
1245 IMG_BACKGROUND_INFO_MUSIC,
1246 IMG_BACKGROUND_INFO_CREDITS,
1247 IMG_BACKGROUND_INFO_PROGRAM,
1248 IMG_BACKGROUND_INFO_LEVELSET,
1249 IMG_BACKGROUND_SETUP,
1250 IMG_BACKGROUND_DOOR,
1252 IMG_TITLESCREEN_INITIAL_1,
1253 IMG_TITLESCREEN_INITIAL_2,
1254 IMG_TITLESCREEN_INITIAL_3,
1255 IMG_TITLESCREEN_INITIAL_4,
1256 IMG_TITLESCREEN_INITIAL_5,
1266 checked_free(graphic_info);
1268 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1271 /* initialize "use_image_size" flag with default value */
1272 for (i = 0; i < num_images; i++)
1273 graphic_info[i].use_image_size = FALSE;
1275 /* initialize "use_image_size" flag from static configuration above */
1276 for (i = 0; full_size_graphics[i] != -1; i++)
1277 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1280 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1281 if (clipmasks_initialized)
1283 for (i = 0; i < num_images; i++)
1285 if (graphic_info[i].clip_mask)
1286 XFreePixmap(display, graphic_info[i].clip_mask);
1287 if (graphic_info[i].clip_gc)
1288 XFreeGC(display, graphic_info[i].clip_gc);
1290 graphic_info[i].clip_mask = None;
1291 graphic_info[i].clip_gc = None;
1296 /* first set all graphic paramaters ... */
1297 for (i = 0; i < num_images; i++)
1298 set_graphic_parameters(i);
1300 /* ... then copy these parameters for cloned graphics */
1301 for (i = 0; i < num_images; i++)
1302 if (graphic_info[i].clone_from != -1)
1303 set_cloned_graphic_parameters(i);
1305 for (i = 0; i < num_images; i++)
1310 int first_frame, last_frame;
1311 int src_bitmap_width, src_bitmap_height;
1313 /* now check if no animation frames are outside of the loaded image */
1315 if (graphic_info[i].bitmap == NULL)
1316 continue; /* skip check for optional images that are undefined */
1318 /* get image size (this can differ from the standard element tile size!) */
1319 width = graphic_info[i].width;
1320 height = graphic_info[i].height;
1322 /* get final bitmap size (with scaling, but without small images) */
1323 src_bitmap_width = graphic_info[i].src_image_width;
1324 src_bitmap_height = graphic_info[i].src_image_height;
1326 /* check if first animation frame is inside specified bitmap */
1329 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1332 /* this avoids calculating wrong start position for out-of-bounds frame */
1333 src_x = graphic_info[i].src_x;
1334 src_y = graphic_info[i].src_y;
1337 if (src_x < 0 || src_y < 0 ||
1338 src_x + width > src_bitmap_width ||
1339 src_y + height > src_bitmap_height)
1341 Error(ERR_RETURN_LINE, "-");
1342 Error(ERR_RETURN, "warning: error found in config file:");
1343 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1344 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1345 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1347 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1348 src_x, src_y, src_bitmap_width, src_bitmap_height);
1349 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1351 if (i == fallback_graphic)
1352 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1354 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1355 Error(ERR_RETURN_LINE, "-");
1357 graphic_info[i] = graphic_info[fallback_graphic];
1360 /* check if last animation frame is inside specified bitmap */
1362 last_frame = graphic_info[i].anim_frames - 1;
1363 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1365 if (src_x < 0 || src_y < 0 ||
1366 src_x + width > src_bitmap_width ||
1367 src_y + height > src_bitmap_height)
1369 Error(ERR_RETURN_LINE, "-");
1370 Error(ERR_RETURN, "warning: error found in config file:");
1371 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1372 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1373 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1375 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1376 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1377 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1379 if (i == fallback_graphic)
1380 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1382 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1383 Error(ERR_RETURN_LINE, "-");
1385 graphic_info[i] = graphic_info[fallback_graphic];
1388 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1389 /* currently we only need a tile clip mask from the first frame */
1390 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1392 if (copy_clipmask_gc == None)
1394 clip_gc_values.graphics_exposures = False;
1395 clip_gc_valuemask = GCGraphicsExposures;
1396 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1397 clip_gc_valuemask, &clip_gc_values);
1400 graphic_info[i].clip_mask =
1401 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1403 src_pixmap = src_bitmap->clip_mask;
1404 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1405 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1407 clip_gc_values.graphics_exposures = False;
1408 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1409 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1411 graphic_info[i].clip_gc =
1412 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1416 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1417 if (copy_clipmask_gc)
1418 XFreeGC(display, copy_clipmask_gc);
1420 clipmasks_initialized = TRUE;
1424 static void InitElementSoundInfo()
1426 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1427 int num_property_mappings = getSoundListPropertyMappingSize();
1430 /* set values to -1 to identify later as "uninitialized" values */
1431 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1432 for (act = 0; act < NUM_ACTIONS; act++)
1433 element_info[i].sound[act] = -1;
1435 /* initialize element/sound mapping from static configuration */
1436 for (i = 0; element_to_sound[i].element > -1; i++)
1438 int element = element_to_sound[i].element;
1439 int action = element_to_sound[i].action;
1440 int sound = element_to_sound[i].sound;
1441 boolean is_class = element_to_sound[i].is_class;
1444 action = ACTION_DEFAULT;
1447 element_info[element].sound[action] = sound;
1449 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1450 if (strEqual(element_info[j].class_name,
1451 element_info[element].class_name))
1452 element_info[j].sound[action] = sound;
1455 /* initialize element class/sound mapping from dynamic configuration */
1456 for (i = 0; i < num_property_mappings; i++)
1458 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1459 int action = property_mapping[i].ext1_index;
1460 int sound = property_mapping[i].artwork_index;
1462 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1466 action = ACTION_DEFAULT;
1468 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1469 if (strEqual(element_info[j].class_name,
1470 element_info[element_class].class_name))
1471 element_info[j].sound[action] = sound;
1474 /* initialize element/sound mapping from dynamic configuration */
1475 for (i = 0; i < num_property_mappings; i++)
1477 int element = property_mapping[i].base_index;
1478 int action = property_mapping[i].ext1_index;
1479 int sound = property_mapping[i].artwork_index;
1481 if (element >= MAX_NUM_ELEMENTS)
1485 action = ACTION_DEFAULT;
1487 element_info[element].sound[action] = sound;
1490 /* now set all '-1' values to element specific default values */
1491 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1493 for (act = 0; act < NUM_ACTIONS; act++)
1495 /* generic default action sound (defined by "[default]" directive) */
1496 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1498 /* look for special default action sound (classic game specific) */
1499 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1500 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1501 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1502 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1503 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1504 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1506 /* !!! there's no such thing as a "default action sound" !!! */
1508 /* look for element specific default sound (independent from action) */
1509 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1510 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1514 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1515 /* !!! make this better !!! */
1516 if (i == EL_EMPTY_SPACE)
1517 default_action_sound = element_info[EL_DEFAULT].sound[act];
1520 /* no sound for this specific action -- use default action sound */
1521 if (element_info[i].sound[act] == -1)
1522 element_info[i].sound[act] = default_action_sound;
1526 /* copy sound settings to some elements that are only stored in level file
1527 in native R'n'D levels, but are used by game engine in native EM levels */
1528 for (i = 0; copy_properties[i][0] != -1; i++)
1529 for (j = 1; j <= 4; j++)
1530 for (act = 0; act < NUM_ACTIONS; act++)
1531 element_info[copy_properties[i][j]].sound[act] =
1532 element_info[copy_properties[i][0]].sound[act];
1535 static void InitGameModeSoundInfo()
1539 /* set values to -1 to identify later as "uninitialized" values */
1540 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1543 /* initialize gamemode/sound mapping from static configuration */
1544 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1546 int gamemode = gamemode_to_sound[i].gamemode;
1547 int sound = gamemode_to_sound[i].sound;
1550 gamemode = GAME_MODE_DEFAULT;
1552 menu.sound[gamemode] = sound;
1555 /* now set all '-1' values to levelset specific default values */
1556 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1557 if (menu.sound[i] == -1)
1558 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1561 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1562 if (menu.sound[i] != -1)
1563 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1567 static void set_sound_parameters(int sound, char **parameter_raw)
1569 int parameter[NUM_SND_ARGS];
1572 /* get integer values from string parameters */
1573 for (i = 0; i < NUM_SND_ARGS; i++)
1575 get_parameter_value(parameter_raw[i],
1576 sound_config_suffix[i].token,
1577 sound_config_suffix[i].type);
1579 /* explicit loop mode setting in configuration overrides default value */
1580 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1581 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1583 /* sound volume to change the original volume when loading the sound file */
1584 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1586 /* sound priority to give certain sounds a higher or lower priority */
1587 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1590 static void InitSoundInfo()
1592 int *sound_effect_properties;
1593 int num_sounds = getSoundListSize();
1596 checked_free(sound_info);
1598 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1599 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1601 /* initialize sound effect for all elements to "no sound" */
1602 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1603 for (j = 0; j < NUM_ACTIONS; j++)
1604 element_info[i].sound[j] = SND_UNDEFINED;
1606 for (i = 0; i < num_sounds; i++)
1608 struct FileInfo *sound = getSoundListEntry(i);
1609 int len_effect_text = strlen(sound->token);
1611 sound_effect_properties[i] = ACTION_OTHER;
1612 sound_info[i].loop = FALSE; /* default: play sound only once */
1615 printf("::: sound %d: '%s'\n", i, sound->token);
1618 /* determine all loop sounds and identify certain sound classes */
1620 for (j = 0; element_action_info[j].suffix; j++)
1622 int len_action_text = strlen(element_action_info[j].suffix);
1624 if (len_action_text < len_effect_text &&
1625 strEqual(&sound->token[len_effect_text - len_action_text],
1626 element_action_info[j].suffix))
1628 sound_effect_properties[i] = element_action_info[j].value;
1629 sound_info[i].loop = element_action_info[j].is_loop_sound;
1635 /* associate elements and some selected sound actions */
1637 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1639 if (element_info[j].class_name)
1641 int len_class_text = strlen(element_info[j].class_name);
1643 if (len_class_text + 1 < len_effect_text &&
1644 strncmp(sound->token,
1645 element_info[j].class_name, len_class_text) == 0 &&
1646 sound->token[len_class_text] == '.')
1648 int sound_action_value = sound_effect_properties[i];
1650 element_info[j].sound[sound_action_value] = i;
1655 set_sound_parameters(i, sound->parameter);
1658 free(sound_effect_properties);
1661 static void InitGameModeMusicInfo()
1663 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1664 int num_property_mappings = getMusicListPropertyMappingSize();
1665 int default_levelset_music = -1;
1668 /* set values to -1 to identify later as "uninitialized" values */
1669 for (i = 0; i < MAX_LEVELS; i++)
1670 levelset.music[i] = -1;
1671 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1674 /* initialize gamemode/music mapping from static configuration */
1675 for (i = 0; gamemode_to_music[i].music > -1; i++)
1677 int gamemode = gamemode_to_music[i].gamemode;
1678 int music = gamemode_to_music[i].music;
1681 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1685 gamemode = GAME_MODE_DEFAULT;
1687 menu.music[gamemode] = music;
1690 /* initialize gamemode/music mapping from dynamic configuration */
1691 for (i = 0; i < num_property_mappings; i++)
1693 int prefix = property_mapping[i].base_index;
1694 int gamemode = property_mapping[i].ext1_index;
1695 int level = property_mapping[i].ext2_index;
1696 int music = property_mapping[i].artwork_index;
1699 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1700 prefix, gamemode, level, music);
1703 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1707 gamemode = GAME_MODE_DEFAULT;
1709 /* level specific music only allowed for in-game music */
1710 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1711 gamemode = GAME_MODE_PLAYING;
1716 default_levelset_music = music;
1719 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1720 levelset.music[level] = music;
1721 if (gamemode != GAME_MODE_PLAYING)
1722 menu.music[gamemode] = music;
1725 /* now set all '-1' values to menu specific default values */
1726 /* (undefined values of "levelset.music[]" might stay at "-1" to
1727 allow dynamic selection of music files from music directory!) */
1728 for (i = 0; i < MAX_LEVELS; i++)
1729 if (levelset.music[i] == -1)
1730 levelset.music[i] = default_levelset_music;
1731 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1732 if (menu.music[i] == -1)
1733 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1736 for (i = 0; i < MAX_LEVELS; i++)
1737 if (levelset.music[i] != -1)
1738 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1739 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1740 if (menu.music[i] != -1)
1741 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1745 static void set_music_parameters(int music, char **parameter_raw)
1747 int parameter[NUM_MUS_ARGS];
1750 /* get integer values from string parameters */
1751 for (i = 0; i < NUM_MUS_ARGS; i++)
1753 get_parameter_value(parameter_raw[i],
1754 music_config_suffix[i].token,
1755 music_config_suffix[i].type);
1757 /* explicit loop mode setting in configuration overrides default value */
1758 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1759 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1762 static void InitMusicInfo()
1764 int num_music = getMusicListSize();
1767 checked_free(music_info);
1769 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1771 for (i = 0; i < num_music; i++)
1773 struct FileInfo *music = getMusicListEntry(i);
1774 int len_music_text = strlen(music->token);
1776 music_info[i].loop = TRUE; /* default: play music in loop mode */
1778 /* determine all loop music */
1780 for (j = 0; music_prefix_info[j].prefix; j++)
1782 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1784 if (len_prefix_text < len_music_text &&
1785 strncmp(music->token,
1786 music_prefix_info[j].prefix, len_prefix_text) == 0)
1788 music_info[i].loop = music_prefix_info[j].is_loop_music;
1794 set_music_parameters(i, music->parameter);
1798 static void ReinitializeGraphics()
1800 InitGraphicInfo(); /* graphic properties mapping */
1801 InitElementGraphicInfo(); /* element game graphic mapping */
1802 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1804 InitElementSmallImages(); /* scale elements to all needed sizes */
1805 InitScaledImages(); /* scale all other images, if needed */
1806 InitFontGraphicInfo(); /* initialize text drawing functions */
1808 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1810 SetMainBackgroundImage(IMG_BACKGROUND);
1811 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1817 static void ReinitializeSounds()
1819 InitSoundInfo(); /* sound properties mapping */
1820 InitElementSoundInfo(); /* element game sound mapping */
1821 InitGameModeSoundInfo(); /* game mode sound mapping */
1823 InitPlayLevelSound(); /* internal game sound settings */
1826 static void ReinitializeMusic()
1828 InitMusicInfo(); /* music properties mapping */
1829 InitGameModeMusicInfo(); /* game mode music mapping */
1832 static int get_special_property_bit(int element, int property_bit_nr)
1834 struct PropertyBitInfo
1840 static struct PropertyBitInfo pb_can_move_into_acid[] =
1842 /* the player may be able fall into acid when gravity is activated */
1847 { EL_SP_MURPHY, 0 },
1848 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1850 /* all elements that can move may be able to also move into acid */
1853 { EL_BUG_RIGHT, 1 },
1856 { EL_SPACESHIP, 2 },
1857 { EL_SPACESHIP_LEFT, 2 },
1858 { EL_SPACESHIP_RIGHT, 2 },
1859 { EL_SPACESHIP_UP, 2 },
1860 { EL_SPACESHIP_DOWN, 2 },
1861 { EL_BD_BUTTERFLY, 3 },
1862 { EL_BD_BUTTERFLY_LEFT, 3 },
1863 { EL_BD_BUTTERFLY_RIGHT, 3 },
1864 { EL_BD_BUTTERFLY_UP, 3 },
1865 { EL_BD_BUTTERFLY_DOWN, 3 },
1866 { EL_BD_FIREFLY, 4 },
1867 { EL_BD_FIREFLY_LEFT, 4 },
1868 { EL_BD_FIREFLY_RIGHT, 4 },
1869 { EL_BD_FIREFLY_UP, 4 },
1870 { EL_BD_FIREFLY_DOWN, 4 },
1872 { EL_YAMYAM_LEFT, 5 },
1873 { EL_YAMYAM_RIGHT, 5 },
1874 { EL_YAMYAM_UP, 5 },
1875 { EL_YAMYAM_DOWN, 5 },
1876 { EL_DARK_YAMYAM, 6 },
1879 { EL_PACMAN_LEFT, 8 },
1880 { EL_PACMAN_RIGHT, 8 },
1881 { EL_PACMAN_UP, 8 },
1882 { EL_PACMAN_DOWN, 8 },
1884 { EL_MOLE_LEFT, 9 },
1885 { EL_MOLE_RIGHT, 9 },
1887 { EL_MOLE_DOWN, 9 },
1891 { EL_SATELLITE, 13 },
1892 { EL_SP_SNIKSNAK, 14 },
1893 { EL_SP_ELECTRON, 15 },
1896 { EL_EMC_ANDROID, 18 },
1901 static struct PropertyBitInfo pb_dont_collide_with[] =
1903 { EL_SP_SNIKSNAK, 0 },
1904 { EL_SP_ELECTRON, 1 },
1912 struct PropertyBitInfo *pb_info;
1915 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1916 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1921 struct PropertyBitInfo *pb_info = NULL;
1924 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1925 if (pb_definition[i].bit_nr == property_bit_nr)
1926 pb_info = pb_definition[i].pb_info;
1928 if (pb_info == NULL)
1931 for (i = 0; pb_info[i].element != -1; i++)
1932 if (pb_info[i].element == element)
1933 return pb_info[i].bit_nr;
1938 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1939 boolean property_value)
1941 int bit_nr = get_special_property_bit(element, property_bit_nr);
1946 *bitfield |= (1 << bit_nr);
1948 *bitfield &= ~(1 << bit_nr);
1952 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1954 int bit_nr = get_special_property_bit(element, property_bit_nr);
1957 return ((*bitfield & (1 << bit_nr)) != 0);
1962 static void resolve_group_element(int group_element, int recursion_depth)
1964 static int group_nr;
1965 static struct ElementGroupInfo *group;
1966 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1969 if (actual_group == NULL) /* not yet initialized */
1972 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1974 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1975 group_element - EL_GROUP_START + 1);
1977 /* replace element which caused too deep recursion by question mark */
1978 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1983 if (recursion_depth == 0) /* initialization */
1985 group = actual_group;
1986 group_nr = group_element - EL_GROUP_START;
1988 group->num_elements_resolved = 0;
1989 group->choice_pos = 0;
1992 for (i = 0; i < actual_group->num_elements; i++)
1994 int element = actual_group->element[i];
1996 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1999 if (IS_GROUP_ELEMENT(element))
2000 resolve_group_element(element, recursion_depth + 1);
2003 group->element_resolved[group->num_elements_resolved++] = element;
2004 element_info[element].in_group[group_nr] = TRUE;
2009 void InitElementPropertiesStatic()
2011 static int ep_diggable[] =
2016 EL_SP_BUGGY_BASE_ACTIVATING,
2019 EL_INVISIBLE_SAND_ACTIVE,
2022 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2023 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2028 EL_SP_BUGGY_BASE_ACTIVE,
2035 static int ep_collectible_only[] =
2057 EL_DYNABOMB_INCREASE_NUMBER,
2058 EL_DYNABOMB_INCREASE_SIZE,
2059 EL_DYNABOMB_INCREASE_POWER,
2077 /* !!! handle separately !!! */
2078 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2084 static int ep_dont_run_into[] =
2086 /* same elements as in 'ep_dont_touch' */
2092 /* same elements as in 'ep_dont_collide_with' */
2104 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2109 EL_SP_BUGGY_BASE_ACTIVE,
2116 static int ep_dont_collide_with[] =
2118 /* same elements as in 'ep_dont_touch' */
2135 static int ep_dont_touch[] =
2145 static int ep_indestructible[] =
2149 EL_ACID_POOL_TOPLEFT,
2150 EL_ACID_POOL_TOPRIGHT,
2151 EL_ACID_POOL_BOTTOMLEFT,
2152 EL_ACID_POOL_BOTTOM,
2153 EL_ACID_POOL_BOTTOMRIGHT,
2154 EL_SP_HARDWARE_GRAY,
2155 EL_SP_HARDWARE_GREEN,
2156 EL_SP_HARDWARE_BLUE,
2158 EL_SP_HARDWARE_YELLOW,
2159 EL_SP_HARDWARE_BASE_1,
2160 EL_SP_HARDWARE_BASE_2,
2161 EL_SP_HARDWARE_BASE_3,
2162 EL_SP_HARDWARE_BASE_4,
2163 EL_SP_HARDWARE_BASE_5,
2164 EL_SP_HARDWARE_BASE_6,
2165 EL_INVISIBLE_STEELWALL,
2166 EL_INVISIBLE_STEELWALL_ACTIVE,
2167 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2168 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2169 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2170 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2171 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2172 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2173 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2174 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2175 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2176 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2177 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2178 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2180 EL_LIGHT_SWITCH_ACTIVE,
2181 EL_SIGN_EXCLAMATION,
2182 EL_SIGN_RADIOACTIVITY,
2189 EL_SIGN_ENTRY_FORBIDDEN,
2190 EL_SIGN_EMERGENCY_EXIT,
2198 EL_STEEL_EXIT_CLOSED,
2200 EL_EM_STEEL_EXIT_CLOSED,
2201 EL_EM_STEEL_EXIT_OPEN,
2202 EL_DC_STEELWALL_1_LEFT,
2203 EL_DC_STEELWALL_1_RIGHT,
2204 EL_DC_STEELWALL_1_TOP,
2205 EL_DC_STEELWALL_1_BOTTOM,
2206 EL_DC_STEELWALL_1_HORIZONTAL,
2207 EL_DC_STEELWALL_1_VERTICAL,
2208 EL_DC_STEELWALL_1_TOPLEFT,
2209 EL_DC_STEELWALL_1_TOPRIGHT,
2210 EL_DC_STEELWALL_1_BOTTOMLEFT,
2211 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2212 EL_DC_STEELWALL_1_TOPLEFT_2,
2213 EL_DC_STEELWALL_1_TOPRIGHT_2,
2214 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2215 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2216 EL_DC_STEELWALL_2_LEFT,
2217 EL_DC_STEELWALL_2_RIGHT,
2218 EL_DC_STEELWALL_2_TOP,
2219 EL_DC_STEELWALL_2_BOTTOM,
2220 EL_DC_STEELWALL_2_HORIZONTAL,
2221 EL_DC_STEELWALL_2_VERTICAL,
2222 EL_DC_STEELWALL_2_MIDDLE,
2223 EL_DC_STEELWALL_2_SINGLE,
2224 EL_STEELWALL_SLIPPERY,
2238 EL_GATE_1_GRAY_ACTIVE,
2239 EL_GATE_2_GRAY_ACTIVE,
2240 EL_GATE_3_GRAY_ACTIVE,
2241 EL_GATE_4_GRAY_ACTIVE,
2250 EL_EM_GATE_1_GRAY_ACTIVE,
2251 EL_EM_GATE_2_GRAY_ACTIVE,
2252 EL_EM_GATE_3_GRAY_ACTIVE,
2253 EL_EM_GATE_4_GRAY_ACTIVE,
2262 EL_EMC_GATE_5_GRAY_ACTIVE,
2263 EL_EMC_GATE_6_GRAY_ACTIVE,
2264 EL_EMC_GATE_7_GRAY_ACTIVE,
2265 EL_EMC_GATE_8_GRAY_ACTIVE,
2267 EL_DC_GATE_WHITE_GRAY,
2268 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2269 EL_DC_GATE_FAKE_GRAY,
2271 EL_SWITCHGATE_OPENING,
2272 EL_SWITCHGATE_CLOSED,
2273 EL_SWITCHGATE_CLOSING,
2275 EL_DC_SWITCHGATE_SWITCH_UP,
2276 EL_DC_SWITCHGATE_SWITCH_DOWN,
2279 EL_TIMEGATE_OPENING,
2281 EL_TIMEGATE_CLOSING,
2283 EL_DC_TIMEGATE_SWITCH,
2284 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2289 EL_TUBE_VERTICAL_LEFT,
2290 EL_TUBE_VERTICAL_RIGHT,
2291 EL_TUBE_HORIZONTAL_UP,
2292 EL_TUBE_HORIZONTAL_DOWN,
2297 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2298 EL_EXPANDABLE_STEELWALL_VERTICAL,
2299 EL_EXPANDABLE_STEELWALL_ANY,
2304 static int ep_slippery[] =
2318 EL_ROBOT_WHEEL_ACTIVE,
2324 EL_ACID_POOL_TOPLEFT,
2325 EL_ACID_POOL_TOPRIGHT,
2335 EL_STEELWALL_SLIPPERY,
2338 EL_EMC_WALL_SLIPPERY_1,
2339 EL_EMC_WALL_SLIPPERY_2,
2340 EL_EMC_WALL_SLIPPERY_3,
2341 EL_EMC_WALL_SLIPPERY_4,
2343 EL_EMC_MAGIC_BALL_ACTIVE,
2348 static int ep_can_change[] =
2353 static int ep_can_move[] =
2355 /* same elements as in 'pb_can_move_into_acid' */
2378 static int ep_can_fall[] =
2392 EL_QUICKSAND_FAST_FULL,
2394 EL_BD_MAGIC_WALL_FULL,
2395 EL_DC_MAGIC_WALL_FULL,
2409 static int ep_can_smash_player[] =
2435 static int ep_can_smash_enemies[] =
2444 static int ep_can_smash_everything[] =
2453 static int ep_explodes_by_fire[] =
2455 /* same elements as in 'ep_explodes_impact' */
2460 /* same elements as in 'ep_explodes_smashed' */
2470 EL_EM_DYNAMITE_ACTIVE,
2471 EL_DYNABOMB_PLAYER_1_ACTIVE,
2472 EL_DYNABOMB_PLAYER_2_ACTIVE,
2473 EL_DYNABOMB_PLAYER_3_ACTIVE,
2474 EL_DYNABOMB_PLAYER_4_ACTIVE,
2475 EL_DYNABOMB_INCREASE_NUMBER,
2476 EL_DYNABOMB_INCREASE_SIZE,
2477 EL_DYNABOMB_INCREASE_POWER,
2478 EL_SP_DISK_RED_ACTIVE,
2492 static int ep_explodes_smashed[] =
2494 /* same elements as in 'ep_explodes_impact' */
2508 static int ep_explodes_impact[] =
2517 static int ep_walkable_over[] =
2521 EL_SOKOBAN_FIELD_EMPTY,
2527 EL_EM_STEEL_EXIT_OPEN,
2536 EL_GATE_1_GRAY_ACTIVE,
2537 EL_GATE_2_GRAY_ACTIVE,
2538 EL_GATE_3_GRAY_ACTIVE,
2539 EL_GATE_4_GRAY_ACTIVE,
2547 static int ep_walkable_inside[] =
2552 EL_TUBE_VERTICAL_LEFT,
2553 EL_TUBE_VERTICAL_RIGHT,
2554 EL_TUBE_HORIZONTAL_UP,
2555 EL_TUBE_HORIZONTAL_DOWN,
2564 static int ep_walkable_under[] =
2569 static int ep_passable_over[] =
2579 EL_EM_GATE_1_GRAY_ACTIVE,
2580 EL_EM_GATE_2_GRAY_ACTIVE,
2581 EL_EM_GATE_3_GRAY_ACTIVE,
2582 EL_EM_GATE_4_GRAY_ACTIVE,
2591 EL_EMC_GATE_5_GRAY_ACTIVE,
2592 EL_EMC_GATE_6_GRAY_ACTIVE,
2593 EL_EMC_GATE_7_GRAY_ACTIVE,
2594 EL_EMC_GATE_8_GRAY_ACTIVE,
2596 EL_DC_GATE_WHITE_GRAY,
2597 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2604 static int ep_passable_inside[] =
2610 EL_SP_PORT_HORIZONTAL,
2611 EL_SP_PORT_VERTICAL,
2613 EL_SP_GRAVITY_PORT_LEFT,
2614 EL_SP_GRAVITY_PORT_RIGHT,
2615 EL_SP_GRAVITY_PORT_UP,
2616 EL_SP_GRAVITY_PORT_DOWN,
2617 EL_SP_GRAVITY_ON_PORT_LEFT,
2618 EL_SP_GRAVITY_ON_PORT_RIGHT,
2619 EL_SP_GRAVITY_ON_PORT_UP,
2620 EL_SP_GRAVITY_ON_PORT_DOWN,
2621 EL_SP_GRAVITY_OFF_PORT_LEFT,
2622 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2623 EL_SP_GRAVITY_OFF_PORT_UP,
2624 EL_SP_GRAVITY_OFF_PORT_DOWN,
2629 static int ep_passable_under[] =
2634 static int ep_droppable[] =
2639 static int ep_explodes_1x1_old[] =
2644 static int ep_pushable[] =
2656 EL_SOKOBAN_FIELD_FULL,
2665 static int ep_explodes_cross_old[] =
2670 static int ep_protected[] =
2672 /* same elements as in 'ep_walkable_inside' */
2676 EL_TUBE_VERTICAL_LEFT,
2677 EL_TUBE_VERTICAL_RIGHT,
2678 EL_TUBE_HORIZONTAL_UP,
2679 EL_TUBE_HORIZONTAL_DOWN,
2685 /* same elements as in 'ep_passable_over' */
2694 EL_EM_GATE_1_GRAY_ACTIVE,
2695 EL_EM_GATE_2_GRAY_ACTIVE,
2696 EL_EM_GATE_3_GRAY_ACTIVE,
2697 EL_EM_GATE_4_GRAY_ACTIVE,
2706 EL_EMC_GATE_5_GRAY_ACTIVE,
2707 EL_EMC_GATE_6_GRAY_ACTIVE,
2708 EL_EMC_GATE_7_GRAY_ACTIVE,
2709 EL_EMC_GATE_8_GRAY_ACTIVE,
2711 EL_DC_GATE_WHITE_GRAY,
2712 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2716 /* same elements as in 'ep_passable_inside' */
2721 EL_SP_PORT_HORIZONTAL,
2722 EL_SP_PORT_VERTICAL,
2724 EL_SP_GRAVITY_PORT_LEFT,
2725 EL_SP_GRAVITY_PORT_RIGHT,
2726 EL_SP_GRAVITY_PORT_UP,
2727 EL_SP_GRAVITY_PORT_DOWN,
2728 EL_SP_GRAVITY_ON_PORT_LEFT,
2729 EL_SP_GRAVITY_ON_PORT_RIGHT,
2730 EL_SP_GRAVITY_ON_PORT_UP,
2731 EL_SP_GRAVITY_ON_PORT_DOWN,
2732 EL_SP_GRAVITY_OFF_PORT_LEFT,
2733 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2734 EL_SP_GRAVITY_OFF_PORT_UP,
2735 EL_SP_GRAVITY_OFF_PORT_DOWN,
2740 static int ep_throwable[] =
2745 static int ep_can_explode[] =
2747 /* same elements as in 'ep_explodes_impact' */
2752 /* same elements as in 'ep_explodes_smashed' */
2758 /* elements that can explode by explosion or by dragonfire */
2762 EL_EM_DYNAMITE_ACTIVE,
2763 EL_DYNABOMB_PLAYER_1_ACTIVE,
2764 EL_DYNABOMB_PLAYER_2_ACTIVE,
2765 EL_DYNABOMB_PLAYER_3_ACTIVE,
2766 EL_DYNABOMB_PLAYER_4_ACTIVE,
2767 EL_DYNABOMB_INCREASE_NUMBER,
2768 EL_DYNABOMB_INCREASE_SIZE,
2769 EL_DYNABOMB_INCREASE_POWER,
2770 EL_SP_DISK_RED_ACTIVE,
2778 /* elements that can explode only by explosion */
2784 static int ep_gravity_reachable[] =
2790 EL_INVISIBLE_SAND_ACTIVE,
2795 EL_SP_PORT_HORIZONTAL,
2796 EL_SP_PORT_VERTICAL,
2798 EL_SP_GRAVITY_PORT_LEFT,
2799 EL_SP_GRAVITY_PORT_RIGHT,
2800 EL_SP_GRAVITY_PORT_UP,
2801 EL_SP_GRAVITY_PORT_DOWN,
2802 EL_SP_GRAVITY_ON_PORT_LEFT,
2803 EL_SP_GRAVITY_ON_PORT_RIGHT,
2804 EL_SP_GRAVITY_ON_PORT_UP,
2805 EL_SP_GRAVITY_ON_PORT_DOWN,
2806 EL_SP_GRAVITY_OFF_PORT_LEFT,
2807 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2808 EL_SP_GRAVITY_OFF_PORT_UP,
2809 EL_SP_GRAVITY_OFF_PORT_DOWN,
2815 static int ep_player[] =
2822 EL_SOKOBAN_FIELD_PLAYER,
2828 static int ep_can_pass_magic_wall[] =
2842 static int ep_can_pass_dc_magic_wall[] =
2858 static int ep_switchable[] =
2862 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2863 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2864 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2865 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2866 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2867 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2868 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2869 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2870 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2871 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2872 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2873 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2874 EL_SWITCHGATE_SWITCH_UP,
2875 EL_SWITCHGATE_SWITCH_DOWN,
2876 EL_DC_SWITCHGATE_SWITCH_UP,
2877 EL_DC_SWITCHGATE_SWITCH_DOWN,
2879 EL_LIGHT_SWITCH_ACTIVE,
2881 EL_DC_TIMEGATE_SWITCH,
2882 EL_BALLOON_SWITCH_LEFT,
2883 EL_BALLOON_SWITCH_RIGHT,
2884 EL_BALLOON_SWITCH_UP,
2885 EL_BALLOON_SWITCH_DOWN,
2886 EL_BALLOON_SWITCH_ANY,
2887 EL_BALLOON_SWITCH_NONE,
2890 EL_EMC_MAGIC_BALL_SWITCH,
2891 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2896 static int ep_bd_element[] =
2930 static int ep_sp_element[] =
2932 /* should always be valid */
2935 /* standard classic Supaplex elements */
2942 EL_SP_HARDWARE_GRAY,
2950 EL_SP_GRAVITY_PORT_RIGHT,
2951 EL_SP_GRAVITY_PORT_DOWN,
2952 EL_SP_GRAVITY_PORT_LEFT,
2953 EL_SP_GRAVITY_PORT_UP,
2958 EL_SP_PORT_VERTICAL,
2959 EL_SP_PORT_HORIZONTAL,
2965 EL_SP_HARDWARE_BASE_1,
2966 EL_SP_HARDWARE_GREEN,
2967 EL_SP_HARDWARE_BLUE,
2969 EL_SP_HARDWARE_YELLOW,
2970 EL_SP_HARDWARE_BASE_2,
2971 EL_SP_HARDWARE_BASE_3,
2972 EL_SP_HARDWARE_BASE_4,
2973 EL_SP_HARDWARE_BASE_5,
2974 EL_SP_HARDWARE_BASE_6,
2978 /* additional elements that appeared in newer Supaplex levels */
2981 /* additional gravity port elements (not switching, but setting gravity) */
2982 EL_SP_GRAVITY_ON_PORT_LEFT,
2983 EL_SP_GRAVITY_ON_PORT_RIGHT,
2984 EL_SP_GRAVITY_ON_PORT_UP,
2985 EL_SP_GRAVITY_ON_PORT_DOWN,
2986 EL_SP_GRAVITY_OFF_PORT_LEFT,
2987 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2988 EL_SP_GRAVITY_OFF_PORT_UP,
2989 EL_SP_GRAVITY_OFF_PORT_DOWN,
2991 /* more than one Murphy in a level results in an inactive clone */
2994 /* runtime Supaplex elements */
2995 EL_SP_DISK_RED_ACTIVE,
2996 EL_SP_TERMINAL_ACTIVE,
2997 EL_SP_BUGGY_BASE_ACTIVATING,
2998 EL_SP_BUGGY_BASE_ACTIVE,
3005 static int ep_sb_element[] =
3010 EL_SOKOBAN_FIELD_EMPTY,
3011 EL_SOKOBAN_FIELD_FULL,
3012 EL_SOKOBAN_FIELD_PLAYER,
3017 EL_INVISIBLE_STEELWALL,
3022 static int ep_gem[] =
3034 static int ep_food_dark_yamyam[] =
3062 static int ep_food_penguin[] =
3076 static int ep_food_pig[] =
3088 static int ep_historic_wall[] =
3099 EL_GATE_1_GRAY_ACTIVE,
3100 EL_GATE_2_GRAY_ACTIVE,
3101 EL_GATE_3_GRAY_ACTIVE,
3102 EL_GATE_4_GRAY_ACTIVE,
3111 EL_EM_GATE_1_GRAY_ACTIVE,
3112 EL_EM_GATE_2_GRAY_ACTIVE,
3113 EL_EM_GATE_3_GRAY_ACTIVE,
3114 EL_EM_GATE_4_GRAY_ACTIVE,
3121 EL_EXPANDABLE_WALL_HORIZONTAL,
3122 EL_EXPANDABLE_WALL_VERTICAL,
3123 EL_EXPANDABLE_WALL_ANY,
3124 EL_EXPANDABLE_WALL_GROWING,
3125 EL_BD_EXPANDABLE_WALL,
3132 EL_SP_HARDWARE_GRAY,
3133 EL_SP_HARDWARE_GREEN,
3134 EL_SP_HARDWARE_BLUE,
3136 EL_SP_HARDWARE_YELLOW,
3137 EL_SP_HARDWARE_BASE_1,
3138 EL_SP_HARDWARE_BASE_2,
3139 EL_SP_HARDWARE_BASE_3,
3140 EL_SP_HARDWARE_BASE_4,
3141 EL_SP_HARDWARE_BASE_5,
3142 EL_SP_HARDWARE_BASE_6,
3144 EL_SP_TERMINAL_ACTIVE,
3147 EL_INVISIBLE_STEELWALL,
3148 EL_INVISIBLE_STEELWALL_ACTIVE,
3150 EL_INVISIBLE_WALL_ACTIVE,
3151 EL_STEELWALL_SLIPPERY,
3168 static int ep_historic_solid[] =
3172 EL_EXPANDABLE_WALL_HORIZONTAL,
3173 EL_EXPANDABLE_WALL_VERTICAL,
3174 EL_EXPANDABLE_WALL_ANY,
3175 EL_BD_EXPANDABLE_WALL,
3188 EL_QUICKSAND_FILLING,
3189 EL_QUICKSAND_EMPTYING,
3191 EL_MAGIC_WALL_ACTIVE,
3192 EL_MAGIC_WALL_EMPTYING,
3193 EL_MAGIC_WALL_FILLING,
3197 EL_BD_MAGIC_WALL_ACTIVE,
3198 EL_BD_MAGIC_WALL_EMPTYING,
3199 EL_BD_MAGIC_WALL_FULL,
3200 EL_BD_MAGIC_WALL_FILLING,
3201 EL_BD_MAGIC_WALL_DEAD,
3210 EL_SP_TERMINAL_ACTIVE,
3214 EL_INVISIBLE_WALL_ACTIVE,
3215 EL_SWITCHGATE_SWITCH_UP,
3216 EL_SWITCHGATE_SWITCH_DOWN,
3217 EL_DC_SWITCHGATE_SWITCH_UP,
3218 EL_DC_SWITCHGATE_SWITCH_DOWN,
3220 EL_TIMEGATE_SWITCH_ACTIVE,
3221 EL_DC_TIMEGATE_SWITCH,
3222 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3234 /* the following elements are a direct copy of "indestructible" elements,
3235 except "EL_ACID", which is "indestructible", but not "solid"! */
3240 EL_ACID_POOL_TOPLEFT,
3241 EL_ACID_POOL_TOPRIGHT,
3242 EL_ACID_POOL_BOTTOMLEFT,
3243 EL_ACID_POOL_BOTTOM,
3244 EL_ACID_POOL_BOTTOMRIGHT,
3245 EL_SP_HARDWARE_GRAY,
3246 EL_SP_HARDWARE_GREEN,
3247 EL_SP_HARDWARE_BLUE,
3249 EL_SP_HARDWARE_YELLOW,
3250 EL_SP_HARDWARE_BASE_1,
3251 EL_SP_HARDWARE_BASE_2,
3252 EL_SP_HARDWARE_BASE_3,
3253 EL_SP_HARDWARE_BASE_4,
3254 EL_SP_HARDWARE_BASE_5,
3255 EL_SP_HARDWARE_BASE_6,
3256 EL_INVISIBLE_STEELWALL,
3257 EL_INVISIBLE_STEELWALL_ACTIVE,
3258 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3259 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3260 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3261 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3262 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3263 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3264 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3265 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3266 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3267 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3268 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3269 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3271 EL_LIGHT_SWITCH_ACTIVE,
3272 EL_SIGN_EXCLAMATION,
3273 EL_SIGN_RADIOACTIVITY,
3280 EL_SIGN_ENTRY_FORBIDDEN,
3281 EL_SIGN_EMERGENCY_EXIT,
3289 EL_STEEL_EXIT_CLOSED,
3291 EL_DC_STEELWALL_1_LEFT,
3292 EL_DC_STEELWALL_1_RIGHT,
3293 EL_DC_STEELWALL_1_TOP,
3294 EL_DC_STEELWALL_1_BOTTOM,
3295 EL_DC_STEELWALL_1_HORIZONTAL,
3296 EL_DC_STEELWALL_1_VERTICAL,
3297 EL_DC_STEELWALL_1_TOPLEFT,
3298 EL_DC_STEELWALL_1_TOPRIGHT,
3299 EL_DC_STEELWALL_1_BOTTOMLEFT,
3300 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3301 EL_DC_STEELWALL_1_TOPLEFT_2,
3302 EL_DC_STEELWALL_1_TOPRIGHT_2,
3303 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3304 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3305 EL_DC_STEELWALL_2_LEFT,
3306 EL_DC_STEELWALL_2_RIGHT,
3307 EL_DC_STEELWALL_2_TOP,
3308 EL_DC_STEELWALL_2_BOTTOM,
3309 EL_DC_STEELWALL_2_HORIZONTAL,
3310 EL_DC_STEELWALL_2_VERTICAL,
3311 EL_DC_STEELWALL_2_MIDDLE,
3312 EL_DC_STEELWALL_2_SINGLE,
3313 EL_STEELWALL_SLIPPERY,
3327 EL_GATE_1_GRAY_ACTIVE,
3328 EL_GATE_2_GRAY_ACTIVE,
3329 EL_GATE_3_GRAY_ACTIVE,
3330 EL_GATE_4_GRAY_ACTIVE,
3339 EL_EM_GATE_1_GRAY_ACTIVE,
3340 EL_EM_GATE_2_GRAY_ACTIVE,
3341 EL_EM_GATE_3_GRAY_ACTIVE,
3342 EL_EM_GATE_4_GRAY_ACTIVE,
3344 EL_SWITCHGATE_OPENING,
3345 EL_SWITCHGATE_CLOSED,
3346 EL_SWITCHGATE_CLOSING,
3348 EL_TIMEGATE_OPENING,
3350 EL_TIMEGATE_CLOSING,
3354 EL_TUBE_VERTICAL_LEFT,
3355 EL_TUBE_VERTICAL_RIGHT,
3356 EL_TUBE_HORIZONTAL_UP,
3357 EL_TUBE_HORIZONTAL_DOWN,
3366 static int ep_classic_enemy[] =
3383 static int ep_belt[] =
3385 EL_CONVEYOR_BELT_1_LEFT,
3386 EL_CONVEYOR_BELT_1_MIDDLE,
3387 EL_CONVEYOR_BELT_1_RIGHT,
3388 EL_CONVEYOR_BELT_2_LEFT,
3389 EL_CONVEYOR_BELT_2_MIDDLE,
3390 EL_CONVEYOR_BELT_2_RIGHT,
3391 EL_CONVEYOR_BELT_3_LEFT,
3392 EL_CONVEYOR_BELT_3_MIDDLE,
3393 EL_CONVEYOR_BELT_3_RIGHT,
3394 EL_CONVEYOR_BELT_4_LEFT,
3395 EL_CONVEYOR_BELT_4_MIDDLE,
3396 EL_CONVEYOR_BELT_4_RIGHT,
3401 static int ep_belt_active[] =
3403 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3404 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3405 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3406 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3407 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3408 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3409 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3410 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3411 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3412 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3413 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3414 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3419 static int ep_belt_switch[] =
3421 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3422 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3423 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3424 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3425 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3426 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3427 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3428 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3429 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3430 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3431 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3432 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3437 static int ep_tube[] =
3444 EL_TUBE_HORIZONTAL_UP,
3445 EL_TUBE_HORIZONTAL_DOWN,
3447 EL_TUBE_VERTICAL_LEFT,
3448 EL_TUBE_VERTICAL_RIGHT,
3454 static int ep_keygate[] =
3464 EL_GATE_1_GRAY_ACTIVE,
3465 EL_GATE_2_GRAY_ACTIVE,
3466 EL_GATE_3_GRAY_ACTIVE,
3467 EL_GATE_4_GRAY_ACTIVE,
3476 EL_EM_GATE_1_GRAY_ACTIVE,
3477 EL_EM_GATE_2_GRAY_ACTIVE,
3478 EL_EM_GATE_3_GRAY_ACTIVE,
3479 EL_EM_GATE_4_GRAY_ACTIVE,
3488 EL_EMC_GATE_5_GRAY_ACTIVE,
3489 EL_EMC_GATE_6_GRAY_ACTIVE,
3490 EL_EMC_GATE_7_GRAY_ACTIVE,
3491 EL_EMC_GATE_8_GRAY_ACTIVE,
3493 EL_DC_GATE_WHITE_GRAY,
3494 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3499 static int ep_amoeboid[] =
3511 static int ep_amoebalive[] =
3522 static int ep_has_editor_content[] =
3544 static int ep_can_turn_each_move[] =
3546 /* !!! do something with this one !!! */
3550 static int ep_can_grow[] =
3564 static int ep_active_bomb[] =
3567 EL_EM_DYNAMITE_ACTIVE,
3568 EL_DYNABOMB_PLAYER_1_ACTIVE,
3569 EL_DYNABOMB_PLAYER_2_ACTIVE,
3570 EL_DYNABOMB_PLAYER_3_ACTIVE,
3571 EL_DYNABOMB_PLAYER_4_ACTIVE,
3572 EL_SP_DISK_RED_ACTIVE,
3577 static int ep_inactive[] =
3587 EL_QUICKSAND_FAST_EMPTY,
3610 EL_GATE_1_GRAY_ACTIVE,
3611 EL_GATE_2_GRAY_ACTIVE,
3612 EL_GATE_3_GRAY_ACTIVE,
3613 EL_GATE_4_GRAY_ACTIVE,
3622 EL_EM_GATE_1_GRAY_ACTIVE,
3623 EL_EM_GATE_2_GRAY_ACTIVE,
3624 EL_EM_GATE_3_GRAY_ACTIVE,
3625 EL_EM_GATE_4_GRAY_ACTIVE,
3634 EL_EMC_GATE_5_GRAY_ACTIVE,
3635 EL_EMC_GATE_6_GRAY_ACTIVE,
3636 EL_EMC_GATE_7_GRAY_ACTIVE,
3637 EL_EMC_GATE_8_GRAY_ACTIVE,
3639 EL_DC_GATE_WHITE_GRAY,
3640 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3641 EL_DC_GATE_FAKE_GRAY,
3644 EL_INVISIBLE_STEELWALL,
3652 EL_WALL_EMERALD_YELLOW,
3653 EL_DYNABOMB_INCREASE_NUMBER,
3654 EL_DYNABOMB_INCREASE_SIZE,
3655 EL_DYNABOMB_INCREASE_POWER,
3659 EL_SOKOBAN_FIELD_EMPTY,
3660 EL_SOKOBAN_FIELD_FULL,
3661 EL_WALL_EMERALD_RED,
3662 EL_WALL_EMERALD_PURPLE,
3663 EL_ACID_POOL_TOPLEFT,
3664 EL_ACID_POOL_TOPRIGHT,
3665 EL_ACID_POOL_BOTTOMLEFT,
3666 EL_ACID_POOL_BOTTOM,
3667 EL_ACID_POOL_BOTTOMRIGHT,
3671 EL_BD_MAGIC_WALL_DEAD,
3673 EL_DC_MAGIC_WALL_DEAD,
3674 EL_AMOEBA_TO_DIAMOND,
3682 EL_SP_GRAVITY_PORT_RIGHT,
3683 EL_SP_GRAVITY_PORT_DOWN,
3684 EL_SP_GRAVITY_PORT_LEFT,
3685 EL_SP_GRAVITY_PORT_UP,
3686 EL_SP_PORT_HORIZONTAL,
3687 EL_SP_PORT_VERTICAL,
3698 EL_SP_HARDWARE_GRAY,
3699 EL_SP_HARDWARE_GREEN,
3700 EL_SP_HARDWARE_BLUE,
3702 EL_SP_HARDWARE_YELLOW,
3703 EL_SP_HARDWARE_BASE_1,
3704 EL_SP_HARDWARE_BASE_2,
3705 EL_SP_HARDWARE_BASE_3,
3706 EL_SP_HARDWARE_BASE_4,
3707 EL_SP_HARDWARE_BASE_5,
3708 EL_SP_HARDWARE_BASE_6,
3709 EL_SP_GRAVITY_ON_PORT_LEFT,
3710 EL_SP_GRAVITY_ON_PORT_RIGHT,
3711 EL_SP_GRAVITY_ON_PORT_UP,
3712 EL_SP_GRAVITY_ON_PORT_DOWN,
3713 EL_SP_GRAVITY_OFF_PORT_LEFT,
3714 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3715 EL_SP_GRAVITY_OFF_PORT_UP,
3716 EL_SP_GRAVITY_OFF_PORT_DOWN,
3717 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3718 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3719 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3720 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3721 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3722 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3723 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3724 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3725 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3726 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3727 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3728 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3729 EL_SIGN_EXCLAMATION,
3730 EL_SIGN_RADIOACTIVITY,
3737 EL_SIGN_ENTRY_FORBIDDEN,
3738 EL_SIGN_EMERGENCY_EXIT,
3746 EL_DC_STEELWALL_1_LEFT,
3747 EL_DC_STEELWALL_1_RIGHT,
3748 EL_DC_STEELWALL_1_TOP,
3749 EL_DC_STEELWALL_1_BOTTOM,
3750 EL_DC_STEELWALL_1_HORIZONTAL,
3751 EL_DC_STEELWALL_1_VERTICAL,
3752 EL_DC_STEELWALL_1_TOPLEFT,
3753 EL_DC_STEELWALL_1_TOPRIGHT,
3754 EL_DC_STEELWALL_1_BOTTOMLEFT,
3755 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3756 EL_DC_STEELWALL_1_TOPLEFT_2,
3757 EL_DC_STEELWALL_1_TOPRIGHT_2,
3758 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3759 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3760 EL_DC_STEELWALL_2_LEFT,
3761 EL_DC_STEELWALL_2_RIGHT,
3762 EL_DC_STEELWALL_2_TOP,
3763 EL_DC_STEELWALL_2_BOTTOM,
3764 EL_DC_STEELWALL_2_HORIZONTAL,
3765 EL_DC_STEELWALL_2_VERTICAL,
3766 EL_DC_STEELWALL_2_MIDDLE,
3767 EL_DC_STEELWALL_2_SINGLE,
3768 EL_STEELWALL_SLIPPERY,
3773 EL_EMC_WALL_SLIPPERY_1,
3774 EL_EMC_WALL_SLIPPERY_2,
3775 EL_EMC_WALL_SLIPPERY_3,
3776 EL_EMC_WALL_SLIPPERY_4,
3797 static int ep_em_slippery_wall[] =
3802 static int ep_gfx_crumbled[] =
3813 static int ep_editor_cascade_active[] =
3815 EL_INTERNAL_CASCADE_BD_ACTIVE,
3816 EL_INTERNAL_CASCADE_EM_ACTIVE,
3817 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3818 EL_INTERNAL_CASCADE_RND_ACTIVE,
3819 EL_INTERNAL_CASCADE_SB_ACTIVE,
3820 EL_INTERNAL_CASCADE_SP_ACTIVE,
3821 EL_INTERNAL_CASCADE_DC_ACTIVE,
3822 EL_INTERNAL_CASCADE_DX_ACTIVE,
3823 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3824 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3825 EL_INTERNAL_CASCADE_CE_ACTIVE,
3826 EL_INTERNAL_CASCADE_GE_ACTIVE,
3827 EL_INTERNAL_CASCADE_REF_ACTIVE,
3828 EL_INTERNAL_CASCADE_USER_ACTIVE,
3829 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3834 static int ep_editor_cascade_inactive[] =
3836 EL_INTERNAL_CASCADE_BD,
3837 EL_INTERNAL_CASCADE_EM,
3838 EL_INTERNAL_CASCADE_EMC,
3839 EL_INTERNAL_CASCADE_RND,
3840 EL_INTERNAL_CASCADE_SB,
3841 EL_INTERNAL_CASCADE_SP,
3842 EL_INTERNAL_CASCADE_DC,
3843 EL_INTERNAL_CASCADE_DX,
3844 EL_INTERNAL_CASCADE_CHARS,
3845 EL_INTERNAL_CASCADE_STEEL_CHARS,
3846 EL_INTERNAL_CASCADE_CE,
3847 EL_INTERNAL_CASCADE_GE,
3848 EL_INTERNAL_CASCADE_REF,
3849 EL_INTERNAL_CASCADE_USER,
3850 EL_INTERNAL_CASCADE_DYNAMIC,
3855 static int ep_obsolete[] =
3859 EL_EM_KEY_1_FILE_OBSOLETE,
3860 EL_EM_KEY_2_FILE_OBSOLETE,
3861 EL_EM_KEY_3_FILE_OBSOLETE,
3862 EL_EM_KEY_4_FILE_OBSOLETE,
3863 EL_ENVELOPE_OBSOLETE,
3872 } element_properties[] =
3874 { ep_diggable, EP_DIGGABLE },
3875 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3876 { ep_dont_run_into, EP_DONT_RUN_INTO },
3877 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3878 { ep_dont_touch, EP_DONT_TOUCH },
3879 { ep_indestructible, EP_INDESTRUCTIBLE },
3880 { ep_slippery, EP_SLIPPERY },
3881 { ep_can_change, EP_CAN_CHANGE },
3882 { ep_can_move, EP_CAN_MOVE },
3883 { ep_can_fall, EP_CAN_FALL },
3884 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3885 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3886 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3887 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3888 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3889 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3890 { ep_walkable_over, EP_WALKABLE_OVER },
3891 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3892 { ep_walkable_under, EP_WALKABLE_UNDER },
3893 { ep_passable_over, EP_PASSABLE_OVER },
3894 { ep_passable_inside, EP_PASSABLE_INSIDE },
3895 { ep_passable_under, EP_PASSABLE_UNDER },
3896 { ep_droppable, EP_DROPPABLE },
3897 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3898 { ep_pushable, EP_PUSHABLE },
3899 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3900 { ep_protected, EP_PROTECTED },
3901 { ep_throwable, EP_THROWABLE },
3902 { ep_can_explode, EP_CAN_EXPLODE },
3903 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3905 { ep_player, EP_PLAYER },
3906 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3907 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3908 { ep_switchable, EP_SWITCHABLE },
3909 { ep_bd_element, EP_BD_ELEMENT },
3910 { ep_sp_element, EP_SP_ELEMENT },
3911 { ep_sb_element, EP_SB_ELEMENT },
3913 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3914 { ep_food_penguin, EP_FOOD_PENGUIN },
3915 { ep_food_pig, EP_FOOD_PIG },
3916 { ep_historic_wall, EP_HISTORIC_WALL },
3917 { ep_historic_solid, EP_HISTORIC_SOLID },
3918 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3919 { ep_belt, EP_BELT },
3920 { ep_belt_active, EP_BELT_ACTIVE },
3921 { ep_belt_switch, EP_BELT_SWITCH },
3922 { ep_tube, EP_TUBE },
3923 { ep_keygate, EP_KEYGATE },
3924 { ep_amoeboid, EP_AMOEBOID },
3925 { ep_amoebalive, EP_AMOEBALIVE },
3926 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3927 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3928 { ep_can_grow, EP_CAN_GROW },
3929 { ep_active_bomb, EP_ACTIVE_BOMB },
3930 { ep_inactive, EP_INACTIVE },
3932 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3934 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3936 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3937 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3939 { ep_obsolete, EP_OBSOLETE },
3946 /* always start with reliable default values (element has no properties) */
3947 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3948 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3949 SET_PROPERTY(i, j, FALSE);
3951 /* set all base element properties from above array definitions */
3952 for (i = 0; element_properties[i].elements != NULL; i++)
3953 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3954 SET_PROPERTY((element_properties[i].elements)[j],
3955 element_properties[i].property, TRUE);
3957 /* copy properties to some elements that are only stored in level file */
3958 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3959 for (j = 0; copy_properties[j][0] != -1; j++)
3960 if (HAS_PROPERTY(copy_properties[j][0], i))
3961 for (k = 1; k <= 4; k++)
3962 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3964 /* set static element properties that are not listed in array definitions */
3965 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
3966 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
3969 void InitElementPropertiesEngine(int engine_version)
3971 static int no_wall_properties[] =
3974 EP_COLLECTIBLE_ONLY,
3976 EP_DONT_COLLIDE_WITH,
3979 EP_CAN_SMASH_PLAYER,
3980 EP_CAN_SMASH_ENEMIES,
3981 EP_CAN_SMASH_EVERYTHING,
3986 EP_FOOD_DARK_YAMYAM,
4002 /* important: after initialization in InitElementPropertiesStatic(), the
4003 elements are not again initialized to a default value; therefore all
4004 changes have to make sure that they leave the element with a defined
4005 property (which means that conditional property changes must be set to
4006 a reliable default value before) */
4008 /* ---------- recursively resolve group elements ------------------------- */
4010 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4011 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
4012 element_info[i].in_group[j] = FALSE;
4014 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4015 resolve_group_element(EL_GROUP_START + i, 0);
4017 /* set all special, combined or engine dependent element properties */
4018 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4020 /* ---------- INACTIVE ------------------------------------------------- */
4021 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4022 i <= EL_CHAR_END) ||
4023 (i >= EL_STEEL_CHAR_START &&
4024 i <= EL_STEEL_CHAR_END)));
4026 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4027 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4028 IS_WALKABLE_INSIDE(i) ||
4029 IS_WALKABLE_UNDER(i)));
4031 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4032 IS_PASSABLE_INSIDE(i) ||
4033 IS_PASSABLE_UNDER(i)));
4035 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4036 IS_PASSABLE_OVER(i)));
4038 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4039 IS_PASSABLE_INSIDE(i)));
4041 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4042 IS_PASSABLE_UNDER(i)));
4044 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4047 /* ---------- COLLECTIBLE ---------------------------------------------- */
4048 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4052 /* ---------- SNAPPABLE ------------------------------------------------ */
4053 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4054 IS_COLLECTIBLE(i) ||
4058 /* ---------- WALL ----------------------------------------------------- */
4059 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4061 for (j = 0; no_wall_properties[j] != -1; j++)
4062 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4063 i >= EL_FIRST_RUNTIME_UNREAL)
4064 SET_PROPERTY(i, EP_WALL, FALSE);
4066 if (IS_HISTORIC_WALL(i))
4067 SET_PROPERTY(i, EP_WALL, TRUE);
4069 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4070 if (engine_version < VERSION_IDENT(2,2,0,0))
4071 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4073 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4075 !IS_COLLECTIBLE(i)));
4077 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4078 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4079 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4081 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4082 IS_INDESTRUCTIBLE(i)));
4084 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4086 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4087 else if (engine_version < VERSION_IDENT(2,2,0,0))
4088 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4090 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4094 if (IS_CUSTOM_ELEMENT(i))
4096 /* these are additional properties which are initially false when set */
4098 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4100 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4101 if (DONT_COLLIDE_WITH(i))
4102 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4104 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4105 if (CAN_SMASH_EVERYTHING(i))
4106 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4107 if (CAN_SMASH_ENEMIES(i))
4108 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4111 /* ---------- CAN_SMASH ------------------------------------------------ */
4112 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4113 CAN_SMASH_ENEMIES(i) ||
4114 CAN_SMASH_EVERYTHING(i)));
4116 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4117 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4118 EXPLODES_BY_FIRE(i)));
4120 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4121 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4122 EXPLODES_SMASHED(i)));
4124 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4125 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4126 EXPLODES_IMPACT(i)));
4128 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4129 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4131 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4132 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4133 i == EL_BLACK_ORB));
4135 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4136 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4138 IS_CUSTOM_ELEMENT(i)));
4140 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4141 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4142 i == EL_SP_ELECTRON));
4144 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4145 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4146 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4147 getMoveIntoAcidProperty(&level, i));
4149 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4150 if (MAYBE_DONT_COLLIDE_WITH(i))
4151 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4152 getDontCollideWithProperty(&level, i));
4154 /* ---------- SP_PORT -------------------------------------------------- */
4155 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4156 IS_PASSABLE_INSIDE(i)));
4158 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4159 for (j = 0; j < level.num_android_clone_elements; j++)
4160 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4162 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4164 /* ---------- CAN_CHANGE ----------------------------------------------- */
4165 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4166 for (j = 0; j < element_info[i].num_change_pages; j++)
4167 if (element_info[i].change_page[j].can_change)
4168 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4170 /* ---------- HAS_ACTION ----------------------------------------------- */
4171 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4172 for (j = 0; j < element_info[i].num_change_pages; j++)
4173 if (element_info[i].change_page[j].has_action)
4174 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4176 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4177 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4180 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4182 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4183 element_info[i].crumbled[ACTION_DEFAULT] !=
4184 element_info[i].graphic[ACTION_DEFAULT]);
4186 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4187 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4188 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4191 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4192 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4193 IS_EDITOR_CASCADE_INACTIVE(i)));
4196 /* dynamically adjust element properties according to game engine version */
4198 static int ep_em_slippery_wall[] =
4203 EL_EXPANDABLE_WALL_HORIZONTAL,
4204 EL_EXPANDABLE_WALL_VERTICAL,
4205 EL_EXPANDABLE_WALL_ANY,
4206 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4207 EL_EXPANDABLE_STEELWALL_VERTICAL,
4208 EL_EXPANDABLE_STEELWALL_ANY,
4209 EL_EXPANDABLE_STEELWALL_GROWING,
4213 /* special EM style gems behaviour */
4214 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4215 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4216 level.em_slippery_gems);
4218 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4219 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4220 (level.em_slippery_gems &&
4221 engine_version > VERSION_IDENT(2,0,1,0)));
4224 /* this is needed because some graphics depend on element properties */
4225 if (game_status == GAME_MODE_PLAYING)
4226 InitElementGraphicInfo();
4229 void InitElementPropertiesAfterLoading(int engine_version)
4233 /* set some other uninitialized values of custom elements in older levels */
4234 if (engine_version < VERSION_IDENT(3,1,0,0))
4236 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4238 int element = EL_CUSTOM_START + i;
4240 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4242 element_info[element].explosion_delay = 17;
4243 element_info[element].ignition_delay = 8;
4248 static void InitGlobal()
4252 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4254 /* check if element_name_info entry defined for each element in "main.h" */
4255 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4256 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4258 element_info[i].token_name = element_name_info[i].token_name;
4259 element_info[i].class_name = element_name_info[i].class_name;
4260 element_info[i].editor_description=element_name_info[i].editor_description;
4263 printf("%04d: %s\n", i, element_name_info[i].token_name);
4267 global.autoplay_leveldir = NULL;
4268 global.convert_leveldir = NULL;
4270 global.frames_per_second = 0;
4271 global.fps_slowdown = FALSE;
4272 global.fps_slowdown_factor = 1;
4275 void Execute_Command(char *command)
4279 if (strEqual(command, "print graphicsinfo.conf"))
4281 printf("# You can configure additional/alternative image files here.\n");
4282 printf("# (The entries below are default and therefore commented out.)\n");
4284 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4286 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4289 for (i = 0; image_config[i].token != NULL; i++)
4290 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4291 image_config[i].value));
4295 else if (strEqual(command, "print soundsinfo.conf"))
4297 printf("# You can configure additional/alternative sound files here.\n");
4298 printf("# (The entries below are default and therefore commented out.)\n");
4300 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4302 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4305 for (i = 0; sound_config[i].token != NULL; i++)
4306 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4307 sound_config[i].value));
4311 else if (strEqual(command, "print musicinfo.conf"))
4313 printf("# You can configure additional/alternative music files here.\n");
4314 printf("# (The entries below are default and therefore commented out.)\n");
4316 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4318 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4321 for (i = 0; music_config[i].token != NULL; i++)
4322 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4323 music_config[i].value));
4327 else if (strEqual(command, "print editorsetup.conf"))
4329 printf("# You can configure your personal editor element list here.\n");
4330 printf("# (The entries below are default and therefore commented out.)\n");
4333 /* this is needed to be able to check element list for cascade elements */
4334 InitElementPropertiesStatic();
4335 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4337 PrintEditorElementList();
4341 else if (strEqual(command, "print helpanim.conf"))
4343 printf("# You can configure different element help animations here.\n");
4344 printf("# (The entries below are default and therefore commented out.)\n");
4347 for (i = 0; helpanim_config[i].token != NULL; i++)
4349 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4350 helpanim_config[i].value));
4352 if (strEqual(helpanim_config[i].token, "end"))
4358 else if (strEqual(command, "print helptext.conf"))
4360 printf("# You can configure different element help text here.\n");
4361 printf("# (The entries below are default and therefore commented out.)\n");
4364 for (i = 0; helptext_config[i].token != NULL; i++)
4365 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4366 helptext_config[i].value));
4370 else if (strncmp(command, "dump level ", 11) == 0)
4372 char *filename = &command[11];
4374 if (!fileExists(filename))
4375 Error(ERR_EXIT, "cannot open file '%s'", filename);
4377 LoadLevelFromFilename(&level, filename);
4382 else if (strncmp(command, "dump tape ", 10) == 0)
4384 char *filename = &command[10];
4386 if (!fileExists(filename))
4387 Error(ERR_EXIT, "cannot open file '%s'", filename);
4389 LoadTapeFromFilename(filename);
4394 else if (strncmp(command, "autoplay ", 9) == 0)
4396 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4398 while (*str_ptr != '\0') /* continue parsing string */
4400 /* cut leading whitespace from string, replace it by string terminator */
4401 while (*str_ptr == ' ' || *str_ptr == '\t')
4404 if (*str_ptr == '\0') /* end of string reached */
4407 if (global.autoplay_leveldir == NULL) /* read level set string */
4409 global.autoplay_leveldir = str_ptr;
4410 global.autoplay_all = TRUE; /* default: play all tapes */
4412 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4413 global.autoplay_level[i] = FALSE;
4415 else /* read level number string */
4417 int level_nr = atoi(str_ptr); /* get level_nr value */
4419 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4420 global.autoplay_level[level_nr] = TRUE;
4422 global.autoplay_all = FALSE;
4425 /* advance string pointer to the next whitespace (or end of string) */
4426 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4430 else if (strncmp(command, "convert ", 8) == 0)
4432 char *str_copy = getStringCopy(&command[8]);
4433 char *str_ptr = strchr(str_copy, ' ');
4435 global.convert_leveldir = str_copy;
4436 global.convert_level_nr = -1;
4438 if (str_ptr != NULL) /* level number follows */
4440 *str_ptr++ = '\0'; /* terminate leveldir string */
4441 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4446 #if defined(TARGET_SDL)
4447 else if (strEqual(command, "SDL_ListModes"))
4452 SDL_Init(SDL_INIT_VIDEO);
4454 /* get available fullscreen/hardware modes */
4455 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4457 /* check if there are any modes available */
4460 printf("No modes available!\n");
4465 /* check if our resolution is restricted */
4466 if (modes == (SDL_Rect **)-1)
4468 printf("All resolutions available.\n");
4472 printf("Available Modes:\n");
4474 for(i = 0; modes[i]; i++)
4475 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4485 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4489 static void InitSetup()
4491 LoadSetup(); /* global setup info */
4493 /* set some options from setup file */
4495 if (setup.options.verbose)
4496 options.verbose = TRUE;
4499 static void InitGameInfo()
4501 game.restart_level = FALSE;
4504 static void InitPlayerInfo()
4508 /* choose default local player */
4509 local_player = &stored_player[0];
4511 for (i = 0; i < MAX_PLAYERS; i++)
4512 stored_player[i].connected = FALSE;
4514 local_player->connected = TRUE;
4517 static void InitArtworkInfo()
4522 static char *get_string_in_brackets(char *string)
4524 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4526 sprintf(string_in_brackets, "[%s]", string);
4528 return string_in_brackets;
4531 static char *get_level_id_suffix(int id_nr)
4533 char *id_suffix = checked_malloc(1 + 3 + 1);
4535 if (id_nr < 0 || id_nr > 999)
4538 sprintf(id_suffix, ".%03d", id_nr);
4544 static char *get_element_class_token(int element)
4546 char *element_class_name = element_info[element].class_name;
4547 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4549 sprintf(element_class_token, "[%s]", element_class_name);
4551 return element_class_token;
4554 static char *get_action_class_token(int action)
4556 char *action_class_name = &element_action_info[action].suffix[1];
4557 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4559 sprintf(action_class_token, "[%s]", action_class_name);
4561 return action_class_token;
4565 static void InitArtworkConfig()
4567 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4568 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4569 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4570 static char *action_id_suffix[NUM_ACTIONS + 1];
4571 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4572 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4573 static char *level_id_suffix[MAX_LEVELS + 1];
4574 static char *dummy[1] = { NULL };
4575 static char *ignore_generic_tokens[] =
4581 static char **ignore_image_tokens;
4582 static char **ignore_sound_tokens;
4583 static char **ignore_music_tokens;
4584 int num_ignore_generic_tokens;
4585 int num_ignore_image_tokens;
4586 int num_ignore_sound_tokens;
4587 int num_ignore_music_tokens;
4590 /* dynamically determine list of generic tokens to be ignored */
4591 num_ignore_generic_tokens = 0;
4592 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4593 num_ignore_generic_tokens++;
4595 /* dynamically determine list of image tokens to be ignored */
4596 num_ignore_image_tokens = num_ignore_generic_tokens;
4597 for (i = 0; image_config_vars[i].token != NULL; i++)
4598 num_ignore_image_tokens++;
4599 ignore_image_tokens =
4600 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4601 for (i = 0; i < num_ignore_generic_tokens; i++)
4602 ignore_image_tokens[i] = ignore_generic_tokens[i];
4603 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4604 ignore_image_tokens[num_ignore_generic_tokens + i] =
4605 image_config_vars[i].token;
4606 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4608 /* dynamically determine list of sound tokens to be ignored */
4609 num_ignore_sound_tokens = num_ignore_generic_tokens;
4610 ignore_sound_tokens =
4611 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4612 for (i = 0; i < num_ignore_generic_tokens; i++)
4613 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4614 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4616 /* dynamically determine list of music tokens to be ignored */
4617 num_ignore_music_tokens = num_ignore_generic_tokens;
4618 ignore_music_tokens =
4619 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4620 for (i = 0; i < num_ignore_generic_tokens; i++)
4621 ignore_music_tokens[i] = ignore_generic_tokens[i];
4622 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4624 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4625 image_id_prefix[i] = element_info[i].token_name;
4626 for (i = 0; i < NUM_FONTS; i++)
4627 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4628 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4631 sound_id_prefix[i] = element_info[i].token_name;
4632 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4633 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4634 get_string_in_brackets(element_info[i].class_name);
4635 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4637 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4638 music_id_prefix[i] = music_prefix_info[i].prefix;
4639 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4641 for (i = 0; i < NUM_ACTIONS; i++)
4642 action_id_suffix[i] = element_action_info[i].suffix;
4643 action_id_suffix[NUM_ACTIONS] = NULL;
4645 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4646 direction_id_suffix[i] = element_direction_info[i].suffix;
4647 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4649 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4650 special_id_suffix[i] = special_suffix_info[i].suffix;
4651 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4653 for (i = 0; i < MAX_LEVELS; i++)
4654 level_id_suffix[i] = get_level_id_suffix(i);
4655 level_id_suffix[MAX_LEVELS] = NULL;
4657 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4658 image_id_prefix, action_id_suffix, direction_id_suffix,
4659 special_id_suffix, ignore_image_tokens);
4660 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4661 sound_id_prefix, action_id_suffix, dummy,
4662 special_id_suffix, ignore_sound_tokens);
4663 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4664 music_id_prefix, special_id_suffix, level_id_suffix,
4665 dummy, ignore_music_tokens);
4668 static void InitMixer()
4676 char *filename_font_initial = NULL;
4677 Bitmap *bitmap_font_initial = NULL;
4681 /* determine settings for initial font (for displaying startup messages) */
4682 for (i = 0; image_config[i].token != NULL; i++)
4684 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4686 char font_token[128];
4689 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4690 len_font_token = strlen(font_token);
4692 if (strEqual(image_config[i].token, font_token))
4693 filename_font_initial = image_config[i].value;
4694 else if (strlen(image_config[i].token) > len_font_token &&
4695 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4697 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4698 font_initial[j].src_x = atoi(image_config[i].value);
4699 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4700 font_initial[j].src_y = atoi(image_config[i].value);
4701 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4702 font_initial[j].width = atoi(image_config[i].value);
4703 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4704 font_initial[j].height = atoi(image_config[i].value);
4709 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4711 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4712 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4715 if (filename_font_initial == NULL) /* should not happen */
4716 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4718 /* create additional image buffers for double-buffering and cross-fading */
4719 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4720 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4721 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4722 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4724 /* initialize screen properties */
4725 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4726 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4728 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4729 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4730 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4732 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4734 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4735 font_initial[j].bitmap = bitmap_font_initial;
4737 InitFontGraphicInfo();
4739 font_height = getFontHeight(FC_RED);
4742 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4744 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4746 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4747 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4749 DrawInitText("Loading graphics", 120, FC_GREEN);
4752 void RedrawBackground()
4754 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4755 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4757 redraw_mask = REDRAW_ALL;
4760 void InitGfxBackground()
4764 fieldbuffer = bitmap_db_field;
4765 SetDrawtoField(DRAW_BACKBUFFER);
4769 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4770 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4772 for (x = 0; x < MAX_BUF_XSIZE; x++)
4773 for (y = 0; y < MAX_BUF_YSIZE; y++)
4776 redraw_mask = REDRAW_ALL;
4779 static void InitLevelInfo()
4781 LoadLevelInfo(); /* global level info */
4782 LoadLevelSetup_LastSeries(); /* last played series info */
4783 LoadLevelSetup_SeriesInfo(); /* last played level info */
4786 void InitLevelArtworkInfo()
4788 LoadLevelArtworkInfo();
4791 static void InitImages()
4793 setLevelArtworkDir(artwork.gfx_first);
4796 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4797 leveldir_current->identifier,
4798 artwork.gfx_current_identifier,
4799 artwork.gfx_current->identifier,
4800 leveldir_current->graphics_set,
4801 leveldir_current->graphics_path);
4804 ReloadCustomImages();
4806 LoadCustomElementDescriptions();
4807 LoadSpecialMenuDesignSettings();
4809 ReinitializeGraphics();
4812 static void InitSound(char *identifier)
4814 if (identifier == NULL)
4815 identifier = artwork.snd_current->identifier;
4817 /* set artwork path to send it to the sound server process */
4818 setLevelArtworkDir(artwork.snd_first);
4820 InitReloadCustomSounds(identifier);
4821 ReinitializeSounds();
4824 static void InitMusic(char *identifier)
4826 if (identifier == NULL)
4827 identifier = artwork.mus_current->identifier;
4829 /* set artwork path to send it to the sound server process */
4830 setLevelArtworkDir(artwork.mus_first);
4832 InitReloadCustomMusic(identifier);
4833 ReinitializeMusic();
4836 void InitNetworkServer()
4838 #if defined(NETWORK_AVALIABLE)
4842 if (!options.network)
4845 #if defined(NETWORK_AVALIABLE)
4846 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4848 if (!ConnectToServer(options.server_host, options.server_port))
4849 Error(ERR_EXIT, "cannot connect to network game server");
4851 SendToServer_PlayerName(setup.player_name);
4852 SendToServer_ProtocolVersion();
4855 SendToServer_NrWanted(nr_wanted);
4859 static char *getNewArtworkIdentifier(int type)
4861 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4862 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4863 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4864 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4865 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4866 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4867 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4868 char *leveldir_identifier = leveldir_current->identifier;
4870 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4871 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4873 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4875 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4876 char *artwork_current_identifier;
4877 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4879 /* leveldir_current may be invalid (level group, parent link) */
4880 if (!validLevelSeries(leveldir_current))
4883 /* 1st step: determine artwork set to be activated in descending order:
4884 --------------------------------------------------------------------
4885 1. setup artwork (when configured to override everything else)
4886 2. artwork set configured in "levelinfo.conf" of current level set
4887 (artwork in level directory will have priority when loading later)
4888 3. artwork in level directory (stored in artwork sub-directory)
4889 4. setup artwork (currently configured in setup menu) */
4891 if (setup_override_artwork)
4892 artwork_current_identifier = setup_artwork_set;
4893 else if (leveldir_artwork_set != NULL)
4894 artwork_current_identifier = leveldir_artwork_set;
4895 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4896 artwork_current_identifier = leveldir_identifier;
4898 artwork_current_identifier = setup_artwork_set;
4901 /* 2nd step: check if it is really needed to reload artwork set
4902 ------------------------------------------------------------ */
4905 if (type == ARTWORK_TYPE_GRAPHICS)
4906 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4907 artwork_new_identifier,
4908 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4909 artwork_current_identifier,
4910 leveldir_current->graphics_set,
4911 leveldir_current->identifier);
4914 /* ---------- reload if level set and also artwork set has changed ------- */
4915 if (leveldir_current_identifier[type] != leveldir_identifier &&
4916 (last_has_level_artwork_set[type] || has_level_artwork_set))
4917 artwork_new_identifier = artwork_current_identifier;
4919 leveldir_current_identifier[type] = leveldir_identifier;
4920 last_has_level_artwork_set[type] = has_level_artwork_set;
4923 if (type == ARTWORK_TYPE_GRAPHICS)
4924 printf("::: 1: '%s'\n", artwork_new_identifier);
4927 /* ---------- reload if "override artwork" setting has changed ----------- */
4928 if (last_override_level_artwork[type] != setup_override_artwork)
4929 artwork_new_identifier = artwork_current_identifier;
4931 last_override_level_artwork[type] = setup_override_artwork;
4934 if (type == ARTWORK_TYPE_GRAPHICS)
4935 printf("::: 2: '%s'\n", artwork_new_identifier);
4938 /* ---------- reload if current artwork identifier has changed ----------- */
4939 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4940 artwork_current_identifier))
4941 artwork_new_identifier = artwork_current_identifier;
4943 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4946 if (type == ARTWORK_TYPE_GRAPHICS)
4947 printf("::: 3: '%s'\n", artwork_new_identifier);
4950 /* ---------- do not reload directly after starting ---------------------- */
4951 if (!initialized[type])
4952 artwork_new_identifier = NULL;
4954 initialized[type] = TRUE;
4957 if (type == ARTWORK_TYPE_GRAPHICS)
4958 printf("::: 4: '%s'\n", artwork_new_identifier);
4962 if (type == ARTWORK_TYPE_GRAPHICS)
4963 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4964 artwork.gfx_current_identifier, artwork_current_identifier,
4965 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4966 artwork_new_identifier);
4969 return artwork_new_identifier;
4972 void ReloadCustomArtwork(int force_reload)
4974 char *gfx_new_identifier;
4975 char *snd_new_identifier;
4976 char *mus_new_identifier;
4977 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4978 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4979 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4980 boolean redraw_screen = FALSE;
4982 force_reload_gfx |= AdjustGraphicsForEMC();
4984 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4985 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4986 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4988 if (gfx_new_identifier != NULL || force_reload_gfx)
4991 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4992 artwork.gfx_current_identifier,
4994 artwork.gfx_current->identifier,
4995 leveldir_current->graphics_set);
4998 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5002 redraw_screen = TRUE;
5005 if (snd_new_identifier != NULL || force_reload_snd)
5007 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5009 InitSound(snd_new_identifier);
5011 redraw_screen = TRUE;
5014 if (mus_new_identifier != NULL || force_reload_mus)
5016 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5018 InitMusic(mus_new_identifier);
5020 redraw_screen = TRUE;
5027 /* force redraw of (open or closed) door graphics */
5028 SetDoorState(DOOR_OPEN_ALL);
5029 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5033 void KeyboardAutoRepeatOffUnlessAutoplay()
5035 if (global.autoplay_leveldir == NULL)
5036 KeyboardAutoRepeatOff();
5040 /* ========================================================================= */
5042 /* ========================================================================= */
5046 InitGlobal(); /* initialize some global variables */
5048 if (options.execute_command)
5049 Execute_Command(options.execute_command);
5051 if (options.serveronly)
5053 #if defined(PLATFORM_UNIX)
5054 NetworkServer(options.server_port, options.serveronly);
5056 Error(ERR_WARN, "networking only supported in Unix version");
5059 exit(0); /* never reached, server loops forever */
5066 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5067 InitArtworkConfig(); /* needed before forking sound child process */
5072 InitRND(NEW_RANDOMIZE);
5073 InitSimpleRandom(NEW_RANDOMIZE);
5078 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5080 InitEventFilter(FilterMouseMotionEvents);
5082 InitElementPropertiesStatic();
5083 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5087 // debug_print_timestamp(0, "INIT");
5089 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5090 InitLevelArtworkInfo();
5091 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5093 InitImages(); /* needs to know current level directory */
5094 InitSound(NULL); /* needs to know current level directory */
5095 InitMusic(NULL); /* needs to know current level directory */
5097 InitGfxBackground();
5103 if (global.autoplay_leveldir)
5108 else if (global.convert_leveldir)
5114 game_status = GAME_MODE_MAIN;
5118 InitNetworkServer();
5121 void CloseAllAndExit(int exit_value)
5126 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5134 #if defined(TARGET_SDL)
5135 if (network_server) /* terminate network server */
5136 SDL_KillThread(server_thread);
5139 CloseVideoDisplay();
5140 ClosePlatformDependentStuff();
5142 if (exit_value != 0)
5143 NotifyUserAboutErrorFile();