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_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
171 special = game_status;
172 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
173 special = GFX_SPECIAL_ARG_MAIN;
174 else if (game_status == GAME_MODE_PLAYING)
175 special = GFX_SPECIAL_ARG_DOOR;
178 return font_info[font_nr].special_bitmap_id[special];
183 void InitFontGraphicInfo()
185 static struct FontBitmapInfo *font_bitmap_info = NULL;
186 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
187 int num_property_mappings = getImageListPropertyMappingSize();
188 int num_font_bitmaps = NUM_FONTS;
191 if (graphic_info == NULL) /* still at startup phase */
193 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
198 /* ---------- initialize font graphic definitions ---------- */
200 /* always start with reliable default values (normal font graphics) */
201 for (i = 0; i < NUM_FONTS; i++)
202 font_info[i].graphic = IMG_FONT_INITIAL_1;
204 /* initialize normal font/graphic mapping from static configuration */
205 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
207 int font_nr = font_to_graphic[i].font_nr;
208 int special = font_to_graphic[i].special;
209 int graphic = font_to_graphic[i].graphic;
214 font_info[font_nr].graphic = graphic;
217 /* always start with reliable default values (special font graphics) */
218 for (i = 0; i < NUM_FONTS; i++)
220 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
222 font_info[i].special_graphic[j] = font_info[i].graphic;
223 font_info[i].special_bitmap_id[j] = i;
227 /* initialize special font/graphic mapping from static configuration */
228 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
230 int font_nr = font_to_graphic[i].font_nr;
231 int special = font_to_graphic[i].special;
232 int graphic = font_to_graphic[i].graphic;
233 int base_graphic = font2baseimg(font_nr);
235 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
237 boolean base_redefined =
238 getImageListEntryFromImageID(base_graphic)->redefined;
239 boolean special_redefined =
240 getImageListEntryFromImageID(graphic)->redefined;
242 /* if the base font ("font.title_1", for example) has been redefined,
243 but not the special font ("font.title_1.LEVELS", for example), do not
244 use an existing (in this case considered obsolete) special font
245 anymore, but use the automatically determined default font */
246 if (base_redefined && !special_redefined)
249 font_info[font_nr].special_graphic[special] = graphic;
250 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
255 /* initialize special font/graphic mapping from dynamic configuration */
256 for (i = 0; i < num_property_mappings; i++)
258 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
259 int special = property_mapping[i].ext3_index;
260 int graphic = property_mapping[i].artwork_index;
265 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
267 font_info[font_nr].special_graphic[special] = graphic;
268 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
273 /* reset non-redefined ".active" font graphics if normal font is redefined */
274 /* (this different treatment is needed because normal and active fonts are
275 independently defined ("active" is not a property of font definitions!) */
276 for (i = 0; i < NUM_FONTS; i++)
278 int font_nr_base = i;
279 int font_nr_active = FONT_ACTIVE(font_nr_base);
281 /* check only those fonts with exist as normal and ".active" variant */
282 if (font_nr_base != font_nr_active)
284 int base_graphic = font_info[font_nr_base].graphic;
285 int active_graphic = font_info[font_nr_active].graphic;
286 boolean base_redefined =
287 getImageListEntryFromImageID(base_graphic)->redefined;
288 boolean active_redefined =
289 getImageListEntryFromImageID(active_graphic)->redefined;
291 /* if the base font ("font.menu_1", for example) has been redefined,
292 but not the active font ("font.menu_1.active", for example), do not
293 use an existing (in this case considered obsolete) active font
294 anymore, but use the automatically determined default font */
295 if (base_redefined && !active_redefined)
296 font_info[font_nr_active].graphic = base_graphic;
298 /* now also check each "special" font (which may be the same as above) */
299 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
301 int base_graphic = font_info[font_nr_base].special_graphic[j];
302 int active_graphic = font_info[font_nr_active].special_graphic[j];
303 boolean base_redefined =
304 getImageListEntryFromImageID(base_graphic)->redefined;
305 boolean active_redefined =
306 getImageListEntryFromImageID(active_graphic)->redefined;
308 /* same as above, but check special graphic definitions, for example:
309 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
310 if (base_redefined && !active_redefined)
312 font_info[font_nr_active].special_graphic[j] =
313 font_info[font_nr_base].special_graphic[j];
314 font_info[font_nr_active].special_bitmap_id[j] =
315 font_info[font_nr_base].special_bitmap_id[j];
321 /* ---------- initialize font bitmap array ---------- */
323 if (font_bitmap_info != NULL)
324 FreeFontInfo(font_bitmap_info);
327 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
329 /* ---------- initialize font bitmap definitions ---------- */
331 for (i = 0; i < NUM_FONTS; i++)
333 if (i < NUM_INITIAL_FONTS)
335 font_bitmap_info[i] = font_initial[i];
339 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
341 int font_bitmap_id = font_info[i].special_bitmap_id[j];
342 int graphic = font_info[i].special_graphic[j];
344 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
345 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
347 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
348 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
351 /* copy font relevant information from graphics information */
352 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
353 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
354 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
355 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
356 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
358 font_bitmap_info[font_bitmap_id].draw_xoffset =
359 graphic_info[graphic].draw_xoffset;
360 font_bitmap_info[font_bitmap_id].draw_yoffset =
361 graphic_info[graphic].draw_yoffset;
363 font_bitmap_info[font_bitmap_id].num_chars =
364 graphic_info[graphic].anim_frames;
365 font_bitmap_info[font_bitmap_id].num_chars_per_line =
366 graphic_info[graphic].anim_frames_per_line;
370 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
373 void InitElementGraphicInfo()
375 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
376 int num_property_mappings = getImageListPropertyMappingSize();
379 if (graphic_info == NULL) /* still at startup phase */
382 /* set values to -1 to identify later as "uninitialized" values */
383 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
385 for (act = 0; act < NUM_ACTIONS; act++)
387 element_info[i].graphic[act] = -1;
388 element_info[i].crumbled[act] = -1;
390 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
392 element_info[i].direction_graphic[act][dir] = -1;
393 element_info[i].direction_crumbled[act][dir] = -1;
398 /* initialize normal element/graphic mapping from static configuration */
399 for (i = 0; element_to_graphic[i].element > -1; i++)
401 int element = element_to_graphic[i].element;
402 int action = element_to_graphic[i].action;
403 int direction = element_to_graphic[i].direction;
404 boolean crumbled = element_to_graphic[i].crumbled;
405 int graphic = element_to_graphic[i].graphic;
406 int base_graphic = el2baseimg(element);
408 if (graphic_info[graphic].bitmap == NULL)
411 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
414 boolean base_redefined =
415 getImageListEntryFromImageID(base_graphic)->redefined;
416 boolean act_dir_redefined =
417 getImageListEntryFromImageID(graphic)->redefined;
419 /* if the base graphic ("emerald", for example) has been redefined,
420 but not the action graphic ("emerald.falling", for example), do not
421 use an existing (in this case considered obsolete) action graphic
422 anymore, but use the automatically determined default graphic */
423 if (base_redefined && !act_dir_redefined)
428 action = ACTION_DEFAULT;
433 element_info[element].direction_crumbled[action][direction] = graphic;
435 element_info[element].crumbled[action] = graphic;
440 element_info[element].direction_graphic[action][direction] = graphic;
442 element_info[element].graphic[action] = graphic;
446 /* initialize normal element/graphic mapping from dynamic configuration */
447 for (i = 0; i < num_property_mappings; i++)
449 int element = property_mapping[i].base_index;
450 int action = property_mapping[i].ext1_index;
451 int direction = property_mapping[i].ext2_index;
452 int special = property_mapping[i].ext3_index;
453 int graphic = property_mapping[i].artwork_index;
454 boolean crumbled = FALSE;
456 if (special == GFX_SPECIAL_ARG_CRUMBLED)
462 if (graphic_info[graphic].bitmap == NULL)
465 if (element >= MAX_NUM_ELEMENTS || special != -1)
469 action = ACTION_DEFAULT;
474 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
475 element_info[element].direction_crumbled[action][dir] = -1;
478 element_info[element].direction_crumbled[action][direction] = graphic;
480 element_info[element].crumbled[action] = graphic;
485 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
486 element_info[element].direction_graphic[action][dir] = -1;
489 element_info[element].direction_graphic[action][direction] = graphic;
491 element_info[element].graphic[action] = graphic;
495 /* now copy all graphics that are defined to be cloned from other graphics */
496 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
498 int graphic = element_info[i].graphic[ACTION_DEFAULT];
499 int crumbled_like, diggable_like;
504 crumbled_like = graphic_info[graphic].crumbled_like;
505 diggable_like = graphic_info[graphic].diggable_like;
507 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
509 for (act = 0; act < NUM_ACTIONS; act++)
510 element_info[i].crumbled[act] =
511 element_info[crumbled_like].crumbled[act];
512 for (act = 0; act < NUM_ACTIONS; act++)
513 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
514 element_info[i].direction_crumbled[act][dir] =
515 element_info[crumbled_like].direction_crumbled[act][dir];
518 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
520 element_info[i].graphic[ACTION_DIGGING] =
521 element_info[diggable_like].graphic[ACTION_DIGGING];
522 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
523 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
524 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
529 /* set hardcoded definitions for some runtime elements without graphic */
530 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
534 /* set hardcoded definitions for some internal elements without graphic */
535 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
537 if (IS_EDITOR_CASCADE_INACTIVE(i))
538 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
539 else if (IS_EDITOR_CASCADE_ACTIVE(i))
540 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
544 /* now set all undefined/invalid graphics to -1 to set to default after it */
545 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
547 for (act = 0; act < NUM_ACTIONS; act++)
551 graphic = element_info[i].graphic[act];
552 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
553 element_info[i].graphic[act] = -1;
555 graphic = element_info[i].crumbled[act];
556 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
557 element_info[i].crumbled[act] = -1;
559 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
561 graphic = element_info[i].direction_graphic[act][dir];
562 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
563 element_info[i].direction_graphic[act][dir] = -1;
565 graphic = element_info[i].direction_crumbled[act][dir];
566 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
567 element_info[i].direction_crumbled[act][dir] = -1;
572 /* adjust graphics with 2nd tile for movement according to direction
573 (do this before correcting '-1' values to minimize calculations) */
574 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
576 for (act = 0; act < NUM_ACTIONS; act++)
578 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
580 int graphic = element_info[i].direction_graphic[act][dir];
581 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
583 if (act == ACTION_FALLING) /* special case */
584 graphic = element_info[i].graphic[act];
587 graphic_info[graphic].double_movement &&
588 graphic_info[graphic].swap_double_tiles != 0)
590 struct GraphicInfo *g = &graphic_info[graphic];
591 int src_x_front = g->src_x;
592 int src_y_front = g->src_y;
593 int src_x_back = g->src_x + g->offset2_x;
594 int src_y_back = g->src_y + g->offset2_y;
595 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
597 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
598 src_y_front < src_y_back);
599 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
600 boolean swap_movement_tiles_autodetected =
601 (!frames_are_ordered_diagonally &&
602 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
603 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
604 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
605 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
608 /* swap frontside and backside graphic tile coordinates, if needed */
609 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
611 /* get current (wrong) backside tile coordinates */
612 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
615 /* set frontside tile coordinates to backside tile coordinates */
616 g->src_x = src_x_back;
617 g->src_y = src_y_back;
619 /* invert tile offset to point to new backside tile coordinates */
623 /* do not swap front and backside tiles again after correction */
624 g->swap_double_tiles = 0;
631 /* now set all '-1' values to element specific default values */
632 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
634 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
635 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
636 int default_direction_graphic[NUM_DIRECTIONS_FULL];
637 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
639 if (default_graphic == -1)
640 default_graphic = IMG_UNKNOWN;
642 if (default_crumbled == -1)
643 default_crumbled = default_graphic;
645 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
646 if (default_crumbled == -1)
647 default_crumbled = IMG_EMPTY;
650 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
652 default_direction_graphic[dir] =
653 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
654 default_direction_crumbled[dir] =
655 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
657 if (default_direction_graphic[dir] == -1)
658 default_direction_graphic[dir] = default_graphic;
660 if (default_direction_crumbled[dir] == -1)
661 default_direction_crumbled[dir] = default_direction_graphic[dir];
663 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
664 if (default_direction_crumbled[dir] == -1)
665 default_direction_crumbled[dir] = default_crumbled;
669 for (act = 0; act < NUM_ACTIONS; act++)
671 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
672 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
673 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
674 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
675 act == ACTION_TURNING_FROM_RIGHT ||
676 act == ACTION_TURNING_FROM_UP ||
677 act == ACTION_TURNING_FROM_DOWN);
679 /* generic default action graphic (defined by "[default]" directive) */
680 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
681 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
682 int default_remove_graphic = IMG_EMPTY;
684 if (act_remove && default_action_graphic != -1)
685 default_remove_graphic = default_action_graphic;
687 /* look for special default action graphic (classic game specific) */
688 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
689 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
690 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
691 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
692 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
693 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
695 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
696 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
697 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
698 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
699 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
700 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
703 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
704 /* !!! make this better !!! */
705 if (i == EL_EMPTY_SPACE)
707 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
708 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
712 if (default_action_graphic == -1)
713 default_action_graphic = default_graphic;
715 if (default_action_crumbled == -1)
716 default_action_crumbled = default_action_graphic;
718 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
719 if (default_action_crumbled == -1)
720 default_action_crumbled = default_crumbled;
723 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
725 /* use action graphic as the default direction graphic, if undefined */
726 int default_action_direction_graphic = element_info[i].graphic[act];
727 int default_action_direction_crumbled = element_info[i].crumbled[act];
729 /* no graphic for current action -- use default direction graphic */
730 if (default_action_direction_graphic == -1)
731 default_action_direction_graphic =
732 (act_remove ? default_remove_graphic :
734 element_info[i].direction_graphic[ACTION_TURNING][dir] :
735 default_action_graphic != default_graphic ?
736 default_action_graphic :
737 default_direction_graphic[dir]);
739 if (element_info[i].direction_graphic[act][dir] == -1)
740 element_info[i].direction_graphic[act][dir] =
741 default_action_direction_graphic;
744 if (default_action_direction_crumbled == -1)
745 default_action_direction_crumbled =
746 element_info[i].direction_graphic[act][dir];
748 if (default_action_direction_crumbled == -1)
749 default_action_direction_crumbled =
750 (act_remove ? default_remove_graphic :
752 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
753 default_action_crumbled != default_crumbled ?
754 default_action_crumbled :
755 default_direction_crumbled[dir]);
758 if (element_info[i].direction_crumbled[act][dir] == -1)
759 element_info[i].direction_crumbled[act][dir] =
760 default_action_direction_crumbled;
763 /* no graphic for this specific action -- use default action graphic */
764 if (element_info[i].graphic[act] == -1)
765 element_info[i].graphic[act] =
766 (act_remove ? default_remove_graphic :
767 act_turning ? element_info[i].graphic[ACTION_TURNING] :
768 default_action_graphic);
770 if (element_info[i].crumbled[act] == -1)
771 element_info[i].crumbled[act] = element_info[i].graphic[act];
773 if (element_info[i].crumbled[act] == -1)
774 element_info[i].crumbled[act] =
775 (act_remove ? default_remove_graphic :
776 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
777 default_action_crumbled);
783 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
784 /* set animation mode to "none" for each graphic with only 1 frame */
785 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
787 for (act = 0; act < NUM_ACTIONS; act++)
789 int graphic = element_info[i].graphic[act];
790 int crumbled = element_info[i].crumbled[act];
792 if (graphic_info[graphic].anim_frames == 1)
793 graphic_info[graphic].anim_mode = ANIM_NONE;
794 if (graphic_info[crumbled].anim_frames == 1)
795 graphic_info[crumbled].anim_mode = ANIM_NONE;
797 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
799 graphic = element_info[i].direction_graphic[act][dir];
800 crumbled = element_info[i].direction_crumbled[act][dir];
802 if (graphic_info[graphic].anim_frames == 1)
803 graphic_info[graphic].anim_mode = ANIM_NONE;
804 if (graphic_info[crumbled].anim_frames == 1)
805 graphic_info[crumbled].anim_mode = ANIM_NONE;
815 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
816 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
818 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
819 element_info[i].token_name, i);
825 void InitElementSpecialGraphicInfo()
827 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
828 int num_property_mappings = getImageListPropertyMappingSize();
831 /* always start with reliable default values */
832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
833 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
834 element_info[i].special_graphic[j] =
835 element_info[i].graphic[ACTION_DEFAULT];
837 /* initialize special element/graphic mapping from static configuration */
838 for (i = 0; element_to_special_graphic[i].element > -1; i++)
840 int element = element_to_special_graphic[i].element;
841 int special = element_to_special_graphic[i].special;
842 int graphic = element_to_special_graphic[i].graphic;
843 int base_graphic = el2baseimg(element);
844 boolean base_redefined =
845 getImageListEntryFromImageID(base_graphic)->redefined;
846 boolean special_redefined =
847 getImageListEntryFromImageID(graphic)->redefined;
849 /* if the base graphic ("emerald", for example) has been redefined,
850 but not the special graphic ("emerald.EDITOR", for example), do not
851 use an existing (in this case considered obsolete) special graphic
852 anymore, but use the automatically created (down-scaled) graphic */
853 if (base_redefined && !special_redefined)
856 element_info[element].special_graphic[special] = graphic;
859 /* initialize special element/graphic mapping from dynamic configuration */
860 for (i = 0; i < num_property_mappings; i++)
862 int element = property_mapping[i].base_index;
863 int special = property_mapping[i].ext3_index;
864 int graphic = property_mapping[i].artwork_index;
866 if (element >= MAX_NUM_ELEMENTS)
869 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
870 element_info[element].special_graphic[special] = graphic;
873 /* now set all undefined/invalid graphics to default */
874 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
875 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
876 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
877 element_info[i].special_graphic[j] =
878 element_info[i].graphic[ACTION_DEFAULT];
881 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
886 if (type != TYPE_TOKEN)
887 return get_parameter_value(value_raw, suffix, type);
889 if (strEqual(value_raw, ARG_UNDEFINED))
890 return ARG_UNDEFINED_VALUE;
892 /* !!! OPTIMIZE THIS BY USING HASH !!! */
893 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
894 if (strEqual(element_info[i].token_name, value_raw))
897 /* !!! OPTIMIZE THIS BY USING HASH !!! */
898 for (i = 0; image_config[i].token != NULL; i++)
900 int len_config_value = strlen(image_config[i].value);
902 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
903 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
904 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
907 if (strEqual(image_config[i].token, value_raw))
916 static int get_scaled_graphic_width(int graphic)
918 int original_width = getOriginalImageWidthFromImageID(graphic);
919 int scale_up_factor = graphic_info[graphic].scale_up_factor;
921 return original_width * scale_up_factor;
924 static int get_scaled_graphic_height(int graphic)
926 int original_height = getOriginalImageHeightFromImageID(graphic);
927 int scale_up_factor = graphic_info[graphic].scale_up_factor;
929 return original_height * scale_up_factor;
932 static void set_graphic_parameters(int graphic)
934 struct FileInfo *image = getImageListEntryFromImageID(graphic);
935 char **parameter_raw = image->parameter;
936 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
937 int parameter[NUM_GFX_ARGS];
938 int anim_frames_per_row = 1, anim_frames_per_col = 1;
939 int anim_frames_per_line = 1;
942 /* if fallback to default artwork is done, also use the default parameters */
943 if (image->fallback_to_default)
944 parameter_raw = image->default_parameter;
946 /* get integer values from string parameters */
947 for (i = 0; i < NUM_GFX_ARGS; i++)
948 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
949 image_config_suffix[i].token,
950 image_config_suffix[i].type);
952 graphic_info[graphic].bitmap = src_bitmap;
954 /* always start with reliable default values */
955 graphic_info[graphic].src_image_width = 0;
956 graphic_info[graphic].src_image_height = 0;
957 graphic_info[graphic].src_x = 0;
958 graphic_info[graphic].src_y = 0;
959 graphic_info[graphic].width = TILEX; /* default for element graphics */
960 graphic_info[graphic].height = TILEY; /* default for element graphics */
961 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
962 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
963 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
964 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
965 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
966 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
967 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
968 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
969 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
970 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
971 graphic_info[graphic].anim_delay_fixed = 0;
972 graphic_info[graphic].anim_delay_random = 0;
973 graphic_info[graphic].post_delay_fixed = 0;
974 graphic_info[graphic].post_delay_random = 0;
975 graphic_info[graphic].fade_delay = -1;
976 graphic_info[graphic].post_delay = -1;
977 graphic_info[graphic].auto_delay = -1;
980 /* optional zoom factor for scaling up the image to a larger size */
981 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
983 if (graphic_info[graphic].scale_up_factor < 1)
984 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
988 if (graphic_info[graphic].use_image_size)
990 /* set new default bitmap size (with scaling, but without small images) */
991 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
992 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
996 /* optional x and y tile position of animation frame sequence */
997 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
998 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
999 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1000 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1002 /* optional x and y pixel position of animation frame sequence */
1003 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1005 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1008 /* optional width and height of each animation frame */
1009 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1011 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1012 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1015 /* optional zoom factor for scaling up the image to a larger size */
1016 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1017 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1018 if (graphic_info[graphic].scale_up_factor < 1)
1019 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1024 /* get final bitmap size (with scaling, but without small images) */
1025 int src_image_width = get_scaled_graphic_width(graphic);
1026 int src_image_height = get_scaled_graphic_height(graphic);
1028 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1029 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1031 graphic_info[graphic].src_image_width = src_image_width;
1032 graphic_info[graphic].src_image_height = src_image_height;
1035 /* correct x or y offset dependent of vertical or horizontal frame order */
1036 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1038 graphic_info[graphic].offset_y =
1039 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1040 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1041 anim_frames_per_line = anim_frames_per_col;
1043 else /* frames are ordered horizontally */
1045 graphic_info[graphic].offset_x =
1046 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1047 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1048 anim_frames_per_line = anim_frames_per_row;
1051 /* optionally, the x and y offset of frames can be specified directly */
1052 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1054 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1057 /* optionally, moving animations may have separate start and end graphics */
1058 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1060 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1061 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1063 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1064 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1065 graphic_info[graphic].offset2_y =
1066 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1067 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1068 else /* frames are ordered horizontally */
1069 graphic_info[graphic].offset2_x =
1070 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1071 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1073 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1074 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1075 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1076 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1077 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1079 /* optionally, the second movement tile can be specified as start tile */
1080 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1081 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1083 /* automatically determine correct number of frames, if not defined */
1084 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1085 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1086 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1087 graphic_info[graphic].anim_frames = anim_frames_per_row;
1088 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1089 graphic_info[graphic].anim_frames = anim_frames_per_col;
1091 graphic_info[graphic].anim_frames = 1;
1093 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1094 graphic_info[graphic].anim_frames = 1;
1096 graphic_info[graphic].anim_frames_per_line =
1097 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1098 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1100 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1101 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1102 graphic_info[graphic].anim_delay = 1;
1104 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1106 if (graphic_info[graphic].anim_frames == 1)
1107 graphic_info[graphic].anim_mode = ANIM_NONE;
1110 /* automatically determine correct start frame, if not defined */
1111 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1112 graphic_info[graphic].anim_start_frame = 0;
1113 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1114 graphic_info[graphic].anim_start_frame =
1115 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1117 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1119 /* animation synchronized with global frame counter, not move position */
1120 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1122 /* optional element for cloning crumble graphics */
1123 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1126 /* optional element for cloning digging graphics */
1127 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1130 /* optional border size for "crumbling" diggable graphics */
1131 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1134 /* this is only used for player "boring" and "sleeping" actions */
1135 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1136 graphic_info[graphic].anim_delay_fixed =
1137 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1138 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1139 graphic_info[graphic].anim_delay_random =
1140 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1141 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1142 graphic_info[graphic].post_delay_fixed =
1143 parameter[GFX_ARG_POST_DELAY_FIXED];
1144 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1145 graphic_info[graphic].post_delay_random =
1146 parameter[GFX_ARG_POST_DELAY_RANDOM];
1148 /* this is only used for toon animations */
1149 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1150 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1152 /* this is only used for drawing font characters */
1153 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1154 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1156 /* this is only used for drawing envelope graphics */
1157 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1159 /* optional graphic for cloning all graphics settings */
1160 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1161 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1163 /* optional settings for drawing title screens */
1164 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1165 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1166 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1167 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1168 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1169 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1172 static void set_cloned_graphic_parameters(int graphic)
1174 int fallback_graphic = IMG_CHAR_EXCLAM;
1175 int max_num_images = getImageListSize();
1176 int clone_graphic = graphic_info[graphic].clone_from;
1177 int num_references_followed = 1;
1179 while (graphic_info[clone_graphic].clone_from != -1 &&
1180 num_references_followed < max_num_images)
1182 clone_graphic = graphic_info[clone_graphic].clone_from;
1184 num_references_followed++;
1187 if (num_references_followed >= max_num_images)
1189 Error(ERR_RETURN_LINE, "-");
1190 Error(ERR_RETURN, "warning: error found in config file:");
1191 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1192 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1193 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1194 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1196 if (graphic == fallback_graphic)
1197 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1199 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1200 Error(ERR_RETURN_LINE, "-");
1202 graphic_info[graphic] = graphic_info[fallback_graphic];
1206 graphic_info[graphic] = graphic_info[clone_graphic];
1207 graphic_info[graphic].clone_from = clone_graphic;
1211 static void InitGraphicInfo()
1213 int fallback_graphic = IMG_CHAR_EXCLAM;
1214 int num_images = getImageListSize();
1217 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1218 static boolean clipmasks_initialized = FALSE;
1220 XGCValues clip_gc_values;
1221 unsigned long clip_gc_valuemask;
1222 GC copy_clipmask_gc = None;
1225 /* use image size as default values for width and height for these images */
1226 static int full_size_graphics[] =
1231 IMG_BACKGROUND_ENVELOPE_1,
1232 IMG_BACKGROUND_ENVELOPE_2,
1233 IMG_BACKGROUND_ENVELOPE_3,
1234 IMG_BACKGROUND_ENVELOPE_4,
1237 IMG_BACKGROUND_TITLE,
1238 IMG_BACKGROUND_MAIN,
1239 IMG_BACKGROUND_LEVELS,
1240 IMG_BACKGROUND_SCORES,
1241 IMG_BACKGROUND_EDITOR,
1242 IMG_BACKGROUND_INFO,
1243 IMG_BACKGROUND_INFO_ELEMENTS,
1244 IMG_BACKGROUND_INFO_MUSIC,
1245 IMG_BACKGROUND_INFO_CREDITS,
1246 IMG_BACKGROUND_INFO_PROGRAM,
1247 IMG_BACKGROUND_INFO_LEVELSET,
1248 IMG_BACKGROUND_SETUP,
1249 IMG_BACKGROUND_DOOR,
1251 IMG_TITLESCREEN_INITIAL_1,
1252 IMG_TITLESCREEN_INITIAL_2,
1253 IMG_TITLESCREEN_INITIAL_3,
1254 IMG_TITLESCREEN_INITIAL_4,
1255 IMG_TITLESCREEN_INITIAL_5,
1265 checked_free(graphic_info);
1267 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1270 /* initialize "use_image_size" flag with default value */
1271 for (i = 0; i < num_images; i++)
1272 graphic_info[i].use_image_size = FALSE;
1274 /* initialize "use_image_size" flag from static configuration above */
1275 for (i = 0; full_size_graphics[i] != -1; i++)
1276 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1279 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1280 if (clipmasks_initialized)
1282 for (i = 0; i < num_images; i++)
1284 if (graphic_info[i].clip_mask)
1285 XFreePixmap(display, graphic_info[i].clip_mask);
1286 if (graphic_info[i].clip_gc)
1287 XFreeGC(display, graphic_info[i].clip_gc);
1289 graphic_info[i].clip_mask = None;
1290 graphic_info[i].clip_gc = None;
1295 /* first set all graphic paramaters ... */
1296 for (i = 0; i < num_images; i++)
1297 set_graphic_parameters(i);
1299 /* ... then copy these parameters for cloned graphics */
1300 for (i = 0; i < num_images; i++)
1301 if (graphic_info[i].clone_from != -1)
1302 set_cloned_graphic_parameters(i);
1304 for (i = 0; i < num_images; i++)
1309 int first_frame, last_frame;
1310 int src_bitmap_width, src_bitmap_height;
1312 /* now check if no animation frames are outside of the loaded image */
1314 if (graphic_info[i].bitmap == NULL)
1315 continue; /* skip check for optional images that are undefined */
1317 /* get image size (this can differ from the standard element tile size!) */
1318 width = graphic_info[i].width;
1319 height = graphic_info[i].height;
1321 /* get final bitmap size (with scaling, but without small images) */
1322 src_bitmap_width = graphic_info[i].src_image_width;
1323 src_bitmap_height = graphic_info[i].src_image_height;
1325 /* check if first animation frame is inside specified bitmap */
1328 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1331 /* this avoids calculating wrong start position for out-of-bounds frame */
1332 src_x = graphic_info[i].src_x;
1333 src_y = graphic_info[i].src_y;
1336 if (src_x < 0 || src_y < 0 ||
1337 src_x + width > src_bitmap_width ||
1338 src_y + height > src_bitmap_height)
1340 Error(ERR_RETURN_LINE, "-");
1341 Error(ERR_RETURN, "warning: error found in config file:");
1342 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1343 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1344 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1346 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1347 src_x, src_y, src_bitmap_width, src_bitmap_height);
1348 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1350 if (i == fallback_graphic)
1351 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1353 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1354 Error(ERR_RETURN_LINE, "-");
1356 graphic_info[i] = graphic_info[fallback_graphic];
1359 /* check if last animation frame is inside specified bitmap */
1361 last_frame = graphic_info[i].anim_frames - 1;
1362 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1364 if (src_x < 0 || src_y < 0 ||
1365 src_x + width > src_bitmap_width ||
1366 src_y + height > src_bitmap_height)
1368 Error(ERR_RETURN_LINE, "-");
1369 Error(ERR_RETURN, "warning: error found in config file:");
1370 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1371 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1372 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1374 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1375 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1376 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1378 if (i == fallback_graphic)
1379 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1381 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1382 Error(ERR_RETURN_LINE, "-");
1384 graphic_info[i] = graphic_info[fallback_graphic];
1387 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1388 /* currently we only need a tile clip mask from the first frame */
1389 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1391 if (copy_clipmask_gc == None)
1393 clip_gc_values.graphics_exposures = False;
1394 clip_gc_valuemask = GCGraphicsExposures;
1395 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1396 clip_gc_valuemask, &clip_gc_values);
1399 graphic_info[i].clip_mask =
1400 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1402 src_pixmap = src_bitmap->clip_mask;
1403 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1404 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1406 clip_gc_values.graphics_exposures = False;
1407 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1408 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1410 graphic_info[i].clip_gc =
1411 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1415 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1416 if (copy_clipmask_gc)
1417 XFreeGC(display, copy_clipmask_gc);
1419 clipmasks_initialized = TRUE;
1423 static void InitElementSoundInfo()
1425 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1426 int num_property_mappings = getSoundListPropertyMappingSize();
1429 /* set values to -1 to identify later as "uninitialized" values */
1430 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1431 for (act = 0; act < NUM_ACTIONS; act++)
1432 element_info[i].sound[act] = -1;
1434 /* initialize element/sound mapping from static configuration */
1435 for (i = 0; element_to_sound[i].element > -1; i++)
1437 int element = element_to_sound[i].element;
1438 int action = element_to_sound[i].action;
1439 int sound = element_to_sound[i].sound;
1440 boolean is_class = element_to_sound[i].is_class;
1443 action = ACTION_DEFAULT;
1446 element_info[element].sound[action] = sound;
1448 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1449 if (strEqual(element_info[j].class_name,
1450 element_info[element].class_name))
1451 element_info[j].sound[action] = sound;
1454 /* initialize element class/sound mapping from dynamic configuration */
1455 for (i = 0; i < num_property_mappings; i++)
1457 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1458 int action = property_mapping[i].ext1_index;
1459 int sound = property_mapping[i].artwork_index;
1461 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1465 action = ACTION_DEFAULT;
1467 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1468 if (strEqual(element_info[j].class_name,
1469 element_info[element_class].class_name))
1470 element_info[j].sound[action] = sound;
1473 /* initialize element/sound mapping from dynamic configuration */
1474 for (i = 0; i < num_property_mappings; i++)
1476 int element = property_mapping[i].base_index;
1477 int action = property_mapping[i].ext1_index;
1478 int sound = property_mapping[i].artwork_index;
1480 if (element >= MAX_NUM_ELEMENTS)
1484 action = ACTION_DEFAULT;
1486 element_info[element].sound[action] = sound;
1489 /* now set all '-1' values to element specific default values */
1490 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1492 for (act = 0; act < NUM_ACTIONS; act++)
1494 /* generic default action sound (defined by "[default]" directive) */
1495 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1497 /* look for special default action sound (classic game specific) */
1498 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1499 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1500 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1501 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1502 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1503 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1505 /* !!! there's no such thing as a "default action sound" !!! */
1507 /* look for element specific default sound (independent from action) */
1508 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1509 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1513 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1514 /* !!! make this better !!! */
1515 if (i == EL_EMPTY_SPACE)
1516 default_action_sound = element_info[EL_DEFAULT].sound[act];
1519 /* no sound for this specific action -- use default action sound */
1520 if (element_info[i].sound[act] == -1)
1521 element_info[i].sound[act] = default_action_sound;
1525 /* copy sound settings to some elements that are only stored in level file
1526 in native R'n'D levels, but are used by game engine in native EM levels */
1527 for (i = 0; copy_properties[i][0] != -1; i++)
1528 for (j = 1; j <= 4; j++)
1529 for (act = 0; act < NUM_ACTIONS; act++)
1530 element_info[copy_properties[i][j]].sound[act] =
1531 element_info[copy_properties[i][0]].sound[act];
1534 static void InitGameModeSoundInfo()
1538 /* set values to -1 to identify later as "uninitialized" values */
1539 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1542 /* initialize gamemode/sound mapping from static configuration */
1543 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1545 int gamemode = gamemode_to_sound[i].gamemode;
1546 int sound = gamemode_to_sound[i].sound;
1549 gamemode = GAME_MODE_DEFAULT;
1551 menu.sound[gamemode] = sound;
1554 /* now set all '-1' values to levelset specific default values */
1555 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1556 if (menu.sound[i] == -1)
1557 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1560 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1561 if (menu.sound[i] != -1)
1562 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1566 static void set_sound_parameters(int sound, char **parameter_raw)
1568 int parameter[NUM_SND_ARGS];
1571 /* get integer values from string parameters */
1572 for (i = 0; i < NUM_SND_ARGS; i++)
1574 get_parameter_value(parameter_raw[i],
1575 sound_config_suffix[i].token,
1576 sound_config_suffix[i].type);
1578 /* explicit loop mode setting in configuration overrides default value */
1579 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1580 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1582 /* sound volume to change the original volume when loading the sound file */
1583 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1585 /* sound priority to give certain sounds a higher or lower priority */
1586 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1589 static void InitSoundInfo()
1591 int *sound_effect_properties;
1592 int num_sounds = getSoundListSize();
1595 checked_free(sound_info);
1597 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1598 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1600 /* initialize sound effect for all elements to "no sound" */
1601 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1602 for (j = 0; j < NUM_ACTIONS; j++)
1603 element_info[i].sound[j] = SND_UNDEFINED;
1605 for (i = 0; i < num_sounds; i++)
1607 struct FileInfo *sound = getSoundListEntry(i);
1608 int len_effect_text = strlen(sound->token);
1610 sound_effect_properties[i] = ACTION_OTHER;
1611 sound_info[i].loop = FALSE; /* default: play sound only once */
1614 printf("::: sound %d: '%s'\n", i, sound->token);
1617 /* determine all loop sounds and identify certain sound classes */
1619 for (j = 0; element_action_info[j].suffix; j++)
1621 int len_action_text = strlen(element_action_info[j].suffix);
1623 if (len_action_text < len_effect_text &&
1624 strEqual(&sound->token[len_effect_text - len_action_text],
1625 element_action_info[j].suffix))
1627 sound_effect_properties[i] = element_action_info[j].value;
1628 sound_info[i].loop = element_action_info[j].is_loop_sound;
1634 /* associate elements and some selected sound actions */
1636 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1638 if (element_info[j].class_name)
1640 int len_class_text = strlen(element_info[j].class_name);
1642 if (len_class_text + 1 < len_effect_text &&
1643 strncmp(sound->token,
1644 element_info[j].class_name, len_class_text) == 0 &&
1645 sound->token[len_class_text] == '.')
1647 int sound_action_value = sound_effect_properties[i];
1649 element_info[j].sound[sound_action_value] = i;
1654 set_sound_parameters(i, sound->parameter);
1657 free(sound_effect_properties);
1660 static void InitGameModeMusicInfo()
1662 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1663 int num_property_mappings = getMusicListPropertyMappingSize();
1664 int default_levelset_music = -1;
1667 /* set values to -1 to identify later as "uninitialized" values */
1668 for (i = 0; i < MAX_LEVELS; i++)
1669 levelset.music[i] = -1;
1670 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1673 /* initialize gamemode/music mapping from static configuration */
1674 for (i = 0; gamemode_to_music[i].music > -1; i++)
1676 int gamemode = gamemode_to_music[i].gamemode;
1677 int music = gamemode_to_music[i].music;
1680 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1684 gamemode = GAME_MODE_DEFAULT;
1686 menu.music[gamemode] = music;
1689 /* initialize gamemode/music mapping from dynamic configuration */
1690 for (i = 0; i < num_property_mappings; i++)
1692 int prefix = property_mapping[i].base_index;
1693 int gamemode = property_mapping[i].ext1_index;
1694 int level = property_mapping[i].ext2_index;
1695 int music = property_mapping[i].artwork_index;
1698 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1699 prefix, gamemode, level, music);
1702 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1706 gamemode = GAME_MODE_DEFAULT;
1708 /* level specific music only allowed for in-game music */
1709 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1710 gamemode = GAME_MODE_PLAYING;
1715 default_levelset_music = music;
1718 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1719 levelset.music[level] = music;
1720 if (gamemode != GAME_MODE_PLAYING)
1721 menu.music[gamemode] = music;
1724 /* now set all '-1' values to menu specific default values */
1725 /* (undefined values of "levelset.music[]" might stay at "-1" to
1726 allow dynamic selection of music files from music directory!) */
1727 for (i = 0; i < MAX_LEVELS; i++)
1728 if (levelset.music[i] == -1)
1729 levelset.music[i] = default_levelset_music;
1730 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1731 if (menu.music[i] == -1)
1732 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1735 for (i = 0; i < MAX_LEVELS; i++)
1736 if (levelset.music[i] != -1)
1737 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1738 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1739 if (menu.music[i] != -1)
1740 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1744 static void set_music_parameters(int music, char **parameter_raw)
1746 int parameter[NUM_MUS_ARGS];
1749 /* get integer values from string parameters */
1750 for (i = 0; i < NUM_MUS_ARGS; i++)
1752 get_parameter_value(parameter_raw[i],
1753 music_config_suffix[i].token,
1754 music_config_suffix[i].type);
1756 /* explicit loop mode setting in configuration overrides default value */
1757 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1758 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1761 static void InitMusicInfo()
1763 int num_music = getMusicListSize();
1766 checked_free(music_info);
1768 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1770 for (i = 0; i < num_music; i++)
1772 struct FileInfo *music = getMusicListEntry(i);
1773 int len_music_text = strlen(music->token);
1775 music_info[i].loop = TRUE; /* default: play music in loop mode */
1777 /* determine all loop music */
1779 for (j = 0; music_prefix_info[j].prefix; j++)
1781 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1783 if (len_prefix_text < len_music_text &&
1784 strncmp(music->token,
1785 music_prefix_info[j].prefix, len_prefix_text) == 0)
1787 music_info[i].loop = music_prefix_info[j].is_loop_music;
1793 set_music_parameters(i, music->parameter);
1797 static void ReinitializeGraphics()
1799 InitGraphicInfo(); /* graphic properties mapping */
1800 InitElementGraphicInfo(); /* element game graphic mapping */
1801 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1803 InitElementSmallImages(); /* scale elements to all needed sizes */
1804 InitScaledImages(); /* scale all other images, if needed */
1805 InitFontGraphicInfo(); /* initialize text drawing functions */
1807 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1809 SetMainBackgroundImage(IMG_BACKGROUND);
1810 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1816 static void ReinitializeSounds()
1818 InitSoundInfo(); /* sound properties mapping */
1819 InitElementSoundInfo(); /* element game sound mapping */
1820 InitGameModeSoundInfo(); /* game mode sound mapping */
1822 InitPlayLevelSound(); /* internal game sound settings */
1825 static void ReinitializeMusic()
1827 InitMusicInfo(); /* music properties mapping */
1828 InitGameModeMusicInfo(); /* game mode music mapping */
1831 static int get_special_property_bit(int element, int property_bit_nr)
1833 struct PropertyBitInfo
1839 static struct PropertyBitInfo pb_can_move_into_acid[] =
1841 /* the player may be able fall into acid when gravity is activated */
1846 { EL_SP_MURPHY, 0 },
1847 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1849 /* all elements that can move may be able to also move into acid */
1852 { EL_BUG_RIGHT, 1 },
1855 { EL_SPACESHIP, 2 },
1856 { EL_SPACESHIP_LEFT, 2 },
1857 { EL_SPACESHIP_RIGHT, 2 },
1858 { EL_SPACESHIP_UP, 2 },
1859 { EL_SPACESHIP_DOWN, 2 },
1860 { EL_BD_BUTTERFLY, 3 },
1861 { EL_BD_BUTTERFLY_LEFT, 3 },
1862 { EL_BD_BUTTERFLY_RIGHT, 3 },
1863 { EL_BD_BUTTERFLY_UP, 3 },
1864 { EL_BD_BUTTERFLY_DOWN, 3 },
1865 { EL_BD_FIREFLY, 4 },
1866 { EL_BD_FIREFLY_LEFT, 4 },
1867 { EL_BD_FIREFLY_RIGHT, 4 },
1868 { EL_BD_FIREFLY_UP, 4 },
1869 { EL_BD_FIREFLY_DOWN, 4 },
1871 { EL_YAMYAM_LEFT, 5 },
1872 { EL_YAMYAM_RIGHT, 5 },
1873 { EL_YAMYAM_UP, 5 },
1874 { EL_YAMYAM_DOWN, 5 },
1875 { EL_DARK_YAMYAM, 6 },
1878 { EL_PACMAN_LEFT, 8 },
1879 { EL_PACMAN_RIGHT, 8 },
1880 { EL_PACMAN_UP, 8 },
1881 { EL_PACMAN_DOWN, 8 },
1883 { EL_MOLE_LEFT, 9 },
1884 { EL_MOLE_RIGHT, 9 },
1886 { EL_MOLE_DOWN, 9 },
1890 { EL_SATELLITE, 13 },
1891 { EL_SP_SNIKSNAK, 14 },
1892 { EL_SP_ELECTRON, 15 },
1895 { EL_EMC_ANDROID, 18 },
1900 static struct PropertyBitInfo pb_dont_collide_with[] =
1902 { EL_SP_SNIKSNAK, 0 },
1903 { EL_SP_ELECTRON, 1 },
1911 struct PropertyBitInfo *pb_info;
1914 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1915 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1920 struct PropertyBitInfo *pb_info = NULL;
1923 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1924 if (pb_definition[i].bit_nr == property_bit_nr)
1925 pb_info = pb_definition[i].pb_info;
1927 if (pb_info == NULL)
1930 for (i = 0; pb_info[i].element != -1; i++)
1931 if (pb_info[i].element == element)
1932 return pb_info[i].bit_nr;
1937 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1938 boolean property_value)
1940 int bit_nr = get_special_property_bit(element, property_bit_nr);
1945 *bitfield |= (1 << bit_nr);
1947 *bitfield &= ~(1 << bit_nr);
1951 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1953 int bit_nr = get_special_property_bit(element, property_bit_nr);
1956 return ((*bitfield & (1 << bit_nr)) != 0);
1961 static void resolve_group_element(int group_element, int recursion_depth)
1963 static int group_nr;
1964 static struct ElementGroupInfo *group;
1965 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1968 if (actual_group == NULL) /* not yet initialized */
1971 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1973 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1974 group_element - EL_GROUP_START + 1);
1976 /* replace element which caused too deep recursion by question mark */
1977 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1982 if (recursion_depth == 0) /* initialization */
1984 group = actual_group;
1985 group_nr = group_element - EL_GROUP_START;
1987 group->num_elements_resolved = 0;
1988 group->choice_pos = 0;
1991 for (i = 0; i < actual_group->num_elements; i++)
1993 int element = actual_group->element[i];
1995 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1998 if (IS_GROUP_ELEMENT(element))
1999 resolve_group_element(element, recursion_depth + 1);
2002 group->element_resolved[group->num_elements_resolved++] = element;
2003 element_info[element].in_group[group_nr] = TRUE;
2008 void InitElementPropertiesStatic()
2010 static int ep_diggable[] =
2015 EL_SP_BUGGY_BASE_ACTIVATING,
2018 EL_INVISIBLE_SAND_ACTIVE,
2021 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2022 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2026 EL_SP_BUGGY_BASE_ACTIVE,
2033 static int ep_collectible_only[] =
2055 EL_DYNABOMB_INCREASE_NUMBER,
2056 EL_DYNABOMB_INCREASE_SIZE,
2057 EL_DYNABOMB_INCREASE_POWER,
2077 static int ep_dont_run_into[] =
2079 /* same elements as in 'ep_dont_touch' */
2085 /* same elements as in 'ep_dont_collide_with' */
2097 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2101 EL_SP_BUGGY_BASE_ACTIVE,
2108 static int ep_dont_collide_with[] =
2110 /* same elements as in 'ep_dont_touch' */
2127 static int ep_dont_touch[] =
2137 static int ep_indestructible[] =
2141 EL_ACID_POOL_TOPLEFT,
2142 EL_ACID_POOL_TOPRIGHT,
2143 EL_ACID_POOL_BOTTOMLEFT,
2144 EL_ACID_POOL_BOTTOM,
2145 EL_ACID_POOL_BOTTOMRIGHT,
2146 EL_SP_HARDWARE_GRAY,
2147 EL_SP_HARDWARE_GREEN,
2148 EL_SP_HARDWARE_BLUE,
2150 EL_SP_HARDWARE_YELLOW,
2151 EL_SP_HARDWARE_BASE_1,
2152 EL_SP_HARDWARE_BASE_2,
2153 EL_SP_HARDWARE_BASE_3,
2154 EL_SP_HARDWARE_BASE_4,
2155 EL_SP_HARDWARE_BASE_5,
2156 EL_SP_HARDWARE_BASE_6,
2157 EL_INVISIBLE_STEELWALL,
2158 EL_INVISIBLE_STEELWALL_ACTIVE,
2159 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2160 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2161 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2162 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2163 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2164 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2165 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2166 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2167 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2168 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2169 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2170 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2172 EL_LIGHT_SWITCH_ACTIVE,
2173 EL_SIGN_EXCLAMATION,
2174 EL_SIGN_RADIOACTIVITY,
2185 EL_STEELWALL_SLIPPERY,
2199 EL_GATE_1_GRAY_ACTIVE,
2200 EL_GATE_2_GRAY_ACTIVE,
2201 EL_GATE_3_GRAY_ACTIVE,
2202 EL_GATE_4_GRAY_ACTIVE,
2211 EL_EM_GATE_1_GRAY_ACTIVE,
2212 EL_EM_GATE_2_GRAY_ACTIVE,
2213 EL_EM_GATE_3_GRAY_ACTIVE,
2214 EL_EM_GATE_4_GRAY_ACTIVE,
2223 EL_EMC_GATE_5_GRAY_ACTIVE,
2224 EL_EMC_GATE_6_GRAY_ACTIVE,
2225 EL_EMC_GATE_7_GRAY_ACTIVE,
2226 EL_EMC_GATE_8_GRAY_ACTIVE,
2228 EL_SWITCHGATE_OPENING,
2229 EL_SWITCHGATE_CLOSED,
2230 EL_SWITCHGATE_CLOSING,
2232 EL_SWITCHGATE_SWITCH_UP,
2233 EL_SWITCHGATE_SWITCH_DOWN,
2236 EL_TIMEGATE_OPENING,
2238 EL_TIMEGATE_CLOSING,
2241 EL_TIMEGATE_SWITCH_ACTIVE,
2246 EL_TUBE_VERTICAL_LEFT,
2247 EL_TUBE_VERTICAL_RIGHT,
2248 EL_TUBE_HORIZONTAL_UP,
2249 EL_TUBE_HORIZONTAL_DOWN,
2258 static int ep_slippery[] =
2272 EL_ROBOT_WHEEL_ACTIVE,
2278 EL_ACID_POOL_TOPLEFT,
2279 EL_ACID_POOL_TOPRIGHT,
2289 EL_STEELWALL_SLIPPERY,
2292 EL_EMC_WALL_SLIPPERY_1,
2293 EL_EMC_WALL_SLIPPERY_2,
2294 EL_EMC_WALL_SLIPPERY_3,
2295 EL_EMC_WALL_SLIPPERY_4,
2297 EL_EMC_MAGIC_BALL_ACTIVE,
2302 static int ep_can_change[] =
2307 static int ep_can_move[] =
2309 /* same elements as in 'pb_can_move_into_acid' */
2332 static int ep_can_fall[] =
2347 EL_BD_MAGIC_WALL_FULL,
2361 static int ep_can_smash_player[] =
2387 static int ep_can_smash_enemies[] =
2396 static int ep_can_smash_everything[] =
2405 static int ep_explodes_by_fire[] =
2407 /* same elements as in 'ep_explodes_impact' */
2412 /* same elements as in 'ep_explodes_smashed' */
2422 EL_EM_DYNAMITE_ACTIVE,
2423 EL_DYNABOMB_PLAYER_1_ACTIVE,
2424 EL_DYNABOMB_PLAYER_2_ACTIVE,
2425 EL_DYNABOMB_PLAYER_3_ACTIVE,
2426 EL_DYNABOMB_PLAYER_4_ACTIVE,
2427 EL_DYNABOMB_INCREASE_NUMBER,
2428 EL_DYNABOMB_INCREASE_SIZE,
2429 EL_DYNABOMB_INCREASE_POWER,
2430 EL_SP_DISK_RED_ACTIVE,
2444 static int ep_explodes_smashed[] =
2446 /* same elements as in 'ep_explodes_impact' */
2460 static int ep_explodes_impact[] =
2469 static int ep_walkable_over[] =
2473 EL_SOKOBAN_FIELD_EMPTY,
2485 EL_GATE_1_GRAY_ACTIVE,
2486 EL_GATE_2_GRAY_ACTIVE,
2487 EL_GATE_3_GRAY_ACTIVE,
2488 EL_GATE_4_GRAY_ACTIVE,
2496 static int ep_walkable_inside[] =
2501 EL_TUBE_VERTICAL_LEFT,
2502 EL_TUBE_VERTICAL_RIGHT,
2503 EL_TUBE_HORIZONTAL_UP,
2504 EL_TUBE_HORIZONTAL_DOWN,
2513 static int ep_walkable_under[] =
2518 static int ep_passable_over[] =
2528 EL_EM_GATE_1_GRAY_ACTIVE,
2529 EL_EM_GATE_2_GRAY_ACTIVE,
2530 EL_EM_GATE_3_GRAY_ACTIVE,
2531 EL_EM_GATE_4_GRAY_ACTIVE,
2540 EL_EMC_GATE_5_GRAY_ACTIVE,
2541 EL_EMC_GATE_6_GRAY_ACTIVE,
2542 EL_EMC_GATE_7_GRAY_ACTIVE,
2543 EL_EMC_GATE_8_GRAY_ACTIVE,
2550 static int ep_passable_inside[] =
2556 EL_SP_PORT_HORIZONTAL,
2557 EL_SP_PORT_VERTICAL,
2559 EL_SP_GRAVITY_PORT_LEFT,
2560 EL_SP_GRAVITY_PORT_RIGHT,
2561 EL_SP_GRAVITY_PORT_UP,
2562 EL_SP_GRAVITY_PORT_DOWN,
2563 EL_SP_GRAVITY_ON_PORT_LEFT,
2564 EL_SP_GRAVITY_ON_PORT_RIGHT,
2565 EL_SP_GRAVITY_ON_PORT_UP,
2566 EL_SP_GRAVITY_ON_PORT_DOWN,
2567 EL_SP_GRAVITY_OFF_PORT_LEFT,
2568 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2569 EL_SP_GRAVITY_OFF_PORT_UP,
2570 EL_SP_GRAVITY_OFF_PORT_DOWN,
2575 static int ep_passable_under[] =
2580 static int ep_droppable[] =
2585 static int ep_explodes_1x1_old[] =
2590 static int ep_pushable[] =
2602 EL_SOKOBAN_FIELD_FULL,
2611 static int ep_explodes_cross_old[] =
2616 static int ep_protected[] =
2618 /* same elements as in 'ep_walkable_inside' */
2622 EL_TUBE_VERTICAL_LEFT,
2623 EL_TUBE_VERTICAL_RIGHT,
2624 EL_TUBE_HORIZONTAL_UP,
2625 EL_TUBE_HORIZONTAL_DOWN,
2631 /* same elements as in 'ep_passable_over' */
2640 EL_EM_GATE_1_GRAY_ACTIVE,
2641 EL_EM_GATE_2_GRAY_ACTIVE,
2642 EL_EM_GATE_3_GRAY_ACTIVE,
2643 EL_EM_GATE_4_GRAY_ACTIVE,
2652 EL_EMC_GATE_5_GRAY_ACTIVE,
2653 EL_EMC_GATE_6_GRAY_ACTIVE,
2654 EL_EMC_GATE_7_GRAY_ACTIVE,
2655 EL_EMC_GATE_8_GRAY_ACTIVE,
2659 /* same elements as in 'ep_passable_inside' */
2664 EL_SP_PORT_HORIZONTAL,
2665 EL_SP_PORT_VERTICAL,
2667 EL_SP_GRAVITY_PORT_LEFT,
2668 EL_SP_GRAVITY_PORT_RIGHT,
2669 EL_SP_GRAVITY_PORT_UP,
2670 EL_SP_GRAVITY_PORT_DOWN,
2671 EL_SP_GRAVITY_ON_PORT_LEFT,
2672 EL_SP_GRAVITY_ON_PORT_RIGHT,
2673 EL_SP_GRAVITY_ON_PORT_UP,
2674 EL_SP_GRAVITY_ON_PORT_DOWN,
2675 EL_SP_GRAVITY_OFF_PORT_LEFT,
2676 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2677 EL_SP_GRAVITY_OFF_PORT_UP,
2678 EL_SP_GRAVITY_OFF_PORT_DOWN,
2683 static int ep_throwable[] =
2688 static int ep_can_explode[] =
2690 /* same elements as in 'ep_explodes_impact' */
2695 /* same elements as in 'ep_explodes_smashed' */
2701 /* elements that can explode by explosion or by dragonfire */
2705 EL_EM_DYNAMITE_ACTIVE,
2706 EL_DYNABOMB_PLAYER_1_ACTIVE,
2707 EL_DYNABOMB_PLAYER_2_ACTIVE,
2708 EL_DYNABOMB_PLAYER_3_ACTIVE,
2709 EL_DYNABOMB_PLAYER_4_ACTIVE,
2710 EL_DYNABOMB_INCREASE_NUMBER,
2711 EL_DYNABOMB_INCREASE_SIZE,
2712 EL_DYNABOMB_INCREASE_POWER,
2713 EL_SP_DISK_RED_ACTIVE,
2721 /* elements that can explode only by explosion */
2727 static int ep_gravity_reachable[] =
2733 EL_INVISIBLE_SAND_ACTIVE,
2738 EL_SP_PORT_HORIZONTAL,
2739 EL_SP_PORT_VERTICAL,
2741 EL_SP_GRAVITY_PORT_LEFT,
2742 EL_SP_GRAVITY_PORT_RIGHT,
2743 EL_SP_GRAVITY_PORT_UP,
2744 EL_SP_GRAVITY_PORT_DOWN,
2745 EL_SP_GRAVITY_ON_PORT_LEFT,
2746 EL_SP_GRAVITY_ON_PORT_RIGHT,
2747 EL_SP_GRAVITY_ON_PORT_UP,
2748 EL_SP_GRAVITY_ON_PORT_DOWN,
2749 EL_SP_GRAVITY_OFF_PORT_LEFT,
2750 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2751 EL_SP_GRAVITY_OFF_PORT_UP,
2752 EL_SP_GRAVITY_OFF_PORT_DOWN,
2758 static int ep_player[] =
2765 EL_SOKOBAN_FIELD_PLAYER,
2771 static int ep_can_pass_magic_wall[] =
2785 static int ep_switchable[] =
2789 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2790 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2791 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2792 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2793 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2794 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2795 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2796 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2797 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2798 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2799 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2800 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2801 EL_SWITCHGATE_SWITCH_UP,
2802 EL_SWITCHGATE_SWITCH_DOWN,
2804 EL_LIGHT_SWITCH_ACTIVE,
2806 EL_BALLOON_SWITCH_LEFT,
2807 EL_BALLOON_SWITCH_RIGHT,
2808 EL_BALLOON_SWITCH_UP,
2809 EL_BALLOON_SWITCH_DOWN,
2810 EL_BALLOON_SWITCH_ANY,
2811 EL_BALLOON_SWITCH_NONE,
2814 EL_EMC_MAGIC_BALL_SWITCH,
2815 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2820 static int ep_bd_element[] =
2854 static int ep_sp_element[] =
2856 /* should always be valid */
2859 /* standard classic Supaplex elements */
2866 EL_SP_HARDWARE_GRAY,
2874 EL_SP_GRAVITY_PORT_RIGHT,
2875 EL_SP_GRAVITY_PORT_DOWN,
2876 EL_SP_GRAVITY_PORT_LEFT,
2877 EL_SP_GRAVITY_PORT_UP,
2882 EL_SP_PORT_VERTICAL,
2883 EL_SP_PORT_HORIZONTAL,
2889 EL_SP_HARDWARE_BASE_1,
2890 EL_SP_HARDWARE_GREEN,
2891 EL_SP_HARDWARE_BLUE,
2893 EL_SP_HARDWARE_YELLOW,
2894 EL_SP_HARDWARE_BASE_2,
2895 EL_SP_HARDWARE_BASE_3,
2896 EL_SP_HARDWARE_BASE_4,
2897 EL_SP_HARDWARE_BASE_5,
2898 EL_SP_HARDWARE_BASE_6,
2902 /* additional elements that appeared in newer Supaplex levels */
2905 /* additional gravity port elements (not switching, but setting gravity) */
2906 EL_SP_GRAVITY_ON_PORT_LEFT,
2907 EL_SP_GRAVITY_ON_PORT_RIGHT,
2908 EL_SP_GRAVITY_ON_PORT_UP,
2909 EL_SP_GRAVITY_ON_PORT_DOWN,
2910 EL_SP_GRAVITY_OFF_PORT_LEFT,
2911 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2912 EL_SP_GRAVITY_OFF_PORT_UP,
2913 EL_SP_GRAVITY_OFF_PORT_DOWN,
2915 /* more than one Murphy in a level results in an inactive clone */
2918 /* runtime Supaplex elements */
2919 EL_SP_DISK_RED_ACTIVE,
2920 EL_SP_TERMINAL_ACTIVE,
2921 EL_SP_BUGGY_BASE_ACTIVATING,
2922 EL_SP_BUGGY_BASE_ACTIVE,
2929 static int ep_sb_element[] =
2934 EL_SOKOBAN_FIELD_EMPTY,
2935 EL_SOKOBAN_FIELD_FULL,
2936 EL_SOKOBAN_FIELD_PLAYER,
2941 EL_INVISIBLE_STEELWALL,
2946 static int ep_gem[] =
2958 static int ep_food_dark_yamyam[] =
2986 static int ep_food_penguin[] =
3000 static int ep_food_pig[] =
3012 static int ep_historic_wall[] =
3023 EL_GATE_1_GRAY_ACTIVE,
3024 EL_GATE_2_GRAY_ACTIVE,
3025 EL_GATE_3_GRAY_ACTIVE,
3026 EL_GATE_4_GRAY_ACTIVE,
3035 EL_EM_GATE_1_GRAY_ACTIVE,
3036 EL_EM_GATE_2_GRAY_ACTIVE,
3037 EL_EM_GATE_3_GRAY_ACTIVE,
3038 EL_EM_GATE_4_GRAY_ACTIVE,
3045 EL_EXPANDABLE_WALL_HORIZONTAL,
3046 EL_EXPANDABLE_WALL_VERTICAL,
3047 EL_EXPANDABLE_WALL_ANY,
3048 EL_EXPANDABLE_WALL_GROWING,
3049 EL_BD_EXPANDABLE_WALL,
3056 EL_SP_HARDWARE_GRAY,
3057 EL_SP_HARDWARE_GREEN,
3058 EL_SP_HARDWARE_BLUE,
3060 EL_SP_HARDWARE_YELLOW,
3061 EL_SP_HARDWARE_BASE_1,
3062 EL_SP_HARDWARE_BASE_2,
3063 EL_SP_HARDWARE_BASE_3,
3064 EL_SP_HARDWARE_BASE_4,
3065 EL_SP_HARDWARE_BASE_5,
3066 EL_SP_HARDWARE_BASE_6,
3068 EL_SP_TERMINAL_ACTIVE,
3071 EL_INVISIBLE_STEELWALL,
3072 EL_INVISIBLE_STEELWALL_ACTIVE,
3074 EL_INVISIBLE_WALL_ACTIVE,
3075 EL_STEELWALL_SLIPPERY,
3092 static int ep_historic_solid[] =
3096 EL_EXPANDABLE_WALL_HORIZONTAL,
3097 EL_EXPANDABLE_WALL_VERTICAL,
3098 EL_EXPANDABLE_WALL_ANY,
3099 EL_BD_EXPANDABLE_WALL,
3112 EL_QUICKSAND_FILLING,
3113 EL_QUICKSAND_EMPTYING,
3115 EL_MAGIC_WALL_ACTIVE,
3116 EL_MAGIC_WALL_EMPTYING,
3117 EL_MAGIC_WALL_FILLING,
3121 EL_BD_MAGIC_WALL_ACTIVE,
3122 EL_BD_MAGIC_WALL_EMPTYING,
3123 EL_BD_MAGIC_WALL_FULL,
3124 EL_BD_MAGIC_WALL_FILLING,
3125 EL_BD_MAGIC_WALL_DEAD,
3134 EL_SP_TERMINAL_ACTIVE,
3138 EL_INVISIBLE_WALL_ACTIVE,
3139 EL_SWITCHGATE_SWITCH_UP,
3140 EL_SWITCHGATE_SWITCH_DOWN,
3142 EL_TIMEGATE_SWITCH_ACTIVE,
3154 /* the following elements are a direct copy of "indestructible" elements,
3155 except "EL_ACID", which is "indestructible", but not "solid"! */
3160 EL_ACID_POOL_TOPLEFT,
3161 EL_ACID_POOL_TOPRIGHT,
3162 EL_ACID_POOL_BOTTOMLEFT,
3163 EL_ACID_POOL_BOTTOM,
3164 EL_ACID_POOL_BOTTOMRIGHT,
3165 EL_SP_HARDWARE_GRAY,
3166 EL_SP_HARDWARE_GREEN,
3167 EL_SP_HARDWARE_BLUE,
3169 EL_SP_HARDWARE_YELLOW,
3170 EL_SP_HARDWARE_BASE_1,
3171 EL_SP_HARDWARE_BASE_2,
3172 EL_SP_HARDWARE_BASE_3,
3173 EL_SP_HARDWARE_BASE_4,
3174 EL_SP_HARDWARE_BASE_5,
3175 EL_SP_HARDWARE_BASE_6,
3176 EL_INVISIBLE_STEELWALL,
3177 EL_INVISIBLE_STEELWALL_ACTIVE,
3178 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3179 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3180 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3181 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3182 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3183 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3184 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3185 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3186 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3187 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3188 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3189 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3191 EL_LIGHT_SWITCH_ACTIVE,
3192 EL_SIGN_EXCLAMATION,
3193 EL_SIGN_RADIOACTIVITY,
3204 EL_STEELWALL_SLIPPERY,
3218 EL_GATE_1_GRAY_ACTIVE,
3219 EL_GATE_2_GRAY_ACTIVE,
3220 EL_GATE_3_GRAY_ACTIVE,
3221 EL_GATE_4_GRAY_ACTIVE,
3230 EL_EM_GATE_1_GRAY_ACTIVE,
3231 EL_EM_GATE_2_GRAY_ACTIVE,
3232 EL_EM_GATE_3_GRAY_ACTIVE,
3233 EL_EM_GATE_4_GRAY_ACTIVE,
3235 EL_SWITCHGATE_OPENING,
3236 EL_SWITCHGATE_CLOSED,
3237 EL_SWITCHGATE_CLOSING,
3239 EL_TIMEGATE_OPENING,
3241 EL_TIMEGATE_CLOSING,
3245 EL_TUBE_VERTICAL_LEFT,
3246 EL_TUBE_VERTICAL_RIGHT,
3247 EL_TUBE_HORIZONTAL_UP,
3248 EL_TUBE_HORIZONTAL_DOWN,
3257 static int ep_classic_enemy[] =
3274 static int ep_belt[] =
3276 EL_CONVEYOR_BELT_1_LEFT,
3277 EL_CONVEYOR_BELT_1_MIDDLE,
3278 EL_CONVEYOR_BELT_1_RIGHT,
3279 EL_CONVEYOR_BELT_2_LEFT,
3280 EL_CONVEYOR_BELT_2_MIDDLE,
3281 EL_CONVEYOR_BELT_2_RIGHT,
3282 EL_CONVEYOR_BELT_3_LEFT,
3283 EL_CONVEYOR_BELT_3_MIDDLE,
3284 EL_CONVEYOR_BELT_3_RIGHT,
3285 EL_CONVEYOR_BELT_4_LEFT,
3286 EL_CONVEYOR_BELT_4_MIDDLE,
3287 EL_CONVEYOR_BELT_4_RIGHT,
3292 static int ep_belt_active[] =
3294 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3295 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3296 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3297 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3298 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3299 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3300 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3301 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3302 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3303 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3304 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3305 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3310 static int ep_belt_switch[] =
3312 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3313 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3314 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3315 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3316 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3317 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3318 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3319 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3320 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3321 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3322 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3323 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3328 static int ep_tube[] =
3335 EL_TUBE_HORIZONTAL_UP,
3336 EL_TUBE_HORIZONTAL_DOWN,
3338 EL_TUBE_VERTICAL_LEFT,
3339 EL_TUBE_VERTICAL_RIGHT,
3345 static int ep_keygate[] =
3355 EL_GATE_1_GRAY_ACTIVE,
3356 EL_GATE_2_GRAY_ACTIVE,
3357 EL_GATE_3_GRAY_ACTIVE,
3358 EL_GATE_4_GRAY_ACTIVE,
3367 EL_EM_GATE_1_GRAY_ACTIVE,
3368 EL_EM_GATE_2_GRAY_ACTIVE,
3369 EL_EM_GATE_3_GRAY_ACTIVE,
3370 EL_EM_GATE_4_GRAY_ACTIVE,
3379 EL_EMC_GATE_5_GRAY_ACTIVE,
3380 EL_EMC_GATE_6_GRAY_ACTIVE,
3381 EL_EMC_GATE_7_GRAY_ACTIVE,
3382 EL_EMC_GATE_8_GRAY_ACTIVE,
3387 static int ep_amoeboid[] =
3399 static int ep_amoebalive[] =
3410 static int ep_has_editor_content[] =
3432 static int ep_can_turn_each_move[] =
3434 /* !!! do something with this one !!! */
3438 static int ep_can_grow[] =
3452 static int ep_active_bomb[] =
3455 EL_EM_DYNAMITE_ACTIVE,
3456 EL_DYNABOMB_PLAYER_1_ACTIVE,
3457 EL_DYNABOMB_PLAYER_2_ACTIVE,
3458 EL_DYNABOMB_PLAYER_3_ACTIVE,
3459 EL_DYNABOMB_PLAYER_4_ACTIVE,
3460 EL_SP_DISK_RED_ACTIVE,
3465 static int ep_inactive[] =
3497 EL_GATE_1_GRAY_ACTIVE,
3498 EL_GATE_2_GRAY_ACTIVE,
3499 EL_GATE_3_GRAY_ACTIVE,
3500 EL_GATE_4_GRAY_ACTIVE,
3509 EL_EM_GATE_1_GRAY_ACTIVE,
3510 EL_EM_GATE_2_GRAY_ACTIVE,
3511 EL_EM_GATE_3_GRAY_ACTIVE,
3512 EL_EM_GATE_4_GRAY_ACTIVE,
3521 EL_EMC_GATE_5_GRAY_ACTIVE,
3522 EL_EMC_GATE_6_GRAY_ACTIVE,
3523 EL_EMC_GATE_7_GRAY_ACTIVE,
3524 EL_EMC_GATE_8_GRAY_ACTIVE,
3527 EL_INVISIBLE_STEELWALL,
3535 EL_WALL_EMERALD_YELLOW,
3536 EL_DYNABOMB_INCREASE_NUMBER,
3537 EL_DYNABOMB_INCREASE_SIZE,
3538 EL_DYNABOMB_INCREASE_POWER,
3542 EL_SOKOBAN_FIELD_EMPTY,
3543 EL_SOKOBAN_FIELD_FULL,
3544 EL_WALL_EMERALD_RED,
3545 EL_WALL_EMERALD_PURPLE,
3546 EL_ACID_POOL_TOPLEFT,
3547 EL_ACID_POOL_TOPRIGHT,
3548 EL_ACID_POOL_BOTTOMLEFT,
3549 EL_ACID_POOL_BOTTOM,
3550 EL_ACID_POOL_BOTTOMRIGHT,
3554 EL_BD_MAGIC_WALL_DEAD,
3555 EL_AMOEBA_TO_DIAMOND,
3563 EL_SP_GRAVITY_PORT_RIGHT,
3564 EL_SP_GRAVITY_PORT_DOWN,
3565 EL_SP_GRAVITY_PORT_LEFT,
3566 EL_SP_GRAVITY_PORT_UP,
3567 EL_SP_PORT_HORIZONTAL,
3568 EL_SP_PORT_VERTICAL,
3579 EL_SP_HARDWARE_GRAY,
3580 EL_SP_HARDWARE_GREEN,
3581 EL_SP_HARDWARE_BLUE,
3583 EL_SP_HARDWARE_YELLOW,
3584 EL_SP_HARDWARE_BASE_1,
3585 EL_SP_HARDWARE_BASE_2,
3586 EL_SP_HARDWARE_BASE_3,
3587 EL_SP_HARDWARE_BASE_4,
3588 EL_SP_HARDWARE_BASE_5,
3589 EL_SP_HARDWARE_BASE_6,
3590 EL_SP_GRAVITY_ON_PORT_LEFT,
3591 EL_SP_GRAVITY_ON_PORT_RIGHT,
3592 EL_SP_GRAVITY_ON_PORT_UP,
3593 EL_SP_GRAVITY_ON_PORT_DOWN,
3594 EL_SP_GRAVITY_OFF_PORT_LEFT,
3595 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3596 EL_SP_GRAVITY_OFF_PORT_UP,
3597 EL_SP_GRAVITY_OFF_PORT_DOWN,
3598 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3599 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3600 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3601 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3602 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3603 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3604 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3605 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3606 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3607 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3608 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3609 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3610 EL_SIGN_EXCLAMATION,
3611 EL_SIGN_RADIOACTIVITY,
3622 EL_STEELWALL_SLIPPERY,
3627 EL_EMC_WALL_SLIPPERY_1,
3628 EL_EMC_WALL_SLIPPERY_2,
3629 EL_EMC_WALL_SLIPPERY_3,
3630 EL_EMC_WALL_SLIPPERY_4,
3651 static int ep_em_slippery_wall[] =
3656 static int ep_gfx_crumbled[] =
3666 static int ep_editor_cascade_active[] =
3668 EL_INTERNAL_CASCADE_BD_ACTIVE,
3669 EL_INTERNAL_CASCADE_EM_ACTIVE,
3670 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3671 EL_INTERNAL_CASCADE_RND_ACTIVE,
3672 EL_INTERNAL_CASCADE_SB_ACTIVE,
3673 EL_INTERNAL_CASCADE_SP_ACTIVE,
3674 EL_INTERNAL_CASCADE_DC_ACTIVE,
3675 EL_INTERNAL_CASCADE_DX_ACTIVE,
3676 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3677 EL_INTERNAL_CASCADE_CE_ACTIVE,
3678 EL_INTERNAL_CASCADE_GE_ACTIVE,
3679 EL_INTERNAL_CASCADE_REF_ACTIVE,
3680 EL_INTERNAL_CASCADE_USER_ACTIVE,
3681 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3686 static int ep_editor_cascade_inactive[] =
3688 EL_INTERNAL_CASCADE_BD,
3689 EL_INTERNAL_CASCADE_EM,
3690 EL_INTERNAL_CASCADE_EMC,
3691 EL_INTERNAL_CASCADE_RND,
3692 EL_INTERNAL_CASCADE_SB,
3693 EL_INTERNAL_CASCADE_SP,
3694 EL_INTERNAL_CASCADE_DC,
3695 EL_INTERNAL_CASCADE_DX,
3696 EL_INTERNAL_CASCADE_CHARS,
3697 EL_INTERNAL_CASCADE_CE,
3698 EL_INTERNAL_CASCADE_GE,
3699 EL_INTERNAL_CASCADE_REF,
3700 EL_INTERNAL_CASCADE_USER,
3701 EL_INTERNAL_CASCADE_DYNAMIC,
3706 static int ep_obsolete[] =
3710 EL_EM_KEY_1_FILE_OBSOLETE,
3711 EL_EM_KEY_2_FILE_OBSOLETE,
3712 EL_EM_KEY_3_FILE_OBSOLETE,
3713 EL_EM_KEY_4_FILE_OBSOLETE,
3714 EL_ENVELOPE_OBSOLETE,
3723 } element_properties[] =
3725 { ep_diggable, EP_DIGGABLE },
3726 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3727 { ep_dont_run_into, EP_DONT_RUN_INTO },
3728 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3729 { ep_dont_touch, EP_DONT_TOUCH },
3730 { ep_indestructible, EP_INDESTRUCTIBLE },
3731 { ep_slippery, EP_SLIPPERY },
3732 { ep_can_change, EP_CAN_CHANGE },
3733 { ep_can_move, EP_CAN_MOVE },
3734 { ep_can_fall, EP_CAN_FALL },
3735 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3736 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3737 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3738 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3739 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3740 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3741 { ep_walkable_over, EP_WALKABLE_OVER },
3742 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3743 { ep_walkable_under, EP_WALKABLE_UNDER },
3744 { ep_passable_over, EP_PASSABLE_OVER },
3745 { ep_passable_inside, EP_PASSABLE_INSIDE },
3746 { ep_passable_under, EP_PASSABLE_UNDER },
3747 { ep_droppable, EP_DROPPABLE },
3748 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3749 { ep_pushable, EP_PUSHABLE },
3750 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3751 { ep_protected, EP_PROTECTED },
3752 { ep_throwable, EP_THROWABLE },
3753 { ep_can_explode, EP_CAN_EXPLODE },
3754 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3756 { ep_player, EP_PLAYER },
3757 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3758 { ep_switchable, EP_SWITCHABLE },
3759 { ep_bd_element, EP_BD_ELEMENT },
3760 { ep_sp_element, EP_SP_ELEMENT },
3761 { ep_sb_element, EP_SB_ELEMENT },
3763 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3764 { ep_food_penguin, EP_FOOD_PENGUIN },
3765 { ep_food_pig, EP_FOOD_PIG },
3766 { ep_historic_wall, EP_HISTORIC_WALL },
3767 { ep_historic_solid, EP_HISTORIC_SOLID },
3768 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3769 { ep_belt, EP_BELT },
3770 { ep_belt_active, EP_BELT_ACTIVE },
3771 { ep_belt_switch, EP_BELT_SWITCH },
3772 { ep_tube, EP_TUBE },
3773 { ep_keygate, EP_KEYGATE },
3774 { ep_amoeboid, EP_AMOEBOID },
3775 { ep_amoebalive, EP_AMOEBALIVE },
3776 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3777 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3778 { ep_can_grow, EP_CAN_GROW },
3779 { ep_active_bomb, EP_ACTIVE_BOMB },
3780 { ep_inactive, EP_INACTIVE },
3782 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3784 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3786 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3787 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3789 { ep_obsolete, EP_OBSOLETE },
3796 /* always start with reliable default values (element has no properties) */
3797 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3798 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3799 SET_PROPERTY(i, j, FALSE);
3801 /* set all base element properties from above array definitions */
3802 for (i = 0; element_properties[i].elements != NULL; i++)
3803 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3804 SET_PROPERTY((element_properties[i].elements)[j],
3805 element_properties[i].property, TRUE);
3807 /* copy properties to some elements that are only stored in level file */
3808 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3809 for (j = 0; copy_properties[j][0] != -1; j++)
3810 if (HAS_PROPERTY(copy_properties[j][0], i))
3811 for (k = 1; k <= 4; k++)
3812 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3815 void InitElementPropertiesEngine(int engine_version)
3817 static int no_wall_properties[] =
3820 EP_COLLECTIBLE_ONLY,
3822 EP_DONT_COLLIDE_WITH,
3825 EP_CAN_SMASH_PLAYER,
3826 EP_CAN_SMASH_ENEMIES,
3827 EP_CAN_SMASH_EVERYTHING,
3832 EP_FOOD_DARK_YAMYAM,
3848 /* important: after initialization in InitElementPropertiesStatic(), the
3849 elements are not again initialized to a default value; therefore all
3850 changes have to make sure that they leave the element with a defined
3851 property (which means that conditional property changes must be set to
3852 a reliable default value before) */
3854 /* ---------- recursively resolve group elements ------------------------- */
3856 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3857 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3858 element_info[i].in_group[j] = FALSE;
3860 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3861 resolve_group_element(EL_GROUP_START + i, 0);
3863 /* set all special, combined or engine dependent element properties */
3864 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3866 /* ---------- INACTIVE ------------------------------------------------- */
3867 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3869 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3870 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3871 IS_WALKABLE_INSIDE(i) ||
3872 IS_WALKABLE_UNDER(i)));
3874 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3875 IS_PASSABLE_INSIDE(i) ||
3876 IS_PASSABLE_UNDER(i)));
3878 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3879 IS_PASSABLE_OVER(i)));
3881 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3882 IS_PASSABLE_INSIDE(i)));
3884 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3885 IS_PASSABLE_UNDER(i)));
3887 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3890 /* ---------- COLLECTIBLE ---------------------------------------------- */
3891 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3895 /* ---------- SNAPPABLE ------------------------------------------------ */
3896 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3897 IS_COLLECTIBLE(i) ||
3901 /* ---------- WALL ----------------------------------------------------- */
3902 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3904 for (j = 0; no_wall_properties[j] != -1; j++)
3905 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3906 i >= EL_FIRST_RUNTIME_UNREAL)
3907 SET_PROPERTY(i, EP_WALL, FALSE);
3909 if (IS_HISTORIC_WALL(i))
3910 SET_PROPERTY(i, EP_WALL, TRUE);
3912 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3913 if (engine_version < VERSION_IDENT(2,2,0,0))
3914 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3916 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3918 !IS_COLLECTIBLE(i)));
3920 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3922 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3923 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3925 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3926 IS_INDESTRUCTIBLE(i)));
3928 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3930 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3931 else if (engine_version < VERSION_IDENT(2,2,0,0))
3932 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3934 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3938 if (IS_CUSTOM_ELEMENT(i))
3940 /* these are additional properties which are initially false when set */
3942 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3944 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3945 if (DONT_COLLIDE_WITH(i))
3946 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3948 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3949 if (CAN_SMASH_EVERYTHING(i))
3950 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3951 if (CAN_SMASH_ENEMIES(i))
3952 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3955 /* ---------- CAN_SMASH ------------------------------------------------ */
3956 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3957 CAN_SMASH_ENEMIES(i) ||
3958 CAN_SMASH_EVERYTHING(i)));
3960 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3961 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3962 EXPLODES_BY_FIRE(i)));
3964 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3965 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3966 EXPLODES_SMASHED(i)));
3968 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3969 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3970 EXPLODES_IMPACT(i)));
3972 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3973 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3975 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3976 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3977 i == EL_BLACK_ORB));
3979 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3980 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3982 IS_CUSTOM_ELEMENT(i)));
3984 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3985 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3986 i == EL_SP_ELECTRON));
3988 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3989 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3990 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3991 getMoveIntoAcidProperty(&level, i));
3993 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3994 if (MAYBE_DONT_COLLIDE_WITH(i))
3995 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3996 getDontCollideWithProperty(&level, i));
3998 /* ---------- SP_PORT -------------------------------------------------- */
3999 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4000 IS_PASSABLE_INSIDE(i)));
4002 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4003 for (j = 0; j < level.num_android_clone_elements; j++)
4004 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4006 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4008 /* ---------- CAN_CHANGE ----------------------------------------------- */
4009 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4010 for (j = 0; j < element_info[i].num_change_pages; j++)
4011 if (element_info[i].change_page[j].can_change)
4012 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4014 /* ---------- HAS_ACTION ----------------------------------------------- */
4015 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4016 for (j = 0; j < element_info[i].num_change_pages; j++)
4017 if (element_info[i].change_page[j].has_action)
4018 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4020 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4021 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4024 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4026 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4027 element_info[i].crumbled[ACTION_DEFAULT] !=
4028 element_info[i].graphic[ACTION_DEFAULT]);
4030 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4031 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4032 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4035 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4036 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4037 IS_EDITOR_CASCADE_INACTIVE(i)));
4040 /* dynamically adjust element properties according to game engine version */
4042 static int ep_em_slippery_wall[] =
4047 EL_EXPANDABLE_WALL_HORIZONTAL,
4048 EL_EXPANDABLE_WALL_VERTICAL,
4049 EL_EXPANDABLE_WALL_ANY,
4053 /* special EM style gems behaviour */
4054 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4055 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4056 level.em_slippery_gems);
4058 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4059 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4060 (level.em_slippery_gems &&
4061 engine_version > VERSION_IDENT(2,0,1,0)));
4064 /* this is needed because some graphics depend on element properties */
4065 if (game_status == GAME_MODE_PLAYING)
4066 InitElementGraphicInfo();
4069 void InitElementPropertiesAfterLoading(int engine_version)
4073 /* set some other uninitialized values of custom elements in older levels */
4074 if (engine_version < VERSION_IDENT(3,1,0,0))
4076 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4078 int element = EL_CUSTOM_START + i;
4080 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4082 element_info[element].explosion_delay = 17;
4083 element_info[element].ignition_delay = 8;
4088 static void InitGlobal()
4092 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4094 /* check if element_name_info entry defined for each element in "main.h" */
4095 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4096 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4098 element_info[i].token_name = element_name_info[i].token_name;
4099 element_info[i].class_name = element_name_info[i].class_name;
4100 element_info[i].editor_description=element_name_info[i].editor_description;
4103 global.autoplay_leveldir = NULL;
4104 global.convert_leveldir = NULL;
4106 global.frames_per_second = 0;
4107 global.fps_slowdown = FALSE;
4108 global.fps_slowdown_factor = 1;
4111 void Execute_Command(char *command)
4115 if (strEqual(command, "print graphicsinfo.conf"))
4117 printf("# You can configure additional/alternative image files here.\n");
4118 printf("# (The entries below are default and therefore commented out.)\n");
4120 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4122 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4125 for (i = 0; image_config[i].token != NULL; i++)
4126 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4127 image_config[i].value));
4131 else if (strEqual(command, "print soundsinfo.conf"))
4133 printf("# You can configure additional/alternative sound files here.\n");
4134 printf("# (The entries below are default and therefore commented out.)\n");
4136 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4138 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4141 for (i = 0; sound_config[i].token != NULL; i++)
4142 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4143 sound_config[i].value));
4147 else if (strEqual(command, "print musicinfo.conf"))
4149 printf("# You can configure additional/alternative music files here.\n");
4150 printf("# (The entries below are default and therefore commented out.)\n");
4152 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4154 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4157 for (i = 0; music_config[i].token != NULL; i++)
4158 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4159 music_config[i].value));
4163 else if (strEqual(command, "print editorsetup.conf"))
4165 printf("# You can configure your personal editor element list here.\n");
4166 printf("# (The entries below are default and therefore commented out.)\n");
4169 /* this is needed to be able to check element list for cascade elements */
4170 InitElementPropertiesStatic();
4171 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4173 PrintEditorElementList();
4177 else if (strEqual(command, "print helpanim.conf"))
4179 printf("# You can configure different element help animations here.\n");
4180 printf("# (The entries below are default and therefore commented out.)\n");
4183 for (i = 0; helpanim_config[i].token != NULL; i++)
4185 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4186 helpanim_config[i].value));
4188 if (strEqual(helpanim_config[i].token, "end"))
4194 else if (strEqual(command, "print helptext.conf"))
4196 printf("# You can configure different element help text here.\n");
4197 printf("# (The entries below are default and therefore commented out.)\n");
4200 for (i = 0; helptext_config[i].token != NULL; i++)
4201 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4202 helptext_config[i].value));
4206 else if (strncmp(command, "dump level ", 11) == 0)
4208 char *filename = &command[11];
4210 if (!fileExists(filename))
4211 Error(ERR_EXIT, "cannot open file '%s'", filename);
4213 LoadLevelFromFilename(&level, filename);
4218 else if (strncmp(command, "dump tape ", 10) == 0)
4220 char *filename = &command[10];
4222 if (!fileExists(filename))
4223 Error(ERR_EXIT, "cannot open file '%s'", filename);
4225 LoadTapeFromFilename(filename);
4230 else if (strncmp(command, "autoplay ", 9) == 0)
4232 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4234 while (*str_ptr != '\0') /* continue parsing string */
4236 /* cut leading whitespace from string, replace it by string terminator */
4237 while (*str_ptr == ' ' || *str_ptr == '\t')
4240 if (*str_ptr == '\0') /* end of string reached */
4243 if (global.autoplay_leveldir == NULL) /* read level set string */
4245 global.autoplay_leveldir = str_ptr;
4246 global.autoplay_all = TRUE; /* default: play all tapes */
4248 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4249 global.autoplay_level[i] = FALSE;
4251 else /* read level number string */
4253 int level_nr = atoi(str_ptr); /* get level_nr value */
4255 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4256 global.autoplay_level[level_nr] = TRUE;
4258 global.autoplay_all = FALSE;
4261 /* advance string pointer to the next whitespace (or end of string) */
4262 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4266 else if (strncmp(command, "convert ", 8) == 0)
4268 char *str_copy = getStringCopy(&command[8]);
4269 char *str_ptr = strchr(str_copy, ' ');
4271 global.convert_leveldir = str_copy;
4272 global.convert_level_nr = -1;
4274 if (str_ptr != NULL) /* level number follows */
4276 *str_ptr++ = '\0'; /* terminate leveldir string */
4277 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4282 #if defined(TARGET_SDL)
4283 else if (strEqual(command, "SDL_ListModes"))
4288 SDL_Init(SDL_INIT_VIDEO);
4290 /* get available fullscreen/hardware modes */
4291 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4293 /* check if there are any modes available */
4296 printf("No modes available!\n");
4301 /* check if our resolution is restricted */
4302 if (modes == (SDL_Rect **)-1)
4304 printf("All resolutions available.\n");
4308 printf("Available Modes:\n");
4310 for(i = 0; modes[i]; i++)
4311 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4321 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4325 static void InitSetup()
4327 LoadSetup(); /* global setup info */
4329 /* set some options from setup file */
4331 if (setup.options.verbose)
4332 options.verbose = TRUE;
4335 static void InitGameInfo()
4337 game.restart_level = FALSE;
4340 static void InitPlayerInfo()
4344 /* choose default local player */
4345 local_player = &stored_player[0];
4347 for (i = 0; i < MAX_PLAYERS; i++)
4348 stored_player[i].connected = FALSE;
4350 local_player->connected = TRUE;
4353 static void InitArtworkInfo()
4358 static char *get_string_in_brackets(char *string)
4360 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4362 sprintf(string_in_brackets, "[%s]", string);
4364 return string_in_brackets;
4367 static char *get_level_id_suffix(int id_nr)
4369 char *id_suffix = checked_malloc(1 + 3 + 1);
4371 if (id_nr < 0 || id_nr > 999)
4374 sprintf(id_suffix, ".%03d", id_nr);
4380 static char *get_element_class_token(int element)
4382 char *element_class_name = element_info[element].class_name;
4383 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4385 sprintf(element_class_token, "[%s]", element_class_name);
4387 return element_class_token;
4390 static char *get_action_class_token(int action)
4392 char *action_class_name = &element_action_info[action].suffix[1];
4393 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4395 sprintf(action_class_token, "[%s]", action_class_name);
4397 return action_class_token;
4401 static void InitArtworkConfig()
4403 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4404 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4405 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4406 static char *action_id_suffix[NUM_ACTIONS + 1];
4407 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4408 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4409 static char *level_id_suffix[MAX_LEVELS + 1];
4410 static char *dummy[1] = { NULL };
4411 static char *ignore_generic_tokens[] =
4417 static char **ignore_image_tokens;
4418 static char **ignore_sound_tokens;
4419 static char **ignore_music_tokens;
4420 int num_ignore_generic_tokens;
4421 int num_ignore_image_tokens;
4422 int num_ignore_sound_tokens;
4423 int num_ignore_music_tokens;
4426 /* dynamically determine list of generic tokens to be ignored */
4427 num_ignore_generic_tokens = 0;
4428 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4429 num_ignore_generic_tokens++;
4431 /* dynamically determine list of image tokens to be ignored */
4432 num_ignore_image_tokens = num_ignore_generic_tokens;
4433 for (i = 0; image_config_vars[i].token != NULL; i++)
4434 num_ignore_image_tokens++;
4435 ignore_image_tokens =
4436 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4437 for (i = 0; i < num_ignore_generic_tokens; i++)
4438 ignore_image_tokens[i] = ignore_generic_tokens[i];
4439 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4440 ignore_image_tokens[num_ignore_generic_tokens + i] =
4441 image_config_vars[i].token;
4442 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4444 /* dynamically determine list of sound tokens to be ignored */
4445 num_ignore_sound_tokens = num_ignore_generic_tokens;
4446 ignore_sound_tokens =
4447 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4448 for (i = 0; i < num_ignore_generic_tokens; i++)
4449 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4450 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4452 /* dynamically determine list of music tokens to be ignored */
4453 num_ignore_music_tokens = num_ignore_generic_tokens;
4454 ignore_music_tokens =
4455 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4456 for (i = 0; i < num_ignore_generic_tokens; i++)
4457 ignore_music_tokens[i] = ignore_generic_tokens[i];
4458 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4461 image_id_prefix[i] = element_info[i].token_name;
4462 for (i = 0; i < NUM_FONTS; i++)
4463 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4464 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4466 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4467 sound_id_prefix[i] = element_info[i].token_name;
4468 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4469 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4470 get_string_in_brackets(element_info[i].class_name);
4471 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4473 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4474 music_id_prefix[i] = music_prefix_info[i].prefix;
4475 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4477 for (i = 0; i < NUM_ACTIONS; i++)
4478 action_id_suffix[i] = element_action_info[i].suffix;
4479 action_id_suffix[NUM_ACTIONS] = NULL;
4481 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4482 direction_id_suffix[i] = element_direction_info[i].suffix;
4483 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4485 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4486 special_id_suffix[i] = special_suffix_info[i].suffix;
4487 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4489 for (i = 0; i < MAX_LEVELS; i++)
4490 level_id_suffix[i] = get_level_id_suffix(i);
4491 level_id_suffix[MAX_LEVELS] = NULL;
4493 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4494 image_id_prefix, action_id_suffix, direction_id_suffix,
4495 special_id_suffix, ignore_image_tokens);
4496 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4497 sound_id_prefix, action_id_suffix, dummy,
4498 special_id_suffix, ignore_sound_tokens);
4499 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4500 music_id_prefix, special_id_suffix, level_id_suffix,
4501 dummy, ignore_music_tokens);
4504 static void InitMixer()
4512 char *filename_font_initial = NULL;
4513 Bitmap *bitmap_font_initial = NULL;
4517 /* determine settings for initial font (for displaying startup messages) */
4518 for (i = 0; image_config[i].token != NULL; i++)
4520 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4522 char font_token[128];
4525 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4526 len_font_token = strlen(font_token);
4528 if (strEqual(image_config[i].token, font_token))
4529 filename_font_initial = image_config[i].value;
4530 else if (strlen(image_config[i].token) > len_font_token &&
4531 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4533 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4534 font_initial[j].src_x = atoi(image_config[i].value);
4535 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4536 font_initial[j].src_y = atoi(image_config[i].value);
4537 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4538 font_initial[j].width = atoi(image_config[i].value);
4539 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4540 font_initial[j].height = atoi(image_config[i].value);
4545 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4547 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4548 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4551 if (filename_font_initial == NULL) /* should not happen */
4552 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4554 /* create additional image buffers for double-buffering and cross-fading */
4555 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4556 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4557 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4558 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4560 /* initialize screen properties */
4561 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4562 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4564 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4565 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4566 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4568 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4570 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4571 font_initial[j].bitmap = bitmap_font_initial;
4573 InitFontGraphicInfo();
4575 font_height = getFontHeight(FC_RED);
4578 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4580 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4582 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4583 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4585 DrawInitText("Loading graphics", 120, FC_GREEN);
4588 void RedrawBackground()
4590 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4591 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4593 redraw_mask = REDRAW_ALL;
4596 void InitGfxBackground()
4600 fieldbuffer = bitmap_db_field;
4601 SetDrawtoField(DRAW_BACKBUFFER);
4605 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4606 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4608 for (x = 0; x < MAX_BUF_XSIZE; x++)
4609 for (y = 0; y < MAX_BUF_YSIZE; y++)
4612 redraw_mask = REDRAW_ALL;
4615 static void InitLevelInfo()
4617 LoadLevelInfo(); /* global level info */
4618 LoadLevelSetup_LastSeries(); /* last played series info */
4619 LoadLevelSetup_SeriesInfo(); /* last played level info */
4622 void InitLevelArtworkInfo()
4624 LoadLevelArtworkInfo();
4627 static void InitImages()
4629 setLevelArtworkDir(artwork.gfx_first);
4632 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4633 leveldir_current->identifier,
4634 artwork.gfx_current_identifier,
4635 artwork.gfx_current->identifier,
4636 leveldir_current->graphics_set,
4637 leveldir_current->graphics_path);
4640 ReloadCustomImages();
4642 LoadCustomElementDescriptions();
4643 LoadSpecialMenuDesignSettings();
4645 ReinitializeGraphics();
4648 static void InitSound(char *identifier)
4650 if (identifier == NULL)
4651 identifier = artwork.snd_current->identifier;
4653 /* set artwork path to send it to the sound server process */
4654 setLevelArtworkDir(artwork.snd_first);
4656 InitReloadCustomSounds(identifier);
4657 ReinitializeSounds();
4660 static void InitMusic(char *identifier)
4662 if (identifier == NULL)
4663 identifier = artwork.mus_current->identifier;
4665 /* set artwork path to send it to the sound server process */
4666 setLevelArtworkDir(artwork.mus_first);
4668 InitReloadCustomMusic(identifier);
4669 ReinitializeMusic();
4672 void InitNetworkServer()
4674 #if defined(NETWORK_AVALIABLE)
4678 if (!options.network)
4681 #if defined(NETWORK_AVALIABLE)
4682 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4684 if (!ConnectToServer(options.server_host, options.server_port))
4685 Error(ERR_EXIT, "cannot connect to network game server");
4687 SendToServer_PlayerName(setup.player_name);
4688 SendToServer_ProtocolVersion();
4691 SendToServer_NrWanted(nr_wanted);
4695 static char *getNewArtworkIdentifier(int type)
4697 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4698 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4699 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4700 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4701 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4702 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4703 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4704 char *leveldir_identifier = leveldir_current->identifier;
4706 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4707 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4709 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4711 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4712 char *artwork_current_identifier;
4713 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4715 /* leveldir_current may be invalid (level group, parent link) */
4716 if (!validLevelSeries(leveldir_current))
4719 /* 1st step: determine artwork set to be activated in descending order:
4720 --------------------------------------------------------------------
4721 1. setup artwork (when configured to override everything else)
4722 2. artwork set configured in "levelinfo.conf" of current level set
4723 (artwork in level directory will have priority when loading later)
4724 3. artwork in level directory (stored in artwork sub-directory)
4725 4. setup artwork (currently configured in setup menu) */
4727 if (setup_override_artwork)
4728 artwork_current_identifier = setup_artwork_set;
4729 else if (leveldir_artwork_set != NULL)
4730 artwork_current_identifier = leveldir_artwork_set;
4731 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4732 artwork_current_identifier = leveldir_identifier;
4734 artwork_current_identifier = setup_artwork_set;
4737 /* 2nd step: check if it is really needed to reload artwork set
4738 ------------------------------------------------------------ */
4741 if (type == ARTWORK_TYPE_GRAPHICS)
4742 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4743 artwork_new_identifier,
4744 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4745 artwork_current_identifier,
4746 leveldir_current->graphics_set,
4747 leveldir_current->identifier);
4750 /* ---------- reload if level set and also artwork set has changed ------- */
4751 if (leveldir_current_identifier[type] != leveldir_identifier &&
4752 (last_has_level_artwork_set[type] || has_level_artwork_set))
4753 artwork_new_identifier = artwork_current_identifier;
4755 leveldir_current_identifier[type] = leveldir_identifier;
4756 last_has_level_artwork_set[type] = has_level_artwork_set;
4759 if (type == ARTWORK_TYPE_GRAPHICS)
4760 printf("::: 1: '%s'\n", artwork_new_identifier);
4763 /* ---------- reload if "override artwork" setting has changed ----------- */
4764 if (last_override_level_artwork[type] != setup_override_artwork)
4765 artwork_new_identifier = artwork_current_identifier;
4767 last_override_level_artwork[type] = setup_override_artwork;
4770 if (type == ARTWORK_TYPE_GRAPHICS)
4771 printf("::: 2: '%s'\n", artwork_new_identifier);
4774 /* ---------- reload if current artwork identifier has changed ----------- */
4775 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4776 artwork_current_identifier))
4777 artwork_new_identifier = artwork_current_identifier;
4779 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4782 if (type == ARTWORK_TYPE_GRAPHICS)
4783 printf("::: 3: '%s'\n", artwork_new_identifier);
4786 /* ---------- do not reload directly after starting ---------------------- */
4787 if (!initialized[type])
4788 artwork_new_identifier = NULL;
4790 initialized[type] = TRUE;
4793 if (type == ARTWORK_TYPE_GRAPHICS)
4794 printf("::: 4: '%s'\n", artwork_new_identifier);
4798 if (type == ARTWORK_TYPE_GRAPHICS)
4799 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4800 artwork.gfx_current_identifier, artwork_current_identifier,
4801 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4802 artwork_new_identifier);
4805 return artwork_new_identifier;
4808 void ReloadCustomArtwork(int force_reload)
4810 char *gfx_new_identifier;
4811 char *snd_new_identifier;
4812 char *mus_new_identifier;
4813 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4814 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4815 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4816 boolean redraw_screen = FALSE;
4818 force_reload_gfx |= AdjustGraphicsForEMC();
4820 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4821 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4822 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4824 if (gfx_new_identifier != NULL || force_reload_gfx)
4827 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4828 artwork.gfx_current_identifier,
4830 artwork.gfx_current->identifier,
4831 leveldir_current->graphics_set);
4834 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4838 redraw_screen = TRUE;
4841 if (snd_new_identifier != NULL || force_reload_snd)
4843 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4845 InitSound(snd_new_identifier);
4847 redraw_screen = TRUE;
4850 if (mus_new_identifier != NULL || force_reload_mus)
4852 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4854 InitMusic(mus_new_identifier);
4856 redraw_screen = TRUE;
4863 /* force redraw of (open or closed) door graphics */
4864 SetDoorState(DOOR_OPEN_ALL);
4865 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4869 void KeyboardAutoRepeatOffUnlessAutoplay()
4871 if (global.autoplay_leveldir == NULL)
4872 KeyboardAutoRepeatOff();
4876 /* ========================================================================= */
4878 /* ========================================================================= */
4882 InitGlobal(); /* initialize some global variables */
4884 if (options.execute_command)
4885 Execute_Command(options.execute_command);
4887 if (options.serveronly)
4889 #if defined(PLATFORM_UNIX)
4890 NetworkServer(options.server_port, options.serveronly);
4892 Error(ERR_WARN, "networking only supported in Unix version");
4895 exit(0); /* never reached, server loops forever */
4902 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4903 InitArtworkConfig(); /* needed before forking sound child process */
4908 InitRND(NEW_RANDOMIZE);
4909 InitSimpleRandom(NEW_RANDOMIZE);
4914 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
4916 InitEventFilter(FilterMouseMotionEvents);
4918 InitElementPropertiesStatic();
4919 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4923 // debug_print_timestamp(0, "INIT");
4925 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
4926 InitLevelArtworkInfo();
4927 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
4929 InitImages(); /* needs to know current level directory */
4930 InitSound(NULL); /* needs to know current level directory */
4931 InitMusic(NULL); /* needs to know current level directory */
4933 InitGfxBackground();
4939 if (global.autoplay_leveldir)
4944 else if (global.convert_leveldir)
4950 game_status = GAME_MODE_MAIN;
4954 InitNetworkServer();
4957 void CloseAllAndExit(int exit_value)
4962 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4970 #if defined(TARGET_SDL)
4971 if (network_server) /* terminate network server */
4972 SDL_KillThread(server_thread);
4975 CloseVideoDisplay();
4976 ClosePlatformDependentStuff();
4978 if (exit_value != 0)
4979 NotifyUserAboutErrorFile();