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_INFO, "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;
978 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
979 graphic_info[graphic].sort_priority = 0; /* default for title screens */
982 /* optional zoom factor for scaling up the image to a larger size */
983 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
984 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
985 if (graphic_info[graphic].scale_up_factor < 1)
986 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
990 if (graphic_info[graphic].use_image_size)
992 /* set new default bitmap size (with scaling, but without small images) */
993 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
994 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
998 /* optional x and y tile position of animation frame sequence */
999 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1000 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1001 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1004 /* optional x and y pixel position of animation frame sequence */
1005 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1007 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1008 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1010 /* optional width and height of each animation frame */
1011 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1012 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1013 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1014 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1017 /* optional zoom factor for scaling up the image to a larger size */
1018 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1019 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1020 if (graphic_info[graphic].scale_up_factor < 1)
1021 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1026 /* get final bitmap size (with scaling, but without small images) */
1027 int src_image_width = get_scaled_graphic_width(graphic);
1028 int src_image_height = get_scaled_graphic_height(graphic);
1030 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1031 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1033 graphic_info[graphic].src_image_width = src_image_width;
1034 graphic_info[graphic].src_image_height = src_image_height;
1037 /* correct x or y offset dependent of vertical or horizontal frame order */
1038 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1040 graphic_info[graphic].offset_y =
1041 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1042 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1043 anim_frames_per_line = anim_frames_per_col;
1045 else /* frames are ordered horizontally */
1047 graphic_info[graphic].offset_x =
1048 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1049 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1050 anim_frames_per_line = anim_frames_per_row;
1053 /* optionally, the x and y offset of frames can be specified directly */
1054 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1056 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1057 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1059 /* optionally, moving animations may have separate start and end graphics */
1060 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1062 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1063 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1065 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1066 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1067 graphic_info[graphic].offset2_y =
1068 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1069 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1070 else /* frames are ordered horizontally */
1071 graphic_info[graphic].offset2_x =
1072 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1073 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1075 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1076 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1077 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1078 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1079 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1081 /* optionally, the second movement tile can be specified as start tile */
1082 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1083 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1085 /* automatically determine correct number of frames, if not defined */
1086 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1087 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1088 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1089 graphic_info[graphic].anim_frames = anim_frames_per_row;
1090 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1091 graphic_info[graphic].anim_frames = anim_frames_per_col;
1093 graphic_info[graphic].anim_frames = 1;
1095 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1096 graphic_info[graphic].anim_frames = 1;
1098 graphic_info[graphic].anim_frames_per_line =
1099 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1100 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1102 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1103 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1104 graphic_info[graphic].anim_delay = 1;
1106 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1108 if (graphic_info[graphic].anim_frames == 1)
1109 graphic_info[graphic].anim_mode = ANIM_NONE;
1112 /* automatically determine correct start frame, if not defined */
1113 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1114 graphic_info[graphic].anim_start_frame = 0;
1115 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1116 graphic_info[graphic].anim_start_frame =
1117 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1119 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1121 /* animation synchronized with global frame counter, not move position */
1122 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1124 /* optional element for cloning crumble graphics */
1125 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1126 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1128 /* optional element for cloning digging graphics */
1129 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1130 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1132 /* optional border size for "crumbling" diggable graphics */
1133 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1134 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1136 /* this is only used for player "boring" and "sleeping" actions */
1137 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1138 graphic_info[graphic].anim_delay_fixed =
1139 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1140 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1141 graphic_info[graphic].anim_delay_random =
1142 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1143 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1144 graphic_info[graphic].post_delay_fixed =
1145 parameter[GFX_ARG_POST_DELAY_FIXED];
1146 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1147 graphic_info[graphic].post_delay_random =
1148 parameter[GFX_ARG_POST_DELAY_RANDOM];
1150 /* this is only used for toon animations */
1151 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1152 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1154 /* this is only used for drawing font characters */
1155 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1156 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1158 /* this is only used for drawing envelope graphics */
1159 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1161 /* optional graphic for cloning all graphics settings */
1162 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1163 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1165 /* optional settings for drawing title screens */
1166 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1167 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1168 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1169 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1170 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1171 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1172 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1173 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1174 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1175 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1178 static void set_cloned_graphic_parameters(int graphic)
1180 int fallback_graphic = IMG_CHAR_EXCLAM;
1181 int max_num_images = getImageListSize();
1182 int clone_graphic = graphic_info[graphic].clone_from;
1183 int num_references_followed = 1;
1185 while (graphic_info[clone_graphic].clone_from != -1 &&
1186 num_references_followed < max_num_images)
1188 clone_graphic = graphic_info[clone_graphic].clone_from;
1190 num_references_followed++;
1193 if (num_references_followed >= max_num_images)
1195 Error(ERR_INFO_LINE, "-");
1196 Error(ERR_INFO, "warning: error found in config file:");
1197 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1198 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1199 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1200 Error(ERR_INFO, "custom graphic rejected for this element/action");
1202 if (graphic == fallback_graphic)
1203 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1205 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1206 Error(ERR_INFO_LINE, "-");
1208 graphic_info[graphic] = graphic_info[fallback_graphic];
1212 graphic_info[graphic] = graphic_info[clone_graphic];
1213 graphic_info[graphic].clone_from = clone_graphic;
1217 static void InitGraphicInfo()
1219 int fallback_graphic = IMG_CHAR_EXCLAM;
1220 int num_images = getImageListSize();
1223 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1224 static boolean clipmasks_initialized = FALSE;
1226 XGCValues clip_gc_values;
1227 unsigned long clip_gc_valuemask;
1228 GC copy_clipmask_gc = None;
1231 /* use image size as default values for width and height for these images */
1232 static int full_size_graphics[] =
1237 IMG_BACKGROUND_ENVELOPE_1,
1238 IMG_BACKGROUND_ENVELOPE_2,
1239 IMG_BACKGROUND_ENVELOPE_3,
1240 IMG_BACKGROUND_ENVELOPE_4,
1243 IMG_BACKGROUND_TITLE,
1244 IMG_BACKGROUND_MESSAGE,
1245 IMG_BACKGROUND_MAIN,
1246 IMG_BACKGROUND_LEVELS,
1247 IMG_BACKGROUND_SCORES,
1248 IMG_BACKGROUND_EDITOR,
1249 IMG_BACKGROUND_INFO,
1250 IMG_BACKGROUND_INFO_ELEMENTS,
1251 IMG_BACKGROUND_INFO_MUSIC,
1252 IMG_BACKGROUND_INFO_CREDITS,
1253 IMG_BACKGROUND_INFO_PROGRAM,
1254 IMG_BACKGROUND_INFO_LEVELSET,
1255 IMG_BACKGROUND_SETUP,
1256 IMG_BACKGROUND_DOOR,
1258 IMG_TITLESCREEN_INITIAL_1,
1259 IMG_TITLESCREEN_INITIAL_2,
1260 IMG_TITLESCREEN_INITIAL_3,
1261 IMG_TITLESCREEN_INITIAL_4,
1262 IMG_TITLESCREEN_INITIAL_5,
1272 checked_free(graphic_info);
1274 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1277 /* initialize "use_image_size" flag with default value */
1278 for (i = 0; i < num_images; i++)
1279 graphic_info[i].use_image_size = FALSE;
1281 /* initialize "use_image_size" flag from static configuration above */
1282 for (i = 0; full_size_graphics[i] != -1; i++)
1283 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1286 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1287 if (clipmasks_initialized)
1289 for (i = 0; i < num_images; i++)
1291 if (graphic_info[i].clip_mask)
1292 XFreePixmap(display, graphic_info[i].clip_mask);
1293 if (graphic_info[i].clip_gc)
1294 XFreeGC(display, graphic_info[i].clip_gc);
1296 graphic_info[i].clip_mask = None;
1297 graphic_info[i].clip_gc = None;
1302 /* first set all graphic paramaters ... */
1303 for (i = 0; i < num_images; i++)
1304 set_graphic_parameters(i);
1306 /* ... then copy these parameters for cloned graphics */
1307 for (i = 0; i < num_images; i++)
1308 if (graphic_info[i].clone_from != -1)
1309 set_cloned_graphic_parameters(i);
1311 for (i = 0; i < num_images; i++)
1316 int first_frame, last_frame;
1317 int src_bitmap_width, src_bitmap_height;
1319 /* now check if no animation frames are outside of the loaded image */
1321 if (graphic_info[i].bitmap == NULL)
1322 continue; /* skip check for optional images that are undefined */
1324 /* get image size (this can differ from the standard element tile size!) */
1325 width = graphic_info[i].width;
1326 height = graphic_info[i].height;
1328 /* get final bitmap size (with scaling, but without small images) */
1329 src_bitmap_width = graphic_info[i].src_image_width;
1330 src_bitmap_height = graphic_info[i].src_image_height;
1332 /* check if first animation frame is inside specified bitmap */
1335 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1338 /* this avoids calculating wrong start position for out-of-bounds frame */
1339 src_x = graphic_info[i].src_x;
1340 src_y = graphic_info[i].src_y;
1343 if (src_x < 0 || src_y < 0 ||
1344 src_x + width > src_bitmap_width ||
1345 src_y + height > src_bitmap_height)
1347 Error(ERR_INFO_LINE, "-");
1348 Error(ERR_INFO, "warning: error found in config file:");
1349 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1350 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1351 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1353 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1354 src_x, src_y, src_bitmap_width, src_bitmap_height);
1355 Error(ERR_INFO, "custom graphic rejected for this element/action");
1357 if (i == fallback_graphic)
1358 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1360 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1361 Error(ERR_INFO_LINE, "-");
1363 graphic_info[i] = graphic_info[fallback_graphic];
1366 /* check if last animation frame is inside specified bitmap */
1368 last_frame = graphic_info[i].anim_frames - 1;
1369 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1371 if (src_x < 0 || src_y < 0 ||
1372 src_x + width > src_bitmap_width ||
1373 src_y + height > src_bitmap_height)
1375 Error(ERR_INFO_LINE, "-");
1376 Error(ERR_INFO, "warning: error found in config file:");
1377 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1378 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1379 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1381 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1382 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1383 Error(ERR_INFO, "custom graphic rejected for this element/action");
1385 if (i == fallback_graphic)
1386 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1388 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1389 Error(ERR_INFO_LINE, "-");
1391 graphic_info[i] = graphic_info[fallback_graphic];
1394 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1395 /* currently we only need a tile clip mask from the first frame */
1396 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1398 if (copy_clipmask_gc == None)
1400 clip_gc_values.graphics_exposures = False;
1401 clip_gc_valuemask = GCGraphicsExposures;
1402 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1403 clip_gc_valuemask, &clip_gc_values);
1406 graphic_info[i].clip_mask =
1407 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1409 src_pixmap = src_bitmap->clip_mask;
1410 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1411 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1413 clip_gc_values.graphics_exposures = False;
1414 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1415 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1417 graphic_info[i].clip_gc =
1418 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1422 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1423 if (copy_clipmask_gc)
1424 XFreeGC(display, copy_clipmask_gc);
1426 clipmasks_initialized = TRUE;
1430 static void InitElementSoundInfo()
1432 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1433 int num_property_mappings = getSoundListPropertyMappingSize();
1436 /* set values to -1 to identify later as "uninitialized" values */
1437 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1438 for (act = 0; act < NUM_ACTIONS; act++)
1439 element_info[i].sound[act] = -1;
1441 /* initialize element/sound mapping from static configuration */
1442 for (i = 0; element_to_sound[i].element > -1; i++)
1444 int element = element_to_sound[i].element;
1445 int action = element_to_sound[i].action;
1446 int sound = element_to_sound[i].sound;
1447 boolean is_class = element_to_sound[i].is_class;
1450 action = ACTION_DEFAULT;
1453 element_info[element].sound[action] = sound;
1455 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1456 if (strEqual(element_info[j].class_name,
1457 element_info[element].class_name))
1458 element_info[j].sound[action] = sound;
1461 /* initialize element class/sound mapping from dynamic configuration */
1462 for (i = 0; i < num_property_mappings; i++)
1464 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1465 int action = property_mapping[i].ext1_index;
1466 int sound = property_mapping[i].artwork_index;
1468 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1472 action = ACTION_DEFAULT;
1474 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1475 if (strEqual(element_info[j].class_name,
1476 element_info[element_class].class_name))
1477 element_info[j].sound[action] = sound;
1480 /* initialize element/sound mapping from dynamic configuration */
1481 for (i = 0; i < num_property_mappings; i++)
1483 int element = property_mapping[i].base_index;
1484 int action = property_mapping[i].ext1_index;
1485 int sound = property_mapping[i].artwork_index;
1487 if (element >= MAX_NUM_ELEMENTS)
1491 action = ACTION_DEFAULT;
1493 element_info[element].sound[action] = sound;
1496 /* now set all '-1' values to element specific default values */
1497 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1499 for (act = 0; act < NUM_ACTIONS; act++)
1501 /* generic default action sound (defined by "[default]" directive) */
1502 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1504 /* look for special default action sound (classic game specific) */
1505 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1506 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1507 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1508 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1509 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1510 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1512 /* !!! there's no such thing as a "default action sound" !!! */
1514 /* look for element specific default sound (independent from action) */
1515 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1516 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1520 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1521 /* !!! make this better !!! */
1522 if (i == EL_EMPTY_SPACE)
1523 default_action_sound = element_info[EL_DEFAULT].sound[act];
1526 /* no sound for this specific action -- use default action sound */
1527 if (element_info[i].sound[act] == -1)
1528 element_info[i].sound[act] = default_action_sound;
1532 /* copy sound settings to some elements that are only stored in level file
1533 in native R'n'D levels, but are used by game engine in native EM levels */
1534 for (i = 0; copy_properties[i][0] != -1; i++)
1535 for (j = 1; j <= 4; j++)
1536 for (act = 0; act < NUM_ACTIONS; act++)
1537 element_info[copy_properties[i][j]].sound[act] =
1538 element_info[copy_properties[i][0]].sound[act];
1541 static void InitGameModeSoundInfo()
1545 /* set values to -1 to identify later as "uninitialized" values */
1546 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1549 /* initialize gamemode/sound mapping from static configuration */
1550 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1552 int gamemode = gamemode_to_sound[i].gamemode;
1553 int sound = gamemode_to_sound[i].sound;
1556 gamemode = GAME_MODE_DEFAULT;
1558 menu.sound[gamemode] = sound;
1561 /* now set all '-1' values to levelset specific default values */
1562 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1563 if (menu.sound[i] == -1)
1564 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1567 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1568 if (menu.sound[i] != -1)
1569 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1573 static void set_sound_parameters(int sound, char **parameter_raw)
1575 int parameter[NUM_SND_ARGS];
1578 /* get integer values from string parameters */
1579 for (i = 0; i < NUM_SND_ARGS; i++)
1581 get_parameter_value(parameter_raw[i],
1582 sound_config_suffix[i].token,
1583 sound_config_suffix[i].type);
1585 /* explicit loop mode setting in configuration overrides default value */
1586 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1587 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1589 /* sound volume to change the original volume when loading the sound file */
1590 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1592 /* sound priority to give certain sounds a higher or lower priority */
1593 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1596 static void InitSoundInfo()
1598 int *sound_effect_properties;
1599 int num_sounds = getSoundListSize();
1602 checked_free(sound_info);
1604 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1605 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1607 /* initialize sound effect for all elements to "no sound" */
1608 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1609 for (j = 0; j < NUM_ACTIONS; j++)
1610 element_info[i].sound[j] = SND_UNDEFINED;
1612 for (i = 0; i < num_sounds; i++)
1614 struct FileInfo *sound = getSoundListEntry(i);
1615 int len_effect_text = strlen(sound->token);
1617 sound_effect_properties[i] = ACTION_OTHER;
1618 sound_info[i].loop = FALSE; /* default: play sound only once */
1621 printf("::: sound %d: '%s'\n", i, sound->token);
1624 /* determine all loop sounds and identify certain sound classes */
1626 for (j = 0; element_action_info[j].suffix; j++)
1628 int len_action_text = strlen(element_action_info[j].suffix);
1630 if (len_action_text < len_effect_text &&
1631 strEqual(&sound->token[len_effect_text - len_action_text],
1632 element_action_info[j].suffix))
1634 sound_effect_properties[i] = element_action_info[j].value;
1635 sound_info[i].loop = element_action_info[j].is_loop_sound;
1641 /* associate elements and some selected sound actions */
1643 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1645 if (element_info[j].class_name)
1647 int len_class_text = strlen(element_info[j].class_name);
1649 if (len_class_text + 1 < len_effect_text &&
1650 strncmp(sound->token,
1651 element_info[j].class_name, len_class_text) == 0 &&
1652 sound->token[len_class_text] == '.')
1654 int sound_action_value = sound_effect_properties[i];
1656 element_info[j].sound[sound_action_value] = i;
1661 set_sound_parameters(i, sound->parameter);
1664 free(sound_effect_properties);
1667 static void InitGameModeMusicInfo()
1669 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1670 int num_property_mappings = getMusicListPropertyMappingSize();
1671 int default_levelset_music = -1;
1674 /* set values to -1 to identify later as "uninitialized" values */
1675 for (i = 0; i < MAX_LEVELS; i++)
1676 levelset.music[i] = -1;
1677 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1680 /* initialize gamemode/music mapping from static configuration */
1681 for (i = 0; gamemode_to_music[i].music > -1; i++)
1683 int gamemode = gamemode_to_music[i].gamemode;
1684 int music = gamemode_to_music[i].music;
1687 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1691 gamemode = GAME_MODE_DEFAULT;
1693 menu.music[gamemode] = music;
1696 /* initialize gamemode/music mapping from dynamic configuration */
1697 for (i = 0; i < num_property_mappings; i++)
1699 int prefix = property_mapping[i].base_index;
1700 int gamemode = property_mapping[i].ext1_index;
1701 int level = property_mapping[i].ext2_index;
1702 int music = property_mapping[i].artwork_index;
1705 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1706 prefix, gamemode, level, music);
1709 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1713 gamemode = GAME_MODE_DEFAULT;
1715 /* level specific music only allowed for in-game music */
1716 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1717 gamemode = GAME_MODE_PLAYING;
1722 default_levelset_music = music;
1725 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1726 levelset.music[level] = music;
1727 if (gamemode != GAME_MODE_PLAYING)
1728 menu.music[gamemode] = music;
1731 /* now set all '-1' values to menu specific default values */
1732 /* (undefined values of "levelset.music[]" might stay at "-1" to
1733 allow dynamic selection of music files from music directory!) */
1734 for (i = 0; i < MAX_LEVELS; i++)
1735 if (levelset.music[i] == -1)
1736 levelset.music[i] = default_levelset_music;
1737 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1738 if (menu.music[i] == -1)
1739 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1742 for (i = 0; i < MAX_LEVELS; i++)
1743 if (levelset.music[i] != -1)
1744 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1745 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1746 if (menu.music[i] != -1)
1747 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1751 static void set_music_parameters(int music, char **parameter_raw)
1753 int parameter[NUM_MUS_ARGS];
1756 /* get integer values from string parameters */
1757 for (i = 0; i < NUM_MUS_ARGS; i++)
1759 get_parameter_value(parameter_raw[i],
1760 music_config_suffix[i].token,
1761 music_config_suffix[i].type);
1763 /* explicit loop mode setting in configuration overrides default value */
1764 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1765 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1768 static void InitMusicInfo()
1770 int num_music = getMusicListSize();
1773 checked_free(music_info);
1775 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1777 for (i = 0; i < num_music; i++)
1779 struct FileInfo *music = getMusicListEntry(i);
1780 int len_music_text = strlen(music->token);
1782 music_info[i].loop = TRUE; /* default: play music in loop mode */
1784 /* determine all loop music */
1786 for (j = 0; music_prefix_info[j].prefix; j++)
1788 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1790 if (len_prefix_text < len_music_text &&
1791 strncmp(music->token,
1792 music_prefix_info[j].prefix, len_prefix_text) == 0)
1794 music_info[i].loop = music_prefix_info[j].is_loop_music;
1800 set_music_parameters(i, music->parameter);
1804 static void ReinitializeGraphics()
1806 InitGraphicInfo(); /* graphic properties mapping */
1807 InitElementGraphicInfo(); /* element game graphic mapping */
1808 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1810 InitElementSmallImages(); /* scale elements to all needed sizes */
1811 InitScaledImages(); /* scale all other images, if needed */
1812 InitFontGraphicInfo(); /* initialize text drawing functions */
1814 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1816 SetMainBackgroundImage(IMG_BACKGROUND);
1817 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1823 static void ReinitializeSounds()
1825 InitSoundInfo(); /* sound properties mapping */
1826 InitElementSoundInfo(); /* element game sound mapping */
1827 InitGameModeSoundInfo(); /* game mode sound mapping */
1829 InitPlayLevelSound(); /* internal game sound settings */
1832 static void ReinitializeMusic()
1834 InitMusicInfo(); /* music properties mapping */
1835 InitGameModeMusicInfo(); /* game mode music mapping */
1838 static int get_special_property_bit(int element, int property_bit_nr)
1840 struct PropertyBitInfo
1846 static struct PropertyBitInfo pb_can_move_into_acid[] =
1848 /* the player may be able fall into acid when gravity is activated */
1853 { EL_SP_MURPHY, 0 },
1854 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1856 /* all elements that can move may be able to also move into acid */
1859 { EL_BUG_RIGHT, 1 },
1862 { EL_SPACESHIP, 2 },
1863 { EL_SPACESHIP_LEFT, 2 },
1864 { EL_SPACESHIP_RIGHT, 2 },
1865 { EL_SPACESHIP_UP, 2 },
1866 { EL_SPACESHIP_DOWN, 2 },
1867 { EL_BD_BUTTERFLY, 3 },
1868 { EL_BD_BUTTERFLY_LEFT, 3 },
1869 { EL_BD_BUTTERFLY_RIGHT, 3 },
1870 { EL_BD_BUTTERFLY_UP, 3 },
1871 { EL_BD_BUTTERFLY_DOWN, 3 },
1872 { EL_BD_FIREFLY, 4 },
1873 { EL_BD_FIREFLY_LEFT, 4 },
1874 { EL_BD_FIREFLY_RIGHT, 4 },
1875 { EL_BD_FIREFLY_UP, 4 },
1876 { EL_BD_FIREFLY_DOWN, 4 },
1878 { EL_YAMYAM_LEFT, 5 },
1879 { EL_YAMYAM_RIGHT, 5 },
1880 { EL_YAMYAM_UP, 5 },
1881 { EL_YAMYAM_DOWN, 5 },
1882 { EL_DARK_YAMYAM, 6 },
1885 { EL_PACMAN_LEFT, 8 },
1886 { EL_PACMAN_RIGHT, 8 },
1887 { EL_PACMAN_UP, 8 },
1888 { EL_PACMAN_DOWN, 8 },
1890 { EL_MOLE_LEFT, 9 },
1891 { EL_MOLE_RIGHT, 9 },
1893 { EL_MOLE_DOWN, 9 },
1897 { EL_SATELLITE, 13 },
1898 { EL_SP_SNIKSNAK, 14 },
1899 { EL_SP_ELECTRON, 15 },
1902 { EL_EMC_ANDROID, 18 },
1907 static struct PropertyBitInfo pb_dont_collide_with[] =
1909 { EL_SP_SNIKSNAK, 0 },
1910 { EL_SP_ELECTRON, 1 },
1918 struct PropertyBitInfo *pb_info;
1921 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1922 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1927 struct PropertyBitInfo *pb_info = NULL;
1930 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1931 if (pb_definition[i].bit_nr == property_bit_nr)
1932 pb_info = pb_definition[i].pb_info;
1934 if (pb_info == NULL)
1937 for (i = 0; pb_info[i].element != -1; i++)
1938 if (pb_info[i].element == element)
1939 return pb_info[i].bit_nr;
1944 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1945 boolean property_value)
1947 int bit_nr = get_special_property_bit(element, property_bit_nr);
1952 *bitfield |= (1 << bit_nr);
1954 *bitfield &= ~(1 << bit_nr);
1958 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1960 int bit_nr = get_special_property_bit(element, property_bit_nr);
1963 return ((*bitfield & (1 << bit_nr)) != 0);
1968 static void ResolveGroupElementExt(int group_element, int recursion_depth)
1970 static int group_nr;
1971 static struct ElementGroupInfo *group;
1972 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1975 if (actual_group == NULL) /* not yet initialized */
1978 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1980 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1981 group_element - EL_GROUP_START + 1);
1983 /* replace element which caused too deep recursion by question mark */
1984 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1989 if (recursion_depth == 0) /* initialization */
1991 group = actual_group;
1992 group_nr = GROUP_NR(group_element);
1994 group->num_elements_resolved = 0;
1995 group->choice_pos = 0;
1997 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1998 element_info[i].in_group[group_nr] = FALSE;
2001 for (i = 0; i < actual_group->num_elements; i++)
2003 int element = actual_group->element[i];
2005 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2008 if (IS_GROUP_ELEMENT(element))
2009 ResolveGroupElementExt(element, recursion_depth + 1);
2012 group->element_resolved[group->num_elements_resolved++] = element;
2013 element_info[element].in_group[group_nr] = TRUE;
2018 void ResolveGroupElement(int group_element)
2020 ResolveGroupElementExt(group_element, 0);
2023 void InitElementPropertiesStatic()
2025 static int ep_diggable[] =
2030 EL_SP_BUGGY_BASE_ACTIVATING,
2033 EL_INVISIBLE_SAND_ACTIVE,
2036 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2037 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2042 EL_SP_BUGGY_BASE_ACTIVE,
2049 static int ep_collectible_only[] =
2071 EL_DYNABOMB_INCREASE_NUMBER,
2072 EL_DYNABOMB_INCREASE_SIZE,
2073 EL_DYNABOMB_INCREASE_POWER,
2091 /* !!! handle separately !!! */
2092 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2098 static int ep_dont_run_into[] =
2100 /* same elements as in 'ep_dont_touch' */
2106 /* same elements as in 'ep_dont_collide_with' */
2118 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2123 EL_SP_BUGGY_BASE_ACTIVE,
2130 static int ep_dont_collide_with[] =
2132 /* same elements as in 'ep_dont_touch' */
2149 static int ep_dont_touch[] =
2159 static int ep_indestructible[] =
2163 EL_ACID_POOL_TOPLEFT,
2164 EL_ACID_POOL_TOPRIGHT,
2165 EL_ACID_POOL_BOTTOMLEFT,
2166 EL_ACID_POOL_BOTTOM,
2167 EL_ACID_POOL_BOTTOMRIGHT,
2168 EL_SP_HARDWARE_GRAY,
2169 EL_SP_HARDWARE_GREEN,
2170 EL_SP_HARDWARE_BLUE,
2172 EL_SP_HARDWARE_YELLOW,
2173 EL_SP_HARDWARE_BASE_1,
2174 EL_SP_HARDWARE_BASE_2,
2175 EL_SP_HARDWARE_BASE_3,
2176 EL_SP_HARDWARE_BASE_4,
2177 EL_SP_HARDWARE_BASE_5,
2178 EL_SP_HARDWARE_BASE_6,
2179 EL_INVISIBLE_STEELWALL,
2180 EL_INVISIBLE_STEELWALL_ACTIVE,
2181 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2182 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2183 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2184 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2185 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2186 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2187 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2188 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2189 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2190 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2191 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2192 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2194 EL_LIGHT_SWITCH_ACTIVE,
2195 EL_SIGN_EXCLAMATION,
2196 EL_SIGN_RADIOACTIVITY,
2203 EL_SIGN_ENTRY_FORBIDDEN,
2204 EL_SIGN_EMERGENCY_EXIT,
2212 EL_STEEL_EXIT_CLOSED,
2214 EL_EM_STEEL_EXIT_CLOSED,
2215 EL_EM_STEEL_EXIT_OPEN,
2216 EL_DC_STEELWALL_1_LEFT,
2217 EL_DC_STEELWALL_1_RIGHT,
2218 EL_DC_STEELWALL_1_TOP,
2219 EL_DC_STEELWALL_1_BOTTOM,
2220 EL_DC_STEELWALL_1_HORIZONTAL,
2221 EL_DC_STEELWALL_1_VERTICAL,
2222 EL_DC_STEELWALL_1_TOPLEFT,
2223 EL_DC_STEELWALL_1_TOPRIGHT,
2224 EL_DC_STEELWALL_1_BOTTOMLEFT,
2225 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2226 EL_DC_STEELWALL_1_TOPLEFT_2,
2227 EL_DC_STEELWALL_1_TOPRIGHT_2,
2228 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2229 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2230 EL_DC_STEELWALL_2_LEFT,
2231 EL_DC_STEELWALL_2_RIGHT,
2232 EL_DC_STEELWALL_2_TOP,
2233 EL_DC_STEELWALL_2_BOTTOM,
2234 EL_DC_STEELWALL_2_HORIZONTAL,
2235 EL_DC_STEELWALL_2_VERTICAL,
2236 EL_DC_STEELWALL_2_MIDDLE,
2237 EL_DC_STEELWALL_2_SINGLE,
2238 EL_STEELWALL_SLIPPERY,
2252 EL_GATE_1_GRAY_ACTIVE,
2253 EL_GATE_2_GRAY_ACTIVE,
2254 EL_GATE_3_GRAY_ACTIVE,
2255 EL_GATE_4_GRAY_ACTIVE,
2264 EL_EM_GATE_1_GRAY_ACTIVE,
2265 EL_EM_GATE_2_GRAY_ACTIVE,
2266 EL_EM_GATE_3_GRAY_ACTIVE,
2267 EL_EM_GATE_4_GRAY_ACTIVE,
2276 EL_EMC_GATE_5_GRAY_ACTIVE,
2277 EL_EMC_GATE_6_GRAY_ACTIVE,
2278 EL_EMC_GATE_7_GRAY_ACTIVE,
2279 EL_EMC_GATE_8_GRAY_ACTIVE,
2281 EL_DC_GATE_WHITE_GRAY,
2282 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2283 EL_DC_GATE_FAKE_GRAY,
2285 EL_SWITCHGATE_OPENING,
2286 EL_SWITCHGATE_CLOSED,
2287 EL_SWITCHGATE_CLOSING,
2289 EL_DC_SWITCHGATE_SWITCH_UP,
2290 EL_DC_SWITCHGATE_SWITCH_DOWN,
2293 EL_TIMEGATE_OPENING,
2295 EL_TIMEGATE_CLOSING,
2297 EL_DC_TIMEGATE_SWITCH,
2298 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2303 EL_TUBE_VERTICAL_LEFT,
2304 EL_TUBE_VERTICAL_RIGHT,
2305 EL_TUBE_HORIZONTAL_UP,
2306 EL_TUBE_HORIZONTAL_DOWN,
2311 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2312 EL_EXPANDABLE_STEELWALL_VERTICAL,
2313 EL_EXPANDABLE_STEELWALL_ANY,
2318 static int ep_slippery[] =
2332 EL_ROBOT_WHEEL_ACTIVE,
2338 EL_ACID_POOL_TOPLEFT,
2339 EL_ACID_POOL_TOPRIGHT,
2349 EL_STEELWALL_SLIPPERY,
2352 EL_EMC_WALL_SLIPPERY_1,
2353 EL_EMC_WALL_SLIPPERY_2,
2354 EL_EMC_WALL_SLIPPERY_3,
2355 EL_EMC_WALL_SLIPPERY_4,
2357 EL_EMC_MAGIC_BALL_ACTIVE,
2362 static int ep_can_change[] =
2367 static int ep_can_move[] =
2369 /* same elements as in 'pb_can_move_into_acid' */
2392 static int ep_can_fall[] =
2406 EL_QUICKSAND_FAST_FULL,
2408 EL_BD_MAGIC_WALL_FULL,
2409 EL_DC_MAGIC_WALL_FULL,
2423 static int ep_can_smash_player[] =
2449 static int ep_can_smash_enemies[] =
2458 static int ep_can_smash_everything[] =
2467 static int ep_explodes_by_fire[] =
2469 /* same elements as in 'ep_explodes_impact' */
2474 /* same elements as in 'ep_explodes_smashed' */
2484 EL_EM_DYNAMITE_ACTIVE,
2485 EL_DYNABOMB_PLAYER_1_ACTIVE,
2486 EL_DYNABOMB_PLAYER_2_ACTIVE,
2487 EL_DYNABOMB_PLAYER_3_ACTIVE,
2488 EL_DYNABOMB_PLAYER_4_ACTIVE,
2489 EL_DYNABOMB_INCREASE_NUMBER,
2490 EL_DYNABOMB_INCREASE_SIZE,
2491 EL_DYNABOMB_INCREASE_POWER,
2492 EL_SP_DISK_RED_ACTIVE,
2506 static int ep_explodes_smashed[] =
2508 /* same elements as in 'ep_explodes_impact' */
2522 static int ep_explodes_impact[] =
2531 static int ep_walkable_over[] =
2535 EL_SOKOBAN_FIELD_EMPTY,
2541 EL_EM_STEEL_EXIT_OPEN,
2550 EL_GATE_1_GRAY_ACTIVE,
2551 EL_GATE_2_GRAY_ACTIVE,
2552 EL_GATE_3_GRAY_ACTIVE,
2553 EL_GATE_4_GRAY_ACTIVE,
2561 static int ep_walkable_inside[] =
2566 EL_TUBE_VERTICAL_LEFT,
2567 EL_TUBE_VERTICAL_RIGHT,
2568 EL_TUBE_HORIZONTAL_UP,
2569 EL_TUBE_HORIZONTAL_DOWN,
2578 static int ep_walkable_under[] =
2583 static int ep_passable_over[] =
2593 EL_EM_GATE_1_GRAY_ACTIVE,
2594 EL_EM_GATE_2_GRAY_ACTIVE,
2595 EL_EM_GATE_3_GRAY_ACTIVE,
2596 EL_EM_GATE_4_GRAY_ACTIVE,
2605 EL_EMC_GATE_5_GRAY_ACTIVE,
2606 EL_EMC_GATE_6_GRAY_ACTIVE,
2607 EL_EMC_GATE_7_GRAY_ACTIVE,
2608 EL_EMC_GATE_8_GRAY_ACTIVE,
2610 EL_DC_GATE_WHITE_GRAY,
2611 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2618 static int ep_passable_inside[] =
2624 EL_SP_PORT_HORIZONTAL,
2625 EL_SP_PORT_VERTICAL,
2627 EL_SP_GRAVITY_PORT_LEFT,
2628 EL_SP_GRAVITY_PORT_RIGHT,
2629 EL_SP_GRAVITY_PORT_UP,
2630 EL_SP_GRAVITY_PORT_DOWN,
2631 EL_SP_GRAVITY_ON_PORT_LEFT,
2632 EL_SP_GRAVITY_ON_PORT_RIGHT,
2633 EL_SP_GRAVITY_ON_PORT_UP,
2634 EL_SP_GRAVITY_ON_PORT_DOWN,
2635 EL_SP_GRAVITY_OFF_PORT_LEFT,
2636 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2637 EL_SP_GRAVITY_OFF_PORT_UP,
2638 EL_SP_GRAVITY_OFF_PORT_DOWN,
2643 static int ep_passable_under[] =
2648 static int ep_droppable[] =
2653 static int ep_explodes_1x1_old[] =
2658 static int ep_pushable[] =
2670 EL_SOKOBAN_FIELD_FULL,
2679 static int ep_explodes_cross_old[] =
2684 static int ep_protected[] =
2686 /* same elements as in 'ep_walkable_inside' */
2690 EL_TUBE_VERTICAL_LEFT,
2691 EL_TUBE_VERTICAL_RIGHT,
2692 EL_TUBE_HORIZONTAL_UP,
2693 EL_TUBE_HORIZONTAL_DOWN,
2699 /* same elements as in 'ep_passable_over' */
2708 EL_EM_GATE_1_GRAY_ACTIVE,
2709 EL_EM_GATE_2_GRAY_ACTIVE,
2710 EL_EM_GATE_3_GRAY_ACTIVE,
2711 EL_EM_GATE_4_GRAY_ACTIVE,
2720 EL_EMC_GATE_5_GRAY_ACTIVE,
2721 EL_EMC_GATE_6_GRAY_ACTIVE,
2722 EL_EMC_GATE_7_GRAY_ACTIVE,
2723 EL_EMC_GATE_8_GRAY_ACTIVE,
2725 EL_DC_GATE_WHITE_GRAY,
2726 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2730 /* same elements as in 'ep_passable_inside' */
2735 EL_SP_PORT_HORIZONTAL,
2736 EL_SP_PORT_VERTICAL,
2738 EL_SP_GRAVITY_PORT_LEFT,
2739 EL_SP_GRAVITY_PORT_RIGHT,
2740 EL_SP_GRAVITY_PORT_UP,
2741 EL_SP_GRAVITY_PORT_DOWN,
2742 EL_SP_GRAVITY_ON_PORT_LEFT,
2743 EL_SP_GRAVITY_ON_PORT_RIGHT,
2744 EL_SP_GRAVITY_ON_PORT_UP,
2745 EL_SP_GRAVITY_ON_PORT_DOWN,
2746 EL_SP_GRAVITY_OFF_PORT_LEFT,
2747 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2748 EL_SP_GRAVITY_OFF_PORT_UP,
2749 EL_SP_GRAVITY_OFF_PORT_DOWN,
2754 static int ep_throwable[] =
2759 static int ep_can_explode[] =
2761 /* same elements as in 'ep_explodes_impact' */
2766 /* same elements as in 'ep_explodes_smashed' */
2772 /* elements that can explode by explosion or by dragonfire */
2776 EL_EM_DYNAMITE_ACTIVE,
2777 EL_DYNABOMB_PLAYER_1_ACTIVE,
2778 EL_DYNABOMB_PLAYER_2_ACTIVE,
2779 EL_DYNABOMB_PLAYER_3_ACTIVE,
2780 EL_DYNABOMB_PLAYER_4_ACTIVE,
2781 EL_DYNABOMB_INCREASE_NUMBER,
2782 EL_DYNABOMB_INCREASE_SIZE,
2783 EL_DYNABOMB_INCREASE_POWER,
2784 EL_SP_DISK_RED_ACTIVE,
2792 /* elements that can explode only by explosion */
2798 static int ep_gravity_reachable[] =
2804 EL_INVISIBLE_SAND_ACTIVE,
2809 EL_SP_PORT_HORIZONTAL,
2810 EL_SP_PORT_VERTICAL,
2812 EL_SP_GRAVITY_PORT_LEFT,
2813 EL_SP_GRAVITY_PORT_RIGHT,
2814 EL_SP_GRAVITY_PORT_UP,
2815 EL_SP_GRAVITY_PORT_DOWN,
2816 EL_SP_GRAVITY_ON_PORT_LEFT,
2817 EL_SP_GRAVITY_ON_PORT_RIGHT,
2818 EL_SP_GRAVITY_ON_PORT_UP,
2819 EL_SP_GRAVITY_ON_PORT_DOWN,
2820 EL_SP_GRAVITY_OFF_PORT_LEFT,
2821 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2822 EL_SP_GRAVITY_OFF_PORT_UP,
2823 EL_SP_GRAVITY_OFF_PORT_DOWN,
2829 static int ep_player[] =
2836 EL_SOKOBAN_FIELD_PLAYER,
2842 static int ep_can_pass_magic_wall[] =
2856 static int ep_can_pass_dc_magic_wall[] =
2872 static int ep_switchable[] =
2876 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2877 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2878 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2879 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2880 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2881 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2882 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2883 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2884 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2885 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2886 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2887 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2888 EL_SWITCHGATE_SWITCH_UP,
2889 EL_SWITCHGATE_SWITCH_DOWN,
2890 EL_DC_SWITCHGATE_SWITCH_UP,
2891 EL_DC_SWITCHGATE_SWITCH_DOWN,
2893 EL_LIGHT_SWITCH_ACTIVE,
2895 EL_DC_TIMEGATE_SWITCH,
2896 EL_BALLOON_SWITCH_LEFT,
2897 EL_BALLOON_SWITCH_RIGHT,
2898 EL_BALLOON_SWITCH_UP,
2899 EL_BALLOON_SWITCH_DOWN,
2900 EL_BALLOON_SWITCH_ANY,
2901 EL_BALLOON_SWITCH_NONE,
2904 EL_EMC_MAGIC_BALL_SWITCH,
2905 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2910 static int ep_bd_element[] =
2944 static int ep_sp_element[] =
2946 /* should always be valid */
2949 /* standard classic Supaplex elements */
2956 EL_SP_HARDWARE_GRAY,
2964 EL_SP_GRAVITY_PORT_RIGHT,
2965 EL_SP_GRAVITY_PORT_DOWN,
2966 EL_SP_GRAVITY_PORT_LEFT,
2967 EL_SP_GRAVITY_PORT_UP,
2972 EL_SP_PORT_VERTICAL,
2973 EL_SP_PORT_HORIZONTAL,
2979 EL_SP_HARDWARE_BASE_1,
2980 EL_SP_HARDWARE_GREEN,
2981 EL_SP_HARDWARE_BLUE,
2983 EL_SP_HARDWARE_YELLOW,
2984 EL_SP_HARDWARE_BASE_2,
2985 EL_SP_HARDWARE_BASE_3,
2986 EL_SP_HARDWARE_BASE_4,
2987 EL_SP_HARDWARE_BASE_5,
2988 EL_SP_HARDWARE_BASE_6,
2992 /* additional elements that appeared in newer Supaplex levels */
2995 /* additional gravity port elements (not switching, but setting gravity) */
2996 EL_SP_GRAVITY_ON_PORT_LEFT,
2997 EL_SP_GRAVITY_ON_PORT_RIGHT,
2998 EL_SP_GRAVITY_ON_PORT_UP,
2999 EL_SP_GRAVITY_ON_PORT_DOWN,
3000 EL_SP_GRAVITY_OFF_PORT_LEFT,
3001 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3002 EL_SP_GRAVITY_OFF_PORT_UP,
3003 EL_SP_GRAVITY_OFF_PORT_DOWN,
3005 /* more than one Murphy in a level results in an inactive clone */
3008 /* runtime Supaplex elements */
3009 EL_SP_DISK_RED_ACTIVE,
3010 EL_SP_TERMINAL_ACTIVE,
3011 EL_SP_BUGGY_BASE_ACTIVATING,
3012 EL_SP_BUGGY_BASE_ACTIVE,
3019 static int ep_sb_element[] =
3024 EL_SOKOBAN_FIELD_EMPTY,
3025 EL_SOKOBAN_FIELD_FULL,
3026 EL_SOKOBAN_FIELD_PLAYER,
3031 EL_INVISIBLE_STEELWALL,
3036 static int ep_gem[] =
3048 static int ep_food_dark_yamyam[] =
3076 static int ep_food_penguin[] =
3090 static int ep_food_pig[] =
3102 static int ep_historic_wall[] =
3113 EL_GATE_1_GRAY_ACTIVE,
3114 EL_GATE_2_GRAY_ACTIVE,
3115 EL_GATE_3_GRAY_ACTIVE,
3116 EL_GATE_4_GRAY_ACTIVE,
3125 EL_EM_GATE_1_GRAY_ACTIVE,
3126 EL_EM_GATE_2_GRAY_ACTIVE,
3127 EL_EM_GATE_3_GRAY_ACTIVE,
3128 EL_EM_GATE_4_GRAY_ACTIVE,
3135 EL_EXPANDABLE_WALL_HORIZONTAL,
3136 EL_EXPANDABLE_WALL_VERTICAL,
3137 EL_EXPANDABLE_WALL_ANY,
3138 EL_EXPANDABLE_WALL_GROWING,
3139 EL_BD_EXPANDABLE_WALL,
3146 EL_SP_HARDWARE_GRAY,
3147 EL_SP_HARDWARE_GREEN,
3148 EL_SP_HARDWARE_BLUE,
3150 EL_SP_HARDWARE_YELLOW,
3151 EL_SP_HARDWARE_BASE_1,
3152 EL_SP_HARDWARE_BASE_2,
3153 EL_SP_HARDWARE_BASE_3,
3154 EL_SP_HARDWARE_BASE_4,
3155 EL_SP_HARDWARE_BASE_5,
3156 EL_SP_HARDWARE_BASE_6,
3158 EL_SP_TERMINAL_ACTIVE,
3161 EL_INVISIBLE_STEELWALL,
3162 EL_INVISIBLE_STEELWALL_ACTIVE,
3164 EL_INVISIBLE_WALL_ACTIVE,
3165 EL_STEELWALL_SLIPPERY,
3182 static int ep_historic_solid[] =
3186 EL_EXPANDABLE_WALL_HORIZONTAL,
3187 EL_EXPANDABLE_WALL_VERTICAL,
3188 EL_EXPANDABLE_WALL_ANY,
3189 EL_BD_EXPANDABLE_WALL,
3202 EL_QUICKSAND_FILLING,
3203 EL_QUICKSAND_EMPTYING,
3205 EL_MAGIC_WALL_ACTIVE,
3206 EL_MAGIC_WALL_EMPTYING,
3207 EL_MAGIC_WALL_FILLING,
3211 EL_BD_MAGIC_WALL_ACTIVE,
3212 EL_BD_MAGIC_WALL_EMPTYING,
3213 EL_BD_MAGIC_WALL_FULL,
3214 EL_BD_MAGIC_WALL_FILLING,
3215 EL_BD_MAGIC_WALL_DEAD,
3224 EL_SP_TERMINAL_ACTIVE,
3228 EL_INVISIBLE_WALL_ACTIVE,
3229 EL_SWITCHGATE_SWITCH_UP,
3230 EL_SWITCHGATE_SWITCH_DOWN,
3231 EL_DC_SWITCHGATE_SWITCH_UP,
3232 EL_DC_SWITCHGATE_SWITCH_DOWN,
3234 EL_TIMEGATE_SWITCH_ACTIVE,
3235 EL_DC_TIMEGATE_SWITCH,
3236 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3248 /* the following elements are a direct copy of "indestructible" elements,
3249 except "EL_ACID", which is "indestructible", but not "solid"! */
3254 EL_ACID_POOL_TOPLEFT,
3255 EL_ACID_POOL_TOPRIGHT,
3256 EL_ACID_POOL_BOTTOMLEFT,
3257 EL_ACID_POOL_BOTTOM,
3258 EL_ACID_POOL_BOTTOMRIGHT,
3259 EL_SP_HARDWARE_GRAY,
3260 EL_SP_HARDWARE_GREEN,
3261 EL_SP_HARDWARE_BLUE,
3263 EL_SP_HARDWARE_YELLOW,
3264 EL_SP_HARDWARE_BASE_1,
3265 EL_SP_HARDWARE_BASE_2,
3266 EL_SP_HARDWARE_BASE_3,
3267 EL_SP_HARDWARE_BASE_4,
3268 EL_SP_HARDWARE_BASE_5,
3269 EL_SP_HARDWARE_BASE_6,
3270 EL_INVISIBLE_STEELWALL,
3271 EL_INVISIBLE_STEELWALL_ACTIVE,
3272 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3273 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3274 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3275 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3276 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3277 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3278 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3279 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3280 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3281 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3282 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3283 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3285 EL_LIGHT_SWITCH_ACTIVE,
3286 EL_SIGN_EXCLAMATION,
3287 EL_SIGN_RADIOACTIVITY,
3294 EL_SIGN_ENTRY_FORBIDDEN,
3295 EL_SIGN_EMERGENCY_EXIT,
3303 EL_STEEL_EXIT_CLOSED,
3305 EL_DC_STEELWALL_1_LEFT,
3306 EL_DC_STEELWALL_1_RIGHT,
3307 EL_DC_STEELWALL_1_TOP,
3308 EL_DC_STEELWALL_1_BOTTOM,
3309 EL_DC_STEELWALL_1_HORIZONTAL,
3310 EL_DC_STEELWALL_1_VERTICAL,
3311 EL_DC_STEELWALL_1_TOPLEFT,
3312 EL_DC_STEELWALL_1_TOPRIGHT,
3313 EL_DC_STEELWALL_1_BOTTOMLEFT,
3314 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3315 EL_DC_STEELWALL_1_TOPLEFT_2,
3316 EL_DC_STEELWALL_1_TOPRIGHT_2,
3317 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3318 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3319 EL_DC_STEELWALL_2_LEFT,
3320 EL_DC_STEELWALL_2_RIGHT,
3321 EL_DC_STEELWALL_2_TOP,
3322 EL_DC_STEELWALL_2_BOTTOM,
3323 EL_DC_STEELWALL_2_HORIZONTAL,
3324 EL_DC_STEELWALL_2_VERTICAL,
3325 EL_DC_STEELWALL_2_MIDDLE,
3326 EL_DC_STEELWALL_2_SINGLE,
3327 EL_STEELWALL_SLIPPERY,
3341 EL_GATE_1_GRAY_ACTIVE,
3342 EL_GATE_2_GRAY_ACTIVE,
3343 EL_GATE_3_GRAY_ACTIVE,
3344 EL_GATE_4_GRAY_ACTIVE,
3353 EL_EM_GATE_1_GRAY_ACTIVE,
3354 EL_EM_GATE_2_GRAY_ACTIVE,
3355 EL_EM_GATE_3_GRAY_ACTIVE,
3356 EL_EM_GATE_4_GRAY_ACTIVE,
3358 EL_SWITCHGATE_OPENING,
3359 EL_SWITCHGATE_CLOSED,
3360 EL_SWITCHGATE_CLOSING,
3362 EL_TIMEGATE_OPENING,
3364 EL_TIMEGATE_CLOSING,
3368 EL_TUBE_VERTICAL_LEFT,
3369 EL_TUBE_VERTICAL_RIGHT,
3370 EL_TUBE_HORIZONTAL_UP,
3371 EL_TUBE_HORIZONTAL_DOWN,
3380 static int ep_classic_enemy[] =
3397 static int ep_belt[] =
3399 EL_CONVEYOR_BELT_1_LEFT,
3400 EL_CONVEYOR_BELT_1_MIDDLE,
3401 EL_CONVEYOR_BELT_1_RIGHT,
3402 EL_CONVEYOR_BELT_2_LEFT,
3403 EL_CONVEYOR_BELT_2_MIDDLE,
3404 EL_CONVEYOR_BELT_2_RIGHT,
3405 EL_CONVEYOR_BELT_3_LEFT,
3406 EL_CONVEYOR_BELT_3_MIDDLE,
3407 EL_CONVEYOR_BELT_3_RIGHT,
3408 EL_CONVEYOR_BELT_4_LEFT,
3409 EL_CONVEYOR_BELT_4_MIDDLE,
3410 EL_CONVEYOR_BELT_4_RIGHT,
3415 static int ep_belt_active[] =
3417 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3418 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3419 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3420 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3421 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3422 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3423 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3424 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3425 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3426 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3427 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3428 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3433 static int ep_belt_switch[] =
3435 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3436 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3437 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3438 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3439 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3440 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3441 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3442 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3443 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3444 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3445 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3446 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3451 static int ep_tube[] =
3458 EL_TUBE_HORIZONTAL_UP,
3459 EL_TUBE_HORIZONTAL_DOWN,
3461 EL_TUBE_VERTICAL_LEFT,
3462 EL_TUBE_VERTICAL_RIGHT,
3468 static int ep_acid_pool[] =
3470 EL_ACID_POOL_TOPLEFT,
3471 EL_ACID_POOL_TOPRIGHT,
3472 EL_ACID_POOL_BOTTOMLEFT,
3473 EL_ACID_POOL_BOTTOM,
3474 EL_ACID_POOL_BOTTOMRIGHT,
3479 static int ep_keygate[] =
3489 EL_GATE_1_GRAY_ACTIVE,
3490 EL_GATE_2_GRAY_ACTIVE,
3491 EL_GATE_3_GRAY_ACTIVE,
3492 EL_GATE_4_GRAY_ACTIVE,
3501 EL_EM_GATE_1_GRAY_ACTIVE,
3502 EL_EM_GATE_2_GRAY_ACTIVE,
3503 EL_EM_GATE_3_GRAY_ACTIVE,
3504 EL_EM_GATE_4_GRAY_ACTIVE,
3513 EL_EMC_GATE_5_GRAY_ACTIVE,
3514 EL_EMC_GATE_6_GRAY_ACTIVE,
3515 EL_EMC_GATE_7_GRAY_ACTIVE,
3516 EL_EMC_GATE_8_GRAY_ACTIVE,
3518 EL_DC_GATE_WHITE_GRAY,
3519 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3524 static int ep_amoeboid[] =
3536 static int ep_amoebalive[] =
3547 static int ep_has_editor_content[] =
3569 static int ep_can_turn_each_move[] =
3571 /* !!! do something with this one !!! */
3575 static int ep_can_grow[] =
3589 static int ep_active_bomb[] =
3592 EL_EM_DYNAMITE_ACTIVE,
3593 EL_DYNABOMB_PLAYER_1_ACTIVE,
3594 EL_DYNABOMB_PLAYER_2_ACTIVE,
3595 EL_DYNABOMB_PLAYER_3_ACTIVE,
3596 EL_DYNABOMB_PLAYER_4_ACTIVE,
3597 EL_SP_DISK_RED_ACTIVE,
3602 static int ep_inactive[] =
3612 EL_QUICKSAND_FAST_EMPTY,
3635 EL_GATE_1_GRAY_ACTIVE,
3636 EL_GATE_2_GRAY_ACTIVE,
3637 EL_GATE_3_GRAY_ACTIVE,
3638 EL_GATE_4_GRAY_ACTIVE,
3647 EL_EM_GATE_1_GRAY_ACTIVE,
3648 EL_EM_GATE_2_GRAY_ACTIVE,
3649 EL_EM_GATE_3_GRAY_ACTIVE,
3650 EL_EM_GATE_4_GRAY_ACTIVE,
3659 EL_EMC_GATE_5_GRAY_ACTIVE,
3660 EL_EMC_GATE_6_GRAY_ACTIVE,
3661 EL_EMC_GATE_7_GRAY_ACTIVE,
3662 EL_EMC_GATE_8_GRAY_ACTIVE,
3664 EL_DC_GATE_WHITE_GRAY,
3665 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3666 EL_DC_GATE_FAKE_GRAY,
3669 EL_INVISIBLE_STEELWALL,
3677 EL_WALL_EMERALD_YELLOW,
3678 EL_DYNABOMB_INCREASE_NUMBER,
3679 EL_DYNABOMB_INCREASE_SIZE,
3680 EL_DYNABOMB_INCREASE_POWER,
3684 EL_SOKOBAN_FIELD_EMPTY,
3685 EL_SOKOBAN_FIELD_FULL,
3686 EL_WALL_EMERALD_RED,
3687 EL_WALL_EMERALD_PURPLE,
3688 EL_ACID_POOL_TOPLEFT,
3689 EL_ACID_POOL_TOPRIGHT,
3690 EL_ACID_POOL_BOTTOMLEFT,
3691 EL_ACID_POOL_BOTTOM,
3692 EL_ACID_POOL_BOTTOMRIGHT,
3696 EL_BD_MAGIC_WALL_DEAD,
3698 EL_DC_MAGIC_WALL_DEAD,
3699 EL_AMOEBA_TO_DIAMOND,
3707 EL_SP_GRAVITY_PORT_RIGHT,
3708 EL_SP_GRAVITY_PORT_DOWN,
3709 EL_SP_GRAVITY_PORT_LEFT,
3710 EL_SP_GRAVITY_PORT_UP,
3711 EL_SP_PORT_HORIZONTAL,
3712 EL_SP_PORT_VERTICAL,
3723 EL_SP_HARDWARE_GRAY,
3724 EL_SP_HARDWARE_GREEN,
3725 EL_SP_HARDWARE_BLUE,
3727 EL_SP_HARDWARE_YELLOW,
3728 EL_SP_HARDWARE_BASE_1,
3729 EL_SP_HARDWARE_BASE_2,
3730 EL_SP_HARDWARE_BASE_3,
3731 EL_SP_HARDWARE_BASE_4,
3732 EL_SP_HARDWARE_BASE_5,
3733 EL_SP_HARDWARE_BASE_6,
3734 EL_SP_GRAVITY_ON_PORT_LEFT,
3735 EL_SP_GRAVITY_ON_PORT_RIGHT,
3736 EL_SP_GRAVITY_ON_PORT_UP,
3737 EL_SP_GRAVITY_ON_PORT_DOWN,
3738 EL_SP_GRAVITY_OFF_PORT_LEFT,
3739 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3740 EL_SP_GRAVITY_OFF_PORT_UP,
3741 EL_SP_GRAVITY_OFF_PORT_DOWN,
3742 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3743 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3744 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3745 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3746 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3747 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3748 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3749 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3750 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3751 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3752 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3753 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3754 EL_SIGN_EXCLAMATION,
3755 EL_SIGN_RADIOACTIVITY,
3762 EL_SIGN_ENTRY_FORBIDDEN,
3763 EL_SIGN_EMERGENCY_EXIT,
3771 EL_DC_STEELWALL_1_LEFT,
3772 EL_DC_STEELWALL_1_RIGHT,
3773 EL_DC_STEELWALL_1_TOP,
3774 EL_DC_STEELWALL_1_BOTTOM,
3775 EL_DC_STEELWALL_1_HORIZONTAL,
3776 EL_DC_STEELWALL_1_VERTICAL,
3777 EL_DC_STEELWALL_1_TOPLEFT,
3778 EL_DC_STEELWALL_1_TOPRIGHT,
3779 EL_DC_STEELWALL_1_BOTTOMLEFT,
3780 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3781 EL_DC_STEELWALL_1_TOPLEFT_2,
3782 EL_DC_STEELWALL_1_TOPRIGHT_2,
3783 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3784 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3785 EL_DC_STEELWALL_2_LEFT,
3786 EL_DC_STEELWALL_2_RIGHT,
3787 EL_DC_STEELWALL_2_TOP,
3788 EL_DC_STEELWALL_2_BOTTOM,
3789 EL_DC_STEELWALL_2_HORIZONTAL,
3790 EL_DC_STEELWALL_2_VERTICAL,
3791 EL_DC_STEELWALL_2_MIDDLE,
3792 EL_DC_STEELWALL_2_SINGLE,
3793 EL_STEELWALL_SLIPPERY,
3798 EL_EMC_WALL_SLIPPERY_1,
3799 EL_EMC_WALL_SLIPPERY_2,
3800 EL_EMC_WALL_SLIPPERY_3,
3801 EL_EMC_WALL_SLIPPERY_4,
3822 static int ep_em_slippery_wall[] =
3827 static int ep_gfx_crumbled[] =
3838 static int ep_editor_cascade_active[] =
3840 EL_INTERNAL_CASCADE_BD_ACTIVE,
3841 EL_INTERNAL_CASCADE_EM_ACTIVE,
3842 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3843 EL_INTERNAL_CASCADE_RND_ACTIVE,
3844 EL_INTERNAL_CASCADE_SB_ACTIVE,
3845 EL_INTERNAL_CASCADE_SP_ACTIVE,
3846 EL_INTERNAL_CASCADE_DC_ACTIVE,
3847 EL_INTERNAL_CASCADE_DX_ACTIVE,
3848 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3849 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3850 EL_INTERNAL_CASCADE_CE_ACTIVE,
3851 EL_INTERNAL_CASCADE_GE_ACTIVE,
3852 EL_INTERNAL_CASCADE_REF_ACTIVE,
3853 EL_INTERNAL_CASCADE_USER_ACTIVE,
3854 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3859 static int ep_editor_cascade_inactive[] =
3861 EL_INTERNAL_CASCADE_BD,
3862 EL_INTERNAL_CASCADE_EM,
3863 EL_INTERNAL_CASCADE_EMC,
3864 EL_INTERNAL_CASCADE_RND,
3865 EL_INTERNAL_CASCADE_SB,
3866 EL_INTERNAL_CASCADE_SP,
3867 EL_INTERNAL_CASCADE_DC,
3868 EL_INTERNAL_CASCADE_DX,
3869 EL_INTERNAL_CASCADE_CHARS,
3870 EL_INTERNAL_CASCADE_STEEL_CHARS,
3871 EL_INTERNAL_CASCADE_CE,
3872 EL_INTERNAL_CASCADE_GE,
3873 EL_INTERNAL_CASCADE_REF,
3874 EL_INTERNAL_CASCADE_USER,
3875 EL_INTERNAL_CASCADE_DYNAMIC,
3880 static int ep_obsolete[] =
3884 EL_EM_KEY_1_FILE_OBSOLETE,
3885 EL_EM_KEY_2_FILE_OBSOLETE,
3886 EL_EM_KEY_3_FILE_OBSOLETE,
3887 EL_EM_KEY_4_FILE_OBSOLETE,
3888 EL_ENVELOPE_OBSOLETE,
3897 } element_properties[] =
3899 { ep_diggable, EP_DIGGABLE },
3900 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3901 { ep_dont_run_into, EP_DONT_RUN_INTO },
3902 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3903 { ep_dont_touch, EP_DONT_TOUCH },
3904 { ep_indestructible, EP_INDESTRUCTIBLE },
3905 { ep_slippery, EP_SLIPPERY },
3906 { ep_can_change, EP_CAN_CHANGE },
3907 { ep_can_move, EP_CAN_MOVE },
3908 { ep_can_fall, EP_CAN_FALL },
3909 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3910 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3911 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3912 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3913 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3914 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3915 { ep_walkable_over, EP_WALKABLE_OVER },
3916 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3917 { ep_walkable_under, EP_WALKABLE_UNDER },
3918 { ep_passable_over, EP_PASSABLE_OVER },
3919 { ep_passable_inside, EP_PASSABLE_INSIDE },
3920 { ep_passable_under, EP_PASSABLE_UNDER },
3921 { ep_droppable, EP_DROPPABLE },
3922 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3923 { ep_pushable, EP_PUSHABLE },
3924 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3925 { ep_protected, EP_PROTECTED },
3926 { ep_throwable, EP_THROWABLE },
3927 { ep_can_explode, EP_CAN_EXPLODE },
3928 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3930 { ep_player, EP_PLAYER },
3931 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3932 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3933 { ep_switchable, EP_SWITCHABLE },
3934 { ep_bd_element, EP_BD_ELEMENT },
3935 { ep_sp_element, EP_SP_ELEMENT },
3936 { ep_sb_element, EP_SB_ELEMENT },
3938 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3939 { ep_food_penguin, EP_FOOD_PENGUIN },
3940 { ep_food_pig, EP_FOOD_PIG },
3941 { ep_historic_wall, EP_HISTORIC_WALL },
3942 { ep_historic_solid, EP_HISTORIC_SOLID },
3943 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3944 { ep_belt, EP_BELT },
3945 { ep_belt_active, EP_BELT_ACTIVE },
3946 { ep_belt_switch, EP_BELT_SWITCH },
3947 { ep_tube, EP_TUBE },
3948 { ep_acid_pool, EP_ACID_POOL },
3949 { ep_keygate, EP_KEYGATE },
3950 { ep_amoeboid, EP_AMOEBOID },
3951 { ep_amoebalive, EP_AMOEBALIVE },
3952 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3953 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3954 { ep_can_grow, EP_CAN_GROW },
3955 { ep_active_bomb, EP_ACTIVE_BOMB },
3956 { ep_inactive, EP_INACTIVE },
3958 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3960 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3962 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3963 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3965 { ep_obsolete, EP_OBSOLETE },
3972 /* always start with reliable default values (element has no properties) */
3973 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3974 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3975 SET_PROPERTY(i, j, FALSE);
3977 /* set all base element properties from above array definitions */
3978 for (i = 0; element_properties[i].elements != NULL; i++)
3979 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3980 SET_PROPERTY((element_properties[i].elements)[j],
3981 element_properties[i].property, TRUE);
3983 /* copy properties to some elements that are only stored in level file */
3984 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3985 for (j = 0; copy_properties[j][0] != -1; j++)
3986 if (HAS_PROPERTY(copy_properties[j][0], i))
3987 for (k = 1; k <= 4; k++)
3988 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3990 /* set static element properties that are not listed in array definitions */
3991 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
3992 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
3995 void InitElementPropertiesEngine(int engine_version)
3997 static int no_wall_properties[] =
4000 EP_COLLECTIBLE_ONLY,
4002 EP_DONT_COLLIDE_WITH,
4005 EP_CAN_SMASH_PLAYER,
4006 EP_CAN_SMASH_ENEMIES,
4007 EP_CAN_SMASH_EVERYTHING,
4012 EP_FOOD_DARK_YAMYAM,
4028 /* important: after initialization in InitElementPropertiesStatic(), the
4029 elements are not again initialized to a default value; therefore all
4030 changes have to make sure that they leave the element with a defined
4031 property (which means that conditional property changes must be set to
4032 a reliable default value before) */
4034 /* resolve group elements */
4035 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4036 ResolveGroupElement(EL_GROUP_START + i);
4038 /* set all special, combined or engine dependent element properties */
4039 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4041 /* ---------- INACTIVE ------------------------------------------------- */
4042 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4043 i <= EL_CHAR_END) ||
4044 (i >= EL_STEEL_CHAR_START &&
4045 i <= EL_STEEL_CHAR_END)));
4047 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4048 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4049 IS_WALKABLE_INSIDE(i) ||
4050 IS_WALKABLE_UNDER(i)));
4052 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4053 IS_PASSABLE_INSIDE(i) ||
4054 IS_PASSABLE_UNDER(i)));
4056 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4057 IS_PASSABLE_OVER(i)));
4059 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4060 IS_PASSABLE_INSIDE(i)));
4062 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4063 IS_PASSABLE_UNDER(i)));
4065 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4068 /* ---------- COLLECTIBLE ---------------------------------------------- */
4069 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4073 /* ---------- SNAPPABLE ------------------------------------------------ */
4074 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4075 IS_COLLECTIBLE(i) ||
4079 /* ---------- WALL ----------------------------------------------------- */
4080 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4082 for (j = 0; no_wall_properties[j] != -1; j++)
4083 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4084 i >= EL_FIRST_RUNTIME_UNREAL)
4085 SET_PROPERTY(i, EP_WALL, FALSE);
4087 if (IS_HISTORIC_WALL(i))
4088 SET_PROPERTY(i, EP_WALL, TRUE);
4090 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4091 if (engine_version < VERSION_IDENT(2,2,0,0))
4092 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4094 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4096 !IS_COLLECTIBLE(i)));
4098 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4099 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4100 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4102 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4103 IS_INDESTRUCTIBLE(i)));
4105 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4107 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4108 else if (engine_version < VERSION_IDENT(2,2,0,0))
4109 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4111 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4115 if (IS_CUSTOM_ELEMENT(i))
4117 /* these are additional properties which are initially false when set */
4119 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4121 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4122 if (DONT_COLLIDE_WITH(i))
4123 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4125 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4126 if (CAN_SMASH_EVERYTHING(i))
4127 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4128 if (CAN_SMASH_ENEMIES(i))
4129 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4132 /* ---------- CAN_SMASH ------------------------------------------------ */
4133 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4134 CAN_SMASH_ENEMIES(i) ||
4135 CAN_SMASH_EVERYTHING(i)));
4137 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4138 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4139 EXPLODES_BY_FIRE(i)));
4141 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4142 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4143 EXPLODES_SMASHED(i)));
4145 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4146 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4147 EXPLODES_IMPACT(i)));
4149 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4150 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4152 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4153 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4154 i == EL_BLACK_ORB));
4156 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4157 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4159 IS_CUSTOM_ELEMENT(i)));
4161 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4162 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4163 i == EL_SP_ELECTRON));
4165 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4166 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4167 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4168 getMoveIntoAcidProperty(&level, i));
4170 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4171 if (MAYBE_DONT_COLLIDE_WITH(i))
4172 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4173 getDontCollideWithProperty(&level, i));
4175 /* ---------- SP_PORT -------------------------------------------------- */
4176 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4177 IS_PASSABLE_INSIDE(i)));
4179 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4180 for (j = 0; j < level.num_android_clone_elements; j++)
4181 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4183 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4185 /* ---------- CAN_CHANGE ----------------------------------------------- */
4186 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4187 for (j = 0; j < element_info[i].num_change_pages; j++)
4188 if (element_info[i].change_page[j].can_change)
4189 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4191 /* ---------- HAS_ACTION ----------------------------------------------- */
4192 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4193 for (j = 0; j < element_info[i].num_change_pages; j++)
4194 if (element_info[i].change_page[j].has_action)
4195 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4197 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4198 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4201 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4203 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4204 element_info[i].crumbled[ACTION_DEFAULT] !=
4205 element_info[i].graphic[ACTION_DEFAULT]);
4207 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4208 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4209 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4212 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4213 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4214 IS_EDITOR_CASCADE_INACTIVE(i)));
4217 /* dynamically adjust element properties according to game engine version */
4219 static int ep_em_slippery_wall[] =
4224 EL_EXPANDABLE_WALL_HORIZONTAL,
4225 EL_EXPANDABLE_WALL_VERTICAL,
4226 EL_EXPANDABLE_WALL_ANY,
4227 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4228 EL_EXPANDABLE_STEELWALL_VERTICAL,
4229 EL_EXPANDABLE_STEELWALL_ANY,
4230 EL_EXPANDABLE_STEELWALL_GROWING,
4234 /* special EM style gems behaviour */
4235 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4236 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4237 level.em_slippery_gems);
4239 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4240 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4241 (level.em_slippery_gems &&
4242 engine_version > VERSION_IDENT(2,0,1,0)));
4245 /* this is needed because some graphics depend on element properties */
4246 if (game_status == GAME_MODE_PLAYING)
4247 InitElementGraphicInfo();
4250 void InitElementPropertiesAfterLoading(int engine_version)
4254 /* set some other uninitialized values of custom elements in older levels */
4255 if (engine_version < VERSION_IDENT(3,1,0,0))
4257 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4259 int element = EL_CUSTOM_START + i;
4261 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4263 element_info[element].explosion_delay = 17;
4264 element_info[element].ignition_delay = 8;
4269 static void InitGlobal()
4273 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4275 /* check if element_name_info entry defined for each element in "main.h" */
4276 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4277 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4279 element_info[i].token_name = element_name_info[i].token_name;
4280 element_info[i].class_name = element_name_info[i].class_name;
4281 element_info[i].editor_description=element_name_info[i].editor_description;
4284 printf("%04d: %s\n", i, element_name_info[i].token_name);
4288 global.autoplay_leveldir = NULL;
4289 global.convert_leveldir = NULL;
4291 global.frames_per_second = 0;
4292 global.fps_slowdown = FALSE;
4293 global.fps_slowdown_factor = 1;
4296 void Execute_Command(char *command)
4300 if (strEqual(command, "print graphicsinfo.conf"))
4302 printf("# You can configure additional/alternative image files here.\n");
4303 printf("# (The entries below are default and therefore commented out.)\n");
4305 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4307 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4310 for (i = 0; image_config[i].token != NULL; i++)
4311 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4312 image_config[i].value));
4316 else if (strEqual(command, "print soundsinfo.conf"))
4318 printf("# You can configure additional/alternative sound files here.\n");
4319 printf("# (The entries below are default and therefore commented out.)\n");
4321 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4323 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4326 for (i = 0; sound_config[i].token != NULL; i++)
4327 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4328 sound_config[i].value));
4332 else if (strEqual(command, "print musicinfo.conf"))
4334 printf("# You can configure additional/alternative music files here.\n");
4335 printf("# (The entries below are default and therefore commented out.)\n");
4337 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4339 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4342 for (i = 0; music_config[i].token != NULL; i++)
4343 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4344 music_config[i].value));
4348 else if (strEqual(command, "print editorsetup.conf"))
4350 printf("# You can configure your personal editor element list here.\n");
4351 printf("# (The entries below are default and therefore commented out.)\n");
4354 /* this is needed to be able to check element list for cascade elements */
4355 InitElementPropertiesStatic();
4356 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4358 PrintEditorElementList();
4362 else if (strEqual(command, "print helpanim.conf"))
4364 printf("# You can configure different element help animations here.\n");
4365 printf("# (The entries below are default and therefore commented out.)\n");
4368 for (i = 0; helpanim_config[i].token != NULL; i++)
4370 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4371 helpanim_config[i].value));
4373 if (strEqual(helpanim_config[i].token, "end"))
4379 else if (strEqual(command, "print helptext.conf"))
4381 printf("# You can configure different element help text here.\n");
4382 printf("# (The entries below are default and therefore commented out.)\n");
4385 for (i = 0; helptext_config[i].token != NULL; i++)
4386 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4387 helptext_config[i].value));
4391 else if (strncmp(command, "dump level ", 11) == 0)
4393 char *filename = &command[11];
4395 if (!fileExists(filename))
4396 Error(ERR_EXIT, "cannot open file '%s'", filename);
4398 LoadLevelFromFilename(&level, filename);
4403 else if (strncmp(command, "dump tape ", 10) == 0)
4405 char *filename = &command[10];
4407 if (!fileExists(filename))
4408 Error(ERR_EXIT, "cannot open file '%s'", filename);
4410 LoadTapeFromFilename(filename);
4415 else if (strncmp(command, "autoplay ", 9) == 0)
4417 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4419 while (*str_ptr != '\0') /* continue parsing string */
4421 /* cut leading whitespace from string, replace it by string terminator */
4422 while (*str_ptr == ' ' || *str_ptr == '\t')
4425 if (*str_ptr == '\0') /* end of string reached */
4428 if (global.autoplay_leveldir == NULL) /* read level set string */
4430 global.autoplay_leveldir = str_ptr;
4431 global.autoplay_all = TRUE; /* default: play all tapes */
4433 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4434 global.autoplay_level[i] = FALSE;
4436 else /* read level number string */
4438 int level_nr = atoi(str_ptr); /* get level_nr value */
4440 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4441 global.autoplay_level[level_nr] = TRUE;
4443 global.autoplay_all = FALSE;
4446 /* advance string pointer to the next whitespace (or end of string) */
4447 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4451 else if (strncmp(command, "convert ", 8) == 0)
4453 char *str_copy = getStringCopy(&command[8]);
4454 char *str_ptr = strchr(str_copy, ' ');
4456 global.convert_leveldir = str_copy;
4457 global.convert_level_nr = -1;
4459 if (str_ptr != NULL) /* level number follows */
4461 *str_ptr++ = '\0'; /* terminate leveldir string */
4462 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4467 #if defined(TARGET_SDL)
4468 else if (strEqual(command, "SDL_ListModes"))
4473 SDL_Init(SDL_INIT_VIDEO);
4475 /* get available fullscreen/hardware modes */
4476 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4478 /* check if there are any modes available */
4481 printf("No modes available!\n");
4486 /* check if our resolution is restricted */
4487 if (modes == (SDL_Rect **)-1)
4489 printf("All resolutions available.\n");
4493 printf("Available Modes:\n");
4495 for(i = 0; modes[i]; i++)
4496 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4506 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4510 static void InitSetup()
4512 LoadSetup(); /* global setup info */
4514 /* set some options from setup file */
4516 if (setup.options.verbose)
4517 options.verbose = TRUE;
4520 static void InitGameInfo()
4522 game.restart_level = FALSE;
4525 static void InitPlayerInfo()
4529 /* choose default local player */
4530 local_player = &stored_player[0];
4532 for (i = 0; i < MAX_PLAYERS; i++)
4533 stored_player[i].connected = FALSE;
4535 local_player->connected = TRUE;
4538 static void InitArtworkInfo()
4543 static char *get_string_in_brackets(char *string)
4545 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4547 sprintf(string_in_brackets, "[%s]", string);
4549 return string_in_brackets;
4552 static char *get_level_id_suffix(int id_nr)
4554 char *id_suffix = checked_malloc(1 + 3 + 1);
4556 if (id_nr < 0 || id_nr > 999)
4559 sprintf(id_suffix, ".%03d", id_nr);
4565 static char *get_element_class_token(int element)
4567 char *element_class_name = element_info[element].class_name;
4568 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4570 sprintf(element_class_token, "[%s]", element_class_name);
4572 return element_class_token;
4575 static char *get_action_class_token(int action)
4577 char *action_class_name = &element_action_info[action].suffix[1];
4578 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4580 sprintf(action_class_token, "[%s]", action_class_name);
4582 return action_class_token;
4586 static void InitArtworkConfig()
4588 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4589 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4590 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4591 static char *action_id_suffix[NUM_ACTIONS + 1];
4592 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4593 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4594 static char *level_id_suffix[MAX_LEVELS + 1];
4595 static char *dummy[1] = { NULL };
4596 static char *ignore_generic_tokens[] =
4602 static char **ignore_image_tokens;
4603 static char **ignore_sound_tokens;
4604 static char **ignore_music_tokens;
4605 int num_ignore_generic_tokens;
4606 int num_ignore_image_tokens;
4607 int num_ignore_sound_tokens;
4608 int num_ignore_music_tokens;
4611 /* dynamically determine list of generic tokens to be ignored */
4612 num_ignore_generic_tokens = 0;
4613 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4614 num_ignore_generic_tokens++;
4616 /* dynamically determine list of image tokens to be ignored */
4617 num_ignore_image_tokens = num_ignore_generic_tokens;
4618 for (i = 0; image_config_vars[i].token != NULL; i++)
4619 num_ignore_image_tokens++;
4620 ignore_image_tokens =
4621 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4622 for (i = 0; i < num_ignore_generic_tokens; i++)
4623 ignore_image_tokens[i] = ignore_generic_tokens[i];
4624 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4625 ignore_image_tokens[num_ignore_generic_tokens + i] =
4626 image_config_vars[i].token;
4627 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4629 /* dynamically determine list of sound tokens to be ignored */
4630 num_ignore_sound_tokens = num_ignore_generic_tokens;
4631 ignore_sound_tokens =
4632 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4633 for (i = 0; i < num_ignore_generic_tokens; i++)
4634 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4635 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4637 /* dynamically determine list of music tokens to be ignored */
4638 num_ignore_music_tokens = num_ignore_generic_tokens;
4639 ignore_music_tokens =
4640 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4641 for (i = 0; i < num_ignore_generic_tokens; i++)
4642 ignore_music_tokens[i] = ignore_generic_tokens[i];
4643 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4645 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4646 image_id_prefix[i] = element_info[i].token_name;
4647 for (i = 0; i < NUM_FONTS; i++)
4648 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4649 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4651 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4652 sound_id_prefix[i] = element_info[i].token_name;
4653 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4654 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4655 get_string_in_brackets(element_info[i].class_name);
4656 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4658 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4659 music_id_prefix[i] = music_prefix_info[i].prefix;
4660 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4662 for (i = 0; i < NUM_ACTIONS; i++)
4663 action_id_suffix[i] = element_action_info[i].suffix;
4664 action_id_suffix[NUM_ACTIONS] = NULL;
4666 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4667 direction_id_suffix[i] = element_direction_info[i].suffix;
4668 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4670 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4671 special_id_suffix[i] = special_suffix_info[i].suffix;
4672 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4674 for (i = 0; i < MAX_LEVELS; i++)
4675 level_id_suffix[i] = get_level_id_suffix(i);
4676 level_id_suffix[MAX_LEVELS] = NULL;
4678 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4679 image_id_prefix, action_id_suffix, direction_id_suffix,
4680 special_id_suffix, ignore_image_tokens);
4681 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4682 sound_id_prefix, action_id_suffix, dummy,
4683 special_id_suffix, ignore_sound_tokens);
4684 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4685 music_id_prefix, special_id_suffix, level_id_suffix,
4686 dummy, ignore_music_tokens);
4689 static void InitMixer()
4697 char *filename_font_initial = NULL;
4698 Bitmap *bitmap_font_initial = NULL;
4702 /* determine settings for initial font (for displaying startup messages) */
4703 for (i = 0; image_config[i].token != NULL; i++)
4705 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4707 char font_token[128];
4710 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4711 len_font_token = strlen(font_token);
4713 if (strEqual(image_config[i].token, font_token))
4714 filename_font_initial = image_config[i].value;
4715 else if (strlen(image_config[i].token) > len_font_token &&
4716 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4718 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4719 font_initial[j].src_x = atoi(image_config[i].value);
4720 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4721 font_initial[j].src_y = atoi(image_config[i].value);
4722 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4723 font_initial[j].width = atoi(image_config[i].value);
4724 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4725 font_initial[j].height = atoi(image_config[i].value);
4730 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4732 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4733 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4736 if (filename_font_initial == NULL) /* should not happen */
4737 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4739 /* create additional image buffers for double-buffering and cross-fading */
4740 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4741 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4742 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4743 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4745 /* initialize screen properties */
4746 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4747 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4749 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4750 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4751 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4753 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4755 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4756 font_initial[j].bitmap = bitmap_font_initial;
4758 InitFontGraphicInfo();
4760 font_height = getFontHeight(FC_RED);
4763 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4765 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4767 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4768 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4770 DrawInitText("Loading graphics", 120, FC_GREEN);
4773 void RedrawBackground()
4775 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4776 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4778 redraw_mask = REDRAW_ALL;
4781 void InitGfxBackground()
4785 fieldbuffer = bitmap_db_field;
4786 SetDrawtoField(DRAW_BACKBUFFER);
4790 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4791 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4793 for (x = 0; x < MAX_BUF_XSIZE; x++)
4794 for (y = 0; y < MAX_BUF_YSIZE; y++)
4797 redraw_mask = REDRAW_ALL;
4800 static void InitLevelInfo()
4802 LoadLevelInfo(); /* global level info */
4803 LoadLevelSetup_LastSeries(); /* last played series info */
4804 LoadLevelSetup_SeriesInfo(); /* last played level info */
4807 void InitLevelArtworkInfo()
4809 LoadLevelArtworkInfo();
4812 static void InitImages()
4814 setLevelArtworkDir(artwork.gfx_first);
4817 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4818 leveldir_current->identifier,
4819 artwork.gfx_current_identifier,
4820 artwork.gfx_current->identifier,
4821 leveldir_current->graphics_set,
4822 leveldir_current->graphics_path);
4825 ReloadCustomImages();
4827 LoadCustomElementDescriptions();
4828 LoadSpecialMenuDesignSettings();
4830 ReinitializeGraphics();
4833 static void InitSound(char *identifier)
4835 if (identifier == NULL)
4836 identifier = artwork.snd_current->identifier;
4838 /* set artwork path to send it to the sound server process */
4839 setLevelArtworkDir(artwork.snd_first);
4841 InitReloadCustomSounds(identifier);
4842 ReinitializeSounds();
4845 static void InitMusic(char *identifier)
4847 if (identifier == NULL)
4848 identifier = artwork.mus_current->identifier;
4850 /* set artwork path to send it to the sound server process */
4851 setLevelArtworkDir(artwork.mus_first);
4853 InitReloadCustomMusic(identifier);
4854 ReinitializeMusic();
4857 void InitNetworkServer()
4859 #if defined(NETWORK_AVALIABLE)
4863 if (!options.network)
4866 #if defined(NETWORK_AVALIABLE)
4867 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4869 if (!ConnectToServer(options.server_host, options.server_port))
4870 Error(ERR_EXIT, "cannot connect to network game server");
4872 SendToServer_PlayerName(setup.player_name);
4873 SendToServer_ProtocolVersion();
4876 SendToServer_NrWanted(nr_wanted);
4880 static char *getNewArtworkIdentifier(int type)
4882 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4883 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4884 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4885 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4886 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4887 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4888 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4889 char *leveldir_identifier = leveldir_current->identifier;
4891 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4892 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4894 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4896 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4897 char *artwork_current_identifier;
4898 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4900 /* leveldir_current may be invalid (level group, parent link) */
4901 if (!validLevelSeries(leveldir_current))
4904 /* 1st step: determine artwork set to be activated in descending order:
4905 --------------------------------------------------------------------
4906 1. setup artwork (when configured to override everything else)
4907 2. artwork set configured in "levelinfo.conf" of current level set
4908 (artwork in level directory will have priority when loading later)
4909 3. artwork in level directory (stored in artwork sub-directory)
4910 4. setup artwork (currently configured in setup menu) */
4912 if (setup_override_artwork)
4913 artwork_current_identifier = setup_artwork_set;
4914 else if (leveldir_artwork_set != NULL)
4915 artwork_current_identifier = leveldir_artwork_set;
4916 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4917 artwork_current_identifier = leveldir_identifier;
4919 artwork_current_identifier = setup_artwork_set;
4922 /* 2nd step: check if it is really needed to reload artwork set
4923 ------------------------------------------------------------ */
4926 if (type == ARTWORK_TYPE_GRAPHICS)
4927 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4928 artwork_new_identifier,
4929 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4930 artwork_current_identifier,
4931 leveldir_current->graphics_set,
4932 leveldir_current->identifier);
4935 /* ---------- reload if level set and also artwork set has changed ------- */
4936 if (leveldir_current_identifier[type] != leveldir_identifier &&
4937 (last_has_level_artwork_set[type] || has_level_artwork_set))
4938 artwork_new_identifier = artwork_current_identifier;
4940 leveldir_current_identifier[type] = leveldir_identifier;
4941 last_has_level_artwork_set[type] = has_level_artwork_set;
4944 if (type == ARTWORK_TYPE_GRAPHICS)
4945 printf("::: 1: '%s'\n", artwork_new_identifier);
4948 /* ---------- reload if "override artwork" setting has changed ----------- */
4949 if (last_override_level_artwork[type] != setup_override_artwork)
4950 artwork_new_identifier = artwork_current_identifier;
4952 last_override_level_artwork[type] = setup_override_artwork;
4955 if (type == ARTWORK_TYPE_GRAPHICS)
4956 printf("::: 2: '%s'\n", artwork_new_identifier);
4959 /* ---------- reload if current artwork identifier has changed ----------- */
4960 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4961 artwork_current_identifier))
4962 artwork_new_identifier = artwork_current_identifier;
4964 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4967 if (type == ARTWORK_TYPE_GRAPHICS)
4968 printf("::: 3: '%s'\n", artwork_new_identifier);
4971 /* ---------- do not reload directly after starting ---------------------- */
4972 if (!initialized[type])
4973 artwork_new_identifier = NULL;
4975 initialized[type] = TRUE;
4978 if (type == ARTWORK_TYPE_GRAPHICS)
4979 printf("::: 4: '%s'\n", artwork_new_identifier);
4983 if (type == ARTWORK_TYPE_GRAPHICS)
4984 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4985 artwork.gfx_current_identifier, artwork_current_identifier,
4986 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4987 artwork_new_identifier);
4990 return artwork_new_identifier;
4993 void ReloadCustomArtwork(int force_reload)
4995 char *gfx_new_identifier;
4996 char *snd_new_identifier;
4997 char *mus_new_identifier;
4998 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4999 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5000 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5001 boolean redraw_screen = FALSE;
5003 force_reload_gfx |= AdjustGraphicsForEMC();
5005 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5006 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5007 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5009 if (gfx_new_identifier != NULL || force_reload_gfx)
5012 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5013 artwork.gfx_current_identifier,
5015 artwork.gfx_current->identifier,
5016 leveldir_current->graphics_set);
5019 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5023 redraw_screen = TRUE;
5026 if (snd_new_identifier != NULL || force_reload_snd)
5028 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5030 InitSound(snd_new_identifier);
5032 redraw_screen = TRUE;
5035 if (mus_new_identifier != NULL || force_reload_mus)
5037 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5039 InitMusic(mus_new_identifier);
5041 redraw_screen = TRUE;
5048 /* force redraw of (open or closed) door graphics */
5049 SetDoorState(DOOR_OPEN_ALL);
5050 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5054 void KeyboardAutoRepeatOffUnlessAutoplay()
5056 if (global.autoplay_leveldir == NULL)
5057 KeyboardAutoRepeatOff();
5061 /* ========================================================================= */
5063 /* ========================================================================= */
5067 InitGlobal(); /* initialize some global variables */
5069 if (options.execute_command)
5070 Execute_Command(options.execute_command);
5072 if (options.serveronly)
5074 #if defined(PLATFORM_UNIX)
5075 NetworkServer(options.server_port, options.serveronly);
5077 Error(ERR_WARN, "networking only supported in Unix version");
5080 exit(0); /* never reached, server loops forever */
5087 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5088 InitArtworkConfig(); /* needed before forking sound child process */
5093 InitRND(NEW_RANDOMIZE);
5094 InitSimpleRandom(NEW_RANDOMIZE);
5099 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5101 InitEventFilter(FilterMouseMotionEvents);
5103 InitElementPropertiesStatic();
5104 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5108 // debug_print_timestamp(0, "INIT");
5110 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5111 InitLevelArtworkInfo();
5112 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5114 InitImages(); /* needs to know current level directory */
5115 InitSound(NULL); /* needs to know current level directory */
5116 InitMusic(NULL); /* needs to know current level directory */
5118 InitGfxBackground();
5124 if (global.autoplay_leveldir)
5129 else if (global.convert_leveldir)
5135 game_status = GAME_MODE_MAIN;
5139 InitNetworkServer();
5142 void CloseAllAndExit(int exit_value)
5147 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5155 #if defined(TARGET_SDL)
5156 if (network_server) /* terminate network server */
5157 SDL_KillThread(server_thread);
5160 CloseVideoDisplay();
5161 ClosePlatformDependentStuff();
5163 if (exit_value != 0)
5164 NotifyUserAboutErrorFile();