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 gadgets_initialized = TRUE;
110 inline void InitElementSmallImagesScaledUp(int graphic)
112 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
115 void InitElementSmallImages()
117 static int special_graphics[] =
119 IMG_EDITOR_ELEMENT_BORDER,
120 IMG_EDITOR_ELEMENT_BORDER_INPUT,
121 IMG_EDITOR_CASCADE_LIST,
122 IMG_EDITOR_CASCADE_LIST_ACTIVE,
125 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126 int num_property_mappings = getImageListPropertyMappingSize();
129 /* initialize normal images from static configuration */
130 for (i = 0; element_to_graphic[i].element > -1; i++)
131 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
133 /* initialize special images from static configuration */
134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
135 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
137 /* initialize images from dynamic configuration (may be elements or other) */
138 for (i = 0; i < num_property_mappings; i++)
139 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
141 /* initialize special images from above list (non-element images) */
142 for (i = 0; special_graphics[i] > -1; i++)
143 InitElementSmallImagesScaledUp(special_graphics[i]);
146 void InitScaledImages()
150 /* scale normal images from static configuration, if not already scaled */
151 for (i = 0; i < NUM_IMAGE_FILES; i++)
152 ScaleImage(i, graphic_info[i].scale_up_factor);
156 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
157 void SetBitmaps_EM(Bitmap **em_bitmap)
159 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
160 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
164 static int getFontBitmapID(int font_nr)
168 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
169 special = game_status;
170 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
171 special = GFX_SPECIAL_ARG_MAIN;
172 else if (game_status == GAME_MODE_PLAYING)
173 special = GFX_SPECIAL_ARG_DOOR;
176 return font_info[font_nr].special_bitmap_id[special];
181 void InitFontGraphicInfo()
183 static struct FontBitmapInfo *font_bitmap_info = NULL;
184 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
185 int num_property_mappings = getImageListPropertyMappingSize();
186 int num_font_bitmaps = NUM_FONTS;
189 if (graphic_info == NULL) /* still at startup phase */
191 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
196 /* ---------- initialize font graphic definitions ---------- */
198 /* always start with reliable default values (normal font graphics) */
199 for (i = 0; i < NUM_FONTS; i++)
200 font_info[i].graphic = IMG_FONT_INITIAL_1;
202 /* initialize normal font/graphic mapping from static configuration */
203 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
205 int font_nr = font_to_graphic[i].font_nr;
206 int special = font_to_graphic[i].special;
207 int graphic = font_to_graphic[i].graphic;
212 font_info[font_nr].graphic = graphic;
215 /* always start with reliable default values (special font graphics) */
216 for (i = 0; i < NUM_FONTS; i++)
218 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
220 font_info[i].special_graphic[j] = font_info[i].graphic;
221 font_info[i].special_bitmap_id[j] = i;
225 /* initialize special font/graphic mapping from static configuration */
226 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
228 int font_nr = font_to_graphic[i].font_nr;
229 int special = font_to_graphic[i].special;
230 int graphic = font_to_graphic[i].graphic;
231 int base_graphic = font2baseimg(font_nr);
233 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
235 boolean base_redefined =
236 getImageListEntryFromImageID(base_graphic)->redefined;
237 boolean special_redefined =
238 getImageListEntryFromImageID(graphic)->redefined;
240 /* if the base font ("font.title_1", for example) has been redefined,
241 but not the special font ("font.title_1.LEVELS", for example), do not
242 use an existing (in this case considered obsolete) special font
243 anymore, but use the automatically determined default font */
244 if (base_redefined && !special_redefined)
247 font_info[font_nr].special_graphic[special] = graphic;
248 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
253 /* initialize special font/graphic mapping from dynamic configuration */
254 for (i = 0; i < num_property_mappings; i++)
256 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
257 int special = property_mapping[i].ext3_index;
258 int graphic = property_mapping[i].artwork_index;
263 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
265 font_info[font_nr].special_graphic[special] = graphic;
266 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
271 /* reset non-redefined ".active" font graphics if normal font is redefined */
272 /* (this different treatment is needed because normal and active fonts are
273 independently defined ("active" is not a property of font definitions!) */
274 for (i = 0; i < NUM_FONTS; i++)
276 int font_nr_base = i;
277 int font_nr_active = FONT_ACTIVE(font_nr_base);
279 /* check only those fonts with exist as normal and ".active" variant */
280 if (font_nr_base != font_nr_active)
282 int base_graphic = font_info[font_nr_base].graphic;
283 int active_graphic = font_info[font_nr_active].graphic;
284 boolean base_redefined =
285 getImageListEntryFromImageID(base_graphic)->redefined;
286 boolean active_redefined =
287 getImageListEntryFromImageID(active_graphic)->redefined;
289 /* if the base font ("font.menu_1", for example) has been redefined,
290 but not the active font ("font.menu_1.active", for example), do not
291 use an existing (in this case considered obsolete) active font
292 anymore, but use the automatically determined default font */
293 if (base_redefined && !active_redefined)
294 font_info[font_nr_active].graphic = base_graphic;
296 /* now also check each "special" font (which may be the same as above) */
297 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
299 int base_graphic = font_info[font_nr_base].special_graphic[j];
300 int active_graphic = font_info[font_nr_active].special_graphic[j];
301 boolean base_redefined =
302 getImageListEntryFromImageID(base_graphic)->redefined;
303 boolean active_redefined =
304 getImageListEntryFromImageID(active_graphic)->redefined;
306 /* same as above, but check special graphic definitions, for example:
307 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
308 if (base_redefined && !active_redefined)
310 font_info[font_nr_active].special_graphic[j] =
311 font_info[font_nr_base].special_graphic[j];
312 font_info[font_nr_active].special_bitmap_id[j] =
313 font_info[font_nr_base].special_bitmap_id[j];
319 /* ---------- initialize font bitmap array ---------- */
321 if (font_bitmap_info != NULL)
322 FreeFontInfo(font_bitmap_info);
325 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
327 /* ---------- initialize font bitmap definitions ---------- */
329 for (i = 0; i < NUM_FONTS; i++)
331 if (i < NUM_INITIAL_FONTS)
333 font_bitmap_info[i] = font_initial[i];
337 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
339 int font_bitmap_id = font_info[i].special_bitmap_id[j];
340 int graphic = font_info[i].special_graphic[j];
342 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
343 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
345 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
346 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
349 /* copy font relevant information from graphics information */
350 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
351 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
352 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
353 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
354 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
356 font_bitmap_info[font_bitmap_id].draw_xoffset =
357 graphic_info[graphic].draw_xoffset;
358 font_bitmap_info[font_bitmap_id].draw_yoffset =
359 graphic_info[graphic].draw_yoffset;
361 font_bitmap_info[font_bitmap_id].num_chars =
362 graphic_info[graphic].anim_frames;
363 font_bitmap_info[font_bitmap_id].num_chars_per_line =
364 graphic_info[graphic].anim_frames_per_line;
368 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
371 void InitElementGraphicInfo()
373 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
374 int num_property_mappings = getImageListPropertyMappingSize();
377 if (graphic_info == NULL) /* still at startup phase */
380 /* set values to -1 to identify later as "uninitialized" values */
381 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
383 for (act = 0; act < NUM_ACTIONS; act++)
385 element_info[i].graphic[act] = -1;
386 element_info[i].crumbled[act] = -1;
388 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
390 element_info[i].direction_graphic[act][dir] = -1;
391 element_info[i].direction_crumbled[act][dir] = -1;
396 /* initialize normal element/graphic mapping from static configuration */
397 for (i = 0; element_to_graphic[i].element > -1; i++)
399 int element = element_to_graphic[i].element;
400 int action = element_to_graphic[i].action;
401 int direction = element_to_graphic[i].direction;
402 boolean crumbled = element_to_graphic[i].crumbled;
403 int graphic = element_to_graphic[i].graphic;
404 int base_graphic = el2baseimg(element);
406 if (graphic_info[graphic].bitmap == NULL)
409 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
412 boolean base_redefined =
413 getImageListEntryFromImageID(base_graphic)->redefined;
414 boolean act_dir_redefined =
415 getImageListEntryFromImageID(graphic)->redefined;
417 /* if the base graphic ("emerald", for example) has been redefined,
418 but not the action graphic ("emerald.falling", for example), do not
419 use an existing (in this case considered obsolete) action graphic
420 anymore, but use the automatically determined default graphic */
421 if (base_redefined && !act_dir_redefined)
426 action = ACTION_DEFAULT;
431 element_info[element].direction_crumbled[action][direction] = graphic;
433 element_info[element].crumbled[action] = graphic;
438 element_info[element].direction_graphic[action][direction] = graphic;
440 element_info[element].graphic[action] = graphic;
444 /* initialize normal element/graphic mapping from dynamic configuration */
445 for (i = 0; i < num_property_mappings; i++)
447 int element = property_mapping[i].base_index;
448 int action = property_mapping[i].ext1_index;
449 int direction = property_mapping[i].ext2_index;
450 int special = property_mapping[i].ext3_index;
451 int graphic = property_mapping[i].artwork_index;
452 boolean crumbled = FALSE;
454 if (special == GFX_SPECIAL_ARG_CRUMBLED)
460 if (graphic_info[graphic].bitmap == NULL)
463 if (element >= MAX_NUM_ELEMENTS || special != -1)
467 action = ACTION_DEFAULT;
472 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
473 element_info[element].direction_crumbled[action][dir] = -1;
476 element_info[element].direction_crumbled[action][direction] = graphic;
478 element_info[element].crumbled[action] = graphic;
483 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
484 element_info[element].direction_graphic[action][dir] = -1;
487 element_info[element].direction_graphic[action][direction] = graphic;
489 element_info[element].graphic[action] = graphic;
493 /* now copy all graphics that are defined to be cloned from other graphics */
494 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
496 int graphic = element_info[i].graphic[ACTION_DEFAULT];
497 int crumbled_like, diggable_like;
502 crumbled_like = graphic_info[graphic].crumbled_like;
503 diggable_like = graphic_info[graphic].diggable_like;
505 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
507 for (act = 0; act < NUM_ACTIONS; act++)
508 element_info[i].crumbled[act] =
509 element_info[crumbled_like].crumbled[act];
510 for (act = 0; act < NUM_ACTIONS; act++)
511 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
512 element_info[i].direction_crumbled[act][dir] =
513 element_info[crumbled_like].direction_crumbled[act][dir];
516 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
518 element_info[i].graphic[ACTION_DIGGING] =
519 element_info[diggable_like].graphic[ACTION_DIGGING];
520 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
521 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
522 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
527 /* set hardcoded definitions for some runtime elements without graphic */
528 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
532 /* set hardcoded definitions for some internal elements without graphic */
533 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
535 if (IS_EDITOR_CASCADE_INACTIVE(i))
536 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
537 else if (IS_EDITOR_CASCADE_ACTIVE(i))
538 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
542 /* now set all undefined/invalid graphics to -1 to set to default after it */
543 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
545 for (act = 0; act < NUM_ACTIONS; act++)
549 graphic = element_info[i].graphic[act];
550 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
551 element_info[i].graphic[act] = -1;
553 graphic = element_info[i].crumbled[act];
554 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
555 element_info[i].crumbled[act] = -1;
557 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
559 graphic = element_info[i].direction_graphic[act][dir];
560 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
561 element_info[i].direction_graphic[act][dir] = -1;
563 graphic = element_info[i].direction_crumbled[act][dir];
564 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
565 element_info[i].direction_crumbled[act][dir] = -1;
570 /* adjust graphics with 2nd tile for movement according to direction
571 (do this before correcting '-1' values to minimize calculations) */
572 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
574 for (act = 0; act < NUM_ACTIONS; act++)
576 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
578 int graphic = element_info[i].direction_graphic[act][dir];
579 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
581 if (act == ACTION_FALLING) /* special case */
582 graphic = element_info[i].graphic[act];
585 graphic_info[graphic].double_movement &&
586 graphic_info[graphic].swap_double_tiles != 0)
588 struct GraphicInfo *g = &graphic_info[graphic];
589 int src_x_front = g->src_x;
590 int src_y_front = g->src_y;
591 int src_x_back = g->src_x + g->offset2_x;
592 int src_y_back = g->src_y + g->offset2_y;
593 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
595 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
596 src_y_front < src_y_back);
597 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
598 boolean swap_movement_tiles_autodetected =
599 (!frames_are_ordered_diagonally &&
600 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
601 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
602 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
603 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
606 /* swap frontside and backside graphic tile coordinates, if needed */
607 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
609 /* get current (wrong) backside tile coordinates */
610 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
613 /* set frontside tile coordinates to backside tile coordinates */
614 g->src_x = src_x_back;
615 g->src_y = src_y_back;
617 /* invert tile offset to point to new backside tile coordinates */
621 /* do not swap front and backside tiles again after correction */
622 g->swap_double_tiles = 0;
629 /* now set all '-1' values to element specific default values */
630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
632 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
633 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
634 int default_direction_graphic[NUM_DIRECTIONS_FULL];
635 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
637 if (default_graphic == -1)
638 default_graphic = IMG_UNKNOWN;
640 if (default_crumbled == -1)
641 default_crumbled = default_graphic;
643 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
644 if (default_crumbled == -1)
645 default_crumbled = IMG_EMPTY;
648 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
650 default_direction_graphic[dir] =
651 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
652 default_direction_crumbled[dir] =
653 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
655 if (default_direction_graphic[dir] == -1)
656 default_direction_graphic[dir] = default_graphic;
658 if (default_direction_crumbled[dir] == -1)
659 default_direction_crumbled[dir] = default_direction_graphic[dir];
661 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
662 if (default_direction_crumbled[dir] == -1)
663 default_direction_crumbled[dir] = default_crumbled;
667 for (act = 0; act < NUM_ACTIONS; act++)
669 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
670 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
671 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
672 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
673 act == ACTION_TURNING_FROM_RIGHT ||
674 act == ACTION_TURNING_FROM_UP ||
675 act == ACTION_TURNING_FROM_DOWN);
677 /* generic default action graphic (defined by "[default]" directive) */
678 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
680 int default_remove_graphic = IMG_EMPTY;
682 if (act_remove && default_action_graphic != -1)
683 default_remove_graphic = default_action_graphic;
685 /* look for special default action graphic (classic game specific) */
686 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
687 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
688 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
689 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
690 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
691 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
693 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
694 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
695 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
696 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
697 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
698 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
701 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
702 /* !!! make this better !!! */
703 if (i == EL_EMPTY_SPACE)
705 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
706 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
710 if (default_action_graphic == -1)
711 default_action_graphic = default_graphic;
713 if (default_action_crumbled == -1)
714 default_action_crumbled = default_action_graphic;
716 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
717 if (default_action_crumbled == -1)
718 default_action_crumbled = default_crumbled;
721 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
723 /* use action graphic as the default direction graphic, if undefined */
724 int default_action_direction_graphic = element_info[i].graphic[act];
725 int default_action_direction_crumbled = element_info[i].crumbled[act];
727 /* no graphic for current action -- use default direction graphic */
728 if (default_action_direction_graphic == -1)
729 default_action_direction_graphic =
730 (act_remove ? default_remove_graphic :
732 element_info[i].direction_graphic[ACTION_TURNING][dir] :
733 default_action_graphic != default_graphic ?
734 default_action_graphic :
735 default_direction_graphic[dir]);
737 if (element_info[i].direction_graphic[act][dir] == -1)
738 element_info[i].direction_graphic[act][dir] =
739 default_action_direction_graphic;
742 if (default_action_direction_crumbled == -1)
743 default_action_direction_crumbled =
744 element_info[i].direction_graphic[act][dir];
746 if (default_action_direction_crumbled == -1)
747 default_action_direction_crumbled =
748 (act_remove ? default_remove_graphic :
750 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
751 default_action_crumbled != default_crumbled ?
752 default_action_crumbled :
753 default_direction_crumbled[dir]);
756 if (element_info[i].direction_crumbled[act][dir] == -1)
757 element_info[i].direction_crumbled[act][dir] =
758 default_action_direction_crumbled;
761 /* no graphic for this specific action -- use default action graphic */
762 if (element_info[i].graphic[act] == -1)
763 element_info[i].graphic[act] =
764 (act_remove ? default_remove_graphic :
765 act_turning ? element_info[i].graphic[ACTION_TURNING] :
766 default_action_graphic);
768 if (element_info[i].crumbled[act] == -1)
769 element_info[i].crumbled[act] = element_info[i].graphic[act];
771 if (element_info[i].crumbled[act] == -1)
772 element_info[i].crumbled[act] =
773 (act_remove ? default_remove_graphic :
774 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
775 default_action_crumbled);
781 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
782 /* set animation mode to "none" for each graphic with only 1 frame */
783 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
785 for (act = 0; act < NUM_ACTIONS; act++)
787 int graphic = element_info[i].graphic[act];
788 int crumbled = element_info[i].crumbled[act];
790 if (graphic_info[graphic].anim_frames == 1)
791 graphic_info[graphic].anim_mode = ANIM_NONE;
792 if (graphic_info[crumbled].anim_frames == 1)
793 graphic_info[crumbled].anim_mode = ANIM_NONE;
795 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
797 graphic = element_info[i].direction_graphic[act][dir];
798 crumbled = element_info[i].direction_crumbled[act][dir];
800 if (graphic_info[graphic].anim_frames == 1)
801 graphic_info[graphic].anim_mode = ANIM_NONE;
802 if (graphic_info[crumbled].anim_frames == 1)
803 graphic_info[crumbled].anim_mode = ANIM_NONE;
813 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
814 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
816 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
817 element_info[i].token_name, i);
823 void InitElementSpecialGraphicInfo()
825 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
826 int num_property_mappings = getImageListPropertyMappingSize();
829 /* always start with reliable default values */
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
832 element_info[i].special_graphic[j] =
833 element_info[i].graphic[ACTION_DEFAULT];
835 /* initialize special element/graphic mapping from static configuration */
836 for (i = 0; element_to_special_graphic[i].element > -1; i++)
838 int element = element_to_special_graphic[i].element;
839 int special = element_to_special_graphic[i].special;
840 int graphic = element_to_special_graphic[i].graphic;
841 int base_graphic = el2baseimg(element);
842 boolean base_redefined =
843 getImageListEntryFromImageID(base_graphic)->redefined;
844 boolean special_redefined =
845 getImageListEntryFromImageID(graphic)->redefined;
847 /* if the base graphic ("emerald", for example) has been redefined,
848 but not the special graphic ("emerald.EDITOR", for example), do not
849 use an existing (in this case considered obsolete) special graphic
850 anymore, but use the automatically created (down-scaled) graphic */
851 if (base_redefined && !special_redefined)
854 element_info[element].special_graphic[special] = graphic;
857 /* initialize special element/graphic mapping from dynamic configuration */
858 for (i = 0; i < num_property_mappings; i++)
860 int element = property_mapping[i].base_index;
861 int special = property_mapping[i].ext3_index;
862 int graphic = property_mapping[i].artwork_index;
864 if (element >= MAX_NUM_ELEMENTS)
867 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
868 element_info[element].special_graphic[special] = graphic;
871 /* now set all undefined/invalid graphics to default */
872 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
873 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
874 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
875 element_info[i].special_graphic[j] =
876 element_info[i].graphic[ACTION_DEFAULT];
879 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
884 if (type != TYPE_TOKEN)
885 return get_parameter_value(value_raw, suffix, type);
887 if (strEqual(value_raw, ARG_UNDEFINED))
888 return ARG_UNDEFINED_VALUE;
890 /* !!! OPTIMIZE THIS BY USING HASH !!! */
891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
892 if (strEqual(element_info[i].token_name, value_raw))
895 /* !!! OPTIMIZE THIS BY USING HASH !!! */
896 for (i = 0; image_config[i].token != NULL; i++)
898 int len_config_value = strlen(image_config[i].value);
900 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
901 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
902 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
905 if (strEqual(image_config[i].token, value_raw))
914 static int get_scaled_graphic_width(int graphic)
916 int original_width = getOriginalImageWidthFromImageID(graphic);
917 int scale_up_factor = graphic_info[graphic].scale_up_factor;
919 return original_width * scale_up_factor;
922 static int get_scaled_graphic_height(int graphic)
924 int original_height = getOriginalImageHeightFromImageID(graphic);
925 int scale_up_factor = graphic_info[graphic].scale_up_factor;
927 return original_height * scale_up_factor;
930 static void set_graphic_parameters(int graphic)
932 struct FileInfo *image = getImageListEntryFromImageID(graphic);
933 char **parameter_raw = image->parameter;
934 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
935 int parameter[NUM_GFX_ARGS];
936 int anim_frames_per_row = 1, anim_frames_per_col = 1;
937 int anim_frames_per_line = 1;
940 /* if fallback to default artwork is done, also use the default parameters */
941 if (image->fallback_to_default)
942 parameter_raw = image->default_parameter;
944 /* get integer values from string parameters */
945 for (i = 0; i < NUM_GFX_ARGS; i++)
946 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
947 image_config_suffix[i].token,
948 image_config_suffix[i].type);
950 graphic_info[graphic].bitmap = src_bitmap;
952 /* always start with reliable default values */
953 graphic_info[graphic].src_image_width = 0;
954 graphic_info[graphic].src_image_height = 0;
955 graphic_info[graphic].src_x = 0;
956 graphic_info[graphic].src_y = 0;
957 graphic_info[graphic].width = TILEX; /* default for element graphics */
958 graphic_info[graphic].height = TILEY; /* default for element graphics */
959 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
960 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
961 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
962 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
963 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
964 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
965 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
966 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
967 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
968 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
969 graphic_info[graphic].anim_delay_fixed = 0;
970 graphic_info[graphic].anim_delay_random = 0;
971 graphic_info[graphic].post_delay_fixed = 0;
972 graphic_info[graphic].post_delay_random = 0;
973 graphic_info[graphic].fade_delay = -1;
974 graphic_info[graphic].post_delay = -1;
975 graphic_info[graphic].auto_delay = -1;
978 /* optional zoom factor for scaling up the image to a larger size */
979 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
980 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
981 if (graphic_info[graphic].scale_up_factor < 1)
982 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
986 if (graphic_info[graphic].use_image_size)
988 /* set new default bitmap size (with scaling, but without small images) */
989 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
990 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
994 /* optional x and y tile position of animation frame sequence */
995 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
996 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
997 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
998 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1000 /* optional x and y pixel position of animation frame sequence */
1001 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1003 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1006 /* optional width and height of each animation frame */
1007 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1008 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1009 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1010 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1013 /* optional zoom factor for scaling up the image to a larger size */
1014 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1015 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1016 if (graphic_info[graphic].scale_up_factor < 1)
1017 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1022 /* get final bitmap size (with scaling, but without small images) */
1023 int src_image_width = get_scaled_graphic_width(graphic);
1024 int src_image_height = get_scaled_graphic_height(graphic);
1026 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1027 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1029 graphic_info[graphic].src_image_width = src_image_width;
1030 graphic_info[graphic].src_image_height = src_image_height;
1033 /* correct x or y offset dependent of vertical or horizontal frame order */
1034 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1036 graphic_info[graphic].offset_y =
1037 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1038 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1039 anim_frames_per_line = anim_frames_per_col;
1041 else /* frames are ordered horizontally */
1043 graphic_info[graphic].offset_x =
1044 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1045 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1046 anim_frames_per_line = anim_frames_per_row;
1049 /* optionally, the x and y offset of frames can be specified directly */
1050 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1051 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1052 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1055 /* optionally, moving animations may have separate start and end graphics */
1056 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1058 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1059 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1061 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1062 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1063 graphic_info[graphic].offset2_y =
1064 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1065 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1066 else /* frames are ordered horizontally */
1067 graphic_info[graphic].offset2_x =
1068 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1069 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1071 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1072 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1074 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1075 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1077 /* optionally, the second movement tile can be specified as start tile */
1078 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1079 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1081 /* automatically determine correct number of frames, if not defined */
1082 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1083 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1084 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1085 graphic_info[graphic].anim_frames = anim_frames_per_row;
1086 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1087 graphic_info[graphic].anim_frames = anim_frames_per_col;
1089 graphic_info[graphic].anim_frames = 1;
1091 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1092 graphic_info[graphic].anim_frames = 1;
1094 graphic_info[graphic].anim_frames_per_line =
1095 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1096 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1098 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1099 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1100 graphic_info[graphic].anim_delay = 1;
1102 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1104 if (graphic_info[graphic].anim_frames == 1)
1105 graphic_info[graphic].anim_mode = ANIM_NONE;
1108 /* automatically determine correct start frame, if not defined */
1109 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1110 graphic_info[graphic].anim_start_frame = 0;
1111 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1112 graphic_info[graphic].anim_start_frame =
1113 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1115 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1117 /* animation synchronized with global frame counter, not move position */
1118 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1120 /* optional element for cloning crumble graphics */
1121 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1122 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1124 /* optional element for cloning digging graphics */
1125 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1126 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1128 /* optional border size for "crumbling" diggable graphics */
1129 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1130 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1132 /* this is only used for player "boring" and "sleeping" actions */
1133 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1134 graphic_info[graphic].anim_delay_fixed =
1135 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1136 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1137 graphic_info[graphic].anim_delay_random =
1138 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1139 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].post_delay_fixed =
1141 parameter[GFX_ARG_POST_DELAY_FIXED];
1142 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1143 graphic_info[graphic].post_delay_random =
1144 parameter[GFX_ARG_POST_DELAY_RANDOM];
1146 /* this is only used for toon animations */
1147 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1148 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1150 /* this is only used for drawing font characters */
1151 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1152 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1154 /* this is only used for drawing envelope graphics */
1155 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1157 /* optional graphic for cloning all graphics settings */
1158 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1159 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1161 /* optional settings for drawing title screens */
1162 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1163 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1164 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1165 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1166 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1167 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1170 static void set_cloned_graphic_parameters(int graphic)
1172 int fallback_graphic = IMG_CHAR_EXCLAM;
1173 int max_num_images = getImageListSize();
1174 int clone_graphic = graphic_info[graphic].clone_from;
1175 int num_references_followed = 1;
1177 while (graphic_info[clone_graphic].clone_from != -1 &&
1178 num_references_followed < max_num_images)
1180 clone_graphic = graphic_info[clone_graphic].clone_from;
1182 num_references_followed++;
1185 if (num_references_followed >= max_num_images)
1187 Error(ERR_RETURN_LINE, "-");
1188 Error(ERR_RETURN, "warning: error found in config file:");
1189 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1190 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1191 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1192 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1194 if (graphic == fallback_graphic)
1195 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1197 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1198 Error(ERR_RETURN_LINE, "-");
1200 graphic_info[graphic] = graphic_info[fallback_graphic];
1204 graphic_info[graphic] = graphic_info[clone_graphic];
1205 graphic_info[graphic].clone_from = clone_graphic;
1209 static void InitGraphicInfo()
1211 int fallback_graphic = IMG_CHAR_EXCLAM;
1212 int num_images = getImageListSize();
1215 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1216 static boolean clipmasks_initialized = FALSE;
1218 XGCValues clip_gc_values;
1219 unsigned long clip_gc_valuemask;
1220 GC copy_clipmask_gc = None;
1223 /* use image size as default values for width and height for these images */
1224 static int full_size_graphics[] =
1229 IMG_BACKGROUND_ENVELOPE_1,
1230 IMG_BACKGROUND_ENVELOPE_2,
1231 IMG_BACKGROUND_ENVELOPE_3,
1232 IMG_BACKGROUND_ENVELOPE_4,
1235 IMG_BACKGROUND_TITLE,
1236 IMG_BACKGROUND_MAIN,
1237 IMG_BACKGROUND_LEVELS,
1238 IMG_BACKGROUND_SCORES,
1239 IMG_BACKGROUND_EDITOR,
1240 IMG_BACKGROUND_INFO,
1241 IMG_BACKGROUND_INFO_ELEMENTS,
1242 IMG_BACKGROUND_INFO_MUSIC,
1243 IMG_BACKGROUND_INFO_CREDITS,
1244 IMG_BACKGROUND_INFO_PROGRAM,
1245 IMG_BACKGROUND_INFO_LEVELSET,
1246 IMG_BACKGROUND_SETUP,
1247 IMG_BACKGROUND_DOOR,
1249 IMG_TITLESCREEN_INITIAL_1,
1250 IMG_TITLESCREEN_INITIAL_2,
1251 IMG_TITLESCREEN_INITIAL_3,
1252 IMG_TITLESCREEN_INITIAL_4,
1253 IMG_TITLESCREEN_INITIAL_5,
1263 checked_free(graphic_info);
1265 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1268 /* initialize "use_image_size" flag with default value */
1269 for (i = 0; i < num_images; i++)
1270 graphic_info[i].use_image_size = FALSE;
1272 /* initialize "use_image_size" flag from static configuration above */
1273 for (i = 0; full_size_graphics[i] != -1; i++)
1274 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1277 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1278 if (clipmasks_initialized)
1280 for (i = 0; i < num_images; i++)
1282 if (graphic_info[i].clip_mask)
1283 XFreePixmap(display, graphic_info[i].clip_mask);
1284 if (graphic_info[i].clip_gc)
1285 XFreeGC(display, graphic_info[i].clip_gc);
1287 graphic_info[i].clip_mask = None;
1288 graphic_info[i].clip_gc = None;
1293 /* first set all graphic paramaters ... */
1294 for (i = 0; i < num_images; i++)
1295 set_graphic_parameters(i);
1297 /* ... then copy these parameters for cloned graphics */
1298 for (i = 0; i < num_images; i++)
1299 if (graphic_info[i].clone_from != -1)
1300 set_cloned_graphic_parameters(i);
1302 for (i = 0; i < num_images; i++)
1307 int first_frame, last_frame;
1308 int src_bitmap_width, src_bitmap_height;
1310 /* now check if no animation frames are outside of the loaded image */
1312 if (graphic_info[i].bitmap == NULL)
1313 continue; /* skip check for optional images that are undefined */
1315 /* get image size (this can differ from the standard element tile size!) */
1316 width = graphic_info[i].width;
1317 height = graphic_info[i].height;
1319 /* get final bitmap size (with scaling, but without small images) */
1320 src_bitmap_width = graphic_info[i].src_image_width;
1321 src_bitmap_height = graphic_info[i].src_image_height;
1323 /* check if first animation frame is inside specified bitmap */
1326 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1329 /* this avoids calculating wrong start position for out-of-bounds frame */
1330 src_x = graphic_info[i].src_x;
1331 src_y = graphic_info[i].src_y;
1334 if (src_x < 0 || src_y < 0 ||
1335 src_x + width > src_bitmap_width ||
1336 src_y + height > src_bitmap_height)
1338 Error(ERR_RETURN_LINE, "-");
1339 Error(ERR_RETURN, "warning: error found in config file:");
1340 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1341 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1342 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1344 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1345 src_x, src_y, src_bitmap_width, src_bitmap_height);
1346 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1348 if (i == fallback_graphic)
1349 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1351 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1352 Error(ERR_RETURN_LINE, "-");
1354 graphic_info[i] = graphic_info[fallback_graphic];
1357 /* check if last animation frame is inside specified bitmap */
1359 last_frame = graphic_info[i].anim_frames - 1;
1360 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1362 if (src_x < 0 || src_y < 0 ||
1363 src_x + width > src_bitmap_width ||
1364 src_y + height > src_bitmap_height)
1366 Error(ERR_RETURN_LINE, "-");
1367 Error(ERR_RETURN, "warning: error found in config file:");
1368 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1369 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1370 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1372 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1373 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1374 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1376 if (i == fallback_graphic)
1377 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1379 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1380 Error(ERR_RETURN_LINE, "-");
1382 graphic_info[i] = graphic_info[fallback_graphic];
1385 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1386 /* currently we only need a tile clip mask from the first frame */
1387 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1389 if (copy_clipmask_gc == None)
1391 clip_gc_values.graphics_exposures = False;
1392 clip_gc_valuemask = GCGraphicsExposures;
1393 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1394 clip_gc_valuemask, &clip_gc_values);
1397 graphic_info[i].clip_mask =
1398 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1400 src_pixmap = src_bitmap->clip_mask;
1401 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1402 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1404 clip_gc_values.graphics_exposures = False;
1405 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1406 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1408 graphic_info[i].clip_gc =
1409 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1413 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1414 if (copy_clipmask_gc)
1415 XFreeGC(display, copy_clipmask_gc);
1417 clipmasks_initialized = TRUE;
1421 static void InitElementSoundInfo()
1423 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1424 int num_property_mappings = getSoundListPropertyMappingSize();
1427 /* set values to -1 to identify later as "uninitialized" values */
1428 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1429 for (act = 0; act < NUM_ACTIONS; act++)
1430 element_info[i].sound[act] = -1;
1432 /* initialize element/sound mapping from static configuration */
1433 for (i = 0; element_to_sound[i].element > -1; i++)
1435 int element = element_to_sound[i].element;
1436 int action = element_to_sound[i].action;
1437 int sound = element_to_sound[i].sound;
1438 boolean is_class = element_to_sound[i].is_class;
1441 action = ACTION_DEFAULT;
1444 element_info[element].sound[action] = sound;
1446 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1447 if (strEqual(element_info[j].class_name,
1448 element_info[element].class_name))
1449 element_info[j].sound[action] = sound;
1452 /* initialize element class/sound mapping from dynamic configuration */
1453 for (i = 0; i < num_property_mappings; i++)
1455 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1456 int action = property_mapping[i].ext1_index;
1457 int sound = property_mapping[i].artwork_index;
1459 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1463 action = ACTION_DEFAULT;
1465 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1466 if (strEqual(element_info[j].class_name,
1467 element_info[element_class].class_name))
1468 element_info[j].sound[action] = sound;
1471 /* initialize element/sound mapping from dynamic configuration */
1472 for (i = 0; i < num_property_mappings; i++)
1474 int element = property_mapping[i].base_index;
1475 int action = property_mapping[i].ext1_index;
1476 int sound = property_mapping[i].artwork_index;
1478 if (element >= MAX_NUM_ELEMENTS)
1482 action = ACTION_DEFAULT;
1484 element_info[element].sound[action] = sound;
1487 /* now set all '-1' values to element specific default values */
1488 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1490 for (act = 0; act < NUM_ACTIONS; act++)
1492 /* generic default action sound (defined by "[default]" directive) */
1493 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1495 /* look for special default action sound (classic game specific) */
1496 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1497 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1498 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1499 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1500 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1501 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1503 /* !!! there's no such thing as a "default action sound" !!! */
1505 /* look for element specific default sound (independent from action) */
1506 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1507 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1511 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1512 /* !!! make this better !!! */
1513 if (i == EL_EMPTY_SPACE)
1514 default_action_sound = element_info[EL_DEFAULT].sound[act];
1517 /* no sound for this specific action -- use default action sound */
1518 if (element_info[i].sound[act] == -1)
1519 element_info[i].sound[act] = default_action_sound;
1523 /* copy sound settings to some elements that are only stored in level file
1524 in native R'n'D levels, but are used by game engine in native EM levels */
1525 for (i = 0; copy_properties[i][0] != -1; i++)
1526 for (j = 1; j <= 4; j++)
1527 for (act = 0; act < NUM_ACTIONS; act++)
1528 element_info[copy_properties[i][j]].sound[act] =
1529 element_info[copy_properties[i][0]].sound[act];
1532 static void InitGameModeSoundInfo()
1536 /* set values to -1 to identify later as "uninitialized" values */
1537 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1540 /* initialize gamemode/sound mapping from static configuration */
1541 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1543 int gamemode = gamemode_to_sound[i].gamemode;
1544 int sound = gamemode_to_sound[i].sound;
1547 gamemode = GAME_MODE_DEFAULT;
1549 menu.sound[gamemode] = sound;
1552 /* now set all '-1' values to levelset specific default values */
1553 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1554 if (menu.sound[i] == -1)
1555 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1558 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1559 if (menu.sound[i] != -1)
1560 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1564 static void set_sound_parameters(int sound, char **parameter_raw)
1566 int parameter[NUM_SND_ARGS];
1569 /* get integer values from string parameters */
1570 for (i = 0; i < NUM_SND_ARGS; i++)
1572 get_parameter_value(parameter_raw[i],
1573 sound_config_suffix[i].token,
1574 sound_config_suffix[i].type);
1576 /* explicit loop mode setting in configuration overrides default value */
1577 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1578 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1580 /* sound volume to change the original volume when loading the sound file */
1581 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1583 /* sound priority to give certain sounds a higher or lower priority */
1584 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1587 static void InitSoundInfo()
1589 int *sound_effect_properties;
1590 int num_sounds = getSoundListSize();
1593 checked_free(sound_info);
1595 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1596 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1598 /* initialize sound effect for all elements to "no sound" */
1599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1600 for (j = 0; j < NUM_ACTIONS; j++)
1601 element_info[i].sound[j] = SND_UNDEFINED;
1603 for (i = 0; i < num_sounds; i++)
1605 struct FileInfo *sound = getSoundListEntry(i);
1606 int len_effect_text = strlen(sound->token);
1608 sound_effect_properties[i] = ACTION_OTHER;
1609 sound_info[i].loop = FALSE; /* default: play sound only once */
1612 printf("::: sound %d: '%s'\n", i, sound->token);
1615 /* determine all loop sounds and identify certain sound classes */
1617 for (j = 0; element_action_info[j].suffix; j++)
1619 int len_action_text = strlen(element_action_info[j].suffix);
1621 if (len_action_text < len_effect_text &&
1622 strEqual(&sound->token[len_effect_text - len_action_text],
1623 element_action_info[j].suffix))
1625 sound_effect_properties[i] = element_action_info[j].value;
1626 sound_info[i].loop = element_action_info[j].is_loop_sound;
1632 /* associate elements and some selected sound actions */
1634 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1636 if (element_info[j].class_name)
1638 int len_class_text = strlen(element_info[j].class_name);
1640 if (len_class_text + 1 < len_effect_text &&
1641 strncmp(sound->token,
1642 element_info[j].class_name, len_class_text) == 0 &&
1643 sound->token[len_class_text] == '.')
1645 int sound_action_value = sound_effect_properties[i];
1647 element_info[j].sound[sound_action_value] = i;
1652 set_sound_parameters(i, sound->parameter);
1655 free(sound_effect_properties);
1658 static void InitGameModeMusicInfo()
1660 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1661 int num_property_mappings = getMusicListPropertyMappingSize();
1662 int default_levelset_music = -1;
1665 /* set values to -1 to identify later as "uninitialized" values */
1666 for (i = 0; i < MAX_LEVELS; i++)
1667 levelset.music[i] = -1;
1668 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1671 /* initialize gamemode/music mapping from static configuration */
1672 for (i = 0; gamemode_to_music[i].music > -1; i++)
1674 int gamemode = gamemode_to_music[i].gamemode;
1675 int music = gamemode_to_music[i].music;
1678 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1682 gamemode = GAME_MODE_DEFAULT;
1684 menu.music[gamemode] = music;
1687 /* initialize gamemode/music mapping from dynamic configuration */
1688 for (i = 0; i < num_property_mappings; i++)
1690 int prefix = property_mapping[i].base_index;
1691 int gamemode = property_mapping[i].ext1_index;
1692 int level = property_mapping[i].ext2_index;
1693 int music = property_mapping[i].artwork_index;
1696 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1697 prefix, gamemode, level, music);
1700 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1704 gamemode = GAME_MODE_DEFAULT;
1706 /* level specific music only allowed for in-game music */
1707 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1708 gamemode = GAME_MODE_PLAYING;
1713 default_levelset_music = music;
1716 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1717 levelset.music[level] = music;
1718 if (gamemode != GAME_MODE_PLAYING)
1719 menu.music[gamemode] = music;
1722 /* now set all '-1' values to menu specific default values */
1723 /* (undefined values of "levelset.music[]" might stay at "-1" to
1724 allow dynamic selection of music files from music directory!) */
1725 for (i = 0; i < MAX_LEVELS; i++)
1726 if (levelset.music[i] == -1)
1727 levelset.music[i] = default_levelset_music;
1728 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1729 if (menu.music[i] == -1)
1730 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1733 for (i = 0; i < MAX_LEVELS; i++)
1734 if (levelset.music[i] != -1)
1735 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1736 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1737 if (menu.music[i] != -1)
1738 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1742 static void set_music_parameters(int music, char **parameter_raw)
1744 int parameter[NUM_MUS_ARGS];
1747 /* get integer values from string parameters */
1748 for (i = 0; i < NUM_MUS_ARGS; i++)
1750 get_parameter_value(parameter_raw[i],
1751 music_config_suffix[i].token,
1752 music_config_suffix[i].type);
1754 /* explicit loop mode setting in configuration overrides default value */
1755 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1756 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1759 static void InitMusicInfo()
1761 int num_music = getMusicListSize();
1764 checked_free(music_info);
1766 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1768 for (i = 0; i < num_music; i++)
1770 struct FileInfo *music = getMusicListEntry(i);
1771 int len_music_text = strlen(music->token);
1773 music_info[i].loop = TRUE; /* default: play music in loop mode */
1775 /* determine all loop music */
1777 for (j = 0; music_prefix_info[j].prefix; j++)
1779 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1781 if (len_prefix_text < len_music_text &&
1782 strncmp(music->token,
1783 music_prefix_info[j].prefix, len_prefix_text) == 0)
1785 music_info[i].loop = music_prefix_info[j].is_loop_music;
1791 set_music_parameters(i, music->parameter);
1795 static void ReinitializeGraphics()
1797 InitGraphicInfo(); /* graphic properties mapping */
1798 InitElementGraphicInfo(); /* element game graphic mapping */
1799 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1801 InitElementSmallImages(); /* scale elements to all needed sizes */
1802 InitScaledImages(); /* scale all other images, if needed */
1803 InitFontGraphicInfo(); /* initialize text drawing functions */
1805 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1807 SetMainBackgroundImage(IMG_BACKGROUND);
1808 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1814 static void ReinitializeSounds()
1816 InitSoundInfo(); /* sound properties mapping */
1817 InitElementSoundInfo(); /* element game sound mapping */
1818 InitGameModeSoundInfo(); /* game mode sound mapping */
1820 InitPlayLevelSound(); /* internal game sound settings */
1823 static void ReinitializeMusic()
1825 InitMusicInfo(); /* music properties mapping */
1826 InitGameModeMusicInfo(); /* game mode music mapping */
1829 static int get_special_property_bit(int element, int property_bit_nr)
1831 struct PropertyBitInfo
1837 static struct PropertyBitInfo pb_can_move_into_acid[] =
1839 /* the player may be able fall into acid when gravity is activated */
1844 { EL_SP_MURPHY, 0 },
1845 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1847 /* all elements that can move may be able to also move into acid */
1850 { EL_BUG_RIGHT, 1 },
1853 { EL_SPACESHIP, 2 },
1854 { EL_SPACESHIP_LEFT, 2 },
1855 { EL_SPACESHIP_RIGHT, 2 },
1856 { EL_SPACESHIP_UP, 2 },
1857 { EL_SPACESHIP_DOWN, 2 },
1858 { EL_BD_BUTTERFLY, 3 },
1859 { EL_BD_BUTTERFLY_LEFT, 3 },
1860 { EL_BD_BUTTERFLY_RIGHT, 3 },
1861 { EL_BD_BUTTERFLY_UP, 3 },
1862 { EL_BD_BUTTERFLY_DOWN, 3 },
1863 { EL_BD_FIREFLY, 4 },
1864 { EL_BD_FIREFLY_LEFT, 4 },
1865 { EL_BD_FIREFLY_RIGHT, 4 },
1866 { EL_BD_FIREFLY_UP, 4 },
1867 { EL_BD_FIREFLY_DOWN, 4 },
1869 { EL_YAMYAM_LEFT, 5 },
1870 { EL_YAMYAM_RIGHT, 5 },
1871 { EL_YAMYAM_UP, 5 },
1872 { EL_YAMYAM_DOWN, 5 },
1873 { EL_DARK_YAMYAM, 6 },
1876 { EL_PACMAN_LEFT, 8 },
1877 { EL_PACMAN_RIGHT, 8 },
1878 { EL_PACMAN_UP, 8 },
1879 { EL_PACMAN_DOWN, 8 },
1881 { EL_MOLE_LEFT, 9 },
1882 { EL_MOLE_RIGHT, 9 },
1884 { EL_MOLE_DOWN, 9 },
1888 { EL_SATELLITE, 13 },
1889 { EL_SP_SNIKSNAK, 14 },
1890 { EL_SP_ELECTRON, 15 },
1893 { EL_EMC_ANDROID, 18 },
1898 static struct PropertyBitInfo pb_dont_collide_with[] =
1900 { EL_SP_SNIKSNAK, 0 },
1901 { EL_SP_ELECTRON, 1 },
1909 struct PropertyBitInfo *pb_info;
1912 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1913 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1918 struct PropertyBitInfo *pb_info = NULL;
1921 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1922 if (pb_definition[i].bit_nr == property_bit_nr)
1923 pb_info = pb_definition[i].pb_info;
1925 if (pb_info == NULL)
1928 for (i = 0; pb_info[i].element != -1; i++)
1929 if (pb_info[i].element == element)
1930 return pb_info[i].bit_nr;
1935 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1936 boolean property_value)
1938 int bit_nr = get_special_property_bit(element, property_bit_nr);
1943 *bitfield |= (1 << bit_nr);
1945 *bitfield &= ~(1 << bit_nr);
1949 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1951 int bit_nr = get_special_property_bit(element, property_bit_nr);
1954 return ((*bitfield & (1 << bit_nr)) != 0);
1959 static void resolve_group_element(int group_element, int recursion_depth)
1961 static int group_nr;
1962 static struct ElementGroupInfo *group;
1963 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1966 if (actual_group == NULL) /* not yet initialized */
1969 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1971 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1972 group_element - EL_GROUP_START + 1);
1974 /* replace element which caused too deep recursion by question mark */
1975 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1980 if (recursion_depth == 0) /* initialization */
1982 group = actual_group;
1983 group_nr = group_element - EL_GROUP_START;
1985 group->num_elements_resolved = 0;
1986 group->choice_pos = 0;
1989 for (i = 0; i < actual_group->num_elements; i++)
1991 int element = actual_group->element[i];
1993 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1996 if (IS_GROUP_ELEMENT(element))
1997 resolve_group_element(element, recursion_depth + 1);
2000 group->element_resolved[group->num_elements_resolved++] = element;
2001 element_info[element].in_group[group_nr] = TRUE;
2006 void InitElementPropertiesStatic()
2008 static int ep_diggable[] =
2013 EL_SP_BUGGY_BASE_ACTIVATING,
2016 EL_INVISIBLE_SAND_ACTIVE,
2019 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2020 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2024 EL_SP_BUGGY_BASE_ACTIVE,
2031 static int ep_collectible_only[] =
2053 EL_DYNABOMB_INCREASE_NUMBER,
2054 EL_DYNABOMB_INCREASE_SIZE,
2055 EL_DYNABOMB_INCREASE_POWER,
2075 static int ep_dont_run_into[] =
2077 /* same elements as in 'ep_dont_touch' */
2083 /* same elements as in 'ep_dont_collide_with' */
2095 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2099 EL_SP_BUGGY_BASE_ACTIVE,
2106 static int ep_dont_collide_with[] =
2108 /* same elements as in 'ep_dont_touch' */
2125 static int ep_dont_touch[] =
2135 static int ep_indestructible[] =
2139 EL_ACID_POOL_TOPLEFT,
2140 EL_ACID_POOL_TOPRIGHT,
2141 EL_ACID_POOL_BOTTOMLEFT,
2142 EL_ACID_POOL_BOTTOM,
2143 EL_ACID_POOL_BOTTOMRIGHT,
2144 EL_SP_HARDWARE_GRAY,
2145 EL_SP_HARDWARE_GREEN,
2146 EL_SP_HARDWARE_BLUE,
2148 EL_SP_HARDWARE_YELLOW,
2149 EL_SP_HARDWARE_BASE_1,
2150 EL_SP_HARDWARE_BASE_2,
2151 EL_SP_HARDWARE_BASE_3,
2152 EL_SP_HARDWARE_BASE_4,
2153 EL_SP_HARDWARE_BASE_5,
2154 EL_SP_HARDWARE_BASE_6,
2155 EL_INVISIBLE_STEELWALL,
2156 EL_INVISIBLE_STEELWALL_ACTIVE,
2157 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2158 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2159 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2160 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2161 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2162 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2163 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2164 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2165 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2166 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2167 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2168 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2170 EL_LIGHT_SWITCH_ACTIVE,
2171 EL_SIGN_EXCLAMATION,
2172 EL_SIGN_RADIOACTIVITY,
2183 EL_STEELWALL_SLIPPERY,
2197 EL_GATE_1_GRAY_ACTIVE,
2198 EL_GATE_2_GRAY_ACTIVE,
2199 EL_GATE_3_GRAY_ACTIVE,
2200 EL_GATE_4_GRAY_ACTIVE,
2209 EL_EM_GATE_1_GRAY_ACTIVE,
2210 EL_EM_GATE_2_GRAY_ACTIVE,
2211 EL_EM_GATE_3_GRAY_ACTIVE,
2212 EL_EM_GATE_4_GRAY_ACTIVE,
2221 EL_EMC_GATE_5_GRAY_ACTIVE,
2222 EL_EMC_GATE_6_GRAY_ACTIVE,
2223 EL_EMC_GATE_7_GRAY_ACTIVE,
2224 EL_EMC_GATE_8_GRAY_ACTIVE,
2226 EL_SWITCHGATE_OPENING,
2227 EL_SWITCHGATE_CLOSED,
2228 EL_SWITCHGATE_CLOSING,
2230 EL_SWITCHGATE_SWITCH_UP,
2231 EL_SWITCHGATE_SWITCH_DOWN,
2234 EL_TIMEGATE_OPENING,
2236 EL_TIMEGATE_CLOSING,
2239 EL_TIMEGATE_SWITCH_ACTIVE,
2244 EL_TUBE_VERTICAL_LEFT,
2245 EL_TUBE_VERTICAL_RIGHT,
2246 EL_TUBE_HORIZONTAL_UP,
2247 EL_TUBE_HORIZONTAL_DOWN,
2256 static int ep_slippery[] =
2270 EL_ROBOT_WHEEL_ACTIVE,
2276 EL_ACID_POOL_TOPLEFT,
2277 EL_ACID_POOL_TOPRIGHT,
2287 EL_STEELWALL_SLIPPERY,
2290 EL_EMC_WALL_SLIPPERY_1,
2291 EL_EMC_WALL_SLIPPERY_2,
2292 EL_EMC_WALL_SLIPPERY_3,
2293 EL_EMC_WALL_SLIPPERY_4,
2295 EL_EMC_MAGIC_BALL_ACTIVE,
2300 static int ep_can_change[] =
2305 static int ep_can_move[] =
2307 /* same elements as in 'pb_can_move_into_acid' */
2330 static int ep_can_fall[] =
2345 EL_BD_MAGIC_WALL_FULL,
2359 static int ep_can_smash_player[] =
2385 static int ep_can_smash_enemies[] =
2394 static int ep_can_smash_everything[] =
2403 static int ep_explodes_by_fire[] =
2405 /* same elements as in 'ep_explodes_impact' */
2410 /* same elements as in 'ep_explodes_smashed' */
2420 EL_EM_DYNAMITE_ACTIVE,
2421 EL_DYNABOMB_PLAYER_1_ACTIVE,
2422 EL_DYNABOMB_PLAYER_2_ACTIVE,
2423 EL_DYNABOMB_PLAYER_3_ACTIVE,
2424 EL_DYNABOMB_PLAYER_4_ACTIVE,
2425 EL_DYNABOMB_INCREASE_NUMBER,
2426 EL_DYNABOMB_INCREASE_SIZE,
2427 EL_DYNABOMB_INCREASE_POWER,
2428 EL_SP_DISK_RED_ACTIVE,
2442 static int ep_explodes_smashed[] =
2444 /* same elements as in 'ep_explodes_impact' */
2458 static int ep_explodes_impact[] =
2467 static int ep_walkable_over[] =
2471 EL_SOKOBAN_FIELD_EMPTY,
2483 EL_GATE_1_GRAY_ACTIVE,
2484 EL_GATE_2_GRAY_ACTIVE,
2485 EL_GATE_3_GRAY_ACTIVE,
2486 EL_GATE_4_GRAY_ACTIVE,
2494 static int ep_walkable_inside[] =
2499 EL_TUBE_VERTICAL_LEFT,
2500 EL_TUBE_VERTICAL_RIGHT,
2501 EL_TUBE_HORIZONTAL_UP,
2502 EL_TUBE_HORIZONTAL_DOWN,
2511 static int ep_walkable_under[] =
2516 static int ep_passable_over[] =
2526 EL_EM_GATE_1_GRAY_ACTIVE,
2527 EL_EM_GATE_2_GRAY_ACTIVE,
2528 EL_EM_GATE_3_GRAY_ACTIVE,
2529 EL_EM_GATE_4_GRAY_ACTIVE,
2538 EL_EMC_GATE_5_GRAY_ACTIVE,
2539 EL_EMC_GATE_6_GRAY_ACTIVE,
2540 EL_EMC_GATE_7_GRAY_ACTIVE,
2541 EL_EMC_GATE_8_GRAY_ACTIVE,
2548 static int ep_passable_inside[] =
2554 EL_SP_PORT_HORIZONTAL,
2555 EL_SP_PORT_VERTICAL,
2557 EL_SP_GRAVITY_PORT_LEFT,
2558 EL_SP_GRAVITY_PORT_RIGHT,
2559 EL_SP_GRAVITY_PORT_UP,
2560 EL_SP_GRAVITY_PORT_DOWN,
2561 EL_SP_GRAVITY_ON_PORT_LEFT,
2562 EL_SP_GRAVITY_ON_PORT_RIGHT,
2563 EL_SP_GRAVITY_ON_PORT_UP,
2564 EL_SP_GRAVITY_ON_PORT_DOWN,
2565 EL_SP_GRAVITY_OFF_PORT_LEFT,
2566 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2567 EL_SP_GRAVITY_OFF_PORT_UP,
2568 EL_SP_GRAVITY_OFF_PORT_DOWN,
2573 static int ep_passable_under[] =
2578 static int ep_droppable[] =
2583 static int ep_explodes_1x1_old[] =
2588 static int ep_pushable[] =
2600 EL_SOKOBAN_FIELD_FULL,
2609 static int ep_explodes_cross_old[] =
2614 static int ep_protected[] =
2616 /* same elements as in 'ep_walkable_inside' */
2620 EL_TUBE_VERTICAL_LEFT,
2621 EL_TUBE_VERTICAL_RIGHT,
2622 EL_TUBE_HORIZONTAL_UP,
2623 EL_TUBE_HORIZONTAL_DOWN,
2629 /* same elements as in 'ep_passable_over' */
2638 EL_EM_GATE_1_GRAY_ACTIVE,
2639 EL_EM_GATE_2_GRAY_ACTIVE,
2640 EL_EM_GATE_3_GRAY_ACTIVE,
2641 EL_EM_GATE_4_GRAY_ACTIVE,
2650 EL_EMC_GATE_5_GRAY_ACTIVE,
2651 EL_EMC_GATE_6_GRAY_ACTIVE,
2652 EL_EMC_GATE_7_GRAY_ACTIVE,
2653 EL_EMC_GATE_8_GRAY_ACTIVE,
2657 /* same elements as in 'ep_passable_inside' */
2662 EL_SP_PORT_HORIZONTAL,
2663 EL_SP_PORT_VERTICAL,
2665 EL_SP_GRAVITY_PORT_LEFT,
2666 EL_SP_GRAVITY_PORT_RIGHT,
2667 EL_SP_GRAVITY_PORT_UP,
2668 EL_SP_GRAVITY_PORT_DOWN,
2669 EL_SP_GRAVITY_ON_PORT_LEFT,
2670 EL_SP_GRAVITY_ON_PORT_RIGHT,
2671 EL_SP_GRAVITY_ON_PORT_UP,
2672 EL_SP_GRAVITY_ON_PORT_DOWN,
2673 EL_SP_GRAVITY_OFF_PORT_LEFT,
2674 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2675 EL_SP_GRAVITY_OFF_PORT_UP,
2676 EL_SP_GRAVITY_OFF_PORT_DOWN,
2681 static int ep_throwable[] =
2686 static int ep_can_explode[] =
2688 /* same elements as in 'ep_explodes_impact' */
2693 /* same elements as in 'ep_explodes_smashed' */
2699 /* elements that can explode by explosion or by dragonfire */
2703 EL_EM_DYNAMITE_ACTIVE,
2704 EL_DYNABOMB_PLAYER_1_ACTIVE,
2705 EL_DYNABOMB_PLAYER_2_ACTIVE,
2706 EL_DYNABOMB_PLAYER_3_ACTIVE,
2707 EL_DYNABOMB_PLAYER_4_ACTIVE,
2708 EL_DYNABOMB_INCREASE_NUMBER,
2709 EL_DYNABOMB_INCREASE_SIZE,
2710 EL_DYNABOMB_INCREASE_POWER,
2711 EL_SP_DISK_RED_ACTIVE,
2719 /* elements that can explode only by explosion */
2725 static int ep_gravity_reachable[] =
2731 EL_INVISIBLE_SAND_ACTIVE,
2736 EL_SP_PORT_HORIZONTAL,
2737 EL_SP_PORT_VERTICAL,
2739 EL_SP_GRAVITY_PORT_LEFT,
2740 EL_SP_GRAVITY_PORT_RIGHT,
2741 EL_SP_GRAVITY_PORT_UP,
2742 EL_SP_GRAVITY_PORT_DOWN,
2743 EL_SP_GRAVITY_ON_PORT_LEFT,
2744 EL_SP_GRAVITY_ON_PORT_RIGHT,
2745 EL_SP_GRAVITY_ON_PORT_UP,
2746 EL_SP_GRAVITY_ON_PORT_DOWN,
2747 EL_SP_GRAVITY_OFF_PORT_LEFT,
2748 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2749 EL_SP_GRAVITY_OFF_PORT_UP,
2750 EL_SP_GRAVITY_OFF_PORT_DOWN,
2756 static int ep_player[] =
2763 EL_SOKOBAN_FIELD_PLAYER,
2769 static int ep_can_pass_magic_wall[] =
2783 static int ep_switchable[] =
2787 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2788 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2789 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2790 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2791 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2792 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2793 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2794 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2795 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2796 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2797 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2798 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2799 EL_SWITCHGATE_SWITCH_UP,
2800 EL_SWITCHGATE_SWITCH_DOWN,
2802 EL_LIGHT_SWITCH_ACTIVE,
2804 EL_BALLOON_SWITCH_LEFT,
2805 EL_BALLOON_SWITCH_RIGHT,
2806 EL_BALLOON_SWITCH_UP,
2807 EL_BALLOON_SWITCH_DOWN,
2808 EL_BALLOON_SWITCH_ANY,
2809 EL_BALLOON_SWITCH_NONE,
2812 EL_EMC_MAGIC_BALL_SWITCH,
2813 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2818 static int ep_bd_element[] =
2852 static int ep_sp_element[] =
2854 /* should always be valid */
2857 /* standard classic Supaplex elements */
2864 EL_SP_HARDWARE_GRAY,
2872 EL_SP_GRAVITY_PORT_RIGHT,
2873 EL_SP_GRAVITY_PORT_DOWN,
2874 EL_SP_GRAVITY_PORT_LEFT,
2875 EL_SP_GRAVITY_PORT_UP,
2880 EL_SP_PORT_VERTICAL,
2881 EL_SP_PORT_HORIZONTAL,
2887 EL_SP_HARDWARE_BASE_1,
2888 EL_SP_HARDWARE_GREEN,
2889 EL_SP_HARDWARE_BLUE,
2891 EL_SP_HARDWARE_YELLOW,
2892 EL_SP_HARDWARE_BASE_2,
2893 EL_SP_HARDWARE_BASE_3,
2894 EL_SP_HARDWARE_BASE_4,
2895 EL_SP_HARDWARE_BASE_5,
2896 EL_SP_HARDWARE_BASE_6,
2900 /* additional elements that appeared in newer Supaplex levels */
2903 /* additional gravity port elements (not switching, but setting gravity) */
2904 EL_SP_GRAVITY_ON_PORT_LEFT,
2905 EL_SP_GRAVITY_ON_PORT_RIGHT,
2906 EL_SP_GRAVITY_ON_PORT_UP,
2907 EL_SP_GRAVITY_ON_PORT_DOWN,
2908 EL_SP_GRAVITY_OFF_PORT_LEFT,
2909 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2910 EL_SP_GRAVITY_OFF_PORT_UP,
2911 EL_SP_GRAVITY_OFF_PORT_DOWN,
2913 /* more than one Murphy in a level results in an inactive clone */
2916 /* runtime Supaplex elements */
2917 EL_SP_DISK_RED_ACTIVE,
2918 EL_SP_TERMINAL_ACTIVE,
2919 EL_SP_BUGGY_BASE_ACTIVATING,
2920 EL_SP_BUGGY_BASE_ACTIVE,
2927 static int ep_sb_element[] =
2932 EL_SOKOBAN_FIELD_EMPTY,
2933 EL_SOKOBAN_FIELD_FULL,
2934 EL_SOKOBAN_FIELD_PLAYER,
2939 EL_INVISIBLE_STEELWALL,
2944 static int ep_gem[] =
2956 static int ep_food_dark_yamyam[] =
2984 static int ep_food_penguin[] =
2998 static int ep_food_pig[] =
3010 static int ep_historic_wall[] =
3021 EL_GATE_1_GRAY_ACTIVE,
3022 EL_GATE_2_GRAY_ACTIVE,
3023 EL_GATE_3_GRAY_ACTIVE,
3024 EL_GATE_4_GRAY_ACTIVE,
3033 EL_EM_GATE_1_GRAY_ACTIVE,
3034 EL_EM_GATE_2_GRAY_ACTIVE,
3035 EL_EM_GATE_3_GRAY_ACTIVE,
3036 EL_EM_GATE_4_GRAY_ACTIVE,
3043 EL_EXPANDABLE_WALL_HORIZONTAL,
3044 EL_EXPANDABLE_WALL_VERTICAL,
3045 EL_EXPANDABLE_WALL_ANY,
3046 EL_EXPANDABLE_WALL_GROWING,
3047 EL_BD_EXPANDABLE_WALL,
3054 EL_SP_HARDWARE_GRAY,
3055 EL_SP_HARDWARE_GREEN,
3056 EL_SP_HARDWARE_BLUE,
3058 EL_SP_HARDWARE_YELLOW,
3059 EL_SP_HARDWARE_BASE_1,
3060 EL_SP_HARDWARE_BASE_2,
3061 EL_SP_HARDWARE_BASE_3,
3062 EL_SP_HARDWARE_BASE_4,
3063 EL_SP_HARDWARE_BASE_5,
3064 EL_SP_HARDWARE_BASE_6,
3066 EL_SP_TERMINAL_ACTIVE,
3069 EL_INVISIBLE_STEELWALL,
3070 EL_INVISIBLE_STEELWALL_ACTIVE,
3072 EL_INVISIBLE_WALL_ACTIVE,
3073 EL_STEELWALL_SLIPPERY,
3090 static int ep_historic_solid[] =
3094 EL_EXPANDABLE_WALL_HORIZONTAL,
3095 EL_EXPANDABLE_WALL_VERTICAL,
3096 EL_EXPANDABLE_WALL_ANY,
3097 EL_BD_EXPANDABLE_WALL,
3110 EL_QUICKSAND_FILLING,
3111 EL_QUICKSAND_EMPTYING,
3113 EL_MAGIC_WALL_ACTIVE,
3114 EL_MAGIC_WALL_EMPTYING,
3115 EL_MAGIC_WALL_FILLING,
3119 EL_BD_MAGIC_WALL_ACTIVE,
3120 EL_BD_MAGIC_WALL_EMPTYING,
3121 EL_BD_MAGIC_WALL_FULL,
3122 EL_BD_MAGIC_WALL_FILLING,
3123 EL_BD_MAGIC_WALL_DEAD,
3132 EL_SP_TERMINAL_ACTIVE,
3136 EL_INVISIBLE_WALL_ACTIVE,
3137 EL_SWITCHGATE_SWITCH_UP,
3138 EL_SWITCHGATE_SWITCH_DOWN,
3140 EL_TIMEGATE_SWITCH_ACTIVE,
3152 /* the following elements are a direct copy of "indestructible" elements,
3153 except "EL_ACID", which is "indestructible", but not "solid"! */
3158 EL_ACID_POOL_TOPLEFT,
3159 EL_ACID_POOL_TOPRIGHT,
3160 EL_ACID_POOL_BOTTOMLEFT,
3161 EL_ACID_POOL_BOTTOM,
3162 EL_ACID_POOL_BOTTOMRIGHT,
3163 EL_SP_HARDWARE_GRAY,
3164 EL_SP_HARDWARE_GREEN,
3165 EL_SP_HARDWARE_BLUE,
3167 EL_SP_HARDWARE_YELLOW,
3168 EL_SP_HARDWARE_BASE_1,
3169 EL_SP_HARDWARE_BASE_2,
3170 EL_SP_HARDWARE_BASE_3,
3171 EL_SP_HARDWARE_BASE_4,
3172 EL_SP_HARDWARE_BASE_5,
3173 EL_SP_HARDWARE_BASE_6,
3174 EL_INVISIBLE_STEELWALL,
3175 EL_INVISIBLE_STEELWALL_ACTIVE,
3176 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3177 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3178 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3179 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3180 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3181 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3182 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3183 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3184 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3185 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3186 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3187 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3189 EL_LIGHT_SWITCH_ACTIVE,
3190 EL_SIGN_EXCLAMATION,
3191 EL_SIGN_RADIOACTIVITY,
3202 EL_STEELWALL_SLIPPERY,
3216 EL_GATE_1_GRAY_ACTIVE,
3217 EL_GATE_2_GRAY_ACTIVE,
3218 EL_GATE_3_GRAY_ACTIVE,
3219 EL_GATE_4_GRAY_ACTIVE,
3228 EL_EM_GATE_1_GRAY_ACTIVE,
3229 EL_EM_GATE_2_GRAY_ACTIVE,
3230 EL_EM_GATE_3_GRAY_ACTIVE,
3231 EL_EM_GATE_4_GRAY_ACTIVE,
3233 EL_SWITCHGATE_OPENING,
3234 EL_SWITCHGATE_CLOSED,
3235 EL_SWITCHGATE_CLOSING,
3237 EL_TIMEGATE_OPENING,
3239 EL_TIMEGATE_CLOSING,
3243 EL_TUBE_VERTICAL_LEFT,
3244 EL_TUBE_VERTICAL_RIGHT,
3245 EL_TUBE_HORIZONTAL_UP,
3246 EL_TUBE_HORIZONTAL_DOWN,
3255 static int ep_classic_enemy[] =
3272 static int ep_belt[] =
3274 EL_CONVEYOR_BELT_1_LEFT,
3275 EL_CONVEYOR_BELT_1_MIDDLE,
3276 EL_CONVEYOR_BELT_1_RIGHT,
3277 EL_CONVEYOR_BELT_2_LEFT,
3278 EL_CONVEYOR_BELT_2_MIDDLE,
3279 EL_CONVEYOR_BELT_2_RIGHT,
3280 EL_CONVEYOR_BELT_3_LEFT,
3281 EL_CONVEYOR_BELT_3_MIDDLE,
3282 EL_CONVEYOR_BELT_3_RIGHT,
3283 EL_CONVEYOR_BELT_4_LEFT,
3284 EL_CONVEYOR_BELT_4_MIDDLE,
3285 EL_CONVEYOR_BELT_4_RIGHT,
3290 static int ep_belt_active[] =
3292 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3293 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3294 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3295 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3296 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3297 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3298 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3299 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3300 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3301 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3302 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3303 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3308 static int ep_belt_switch[] =
3310 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3311 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3312 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3313 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3314 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3315 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3316 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3317 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3318 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3319 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3320 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3321 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3326 static int ep_tube[] =
3333 EL_TUBE_HORIZONTAL_UP,
3334 EL_TUBE_HORIZONTAL_DOWN,
3336 EL_TUBE_VERTICAL_LEFT,
3337 EL_TUBE_VERTICAL_RIGHT,
3343 static int ep_keygate[] =
3353 EL_GATE_1_GRAY_ACTIVE,
3354 EL_GATE_2_GRAY_ACTIVE,
3355 EL_GATE_3_GRAY_ACTIVE,
3356 EL_GATE_4_GRAY_ACTIVE,
3365 EL_EM_GATE_1_GRAY_ACTIVE,
3366 EL_EM_GATE_2_GRAY_ACTIVE,
3367 EL_EM_GATE_3_GRAY_ACTIVE,
3368 EL_EM_GATE_4_GRAY_ACTIVE,
3377 EL_EMC_GATE_5_GRAY_ACTIVE,
3378 EL_EMC_GATE_6_GRAY_ACTIVE,
3379 EL_EMC_GATE_7_GRAY_ACTIVE,
3380 EL_EMC_GATE_8_GRAY_ACTIVE,
3385 static int ep_amoeboid[] =
3397 static int ep_amoebalive[] =
3408 static int ep_has_editor_content[] =
3430 static int ep_can_turn_each_move[] =
3432 /* !!! do something with this one !!! */
3436 static int ep_can_grow[] =
3450 static int ep_active_bomb[] =
3453 EL_EM_DYNAMITE_ACTIVE,
3454 EL_DYNABOMB_PLAYER_1_ACTIVE,
3455 EL_DYNABOMB_PLAYER_2_ACTIVE,
3456 EL_DYNABOMB_PLAYER_3_ACTIVE,
3457 EL_DYNABOMB_PLAYER_4_ACTIVE,
3458 EL_SP_DISK_RED_ACTIVE,
3463 static int ep_inactive[] =
3495 EL_GATE_1_GRAY_ACTIVE,
3496 EL_GATE_2_GRAY_ACTIVE,
3497 EL_GATE_3_GRAY_ACTIVE,
3498 EL_GATE_4_GRAY_ACTIVE,
3507 EL_EM_GATE_1_GRAY_ACTIVE,
3508 EL_EM_GATE_2_GRAY_ACTIVE,
3509 EL_EM_GATE_3_GRAY_ACTIVE,
3510 EL_EM_GATE_4_GRAY_ACTIVE,
3519 EL_EMC_GATE_5_GRAY_ACTIVE,
3520 EL_EMC_GATE_6_GRAY_ACTIVE,
3521 EL_EMC_GATE_7_GRAY_ACTIVE,
3522 EL_EMC_GATE_8_GRAY_ACTIVE,
3525 EL_INVISIBLE_STEELWALL,
3533 EL_WALL_EMERALD_YELLOW,
3534 EL_DYNABOMB_INCREASE_NUMBER,
3535 EL_DYNABOMB_INCREASE_SIZE,
3536 EL_DYNABOMB_INCREASE_POWER,
3540 EL_SOKOBAN_FIELD_EMPTY,
3541 EL_SOKOBAN_FIELD_FULL,
3542 EL_WALL_EMERALD_RED,
3543 EL_WALL_EMERALD_PURPLE,
3544 EL_ACID_POOL_TOPLEFT,
3545 EL_ACID_POOL_TOPRIGHT,
3546 EL_ACID_POOL_BOTTOMLEFT,
3547 EL_ACID_POOL_BOTTOM,
3548 EL_ACID_POOL_BOTTOMRIGHT,
3552 EL_BD_MAGIC_WALL_DEAD,
3553 EL_AMOEBA_TO_DIAMOND,
3561 EL_SP_GRAVITY_PORT_RIGHT,
3562 EL_SP_GRAVITY_PORT_DOWN,
3563 EL_SP_GRAVITY_PORT_LEFT,
3564 EL_SP_GRAVITY_PORT_UP,
3565 EL_SP_PORT_HORIZONTAL,
3566 EL_SP_PORT_VERTICAL,
3577 EL_SP_HARDWARE_GRAY,
3578 EL_SP_HARDWARE_GREEN,
3579 EL_SP_HARDWARE_BLUE,
3581 EL_SP_HARDWARE_YELLOW,
3582 EL_SP_HARDWARE_BASE_1,
3583 EL_SP_HARDWARE_BASE_2,
3584 EL_SP_HARDWARE_BASE_3,
3585 EL_SP_HARDWARE_BASE_4,
3586 EL_SP_HARDWARE_BASE_5,
3587 EL_SP_HARDWARE_BASE_6,
3588 EL_SP_GRAVITY_ON_PORT_LEFT,
3589 EL_SP_GRAVITY_ON_PORT_RIGHT,
3590 EL_SP_GRAVITY_ON_PORT_UP,
3591 EL_SP_GRAVITY_ON_PORT_DOWN,
3592 EL_SP_GRAVITY_OFF_PORT_LEFT,
3593 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3594 EL_SP_GRAVITY_OFF_PORT_UP,
3595 EL_SP_GRAVITY_OFF_PORT_DOWN,
3596 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3597 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3598 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3599 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3600 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3601 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3602 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3603 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3604 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3605 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3606 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3607 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3608 EL_SIGN_EXCLAMATION,
3609 EL_SIGN_RADIOACTIVITY,
3620 EL_STEELWALL_SLIPPERY,
3625 EL_EMC_WALL_SLIPPERY_1,
3626 EL_EMC_WALL_SLIPPERY_2,
3627 EL_EMC_WALL_SLIPPERY_3,
3628 EL_EMC_WALL_SLIPPERY_4,
3649 static int ep_em_slippery_wall[] =
3654 static int ep_gfx_crumbled[] =
3664 static int ep_editor_cascade_active[] =
3666 EL_INTERNAL_CASCADE_BD_ACTIVE,
3667 EL_INTERNAL_CASCADE_EM_ACTIVE,
3668 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3669 EL_INTERNAL_CASCADE_RND_ACTIVE,
3670 EL_INTERNAL_CASCADE_SB_ACTIVE,
3671 EL_INTERNAL_CASCADE_SP_ACTIVE,
3672 EL_INTERNAL_CASCADE_DC_ACTIVE,
3673 EL_INTERNAL_CASCADE_DX_ACTIVE,
3674 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3675 EL_INTERNAL_CASCADE_CE_ACTIVE,
3676 EL_INTERNAL_CASCADE_GE_ACTIVE,
3677 EL_INTERNAL_CASCADE_REF_ACTIVE,
3678 EL_INTERNAL_CASCADE_USER_ACTIVE,
3679 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3684 static int ep_editor_cascade_inactive[] =
3686 EL_INTERNAL_CASCADE_BD,
3687 EL_INTERNAL_CASCADE_EM,
3688 EL_INTERNAL_CASCADE_EMC,
3689 EL_INTERNAL_CASCADE_RND,
3690 EL_INTERNAL_CASCADE_SB,
3691 EL_INTERNAL_CASCADE_SP,
3692 EL_INTERNAL_CASCADE_DC,
3693 EL_INTERNAL_CASCADE_DX,
3694 EL_INTERNAL_CASCADE_CHARS,
3695 EL_INTERNAL_CASCADE_CE,
3696 EL_INTERNAL_CASCADE_GE,
3697 EL_INTERNAL_CASCADE_REF,
3698 EL_INTERNAL_CASCADE_USER,
3699 EL_INTERNAL_CASCADE_DYNAMIC,
3704 static int ep_obsolete[] =
3708 EL_EM_KEY_1_FILE_OBSOLETE,
3709 EL_EM_KEY_2_FILE_OBSOLETE,
3710 EL_EM_KEY_3_FILE_OBSOLETE,
3711 EL_EM_KEY_4_FILE_OBSOLETE,
3712 EL_ENVELOPE_OBSOLETE,
3721 } element_properties[] =
3723 { ep_diggable, EP_DIGGABLE },
3724 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3725 { ep_dont_run_into, EP_DONT_RUN_INTO },
3726 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3727 { ep_dont_touch, EP_DONT_TOUCH },
3728 { ep_indestructible, EP_INDESTRUCTIBLE },
3729 { ep_slippery, EP_SLIPPERY },
3730 { ep_can_change, EP_CAN_CHANGE },
3731 { ep_can_move, EP_CAN_MOVE },
3732 { ep_can_fall, EP_CAN_FALL },
3733 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3734 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3735 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3736 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3737 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3738 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3739 { ep_walkable_over, EP_WALKABLE_OVER },
3740 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3741 { ep_walkable_under, EP_WALKABLE_UNDER },
3742 { ep_passable_over, EP_PASSABLE_OVER },
3743 { ep_passable_inside, EP_PASSABLE_INSIDE },
3744 { ep_passable_under, EP_PASSABLE_UNDER },
3745 { ep_droppable, EP_DROPPABLE },
3746 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3747 { ep_pushable, EP_PUSHABLE },
3748 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3749 { ep_protected, EP_PROTECTED },
3750 { ep_throwable, EP_THROWABLE },
3751 { ep_can_explode, EP_CAN_EXPLODE },
3752 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3754 { ep_player, EP_PLAYER },
3755 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3756 { ep_switchable, EP_SWITCHABLE },
3757 { ep_bd_element, EP_BD_ELEMENT },
3758 { ep_sp_element, EP_SP_ELEMENT },
3759 { ep_sb_element, EP_SB_ELEMENT },
3761 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3762 { ep_food_penguin, EP_FOOD_PENGUIN },
3763 { ep_food_pig, EP_FOOD_PIG },
3764 { ep_historic_wall, EP_HISTORIC_WALL },
3765 { ep_historic_solid, EP_HISTORIC_SOLID },
3766 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3767 { ep_belt, EP_BELT },
3768 { ep_belt_active, EP_BELT_ACTIVE },
3769 { ep_belt_switch, EP_BELT_SWITCH },
3770 { ep_tube, EP_TUBE },
3771 { ep_keygate, EP_KEYGATE },
3772 { ep_amoeboid, EP_AMOEBOID },
3773 { ep_amoebalive, EP_AMOEBALIVE },
3774 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3775 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3776 { ep_can_grow, EP_CAN_GROW },
3777 { ep_active_bomb, EP_ACTIVE_BOMB },
3778 { ep_inactive, EP_INACTIVE },
3780 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3782 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3784 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3785 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3787 { ep_obsolete, EP_OBSOLETE },
3794 /* always start with reliable default values (element has no properties) */
3795 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3796 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3797 SET_PROPERTY(i, j, FALSE);
3799 /* set all base element properties from above array definitions */
3800 for (i = 0; element_properties[i].elements != NULL; i++)
3801 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3802 SET_PROPERTY((element_properties[i].elements)[j],
3803 element_properties[i].property, TRUE);
3805 /* copy properties to some elements that are only stored in level file */
3806 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3807 for (j = 0; copy_properties[j][0] != -1; j++)
3808 if (HAS_PROPERTY(copy_properties[j][0], i))
3809 for (k = 1; k <= 4; k++)
3810 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3813 void InitElementPropertiesEngine(int engine_version)
3815 static int no_wall_properties[] =
3818 EP_COLLECTIBLE_ONLY,
3820 EP_DONT_COLLIDE_WITH,
3823 EP_CAN_SMASH_PLAYER,
3824 EP_CAN_SMASH_ENEMIES,
3825 EP_CAN_SMASH_EVERYTHING,
3830 EP_FOOD_DARK_YAMYAM,
3846 /* important: after initialization in InitElementPropertiesStatic(), the
3847 elements are not again initialized to a default value; therefore all
3848 changes have to make sure that they leave the element with a defined
3849 property (which means that conditional property changes must be set to
3850 a reliable default value before) */
3852 /* ---------- recursively resolve group elements ------------------------- */
3854 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3855 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3856 element_info[i].in_group[j] = FALSE;
3858 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3859 resolve_group_element(EL_GROUP_START + i, 0);
3861 /* set all special, combined or engine dependent element properties */
3862 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3864 /* ---------- INACTIVE ------------------------------------------------- */
3865 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3867 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3868 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3869 IS_WALKABLE_INSIDE(i) ||
3870 IS_WALKABLE_UNDER(i)));
3872 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3873 IS_PASSABLE_INSIDE(i) ||
3874 IS_PASSABLE_UNDER(i)));
3876 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3877 IS_PASSABLE_OVER(i)));
3879 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3880 IS_PASSABLE_INSIDE(i)));
3882 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3883 IS_PASSABLE_UNDER(i)));
3885 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3888 /* ---------- COLLECTIBLE ---------------------------------------------- */
3889 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3893 /* ---------- SNAPPABLE ------------------------------------------------ */
3894 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3895 IS_COLLECTIBLE(i) ||
3899 /* ---------- WALL ----------------------------------------------------- */
3900 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3902 for (j = 0; no_wall_properties[j] != -1; j++)
3903 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3904 i >= EL_FIRST_RUNTIME_UNREAL)
3905 SET_PROPERTY(i, EP_WALL, FALSE);
3907 if (IS_HISTORIC_WALL(i))
3908 SET_PROPERTY(i, EP_WALL, TRUE);
3910 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3911 if (engine_version < VERSION_IDENT(2,2,0,0))
3912 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3914 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3916 !IS_COLLECTIBLE(i)));
3918 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3920 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3921 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3923 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3924 IS_INDESTRUCTIBLE(i)));
3926 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3928 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3929 else if (engine_version < VERSION_IDENT(2,2,0,0))
3930 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3932 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3936 if (IS_CUSTOM_ELEMENT(i))
3938 /* these are additional properties which are initially false when set */
3940 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3942 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3943 if (DONT_COLLIDE_WITH(i))
3944 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3946 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3947 if (CAN_SMASH_EVERYTHING(i))
3948 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3949 if (CAN_SMASH_ENEMIES(i))
3950 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3953 /* ---------- CAN_SMASH ------------------------------------------------ */
3954 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3955 CAN_SMASH_ENEMIES(i) ||
3956 CAN_SMASH_EVERYTHING(i)));
3958 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3959 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3960 EXPLODES_BY_FIRE(i)));
3962 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3963 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3964 EXPLODES_SMASHED(i)));
3966 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3967 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3968 EXPLODES_IMPACT(i)));
3970 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3971 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3973 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3974 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3975 i == EL_BLACK_ORB));
3977 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3978 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3980 IS_CUSTOM_ELEMENT(i)));
3982 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3983 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3984 i == EL_SP_ELECTRON));
3986 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3987 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3988 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3989 getMoveIntoAcidProperty(&level, i));
3991 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3992 if (MAYBE_DONT_COLLIDE_WITH(i))
3993 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3994 getDontCollideWithProperty(&level, i));
3996 /* ---------- SP_PORT -------------------------------------------------- */
3997 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3998 IS_PASSABLE_INSIDE(i)));
4000 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4001 for (j = 0; j < level.num_android_clone_elements; j++)
4002 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4004 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4006 /* ---------- CAN_CHANGE ----------------------------------------------- */
4007 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4008 for (j = 0; j < element_info[i].num_change_pages; j++)
4009 if (element_info[i].change_page[j].can_change)
4010 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4012 /* ---------- HAS_ACTION ----------------------------------------------- */
4013 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4014 for (j = 0; j < element_info[i].num_change_pages; j++)
4015 if (element_info[i].change_page[j].has_action)
4016 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4018 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4019 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4022 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4024 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4025 element_info[i].crumbled[ACTION_DEFAULT] !=
4026 element_info[i].graphic[ACTION_DEFAULT]);
4028 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4029 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4030 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4033 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4034 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4035 IS_EDITOR_CASCADE_INACTIVE(i)));
4038 /* dynamically adjust element properties according to game engine version */
4040 static int ep_em_slippery_wall[] =
4045 EL_EXPANDABLE_WALL_HORIZONTAL,
4046 EL_EXPANDABLE_WALL_VERTICAL,
4047 EL_EXPANDABLE_WALL_ANY,
4051 /* special EM style gems behaviour */
4052 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4053 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4054 level.em_slippery_gems);
4056 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4057 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4058 (level.em_slippery_gems &&
4059 engine_version > VERSION_IDENT(2,0,1,0)));
4062 /* this is needed because some graphics depend on element properties */
4063 if (game_status == GAME_MODE_PLAYING)
4064 InitElementGraphicInfo();
4067 void InitElementPropertiesAfterLoading(int engine_version)
4071 /* set some other uninitialized values of custom elements in older levels */
4072 if (engine_version < VERSION_IDENT(3,1,0,0))
4074 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4076 int element = EL_CUSTOM_START + i;
4078 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4080 element_info[element].explosion_delay = 17;
4081 element_info[element].ignition_delay = 8;
4086 static void InitGlobal()
4090 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4092 /* check if element_name_info entry defined for each element in "main.h" */
4093 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4094 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4096 element_info[i].token_name = element_name_info[i].token_name;
4097 element_info[i].class_name = element_name_info[i].class_name;
4098 element_info[i].editor_description=element_name_info[i].editor_description;
4101 global.autoplay_leveldir = NULL;
4102 global.convert_leveldir = NULL;
4104 global.frames_per_second = 0;
4105 global.fps_slowdown = FALSE;
4106 global.fps_slowdown_factor = 1;
4109 void Execute_Command(char *command)
4113 if (strEqual(command, "print graphicsinfo.conf"))
4115 printf("# You can configure additional/alternative image files here.\n");
4116 printf("# (The entries below are default and therefore commented out.)\n");
4118 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4120 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4123 for (i = 0; image_config[i].token != NULL; i++)
4124 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4125 image_config[i].value));
4129 else if (strEqual(command, "print soundsinfo.conf"))
4131 printf("# You can configure additional/alternative sound files here.\n");
4132 printf("# (The entries below are default and therefore commented out.)\n");
4134 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4136 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4139 for (i = 0; sound_config[i].token != NULL; i++)
4140 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4141 sound_config[i].value));
4145 else if (strEqual(command, "print musicinfo.conf"))
4147 printf("# You can configure additional/alternative music files here.\n");
4148 printf("# (The entries below are default and therefore commented out.)\n");
4150 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4152 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4155 for (i = 0; music_config[i].token != NULL; i++)
4156 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4157 music_config[i].value));
4161 else if (strEqual(command, "print editorsetup.conf"))
4163 printf("# You can configure your personal editor element list here.\n");
4164 printf("# (The entries below are default and therefore commented out.)\n");
4167 /* this is needed to be able to check element list for cascade elements */
4168 InitElementPropertiesStatic();
4169 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4171 PrintEditorElementList();
4175 else if (strEqual(command, "print helpanim.conf"))
4177 printf("# You can configure different element help animations here.\n");
4178 printf("# (The entries below are default and therefore commented out.)\n");
4181 for (i = 0; helpanim_config[i].token != NULL; i++)
4183 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4184 helpanim_config[i].value));
4186 if (strEqual(helpanim_config[i].token, "end"))
4192 else if (strEqual(command, "print helptext.conf"))
4194 printf("# You can configure different element help text here.\n");
4195 printf("# (The entries below are default and therefore commented out.)\n");
4198 for (i = 0; helptext_config[i].token != NULL; i++)
4199 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4200 helptext_config[i].value));
4204 else if (strncmp(command, "dump level ", 11) == 0)
4206 char *filename = &command[11];
4208 if (!fileExists(filename))
4209 Error(ERR_EXIT, "cannot open file '%s'", filename);
4211 LoadLevelFromFilename(&level, filename);
4216 else if (strncmp(command, "dump tape ", 10) == 0)
4218 char *filename = &command[10];
4220 if (!fileExists(filename))
4221 Error(ERR_EXIT, "cannot open file '%s'", filename);
4223 LoadTapeFromFilename(filename);
4228 else if (strncmp(command, "autoplay ", 9) == 0)
4230 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4232 while (*str_ptr != '\0') /* continue parsing string */
4234 /* cut leading whitespace from string, replace it by string terminator */
4235 while (*str_ptr == ' ' || *str_ptr == '\t')
4238 if (*str_ptr == '\0') /* end of string reached */
4241 if (global.autoplay_leveldir == NULL) /* read level set string */
4243 global.autoplay_leveldir = str_ptr;
4244 global.autoplay_all = TRUE; /* default: play all tapes */
4246 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4247 global.autoplay_level[i] = FALSE;
4249 else /* read level number string */
4251 int level_nr = atoi(str_ptr); /* get level_nr value */
4253 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4254 global.autoplay_level[level_nr] = TRUE;
4256 global.autoplay_all = FALSE;
4259 /* advance string pointer to the next whitespace (or end of string) */
4260 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4264 else if (strncmp(command, "convert ", 8) == 0)
4266 char *str_copy = getStringCopy(&command[8]);
4267 char *str_ptr = strchr(str_copy, ' ');
4269 global.convert_leveldir = str_copy;
4270 global.convert_level_nr = -1;
4272 if (str_ptr != NULL) /* level number follows */
4274 *str_ptr++ = '\0'; /* terminate leveldir string */
4275 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4280 #if defined(TARGET_SDL)
4281 else if (strEqual(command, "SDL_ListModes"))
4286 SDL_Init(SDL_INIT_VIDEO);
4288 /* get available fullscreen/hardware modes */
4289 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4291 /* check if there are any modes available */
4294 printf("No modes available!\n");
4299 /* check if our resolution is restricted */
4300 if (modes == (SDL_Rect **)-1)
4302 printf("All resolutions available.\n");
4306 printf("Available Modes:\n");
4308 for(i = 0; modes[i]; i++)
4309 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4319 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4323 static void InitSetup()
4325 LoadSetup(); /* global setup info */
4327 /* set some options from setup file */
4329 if (setup.options.verbose)
4330 options.verbose = TRUE;
4333 static void InitGameInfo()
4335 game.restart_level = FALSE;
4338 static void InitPlayerInfo()
4342 /* choose default local player */
4343 local_player = &stored_player[0];
4345 for (i = 0; i < MAX_PLAYERS; i++)
4346 stored_player[i].connected = FALSE;
4348 local_player->connected = TRUE;
4351 static void InitArtworkInfo()
4356 static char *get_string_in_brackets(char *string)
4358 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4360 sprintf(string_in_brackets, "[%s]", string);
4362 return string_in_brackets;
4365 static char *get_level_id_suffix(int id_nr)
4367 char *id_suffix = checked_malloc(1 + 3 + 1);
4369 if (id_nr < 0 || id_nr > 999)
4372 sprintf(id_suffix, ".%03d", id_nr);
4378 static char *get_element_class_token(int element)
4380 char *element_class_name = element_info[element].class_name;
4381 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4383 sprintf(element_class_token, "[%s]", element_class_name);
4385 return element_class_token;
4388 static char *get_action_class_token(int action)
4390 char *action_class_name = &element_action_info[action].suffix[1];
4391 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4393 sprintf(action_class_token, "[%s]", action_class_name);
4395 return action_class_token;
4399 static void InitArtworkConfig()
4401 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4402 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4403 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4404 static char *action_id_suffix[NUM_ACTIONS + 1];
4405 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4406 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4407 static char *level_id_suffix[MAX_LEVELS + 1];
4408 static char *dummy[1] = { NULL };
4409 static char *ignore_generic_tokens[] =
4415 static char **ignore_image_tokens;
4416 static char **ignore_sound_tokens;
4417 static char **ignore_music_tokens;
4418 int num_ignore_generic_tokens;
4419 int num_ignore_image_tokens;
4420 int num_ignore_sound_tokens;
4421 int num_ignore_music_tokens;
4424 /* dynamically determine list of generic tokens to be ignored */
4425 num_ignore_generic_tokens = 0;
4426 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4427 num_ignore_generic_tokens++;
4429 /* dynamically determine list of image tokens to be ignored */
4430 num_ignore_image_tokens = num_ignore_generic_tokens;
4431 for (i = 0; image_config_vars[i].token != NULL; i++)
4432 num_ignore_image_tokens++;
4433 ignore_image_tokens =
4434 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4435 for (i = 0; i < num_ignore_generic_tokens; i++)
4436 ignore_image_tokens[i] = ignore_generic_tokens[i];
4437 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4438 ignore_image_tokens[num_ignore_generic_tokens + i] =
4439 image_config_vars[i].token;
4440 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4442 /* dynamically determine list of sound tokens to be ignored */
4443 num_ignore_sound_tokens = num_ignore_generic_tokens;
4444 ignore_sound_tokens =
4445 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4446 for (i = 0; i < num_ignore_generic_tokens; i++)
4447 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4448 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4450 /* dynamically determine list of music tokens to be ignored */
4451 num_ignore_music_tokens = num_ignore_generic_tokens;
4452 ignore_music_tokens =
4453 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4454 for (i = 0; i < num_ignore_generic_tokens; i++)
4455 ignore_music_tokens[i] = ignore_generic_tokens[i];
4456 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4458 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4459 image_id_prefix[i] = element_info[i].token_name;
4460 for (i = 0; i < NUM_FONTS; i++)
4461 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4462 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4464 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4465 sound_id_prefix[i] = element_info[i].token_name;
4466 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4467 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4468 get_string_in_brackets(element_info[i].class_name);
4469 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4471 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4472 music_id_prefix[i] = music_prefix_info[i].prefix;
4473 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4475 for (i = 0; i < NUM_ACTIONS; i++)
4476 action_id_suffix[i] = element_action_info[i].suffix;
4477 action_id_suffix[NUM_ACTIONS] = NULL;
4479 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4480 direction_id_suffix[i] = element_direction_info[i].suffix;
4481 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4483 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4484 special_id_suffix[i] = special_suffix_info[i].suffix;
4485 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4487 for (i = 0; i < MAX_LEVELS; i++)
4488 level_id_suffix[i] = get_level_id_suffix(i);
4489 level_id_suffix[MAX_LEVELS] = NULL;
4491 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4492 image_id_prefix, action_id_suffix, direction_id_suffix,
4493 special_id_suffix, ignore_image_tokens);
4494 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4495 sound_id_prefix, action_id_suffix, dummy,
4496 special_id_suffix, ignore_sound_tokens);
4497 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4498 music_id_prefix, special_id_suffix, level_id_suffix,
4499 dummy, ignore_music_tokens);
4502 static void InitMixer()
4510 char *filename_font_initial = NULL;
4511 Bitmap *bitmap_font_initial = NULL;
4515 /* determine settings for initial font (for displaying startup messages) */
4516 for (i = 0; image_config[i].token != NULL; i++)
4518 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4520 char font_token[128];
4523 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4524 len_font_token = strlen(font_token);
4526 if (strEqual(image_config[i].token, font_token))
4527 filename_font_initial = image_config[i].value;
4528 else if (strlen(image_config[i].token) > len_font_token &&
4529 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4531 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4532 font_initial[j].src_x = atoi(image_config[i].value);
4533 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4534 font_initial[j].src_y = atoi(image_config[i].value);
4535 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4536 font_initial[j].width = atoi(image_config[i].value);
4537 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4538 font_initial[j].height = atoi(image_config[i].value);
4543 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4545 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4546 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4549 if (filename_font_initial == NULL) /* should not happen */
4550 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4552 /* create additional image buffers for double-buffering and cross-fading */
4553 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4554 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4555 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4556 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4558 /* initialize screen properties */
4559 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4560 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4562 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4563 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4564 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4566 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4568 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4569 font_initial[j].bitmap = bitmap_font_initial;
4571 InitFontGraphicInfo();
4573 font_height = getFontHeight(FC_RED);
4576 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4578 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4580 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4581 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4583 DrawInitText("Loading graphics", 120, FC_GREEN);
4586 void RedrawBackground()
4588 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4589 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4591 redraw_mask = REDRAW_ALL;
4594 void InitGfxBackground()
4598 fieldbuffer = bitmap_db_field;
4599 SetDrawtoField(DRAW_BACKBUFFER);
4603 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4604 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4606 for (x = 0; x < MAX_BUF_XSIZE; x++)
4607 for (y = 0; y < MAX_BUF_YSIZE; y++)
4610 redraw_mask = REDRAW_ALL;
4613 static void InitLevelInfo()
4615 LoadLevelInfo(); /* global level info */
4616 LoadLevelSetup_LastSeries(); /* last played series info */
4617 LoadLevelSetup_SeriesInfo(); /* last played level info */
4620 void InitLevelArtworkInfo()
4622 LoadLevelArtworkInfo();
4625 static void InitImages()
4627 setLevelArtworkDir(artwork.gfx_first);
4630 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4631 leveldir_current->identifier,
4632 artwork.gfx_current_identifier,
4633 artwork.gfx_current->identifier,
4634 leveldir_current->graphics_set,
4635 leveldir_current->graphics_path);
4638 ReloadCustomImages();
4640 LoadCustomElementDescriptions();
4641 LoadSpecialMenuDesignSettings();
4643 ReinitializeGraphics();
4646 static void InitSound(char *identifier)
4648 if (identifier == NULL)
4649 identifier = artwork.snd_current->identifier;
4651 /* set artwork path to send it to the sound server process */
4652 setLevelArtworkDir(artwork.snd_first);
4654 InitReloadCustomSounds(identifier);
4655 ReinitializeSounds();
4658 static void InitMusic(char *identifier)
4660 if (identifier == NULL)
4661 identifier = artwork.mus_current->identifier;
4663 /* set artwork path to send it to the sound server process */
4664 setLevelArtworkDir(artwork.mus_first);
4666 InitReloadCustomMusic(identifier);
4667 ReinitializeMusic();
4670 void InitNetworkServer()
4672 #if defined(NETWORK_AVALIABLE)
4676 if (!options.network)
4679 #if defined(NETWORK_AVALIABLE)
4680 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4682 if (!ConnectToServer(options.server_host, options.server_port))
4683 Error(ERR_EXIT, "cannot connect to network game server");
4685 SendToServer_PlayerName(setup.player_name);
4686 SendToServer_ProtocolVersion();
4689 SendToServer_NrWanted(nr_wanted);
4693 static char *getNewArtworkIdentifier(int type)
4695 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4696 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4697 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4698 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4699 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4700 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4701 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4702 char *leveldir_identifier = leveldir_current->identifier;
4704 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4705 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4707 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4709 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4710 char *artwork_current_identifier;
4711 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4713 /* leveldir_current may be invalid (level group, parent link) */
4714 if (!validLevelSeries(leveldir_current))
4717 /* 1st step: determine artwork set to be activated in descending order:
4718 --------------------------------------------------------------------
4719 1. setup artwork (when configured to override everything else)
4720 2. artwork set configured in "levelinfo.conf" of current level set
4721 (artwork in level directory will have priority when loading later)
4722 3. artwork in level directory (stored in artwork sub-directory)
4723 4. setup artwork (currently configured in setup menu) */
4725 if (setup_override_artwork)
4726 artwork_current_identifier = setup_artwork_set;
4727 else if (leveldir_artwork_set != NULL)
4728 artwork_current_identifier = leveldir_artwork_set;
4729 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4730 artwork_current_identifier = leveldir_identifier;
4732 artwork_current_identifier = setup_artwork_set;
4735 /* 2nd step: check if it is really needed to reload artwork set
4736 ------------------------------------------------------------ */
4739 if (type == ARTWORK_TYPE_GRAPHICS)
4740 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4741 artwork_new_identifier,
4742 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4743 artwork_current_identifier,
4744 leveldir_current->graphics_set,
4745 leveldir_current->identifier);
4748 /* ---------- reload if level set and also artwork set has changed ------- */
4749 if (leveldir_current_identifier[type] != leveldir_identifier &&
4750 (last_has_level_artwork_set[type] || has_level_artwork_set))
4751 artwork_new_identifier = artwork_current_identifier;
4753 leveldir_current_identifier[type] = leveldir_identifier;
4754 last_has_level_artwork_set[type] = has_level_artwork_set;
4757 if (type == ARTWORK_TYPE_GRAPHICS)
4758 printf("::: 1: '%s'\n", artwork_new_identifier);
4761 /* ---------- reload if "override artwork" setting has changed ----------- */
4762 if (last_override_level_artwork[type] != setup_override_artwork)
4763 artwork_new_identifier = artwork_current_identifier;
4765 last_override_level_artwork[type] = setup_override_artwork;
4768 if (type == ARTWORK_TYPE_GRAPHICS)
4769 printf("::: 2: '%s'\n", artwork_new_identifier);
4772 /* ---------- reload if current artwork identifier has changed ----------- */
4773 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4774 artwork_current_identifier))
4775 artwork_new_identifier = artwork_current_identifier;
4777 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4780 if (type == ARTWORK_TYPE_GRAPHICS)
4781 printf("::: 3: '%s'\n", artwork_new_identifier);
4784 /* ---------- do not reload directly after starting ---------------------- */
4785 if (!initialized[type])
4786 artwork_new_identifier = NULL;
4788 initialized[type] = TRUE;
4791 if (type == ARTWORK_TYPE_GRAPHICS)
4792 printf("::: 4: '%s'\n", artwork_new_identifier);
4796 if (type == ARTWORK_TYPE_GRAPHICS)
4797 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4798 artwork.gfx_current_identifier, artwork_current_identifier,
4799 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4800 artwork_new_identifier);
4803 return artwork_new_identifier;
4806 void ReloadCustomArtwork(int force_reload)
4808 char *gfx_new_identifier;
4809 char *snd_new_identifier;
4810 char *mus_new_identifier;
4811 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4812 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4813 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4814 boolean redraw_screen = FALSE;
4816 force_reload_gfx |= AdjustGraphicsForEMC();
4818 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4819 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4820 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4822 if (gfx_new_identifier != NULL || force_reload_gfx)
4825 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4826 artwork.gfx_current_identifier,
4828 artwork.gfx_current->identifier,
4829 leveldir_current->graphics_set);
4832 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4836 redraw_screen = TRUE;
4839 if (snd_new_identifier != NULL || force_reload_snd)
4841 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4843 InitSound(snd_new_identifier);
4845 redraw_screen = TRUE;
4848 if (mus_new_identifier != NULL || force_reload_mus)
4850 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4852 InitMusic(mus_new_identifier);
4854 redraw_screen = TRUE;
4861 /* force redraw of (open or closed) door graphics */
4862 SetDoorState(DOOR_OPEN_ALL);
4863 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4867 void KeyboardAutoRepeatOffUnlessAutoplay()
4869 if (global.autoplay_leveldir == NULL)
4870 KeyboardAutoRepeatOff();
4874 /* ========================================================================= */
4876 /* ========================================================================= */
4880 InitGlobal(); /* initialize some global variables */
4882 if (options.execute_command)
4883 Execute_Command(options.execute_command);
4885 if (options.serveronly)
4887 #if defined(PLATFORM_UNIX)
4888 NetworkServer(options.server_port, options.serveronly);
4890 Error(ERR_WARN, "networking only supported in Unix version");
4893 exit(0); /* never reached, server loops forever */
4900 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4901 InitArtworkConfig(); /* needed before forking sound child process */
4906 InitRND(NEW_RANDOMIZE);
4907 InitSimpleRandom(NEW_RANDOMIZE);
4912 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
4914 InitEventFilter(FilterMouseMotionEvents);
4916 InitElementPropertiesStatic();
4917 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4921 // debug_print_timestamp(0, "INIT");
4923 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
4924 InitLevelArtworkInfo();
4925 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
4927 InitImages(); /* needs to know current level directory */
4928 InitSound(NULL); /* needs to know current level directory */
4929 InitMusic(NULL); /* needs to know current level directory */
4931 InitGfxBackground();
4937 if (global.autoplay_leveldir)
4942 else if (global.convert_leveldir)
4948 game_status = GAME_MODE_MAIN;
4952 InitNetworkServer();
4955 void CloseAllAndExit(int exit_value)
4960 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4968 #if defined(TARGET_SDL)
4969 if (network_server) /* terminate network server */
4970 SDL_KillThread(server_thread);
4973 CloseVideoDisplay();
4974 ClosePlatformDependentStuff();
4976 if (exit_value != 0)
4977 NotifyUserAboutErrorFile();