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 if (graphic_info[graphic].use_image_size)
980 /* set default bitmap size (with scaling, but without small images) */
981 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
982 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
986 /* optional x and y tile position of animation frame sequence */
987 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
989 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
992 /* optional x and y pixel position of animation frame sequence */
993 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
995 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
996 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
998 /* optional width and height of each animation frame */
999 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1000 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1001 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1002 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1004 /* optional zoom factor for scaling up the image to a larger size */
1005 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1006 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1007 if (graphic_info[graphic].scale_up_factor < 1)
1008 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1012 /* get final bitmap size (with scaling, but without small images) */
1013 int src_image_width = get_scaled_graphic_width(graphic);
1014 int src_image_height = get_scaled_graphic_height(graphic);
1016 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1017 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1019 graphic_info[graphic].src_image_width = src_image_width;
1020 graphic_info[graphic].src_image_height = src_image_height;
1023 /* correct x or y offset dependent of vertical or horizontal frame order */
1024 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1026 graphic_info[graphic].offset_y =
1027 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1028 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1029 anim_frames_per_line = anim_frames_per_col;
1031 else /* frames are ordered horizontally */
1033 graphic_info[graphic].offset_x =
1034 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1035 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1036 anim_frames_per_line = anim_frames_per_row;
1039 /* optionally, the x and y offset of frames can be specified directly */
1040 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1041 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1042 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1043 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1045 /* optionally, moving animations may have separate start and end graphics */
1046 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1048 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1049 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1051 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1052 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1053 graphic_info[graphic].offset2_y =
1054 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1055 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1056 else /* frames are ordered horizontally */
1057 graphic_info[graphic].offset2_x =
1058 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1059 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1061 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1062 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1063 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1064 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1065 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1067 /* optionally, the second movement tile can be specified as start tile */
1068 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1069 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1071 /* automatically determine correct number of frames, if not defined */
1072 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1074 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1075 graphic_info[graphic].anim_frames = anim_frames_per_row;
1076 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1077 graphic_info[graphic].anim_frames = anim_frames_per_col;
1079 graphic_info[graphic].anim_frames = 1;
1081 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1082 graphic_info[graphic].anim_frames = 1;
1084 graphic_info[graphic].anim_frames_per_line =
1085 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1086 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1088 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1089 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1090 graphic_info[graphic].anim_delay = 1;
1092 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1094 if (graphic_info[graphic].anim_frames == 1)
1095 graphic_info[graphic].anim_mode = ANIM_NONE;
1098 /* automatically determine correct start frame, if not defined */
1099 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1100 graphic_info[graphic].anim_start_frame = 0;
1101 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1102 graphic_info[graphic].anim_start_frame =
1103 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1105 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1107 /* animation synchronized with global frame counter, not move position */
1108 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1110 /* optional element for cloning crumble graphics */
1111 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1112 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1114 /* optional element for cloning digging graphics */
1115 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1116 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1118 /* optional border size for "crumbling" diggable graphics */
1119 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1120 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1122 /* this is only used for player "boring" and "sleeping" actions */
1123 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].anim_delay_fixed =
1125 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1126 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1127 graphic_info[graphic].anim_delay_random =
1128 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1129 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1130 graphic_info[graphic].post_delay_fixed =
1131 parameter[GFX_ARG_POST_DELAY_FIXED];
1132 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1133 graphic_info[graphic].post_delay_random =
1134 parameter[GFX_ARG_POST_DELAY_RANDOM];
1136 /* this is only used for toon animations */
1137 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1138 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1140 /* this is only used for drawing font characters */
1141 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1142 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1144 /* this is only used for drawing envelope graphics */
1145 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1147 /* optional graphic for cloning all graphics settings */
1148 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1149 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1151 /* optional settings for drawing title screens */
1152 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1153 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1154 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1155 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1156 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1157 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1160 static void set_cloned_graphic_parameters(int graphic)
1162 int fallback_graphic = IMG_CHAR_EXCLAM;
1163 int max_num_images = getImageListSize();
1164 int clone_graphic = graphic_info[graphic].clone_from;
1165 int num_references_followed = 1;
1167 while (graphic_info[clone_graphic].clone_from != -1 &&
1168 num_references_followed < max_num_images)
1170 clone_graphic = graphic_info[clone_graphic].clone_from;
1172 num_references_followed++;
1175 if (num_references_followed >= max_num_images)
1177 Error(ERR_RETURN_LINE, "-");
1178 Error(ERR_RETURN, "warning: error found in config file:");
1179 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1180 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1181 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1182 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1184 if (graphic == fallback_graphic)
1185 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1187 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1188 Error(ERR_RETURN_LINE, "-");
1190 graphic_info[graphic] = graphic_info[fallback_graphic];
1194 graphic_info[graphic] = graphic_info[clone_graphic];
1195 graphic_info[graphic].clone_from = clone_graphic;
1199 static void InitGraphicInfo()
1201 int fallback_graphic = IMG_CHAR_EXCLAM;
1202 int num_images = getImageListSize();
1205 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1206 static boolean clipmasks_initialized = FALSE;
1208 XGCValues clip_gc_values;
1209 unsigned long clip_gc_valuemask;
1210 GC copy_clipmask_gc = None;
1213 /* use image size as default values for width and height for these images */
1214 static int full_size_graphics[] =
1219 IMG_BACKGROUND_ENVELOPE_1,
1220 IMG_BACKGROUND_ENVELOPE_2,
1221 IMG_BACKGROUND_ENVELOPE_3,
1222 IMG_BACKGROUND_ENVELOPE_4,
1225 IMG_BACKGROUND_TITLE,
1226 IMG_BACKGROUND_MAIN,
1227 IMG_BACKGROUND_LEVELS,
1228 IMG_BACKGROUND_SCORES,
1229 IMG_BACKGROUND_EDITOR,
1230 IMG_BACKGROUND_INFO,
1231 IMG_BACKGROUND_INFO_ELEMENTS,
1232 IMG_BACKGROUND_INFO_MUSIC,
1233 IMG_BACKGROUND_INFO_CREDITS,
1234 IMG_BACKGROUND_INFO_PROGRAM,
1235 IMG_BACKGROUND_INFO_LEVELSET,
1236 IMG_BACKGROUND_SETUP,
1237 IMG_BACKGROUND_DOOR,
1239 IMG_TITLESCREEN_INITIAL_1,
1240 IMG_TITLESCREEN_INITIAL_2,
1241 IMG_TITLESCREEN_INITIAL_3,
1242 IMG_TITLESCREEN_INITIAL_4,
1243 IMG_TITLESCREEN_INITIAL_5,
1253 checked_free(graphic_info);
1255 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1258 /* initialize "use_image_size" flag with default value */
1259 for (i = 0; i < num_images; i++)
1260 graphic_info[i].use_image_size = FALSE;
1262 /* initialize "use_image_size" flag from static configuration above */
1263 for (i = 0; full_size_graphics[i] != -1; i++)
1264 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1267 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1268 if (clipmasks_initialized)
1270 for (i = 0; i < num_images; i++)
1272 if (graphic_info[i].clip_mask)
1273 XFreePixmap(display, graphic_info[i].clip_mask);
1274 if (graphic_info[i].clip_gc)
1275 XFreeGC(display, graphic_info[i].clip_gc);
1277 graphic_info[i].clip_mask = None;
1278 graphic_info[i].clip_gc = None;
1283 /* first set all graphic paramaters ... */
1284 for (i = 0; i < num_images; i++)
1285 set_graphic_parameters(i);
1287 /* ... then copy these parameters for cloned graphics */
1288 for (i = 0; i < num_images; i++)
1289 if (graphic_info[i].clone_from != -1)
1290 set_cloned_graphic_parameters(i);
1292 for (i = 0; i < num_images; i++)
1297 int first_frame, last_frame;
1298 int src_bitmap_width, src_bitmap_height;
1300 /* now check if no animation frames are outside of the loaded image */
1302 if (graphic_info[i].bitmap == NULL)
1303 continue; /* skip check for optional images that are undefined */
1305 /* get image size (this can differ from the standard element tile size!) */
1306 width = graphic_info[i].width;
1307 height = graphic_info[i].height;
1309 /* get final bitmap size (with scaling, but without small images) */
1310 src_bitmap_width = graphic_info[i].src_image_width;
1311 src_bitmap_height = graphic_info[i].src_image_height;
1313 /* check if first animation frame is inside specified bitmap */
1316 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1319 /* this avoids calculating wrong start position for out-of-bounds frame */
1320 src_x = graphic_info[i].src_x;
1321 src_y = graphic_info[i].src_y;
1324 if (src_x < 0 || src_y < 0 ||
1325 src_x + width > src_bitmap_width ||
1326 src_y + height > src_bitmap_height)
1328 Error(ERR_RETURN_LINE, "-");
1329 Error(ERR_RETURN, "warning: error found in config file:");
1330 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1331 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1332 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1334 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1335 src_x, src_y, src_bitmap_width, src_bitmap_height);
1336 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1338 if (i == fallback_graphic)
1339 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1341 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1342 Error(ERR_RETURN_LINE, "-");
1344 graphic_info[i] = graphic_info[fallback_graphic];
1347 /* check if last animation frame is inside specified bitmap */
1349 last_frame = graphic_info[i].anim_frames - 1;
1350 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1352 if (src_x < 0 || src_y < 0 ||
1353 src_x + width > src_bitmap_width ||
1354 src_y + height > src_bitmap_height)
1356 Error(ERR_RETURN_LINE, "-");
1357 Error(ERR_RETURN, "warning: error found in config file:");
1358 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1359 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1360 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1362 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1363 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1364 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1366 if (i == fallback_graphic)
1367 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1369 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1370 Error(ERR_RETURN_LINE, "-");
1372 graphic_info[i] = graphic_info[fallback_graphic];
1375 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1376 /* currently we only need a tile clip mask from the first frame */
1377 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1379 if (copy_clipmask_gc == None)
1381 clip_gc_values.graphics_exposures = False;
1382 clip_gc_valuemask = GCGraphicsExposures;
1383 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1384 clip_gc_valuemask, &clip_gc_values);
1387 graphic_info[i].clip_mask =
1388 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1390 src_pixmap = src_bitmap->clip_mask;
1391 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1392 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1394 clip_gc_values.graphics_exposures = False;
1395 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1396 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1398 graphic_info[i].clip_gc =
1399 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1403 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1404 if (copy_clipmask_gc)
1405 XFreeGC(display, copy_clipmask_gc);
1407 clipmasks_initialized = TRUE;
1411 static void InitElementSoundInfo()
1413 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1414 int num_property_mappings = getSoundListPropertyMappingSize();
1417 /* set values to -1 to identify later as "uninitialized" values */
1418 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1419 for (act = 0; act < NUM_ACTIONS; act++)
1420 element_info[i].sound[act] = -1;
1422 /* initialize element/sound mapping from static configuration */
1423 for (i = 0; element_to_sound[i].element > -1; i++)
1425 int element = element_to_sound[i].element;
1426 int action = element_to_sound[i].action;
1427 int sound = element_to_sound[i].sound;
1428 boolean is_class = element_to_sound[i].is_class;
1431 action = ACTION_DEFAULT;
1434 element_info[element].sound[action] = sound;
1436 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1437 if (strEqual(element_info[j].class_name,
1438 element_info[element].class_name))
1439 element_info[j].sound[action] = sound;
1442 /* initialize element class/sound mapping from dynamic configuration */
1443 for (i = 0; i < num_property_mappings; i++)
1445 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1446 int action = property_mapping[i].ext1_index;
1447 int sound = property_mapping[i].artwork_index;
1449 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1453 action = ACTION_DEFAULT;
1455 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1456 if (strEqual(element_info[j].class_name,
1457 element_info[element_class].class_name))
1458 element_info[j].sound[action] = sound;
1461 /* initialize element/sound mapping from dynamic configuration */
1462 for (i = 0; i < num_property_mappings; i++)
1464 int element = property_mapping[i].base_index;
1465 int action = property_mapping[i].ext1_index;
1466 int sound = property_mapping[i].artwork_index;
1468 if (element >= MAX_NUM_ELEMENTS)
1472 action = ACTION_DEFAULT;
1474 element_info[element].sound[action] = sound;
1477 /* now set all '-1' values to element specific default values */
1478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1480 for (act = 0; act < NUM_ACTIONS; act++)
1482 /* generic default action sound (defined by "[default]" directive) */
1483 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1485 /* look for special default action sound (classic game specific) */
1486 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1487 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1488 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1489 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1490 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1491 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1493 /* !!! there's no such thing as a "default action sound" !!! */
1495 /* look for element specific default sound (independent from action) */
1496 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1497 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1501 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1502 /* !!! make this better !!! */
1503 if (i == EL_EMPTY_SPACE)
1504 default_action_sound = element_info[EL_DEFAULT].sound[act];
1507 /* no sound for this specific action -- use default action sound */
1508 if (element_info[i].sound[act] == -1)
1509 element_info[i].sound[act] = default_action_sound;
1513 /* copy sound settings to some elements that are only stored in level file
1514 in native R'n'D levels, but are used by game engine in native EM levels */
1515 for (i = 0; copy_properties[i][0] != -1; i++)
1516 for (j = 1; j <= 4; j++)
1517 for (act = 0; act < NUM_ACTIONS; act++)
1518 element_info[copy_properties[i][j]].sound[act] =
1519 element_info[copy_properties[i][0]].sound[act];
1522 static void InitGameModeSoundInfo()
1526 /* set values to -1 to identify later as "uninitialized" values */
1527 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1530 /* initialize gamemode/sound mapping from static configuration */
1531 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1533 int gamemode = gamemode_to_sound[i].gamemode;
1534 int sound = gamemode_to_sound[i].sound;
1537 gamemode = GAME_MODE_DEFAULT;
1539 menu.sound[gamemode] = sound;
1542 /* now set all '-1' values to levelset specific default values */
1543 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1544 if (menu.sound[i] == -1)
1545 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1548 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1549 if (menu.sound[i] != -1)
1550 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1554 static void set_sound_parameters(int sound, char **parameter_raw)
1556 int parameter[NUM_SND_ARGS];
1559 /* get integer values from string parameters */
1560 for (i = 0; i < NUM_SND_ARGS; i++)
1562 get_parameter_value(parameter_raw[i],
1563 sound_config_suffix[i].token,
1564 sound_config_suffix[i].type);
1566 /* explicit loop mode setting in configuration overrides default value */
1567 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1568 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1570 /* sound volume to change the original volume when loading the sound file */
1571 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1573 /* sound priority to give certain sounds a higher or lower priority */
1574 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1577 static void InitSoundInfo()
1579 int *sound_effect_properties;
1580 int num_sounds = getSoundListSize();
1583 checked_free(sound_info);
1585 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1586 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1588 /* initialize sound effect for all elements to "no sound" */
1589 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1590 for (j = 0; j < NUM_ACTIONS; j++)
1591 element_info[i].sound[j] = SND_UNDEFINED;
1593 for (i = 0; i < num_sounds; i++)
1595 struct FileInfo *sound = getSoundListEntry(i);
1596 int len_effect_text = strlen(sound->token);
1598 sound_effect_properties[i] = ACTION_OTHER;
1599 sound_info[i].loop = FALSE; /* default: play sound only once */
1602 printf("::: sound %d: '%s'\n", i, sound->token);
1605 /* determine all loop sounds and identify certain sound classes */
1607 for (j = 0; element_action_info[j].suffix; j++)
1609 int len_action_text = strlen(element_action_info[j].suffix);
1611 if (len_action_text < len_effect_text &&
1612 strEqual(&sound->token[len_effect_text - len_action_text],
1613 element_action_info[j].suffix))
1615 sound_effect_properties[i] = element_action_info[j].value;
1616 sound_info[i].loop = element_action_info[j].is_loop_sound;
1622 /* associate elements and some selected sound actions */
1624 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1626 if (element_info[j].class_name)
1628 int len_class_text = strlen(element_info[j].class_name);
1630 if (len_class_text + 1 < len_effect_text &&
1631 strncmp(sound->token,
1632 element_info[j].class_name, len_class_text) == 0 &&
1633 sound->token[len_class_text] == '.')
1635 int sound_action_value = sound_effect_properties[i];
1637 element_info[j].sound[sound_action_value] = i;
1642 set_sound_parameters(i, sound->parameter);
1645 free(sound_effect_properties);
1648 static void InitGameModeMusicInfo()
1650 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1651 int num_property_mappings = getMusicListPropertyMappingSize();
1652 int default_levelset_music = -1;
1655 /* set values to -1 to identify later as "uninitialized" values */
1656 for (i = 0; i < MAX_LEVELS; i++)
1657 levelset.music[i] = -1;
1658 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1661 /* initialize gamemode/music mapping from static configuration */
1662 for (i = 0; gamemode_to_music[i].music > -1; i++)
1664 int gamemode = gamemode_to_music[i].gamemode;
1665 int music = gamemode_to_music[i].music;
1668 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1672 gamemode = GAME_MODE_DEFAULT;
1674 menu.music[gamemode] = music;
1677 /* initialize gamemode/music mapping from dynamic configuration */
1678 for (i = 0; i < num_property_mappings; i++)
1680 int prefix = property_mapping[i].base_index;
1681 int gamemode = property_mapping[i].ext1_index;
1682 int level = property_mapping[i].ext2_index;
1683 int music = property_mapping[i].artwork_index;
1686 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1687 prefix, gamemode, level, music);
1690 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1694 gamemode = GAME_MODE_DEFAULT;
1696 /* level specific music only allowed for in-game music */
1697 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1698 gamemode = GAME_MODE_PLAYING;
1703 default_levelset_music = music;
1706 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1707 levelset.music[level] = music;
1708 if (gamemode != GAME_MODE_PLAYING)
1709 menu.music[gamemode] = music;
1712 /* now set all '-1' values to menu specific default values */
1713 /* (undefined values of "levelset.music[]" might stay at "-1" to
1714 allow dynamic selection of music files from music directory!) */
1715 for (i = 0; i < MAX_LEVELS; i++)
1716 if (levelset.music[i] == -1)
1717 levelset.music[i] = default_levelset_music;
1718 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1719 if (menu.music[i] == -1)
1720 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1723 for (i = 0; i < MAX_LEVELS; i++)
1724 if (levelset.music[i] != -1)
1725 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1726 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1727 if (menu.music[i] != -1)
1728 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1732 static void set_music_parameters(int music, char **parameter_raw)
1734 int parameter[NUM_MUS_ARGS];
1737 /* get integer values from string parameters */
1738 for (i = 0; i < NUM_MUS_ARGS; i++)
1740 get_parameter_value(parameter_raw[i],
1741 music_config_suffix[i].token,
1742 music_config_suffix[i].type);
1744 /* explicit loop mode setting in configuration overrides default value */
1745 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1746 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1749 static void InitMusicInfo()
1751 int num_music = getMusicListSize();
1754 checked_free(music_info);
1756 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1758 for (i = 0; i < num_music; i++)
1760 struct FileInfo *music = getMusicListEntry(i);
1761 int len_music_text = strlen(music->token);
1763 music_info[i].loop = TRUE; /* default: play music in loop mode */
1765 /* determine all loop music */
1767 for (j = 0; music_prefix_info[j].prefix; j++)
1769 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1771 if (len_prefix_text < len_music_text &&
1772 strncmp(music->token,
1773 music_prefix_info[j].prefix, len_prefix_text) == 0)
1775 music_info[i].loop = music_prefix_info[j].is_loop_music;
1781 set_music_parameters(i, music->parameter);
1785 static void ReinitializeGraphics()
1787 InitGraphicInfo(); /* graphic properties mapping */
1788 InitElementGraphicInfo(); /* element game graphic mapping */
1789 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1791 InitElementSmallImages(); /* scale elements to all needed sizes */
1792 InitScaledImages(); /* scale all other images, if needed */
1793 InitFontGraphicInfo(); /* initialize text drawing functions */
1795 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1797 SetMainBackgroundImage(IMG_BACKGROUND);
1798 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1804 static void ReinitializeSounds()
1806 InitSoundInfo(); /* sound properties mapping */
1807 InitElementSoundInfo(); /* element game sound mapping */
1808 InitGameModeSoundInfo(); /* game mode sound mapping */
1810 InitPlayLevelSound(); /* internal game sound settings */
1813 static void ReinitializeMusic()
1815 InitMusicInfo(); /* music properties mapping */
1816 InitGameModeMusicInfo(); /* game mode music mapping */
1819 static int get_special_property_bit(int element, int property_bit_nr)
1821 struct PropertyBitInfo
1827 static struct PropertyBitInfo pb_can_move_into_acid[] =
1829 /* the player may be able fall into acid when gravity is activated */
1834 { EL_SP_MURPHY, 0 },
1835 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1837 /* all elements that can move may be able to also move into acid */
1840 { EL_BUG_RIGHT, 1 },
1843 { EL_SPACESHIP, 2 },
1844 { EL_SPACESHIP_LEFT, 2 },
1845 { EL_SPACESHIP_RIGHT, 2 },
1846 { EL_SPACESHIP_UP, 2 },
1847 { EL_SPACESHIP_DOWN, 2 },
1848 { EL_BD_BUTTERFLY, 3 },
1849 { EL_BD_BUTTERFLY_LEFT, 3 },
1850 { EL_BD_BUTTERFLY_RIGHT, 3 },
1851 { EL_BD_BUTTERFLY_UP, 3 },
1852 { EL_BD_BUTTERFLY_DOWN, 3 },
1853 { EL_BD_FIREFLY, 4 },
1854 { EL_BD_FIREFLY_LEFT, 4 },
1855 { EL_BD_FIREFLY_RIGHT, 4 },
1856 { EL_BD_FIREFLY_UP, 4 },
1857 { EL_BD_FIREFLY_DOWN, 4 },
1859 { EL_YAMYAM_LEFT, 5 },
1860 { EL_YAMYAM_RIGHT, 5 },
1861 { EL_YAMYAM_UP, 5 },
1862 { EL_YAMYAM_DOWN, 5 },
1863 { EL_DARK_YAMYAM, 6 },
1866 { EL_PACMAN_LEFT, 8 },
1867 { EL_PACMAN_RIGHT, 8 },
1868 { EL_PACMAN_UP, 8 },
1869 { EL_PACMAN_DOWN, 8 },
1871 { EL_MOLE_LEFT, 9 },
1872 { EL_MOLE_RIGHT, 9 },
1874 { EL_MOLE_DOWN, 9 },
1878 { EL_SATELLITE, 13 },
1879 { EL_SP_SNIKSNAK, 14 },
1880 { EL_SP_ELECTRON, 15 },
1883 { EL_EMC_ANDROID, 18 },
1888 static struct PropertyBitInfo pb_dont_collide_with[] =
1890 { EL_SP_SNIKSNAK, 0 },
1891 { EL_SP_ELECTRON, 1 },
1899 struct PropertyBitInfo *pb_info;
1902 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1903 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1908 struct PropertyBitInfo *pb_info = NULL;
1911 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1912 if (pb_definition[i].bit_nr == property_bit_nr)
1913 pb_info = pb_definition[i].pb_info;
1915 if (pb_info == NULL)
1918 for (i = 0; pb_info[i].element != -1; i++)
1919 if (pb_info[i].element == element)
1920 return pb_info[i].bit_nr;
1925 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1926 boolean property_value)
1928 int bit_nr = get_special_property_bit(element, property_bit_nr);
1933 *bitfield |= (1 << bit_nr);
1935 *bitfield &= ~(1 << bit_nr);
1939 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1941 int bit_nr = get_special_property_bit(element, property_bit_nr);
1944 return ((*bitfield & (1 << bit_nr)) != 0);
1949 static void resolve_group_element(int group_element, int recursion_depth)
1951 static int group_nr;
1952 static struct ElementGroupInfo *group;
1953 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1956 if (actual_group == NULL) /* not yet initialized */
1959 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1961 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1962 group_element - EL_GROUP_START + 1);
1964 /* replace element which caused too deep recursion by question mark */
1965 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1970 if (recursion_depth == 0) /* initialization */
1972 group = actual_group;
1973 group_nr = group_element - EL_GROUP_START;
1975 group->num_elements_resolved = 0;
1976 group->choice_pos = 0;
1979 for (i = 0; i < actual_group->num_elements; i++)
1981 int element = actual_group->element[i];
1983 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1986 if (IS_GROUP_ELEMENT(element))
1987 resolve_group_element(element, recursion_depth + 1);
1990 group->element_resolved[group->num_elements_resolved++] = element;
1991 element_info[element].in_group[group_nr] = TRUE;
1996 void InitElementPropertiesStatic()
1998 static int ep_diggable[] =
2003 EL_SP_BUGGY_BASE_ACTIVATING,
2006 EL_INVISIBLE_SAND_ACTIVE,
2009 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2010 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2014 EL_SP_BUGGY_BASE_ACTIVE,
2021 static int ep_collectible_only[] =
2043 EL_DYNABOMB_INCREASE_NUMBER,
2044 EL_DYNABOMB_INCREASE_SIZE,
2045 EL_DYNABOMB_INCREASE_POWER,
2065 static int ep_dont_run_into[] =
2067 /* same elements as in 'ep_dont_touch' */
2073 /* same elements as in 'ep_dont_collide_with' */
2085 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2089 EL_SP_BUGGY_BASE_ACTIVE,
2096 static int ep_dont_collide_with[] =
2098 /* same elements as in 'ep_dont_touch' */
2115 static int ep_dont_touch[] =
2125 static int ep_indestructible[] =
2129 EL_ACID_POOL_TOPLEFT,
2130 EL_ACID_POOL_TOPRIGHT,
2131 EL_ACID_POOL_BOTTOMLEFT,
2132 EL_ACID_POOL_BOTTOM,
2133 EL_ACID_POOL_BOTTOMRIGHT,
2134 EL_SP_HARDWARE_GRAY,
2135 EL_SP_HARDWARE_GREEN,
2136 EL_SP_HARDWARE_BLUE,
2138 EL_SP_HARDWARE_YELLOW,
2139 EL_SP_HARDWARE_BASE_1,
2140 EL_SP_HARDWARE_BASE_2,
2141 EL_SP_HARDWARE_BASE_3,
2142 EL_SP_HARDWARE_BASE_4,
2143 EL_SP_HARDWARE_BASE_5,
2144 EL_SP_HARDWARE_BASE_6,
2145 EL_INVISIBLE_STEELWALL,
2146 EL_INVISIBLE_STEELWALL_ACTIVE,
2147 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2148 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2149 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2150 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2151 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2152 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2153 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2154 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2155 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2156 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2157 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2158 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2160 EL_LIGHT_SWITCH_ACTIVE,
2161 EL_SIGN_EXCLAMATION,
2162 EL_SIGN_RADIOACTIVITY,
2173 EL_STEELWALL_SLIPPERY,
2187 EL_GATE_1_GRAY_ACTIVE,
2188 EL_GATE_2_GRAY_ACTIVE,
2189 EL_GATE_3_GRAY_ACTIVE,
2190 EL_GATE_4_GRAY_ACTIVE,
2199 EL_EM_GATE_1_GRAY_ACTIVE,
2200 EL_EM_GATE_2_GRAY_ACTIVE,
2201 EL_EM_GATE_3_GRAY_ACTIVE,
2202 EL_EM_GATE_4_GRAY_ACTIVE,
2211 EL_EMC_GATE_5_GRAY_ACTIVE,
2212 EL_EMC_GATE_6_GRAY_ACTIVE,
2213 EL_EMC_GATE_7_GRAY_ACTIVE,
2214 EL_EMC_GATE_8_GRAY_ACTIVE,
2216 EL_SWITCHGATE_OPENING,
2217 EL_SWITCHGATE_CLOSED,
2218 EL_SWITCHGATE_CLOSING,
2220 EL_SWITCHGATE_SWITCH_UP,
2221 EL_SWITCHGATE_SWITCH_DOWN,
2224 EL_TIMEGATE_OPENING,
2226 EL_TIMEGATE_CLOSING,
2229 EL_TIMEGATE_SWITCH_ACTIVE,
2234 EL_TUBE_VERTICAL_LEFT,
2235 EL_TUBE_VERTICAL_RIGHT,
2236 EL_TUBE_HORIZONTAL_UP,
2237 EL_TUBE_HORIZONTAL_DOWN,
2246 static int ep_slippery[] =
2260 EL_ROBOT_WHEEL_ACTIVE,
2266 EL_ACID_POOL_TOPLEFT,
2267 EL_ACID_POOL_TOPRIGHT,
2277 EL_STEELWALL_SLIPPERY,
2280 EL_EMC_WALL_SLIPPERY_1,
2281 EL_EMC_WALL_SLIPPERY_2,
2282 EL_EMC_WALL_SLIPPERY_3,
2283 EL_EMC_WALL_SLIPPERY_4,
2285 EL_EMC_MAGIC_BALL_ACTIVE,
2290 static int ep_can_change[] =
2295 static int ep_can_move[] =
2297 /* same elements as in 'pb_can_move_into_acid' */
2320 static int ep_can_fall[] =
2335 EL_BD_MAGIC_WALL_FULL,
2349 static int ep_can_smash_player[] =
2375 static int ep_can_smash_enemies[] =
2384 static int ep_can_smash_everything[] =
2393 static int ep_explodes_by_fire[] =
2395 /* same elements as in 'ep_explodes_impact' */
2400 /* same elements as in 'ep_explodes_smashed' */
2410 EL_EM_DYNAMITE_ACTIVE,
2411 EL_DYNABOMB_PLAYER_1_ACTIVE,
2412 EL_DYNABOMB_PLAYER_2_ACTIVE,
2413 EL_DYNABOMB_PLAYER_3_ACTIVE,
2414 EL_DYNABOMB_PLAYER_4_ACTIVE,
2415 EL_DYNABOMB_INCREASE_NUMBER,
2416 EL_DYNABOMB_INCREASE_SIZE,
2417 EL_DYNABOMB_INCREASE_POWER,
2418 EL_SP_DISK_RED_ACTIVE,
2432 static int ep_explodes_smashed[] =
2434 /* same elements as in 'ep_explodes_impact' */
2448 static int ep_explodes_impact[] =
2457 static int ep_walkable_over[] =
2461 EL_SOKOBAN_FIELD_EMPTY,
2473 EL_GATE_1_GRAY_ACTIVE,
2474 EL_GATE_2_GRAY_ACTIVE,
2475 EL_GATE_3_GRAY_ACTIVE,
2476 EL_GATE_4_GRAY_ACTIVE,
2484 static int ep_walkable_inside[] =
2489 EL_TUBE_VERTICAL_LEFT,
2490 EL_TUBE_VERTICAL_RIGHT,
2491 EL_TUBE_HORIZONTAL_UP,
2492 EL_TUBE_HORIZONTAL_DOWN,
2501 static int ep_walkable_under[] =
2506 static int ep_passable_over[] =
2516 EL_EM_GATE_1_GRAY_ACTIVE,
2517 EL_EM_GATE_2_GRAY_ACTIVE,
2518 EL_EM_GATE_3_GRAY_ACTIVE,
2519 EL_EM_GATE_4_GRAY_ACTIVE,
2528 EL_EMC_GATE_5_GRAY_ACTIVE,
2529 EL_EMC_GATE_6_GRAY_ACTIVE,
2530 EL_EMC_GATE_7_GRAY_ACTIVE,
2531 EL_EMC_GATE_8_GRAY_ACTIVE,
2538 static int ep_passable_inside[] =
2544 EL_SP_PORT_HORIZONTAL,
2545 EL_SP_PORT_VERTICAL,
2547 EL_SP_GRAVITY_PORT_LEFT,
2548 EL_SP_GRAVITY_PORT_RIGHT,
2549 EL_SP_GRAVITY_PORT_UP,
2550 EL_SP_GRAVITY_PORT_DOWN,
2551 EL_SP_GRAVITY_ON_PORT_LEFT,
2552 EL_SP_GRAVITY_ON_PORT_RIGHT,
2553 EL_SP_GRAVITY_ON_PORT_UP,
2554 EL_SP_GRAVITY_ON_PORT_DOWN,
2555 EL_SP_GRAVITY_OFF_PORT_LEFT,
2556 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2557 EL_SP_GRAVITY_OFF_PORT_UP,
2558 EL_SP_GRAVITY_OFF_PORT_DOWN,
2563 static int ep_passable_under[] =
2568 static int ep_droppable[] =
2573 static int ep_explodes_1x1_old[] =
2578 static int ep_pushable[] =
2590 EL_SOKOBAN_FIELD_FULL,
2599 static int ep_explodes_cross_old[] =
2604 static int ep_protected[] =
2606 /* same elements as in 'ep_walkable_inside' */
2610 EL_TUBE_VERTICAL_LEFT,
2611 EL_TUBE_VERTICAL_RIGHT,
2612 EL_TUBE_HORIZONTAL_UP,
2613 EL_TUBE_HORIZONTAL_DOWN,
2619 /* same elements as in 'ep_passable_over' */
2628 EL_EM_GATE_1_GRAY_ACTIVE,
2629 EL_EM_GATE_2_GRAY_ACTIVE,
2630 EL_EM_GATE_3_GRAY_ACTIVE,
2631 EL_EM_GATE_4_GRAY_ACTIVE,
2640 EL_EMC_GATE_5_GRAY_ACTIVE,
2641 EL_EMC_GATE_6_GRAY_ACTIVE,
2642 EL_EMC_GATE_7_GRAY_ACTIVE,
2643 EL_EMC_GATE_8_GRAY_ACTIVE,
2647 /* same elements as in 'ep_passable_inside' */
2652 EL_SP_PORT_HORIZONTAL,
2653 EL_SP_PORT_VERTICAL,
2655 EL_SP_GRAVITY_PORT_LEFT,
2656 EL_SP_GRAVITY_PORT_RIGHT,
2657 EL_SP_GRAVITY_PORT_UP,
2658 EL_SP_GRAVITY_PORT_DOWN,
2659 EL_SP_GRAVITY_ON_PORT_LEFT,
2660 EL_SP_GRAVITY_ON_PORT_RIGHT,
2661 EL_SP_GRAVITY_ON_PORT_UP,
2662 EL_SP_GRAVITY_ON_PORT_DOWN,
2663 EL_SP_GRAVITY_OFF_PORT_LEFT,
2664 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2665 EL_SP_GRAVITY_OFF_PORT_UP,
2666 EL_SP_GRAVITY_OFF_PORT_DOWN,
2671 static int ep_throwable[] =
2676 static int ep_can_explode[] =
2678 /* same elements as in 'ep_explodes_impact' */
2683 /* same elements as in 'ep_explodes_smashed' */
2689 /* elements that can explode by explosion or by dragonfire */
2693 EL_EM_DYNAMITE_ACTIVE,
2694 EL_DYNABOMB_PLAYER_1_ACTIVE,
2695 EL_DYNABOMB_PLAYER_2_ACTIVE,
2696 EL_DYNABOMB_PLAYER_3_ACTIVE,
2697 EL_DYNABOMB_PLAYER_4_ACTIVE,
2698 EL_DYNABOMB_INCREASE_NUMBER,
2699 EL_DYNABOMB_INCREASE_SIZE,
2700 EL_DYNABOMB_INCREASE_POWER,
2701 EL_SP_DISK_RED_ACTIVE,
2709 /* elements that can explode only by explosion */
2715 static int ep_gravity_reachable[] =
2721 EL_INVISIBLE_SAND_ACTIVE,
2726 EL_SP_PORT_HORIZONTAL,
2727 EL_SP_PORT_VERTICAL,
2729 EL_SP_GRAVITY_PORT_LEFT,
2730 EL_SP_GRAVITY_PORT_RIGHT,
2731 EL_SP_GRAVITY_PORT_UP,
2732 EL_SP_GRAVITY_PORT_DOWN,
2733 EL_SP_GRAVITY_ON_PORT_LEFT,
2734 EL_SP_GRAVITY_ON_PORT_RIGHT,
2735 EL_SP_GRAVITY_ON_PORT_UP,
2736 EL_SP_GRAVITY_ON_PORT_DOWN,
2737 EL_SP_GRAVITY_OFF_PORT_LEFT,
2738 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2739 EL_SP_GRAVITY_OFF_PORT_UP,
2740 EL_SP_GRAVITY_OFF_PORT_DOWN,
2746 static int ep_player[] =
2753 EL_SOKOBAN_FIELD_PLAYER,
2759 static int ep_can_pass_magic_wall[] =
2773 static int ep_switchable[] =
2777 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2778 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2779 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2780 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2781 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2782 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2783 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2784 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2785 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2786 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2787 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2788 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2789 EL_SWITCHGATE_SWITCH_UP,
2790 EL_SWITCHGATE_SWITCH_DOWN,
2792 EL_LIGHT_SWITCH_ACTIVE,
2794 EL_BALLOON_SWITCH_LEFT,
2795 EL_BALLOON_SWITCH_RIGHT,
2796 EL_BALLOON_SWITCH_UP,
2797 EL_BALLOON_SWITCH_DOWN,
2798 EL_BALLOON_SWITCH_ANY,
2799 EL_BALLOON_SWITCH_NONE,
2802 EL_EMC_MAGIC_BALL_SWITCH,
2803 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2808 static int ep_bd_element[] =
2842 static int ep_sp_element[] =
2844 /* should always be valid */
2847 /* standard classic Supaplex elements */
2854 EL_SP_HARDWARE_GRAY,
2862 EL_SP_GRAVITY_PORT_RIGHT,
2863 EL_SP_GRAVITY_PORT_DOWN,
2864 EL_SP_GRAVITY_PORT_LEFT,
2865 EL_SP_GRAVITY_PORT_UP,
2870 EL_SP_PORT_VERTICAL,
2871 EL_SP_PORT_HORIZONTAL,
2877 EL_SP_HARDWARE_BASE_1,
2878 EL_SP_HARDWARE_GREEN,
2879 EL_SP_HARDWARE_BLUE,
2881 EL_SP_HARDWARE_YELLOW,
2882 EL_SP_HARDWARE_BASE_2,
2883 EL_SP_HARDWARE_BASE_3,
2884 EL_SP_HARDWARE_BASE_4,
2885 EL_SP_HARDWARE_BASE_5,
2886 EL_SP_HARDWARE_BASE_6,
2890 /* additional elements that appeared in newer Supaplex levels */
2893 /* additional gravity port elements (not switching, but setting gravity) */
2894 EL_SP_GRAVITY_ON_PORT_LEFT,
2895 EL_SP_GRAVITY_ON_PORT_RIGHT,
2896 EL_SP_GRAVITY_ON_PORT_UP,
2897 EL_SP_GRAVITY_ON_PORT_DOWN,
2898 EL_SP_GRAVITY_OFF_PORT_LEFT,
2899 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2900 EL_SP_GRAVITY_OFF_PORT_UP,
2901 EL_SP_GRAVITY_OFF_PORT_DOWN,
2903 /* more than one Murphy in a level results in an inactive clone */
2906 /* runtime Supaplex elements */
2907 EL_SP_DISK_RED_ACTIVE,
2908 EL_SP_TERMINAL_ACTIVE,
2909 EL_SP_BUGGY_BASE_ACTIVATING,
2910 EL_SP_BUGGY_BASE_ACTIVE,
2917 static int ep_sb_element[] =
2922 EL_SOKOBAN_FIELD_EMPTY,
2923 EL_SOKOBAN_FIELD_FULL,
2924 EL_SOKOBAN_FIELD_PLAYER,
2929 EL_INVISIBLE_STEELWALL,
2934 static int ep_gem[] =
2946 static int ep_food_dark_yamyam[] =
2974 static int ep_food_penguin[] =
2988 static int ep_food_pig[] =
3000 static int ep_historic_wall[] =
3011 EL_GATE_1_GRAY_ACTIVE,
3012 EL_GATE_2_GRAY_ACTIVE,
3013 EL_GATE_3_GRAY_ACTIVE,
3014 EL_GATE_4_GRAY_ACTIVE,
3023 EL_EM_GATE_1_GRAY_ACTIVE,
3024 EL_EM_GATE_2_GRAY_ACTIVE,
3025 EL_EM_GATE_3_GRAY_ACTIVE,
3026 EL_EM_GATE_4_GRAY_ACTIVE,
3033 EL_EXPANDABLE_WALL_HORIZONTAL,
3034 EL_EXPANDABLE_WALL_VERTICAL,
3035 EL_EXPANDABLE_WALL_ANY,
3036 EL_EXPANDABLE_WALL_GROWING,
3037 EL_BD_EXPANDABLE_WALL,
3044 EL_SP_HARDWARE_GRAY,
3045 EL_SP_HARDWARE_GREEN,
3046 EL_SP_HARDWARE_BLUE,
3048 EL_SP_HARDWARE_YELLOW,
3049 EL_SP_HARDWARE_BASE_1,
3050 EL_SP_HARDWARE_BASE_2,
3051 EL_SP_HARDWARE_BASE_3,
3052 EL_SP_HARDWARE_BASE_4,
3053 EL_SP_HARDWARE_BASE_5,
3054 EL_SP_HARDWARE_BASE_6,
3056 EL_SP_TERMINAL_ACTIVE,
3059 EL_INVISIBLE_STEELWALL,
3060 EL_INVISIBLE_STEELWALL_ACTIVE,
3062 EL_INVISIBLE_WALL_ACTIVE,
3063 EL_STEELWALL_SLIPPERY,
3080 static int ep_historic_solid[] =
3084 EL_EXPANDABLE_WALL_HORIZONTAL,
3085 EL_EXPANDABLE_WALL_VERTICAL,
3086 EL_EXPANDABLE_WALL_ANY,
3087 EL_BD_EXPANDABLE_WALL,
3100 EL_QUICKSAND_FILLING,
3101 EL_QUICKSAND_EMPTYING,
3103 EL_MAGIC_WALL_ACTIVE,
3104 EL_MAGIC_WALL_EMPTYING,
3105 EL_MAGIC_WALL_FILLING,
3109 EL_BD_MAGIC_WALL_ACTIVE,
3110 EL_BD_MAGIC_WALL_EMPTYING,
3111 EL_BD_MAGIC_WALL_FULL,
3112 EL_BD_MAGIC_WALL_FILLING,
3113 EL_BD_MAGIC_WALL_DEAD,
3122 EL_SP_TERMINAL_ACTIVE,
3126 EL_INVISIBLE_WALL_ACTIVE,
3127 EL_SWITCHGATE_SWITCH_UP,
3128 EL_SWITCHGATE_SWITCH_DOWN,
3130 EL_TIMEGATE_SWITCH_ACTIVE,
3142 /* the following elements are a direct copy of "indestructible" elements,
3143 except "EL_ACID", which is "indestructible", but not "solid"! */
3148 EL_ACID_POOL_TOPLEFT,
3149 EL_ACID_POOL_TOPRIGHT,
3150 EL_ACID_POOL_BOTTOMLEFT,
3151 EL_ACID_POOL_BOTTOM,
3152 EL_ACID_POOL_BOTTOMRIGHT,
3153 EL_SP_HARDWARE_GRAY,
3154 EL_SP_HARDWARE_GREEN,
3155 EL_SP_HARDWARE_BLUE,
3157 EL_SP_HARDWARE_YELLOW,
3158 EL_SP_HARDWARE_BASE_1,
3159 EL_SP_HARDWARE_BASE_2,
3160 EL_SP_HARDWARE_BASE_3,
3161 EL_SP_HARDWARE_BASE_4,
3162 EL_SP_HARDWARE_BASE_5,
3163 EL_SP_HARDWARE_BASE_6,
3164 EL_INVISIBLE_STEELWALL,
3165 EL_INVISIBLE_STEELWALL_ACTIVE,
3166 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3167 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3168 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3169 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3170 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3171 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3172 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3173 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3174 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3175 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3176 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3177 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3179 EL_LIGHT_SWITCH_ACTIVE,
3180 EL_SIGN_EXCLAMATION,
3181 EL_SIGN_RADIOACTIVITY,
3192 EL_STEELWALL_SLIPPERY,
3206 EL_GATE_1_GRAY_ACTIVE,
3207 EL_GATE_2_GRAY_ACTIVE,
3208 EL_GATE_3_GRAY_ACTIVE,
3209 EL_GATE_4_GRAY_ACTIVE,
3218 EL_EM_GATE_1_GRAY_ACTIVE,
3219 EL_EM_GATE_2_GRAY_ACTIVE,
3220 EL_EM_GATE_3_GRAY_ACTIVE,
3221 EL_EM_GATE_4_GRAY_ACTIVE,
3223 EL_SWITCHGATE_OPENING,
3224 EL_SWITCHGATE_CLOSED,
3225 EL_SWITCHGATE_CLOSING,
3227 EL_TIMEGATE_OPENING,
3229 EL_TIMEGATE_CLOSING,
3233 EL_TUBE_VERTICAL_LEFT,
3234 EL_TUBE_VERTICAL_RIGHT,
3235 EL_TUBE_HORIZONTAL_UP,
3236 EL_TUBE_HORIZONTAL_DOWN,
3245 static int ep_classic_enemy[] =
3262 static int ep_belt[] =
3264 EL_CONVEYOR_BELT_1_LEFT,
3265 EL_CONVEYOR_BELT_1_MIDDLE,
3266 EL_CONVEYOR_BELT_1_RIGHT,
3267 EL_CONVEYOR_BELT_2_LEFT,
3268 EL_CONVEYOR_BELT_2_MIDDLE,
3269 EL_CONVEYOR_BELT_2_RIGHT,
3270 EL_CONVEYOR_BELT_3_LEFT,
3271 EL_CONVEYOR_BELT_3_MIDDLE,
3272 EL_CONVEYOR_BELT_3_RIGHT,
3273 EL_CONVEYOR_BELT_4_LEFT,
3274 EL_CONVEYOR_BELT_4_MIDDLE,
3275 EL_CONVEYOR_BELT_4_RIGHT,
3280 static int ep_belt_active[] =
3282 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3283 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3284 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3285 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3286 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3287 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3288 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3289 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3290 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3291 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3292 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3293 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3298 static int ep_belt_switch[] =
3300 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3301 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3302 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3303 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3304 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3305 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3306 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3307 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3308 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3309 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3310 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3311 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3316 static int ep_tube[] =
3323 EL_TUBE_HORIZONTAL_UP,
3324 EL_TUBE_HORIZONTAL_DOWN,
3326 EL_TUBE_VERTICAL_LEFT,
3327 EL_TUBE_VERTICAL_RIGHT,
3333 static int ep_keygate[] =
3343 EL_GATE_1_GRAY_ACTIVE,
3344 EL_GATE_2_GRAY_ACTIVE,
3345 EL_GATE_3_GRAY_ACTIVE,
3346 EL_GATE_4_GRAY_ACTIVE,
3355 EL_EM_GATE_1_GRAY_ACTIVE,
3356 EL_EM_GATE_2_GRAY_ACTIVE,
3357 EL_EM_GATE_3_GRAY_ACTIVE,
3358 EL_EM_GATE_4_GRAY_ACTIVE,
3367 EL_EMC_GATE_5_GRAY_ACTIVE,
3368 EL_EMC_GATE_6_GRAY_ACTIVE,
3369 EL_EMC_GATE_7_GRAY_ACTIVE,
3370 EL_EMC_GATE_8_GRAY_ACTIVE,
3375 static int ep_amoeboid[] =
3387 static int ep_amoebalive[] =
3398 static int ep_has_editor_content[] =
3420 static int ep_can_turn_each_move[] =
3422 /* !!! do something with this one !!! */
3426 static int ep_can_grow[] =
3440 static int ep_active_bomb[] =
3443 EL_EM_DYNAMITE_ACTIVE,
3444 EL_DYNABOMB_PLAYER_1_ACTIVE,
3445 EL_DYNABOMB_PLAYER_2_ACTIVE,
3446 EL_DYNABOMB_PLAYER_3_ACTIVE,
3447 EL_DYNABOMB_PLAYER_4_ACTIVE,
3448 EL_SP_DISK_RED_ACTIVE,
3453 static int ep_inactive[] =
3485 EL_GATE_1_GRAY_ACTIVE,
3486 EL_GATE_2_GRAY_ACTIVE,
3487 EL_GATE_3_GRAY_ACTIVE,
3488 EL_GATE_4_GRAY_ACTIVE,
3497 EL_EM_GATE_1_GRAY_ACTIVE,
3498 EL_EM_GATE_2_GRAY_ACTIVE,
3499 EL_EM_GATE_3_GRAY_ACTIVE,
3500 EL_EM_GATE_4_GRAY_ACTIVE,
3509 EL_EMC_GATE_5_GRAY_ACTIVE,
3510 EL_EMC_GATE_6_GRAY_ACTIVE,
3511 EL_EMC_GATE_7_GRAY_ACTIVE,
3512 EL_EMC_GATE_8_GRAY_ACTIVE,
3515 EL_INVISIBLE_STEELWALL,
3523 EL_WALL_EMERALD_YELLOW,
3524 EL_DYNABOMB_INCREASE_NUMBER,
3525 EL_DYNABOMB_INCREASE_SIZE,
3526 EL_DYNABOMB_INCREASE_POWER,
3530 EL_SOKOBAN_FIELD_EMPTY,
3531 EL_SOKOBAN_FIELD_FULL,
3532 EL_WALL_EMERALD_RED,
3533 EL_WALL_EMERALD_PURPLE,
3534 EL_ACID_POOL_TOPLEFT,
3535 EL_ACID_POOL_TOPRIGHT,
3536 EL_ACID_POOL_BOTTOMLEFT,
3537 EL_ACID_POOL_BOTTOM,
3538 EL_ACID_POOL_BOTTOMRIGHT,
3542 EL_BD_MAGIC_WALL_DEAD,
3543 EL_AMOEBA_TO_DIAMOND,
3551 EL_SP_GRAVITY_PORT_RIGHT,
3552 EL_SP_GRAVITY_PORT_DOWN,
3553 EL_SP_GRAVITY_PORT_LEFT,
3554 EL_SP_GRAVITY_PORT_UP,
3555 EL_SP_PORT_HORIZONTAL,
3556 EL_SP_PORT_VERTICAL,
3567 EL_SP_HARDWARE_GRAY,
3568 EL_SP_HARDWARE_GREEN,
3569 EL_SP_HARDWARE_BLUE,
3571 EL_SP_HARDWARE_YELLOW,
3572 EL_SP_HARDWARE_BASE_1,
3573 EL_SP_HARDWARE_BASE_2,
3574 EL_SP_HARDWARE_BASE_3,
3575 EL_SP_HARDWARE_BASE_4,
3576 EL_SP_HARDWARE_BASE_5,
3577 EL_SP_HARDWARE_BASE_6,
3578 EL_SP_GRAVITY_ON_PORT_LEFT,
3579 EL_SP_GRAVITY_ON_PORT_RIGHT,
3580 EL_SP_GRAVITY_ON_PORT_UP,
3581 EL_SP_GRAVITY_ON_PORT_DOWN,
3582 EL_SP_GRAVITY_OFF_PORT_LEFT,
3583 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3584 EL_SP_GRAVITY_OFF_PORT_UP,
3585 EL_SP_GRAVITY_OFF_PORT_DOWN,
3586 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3587 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3588 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3589 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3590 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3591 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3592 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3593 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3594 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3595 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3596 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3597 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3598 EL_SIGN_EXCLAMATION,
3599 EL_SIGN_RADIOACTIVITY,
3610 EL_STEELWALL_SLIPPERY,
3615 EL_EMC_WALL_SLIPPERY_1,
3616 EL_EMC_WALL_SLIPPERY_2,
3617 EL_EMC_WALL_SLIPPERY_3,
3618 EL_EMC_WALL_SLIPPERY_4,
3639 static int ep_em_slippery_wall[] =
3644 static int ep_gfx_crumbled[] =
3654 static int ep_editor_cascade_active[] =
3656 EL_INTERNAL_CASCADE_BD_ACTIVE,
3657 EL_INTERNAL_CASCADE_EM_ACTIVE,
3658 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3659 EL_INTERNAL_CASCADE_RND_ACTIVE,
3660 EL_INTERNAL_CASCADE_SB_ACTIVE,
3661 EL_INTERNAL_CASCADE_SP_ACTIVE,
3662 EL_INTERNAL_CASCADE_DC_ACTIVE,
3663 EL_INTERNAL_CASCADE_DX_ACTIVE,
3664 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3665 EL_INTERNAL_CASCADE_CE_ACTIVE,
3666 EL_INTERNAL_CASCADE_GE_ACTIVE,
3667 EL_INTERNAL_CASCADE_REF_ACTIVE,
3668 EL_INTERNAL_CASCADE_USER_ACTIVE,
3669 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3674 static int ep_editor_cascade_inactive[] =
3676 EL_INTERNAL_CASCADE_BD,
3677 EL_INTERNAL_CASCADE_EM,
3678 EL_INTERNAL_CASCADE_EMC,
3679 EL_INTERNAL_CASCADE_RND,
3680 EL_INTERNAL_CASCADE_SB,
3681 EL_INTERNAL_CASCADE_SP,
3682 EL_INTERNAL_CASCADE_DC,
3683 EL_INTERNAL_CASCADE_DX,
3684 EL_INTERNAL_CASCADE_CHARS,
3685 EL_INTERNAL_CASCADE_CE,
3686 EL_INTERNAL_CASCADE_GE,
3687 EL_INTERNAL_CASCADE_REF,
3688 EL_INTERNAL_CASCADE_USER,
3689 EL_INTERNAL_CASCADE_DYNAMIC,
3694 static int ep_obsolete[] =
3698 EL_EM_KEY_1_FILE_OBSOLETE,
3699 EL_EM_KEY_2_FILE_OBSOLETE,
3700 EL_EM_KEY_3_FILE_OBSOLETE,
3701 EL_EM_KEY_4_FILE_OBSOLETE,
3702 EL_ENVELOPE_OBSOLETE,
3711 } element_properties[] =
3713 { ep_diggable, EP_DIGGABLE },
3714 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3715 { ep_dont_run_into, EP_DONT_RUN_INTO },
3716 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3717 { ep_dont_touch, EP_DONT_TOUCH },
3718 { ep_indestructible, EP_INDESTRUCTIBLE },
3719 { ep_slippery, EP_SLIPPERY },
3720 { ep_can_change, EP_CAN_CHANGE },
3721 { ep_can_move, EP_CAN_MOVE },
3722 { ep_can_fall, EP_CAN_FALL },
3723 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3724 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3725 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3726 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3727 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3728 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3729 { ep_walkable_over, EP_WALKABLE_OVER },
3730 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3731 { ep_walkable_under, EP_WALKABLE_UNDER },
3732 { ep_passable_over, EP_PASSABLE_OVER },
3733 { ep_passable_inside, EP_PASSABLE_INSIDE },
3734 { ep_passable_under, EP_PASSABLE_UNDER },
3735 { ep_droppable, EP_DROPPABLE },
3736 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3737 { ep_pushable, EP_PUSHABLE },
3738 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3739 { ep_protected, EP_PROTECTED },
3740 { ep_throwable, EP_THROWABLE },
3741 { ep_can_explode, EP_CAN_EXPLODE },
3742 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3744 { ep_player, EP_PLAYER },
3745 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3746 { ep_switchable, EP_SWITCHABLE },
3747 { ep_bd_element, EP_BD_ELEMENT },
3748 { ep_sp_element, EP_SP_ELEMENT },
3749 { ep_sb_element, EP_SB_ELEMENT },
3751 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3752 { ep_food_penguin, EP_FOOD_PENGUIN },
3753 { ep_food_pig, EP_FOOD_PIG },
3754 { ep_historic_wall, EP_HISTORIC_WALL },
3755 { ep_historic_solid, EP_HISTORIC_SOLID },
3756 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3757 { ep_belt, EP_BELT },
3758 { ep_belt_active, EP_BELT_ACTIVE },
3759 { ep_belt_switch, EP_BELT_SWITCH },
3760 { ep_tube, EP_TUBE },
3761 { ep_keygate, EP_KEYGATE },
3762 { ep_amoeboid, EP_AMOEBOID },
3763 { ep_amoebalive, EP_AMOEBALIVE },
3764 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3765 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3766 { ep_can_grow, EP_CAN_GROW },
3767 { ep_active_bomb, EP_ACTIVE_BOMB },
3768 { ep_inactive, EP_INACTIVE },
3770 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3772 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3774 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3775 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3777 { ep_obsolete, EP_OBSOLETE },
3784 /* always start with reliable default values (element has no properties) */
3785 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3786 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3787 SET_PROPERTY(i, j, FALSE);
3789 /* set all base element properties from above array definitions */
3790 for (i = 0; element_properties[i].elements != NULL; i++)
3791 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3792 SET_PROPERTY((element_properties[i].elements)[j],
3793 element_properties[i].property, TRUE);
3795 /* copy properties to some elements that are only stored in level file */
3796 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3797 for (j = 0; copy_properties[j][0] != -1; j++)
3798 if (HAS_PROPERTY(copy_properties[j][0], i))
3799 for (k = 1; k <= 4; k++)
3800 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3803 void InitElementPropertiesEngine(int engine_version)
3805 static int no_wall_properties[] =
3808 EP_COLLECTIBLE_ONLY,
3810 EP_DONT_COLLIDE_WITH,
3813 EP_CAN_SMASH_PLAYER,
3814 EP_CAN_SMASH_ENEMIES,
3815 EP_CAN_SMASH_EVERYTHING,
3820 EP_FOOD_DARK_YAMYAM,
3836 /* important: after initialization in InitElementPropertiesStatic(), the
3837 elements are not again initialized to a default value; therefore all
3838 changes have to make sure that they leave the element with a defined
3839 property (which means that conditional property changes must be set to
3840 a reliable default value before) */
3842 /* ---------- recursively resolve group elements ------------------------- */
3844 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3845 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3846 element_info[i].in_group[j] = FALSE;
3848 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3849 resolve_group_element(EL_GROUP_START + i, 0);
3851 /* set all special, combined or engine dependent element properties */
3852 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3854 /* ---------- INACTIVE ------------------------------------------------- */
3855 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3857 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3858 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3859 IS_WALKABLE_INSIDE(i) ||
3860 IS_WALKABLE_UNDER(i)));
3862 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3863 IS_PASSABLE_INSIDE(i) ||
3864 IS_PASSABLE_UNDER(i)));
3866 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3867 IS_PASSABLE_OVER(i)));
3869 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3870 IS_PASSABLE_INSIDE(i)));
3872 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3873 IS_PASSABLE_UNDER(i)));
3875 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3878 /* ---------- COLLECTIBLE ---------------------------------------------- */
3879 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3883 /* ---------- SNAPPABLE ------------------------------------------------ */
3884 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3885 IS_COLLECTIBLE(i) ||
3889 /* ---------- WALL ----------------------------------------------------- */
3890 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3892 for (j = 0; no_wall_properties[j] != -1; j++)
3893 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3894 i >= EL_FIRST_RUNTIME_UNREAL)
3895 SET_PROPERTY(i, EP_WALL, FALSE);
3897 if (IS_HISTORIC_WALL(i))
3898 SET_PROPERTY(i, EP_WALL, TRUE);
3900 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3901 if (engine_version < VERSION_IDENT(2,2,0,0))
3902 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3904 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3906 !IS_COLLECTIBLE(i)));
3908 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3910 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3911 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3913 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3914 IS_INDESTRUCTIBLE(i)));
3916 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3918 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3919 else if (engine_version < VERSION_IDENT(2,2,0,0))
3920 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3922 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3926 if (IS_CUSTOM_ELEMENT(i))
3928 /* these are additional properties which are initially false when set */
3930 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3932 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3933 if (DONT_COLLIDE_WITH(i))
3934 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3936 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3937 if (CAN_SMASH_EVERYTHING(i))
3938 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3939 if (CAN_SMASH_ENEMIES(i))
3940 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3943 /* ---------- CAN_SMASH ------------------------------------------------ */
3944 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3945 CAN_SMASH_ENEMIES(i) ||
3946 CAN_SMASH_EVERYTHING(i)));
3948 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3949 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3950 EXPLODES_BY_FIRE(i)));
3952 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3953 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3954 EXPLODES_SMASHED(i)));
3956 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3957 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3958 EXPLODES_IMPACT(i)));
3960 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3961 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3963 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3964 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3965 i == EL_BLACK_ORB));
3967 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3968 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3970 IS_CUSTOM_ELEMENT(i)));
3972 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3973 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3974 i == EL_SP_ELECTRON));
3976 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3977 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3978 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3979 getMoveIntoAcidProperty(&level, i));
3981 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3982 if (MAYBE_DONT_COLLIDE_WITH(i))
3983 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3984 getDontCollideWithProperty(&level, i));
3986 /* ---------- SP_PORT -------------------------------------------------- */
3987 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3988 IS_PASSABLE_INSIDE(i)));
3990 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3991 for (j = 0; j < level.num_android_clone_elements; j++)
3992 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3994 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3996 /* ---------- CAN_CHANGE ----------------------------------------------- */
3997 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3998 for (j = 0; j < element_info[i].num_change_pages; j++)
3999 if (element_info[i].change_page[j].can_change)
4000 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4002 /* ---------- HAS_ACTION ----------------------------------------------- */
4003 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4004 for (j = 0; j < element_info[i].num_change_pages; j++)
4005 if (element_info[i].change_page[j].has_action)
4006 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4008 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4009 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4012 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4014 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4015 element_info[i].crumbled[ACTION_DEFAULT] !=
4016 element_info[i].graphic[ACTION_DEFAULT]);
4018 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4019 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4020 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4023 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4024 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4025 IS_EDITOR_CASCADE_INACTIVE(i)));
4028 /* dynamically adjust element properties according to game engine version */
4030 static int ep_em_slippery_wall[] =
4035 EL_EXPANDABLE_WALL_HORIZONTAL,
4036 EL_EXPANDABLE_WALL_VERTICAL,
4037 EL_EXPANDABLE_WALL_ANY,
4041 /* special EM style gems behaviour */
4042 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4043 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4044 level.em_slippery_gems);
4046 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4047 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4048 (level.em_slippery_gems &&
4049 engine_version > VERSION_IDENT(2,0,1,0)));
4052 /* this is needed because some graphics depend on element properties */
4053 if (game_status == GAME_MODE_PLAYING)
4054 InitElementGraphicInfo();
4057 void InitElementPropertiesAfterLoading(int engine_version)
4061 /* set some other uninitialized values of custom elements in older levels */
4062 if (engine_version < VERSION_IDENT(3,1,0,0))
4064 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4066 int element = EL_CUSTOM_START + i;
4068 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4070 element_info[element].explosion_delay = 17;
4071 element_info[element].ignition_delay = 8;
4076 static void InitGlobal()
4080 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4082 /* check if element_name_info entry defined for each element in "main.h" */
4083 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4084 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4086 element_info[i].token_name = element_name_info[i].token_name;
4087 element_info[i].class_name = element_name_info[i].class_name;
4088 element_info[i].editor_description=element_name_info[i].editor_description;
4091 global.autoplay_leveldir = NULL;
4092 global.convert_leveldir = NULL;
4094 global.frames_per_second = 0;
4095 global.fps_slowdown = FALSE;
4096 global.fps_slowdown_factor = 1;
4099 void Execute_Command(char *command)
4103 if (strEqual(command, "print graphicsinfo.conf"))
4105 printf("# You can configure additional/alternative image files here.\n");
4106 printf("# (The entries below are default and therefore commented out.)\n");
4108 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4110 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4113 for (i = 0; image_config[i].token != NULL; i++)
4114 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4115 image_config[i].value));
4119 else if (strEqual(command, "print soundsinfo.conf"))
4121 printf("# You can configure additional/alternative sound files here.\n");
4122 printf("# (The entries below are default and therefore commented out.)\n");
4124 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4126 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4129 for (i = 0; sound_config[i].token != NULL; i++)
4130 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4131 sound_config[i].value));
4135 else if (strEqual(command, "print musicinfo.conf"))
4137 printf("# You can configure additional/alternative music files here.\n");
4138 printf("# (The entries below are default and therefore commented out.)\n");
4140 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4142 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4145 for (i = 0; music_config[i].token != NULL; i++)
4146 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4147 music_config[i].value));
4151 else if (strEqual(command, "print editorsetup.conf"))
4153 printf("# You can configure your personal editor element list here.\n");
4154 printf("# (The entries below are default and therefore commented out.)\n");
4157 /* this is needed to be able to check element list for cascade elements */
4158 InitElementPropertiesStatic();
4159 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4161 PrintEditorElementList();
4165 else if (strEqual(command, "print helpanim.conf"))
4167 printf("# You can configure different element help animations here.\n");
4168 printf("# (The entries below are default and therefore commented out.)\n");
4171 for (i = 0; helpanim_config[i].token != NULL; i++)
4173 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4174 helpanim_config[i].value));
4176 if (strEqual(helpanim_config[i].token, "end"))
4182 else if (strEqual(command, "print helptext.conf"))
4184 printf("# You can configure different element help text here.\n");
4185 printf("# (The entries below are default and therefore commented out.)\n");
4188 for (i = 0; helptext_config[i].token != NULL; i++)
4189 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4190 helptext_config[i].value));
4194 else if (strncmp(command, "dump level ", 11) == 0)
4196 char *filename = &command[11];
4198 if (!fileExists(filename))
4199 Error(ERR_EXIT, "cannot open file '%s'", filename);
4201 LoadLevelFromFilename(&level, filename);
4206 else if (strncmp(command, "dump tape ", 10) == 0)
4208 char *filename = &command[10];
4210 if (!fileExists(filename))
4211 Error(ERR_EXIT, "cannot open file '%s'", filename);
4213 LoadTapeFromFilename(filename);
4218 else if (strncmp(command, "autoplay ", 9) == 0)
4220 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4222 while (*str_ptr != '\0') /* continue parsing string */
4224 /* cut leading whitespace from string, replace it by string terminator */
4225 while (*str_ptr == ' ' || *str_ptr == '\t')
4228 if (*str_ptr == '\0') /* end of string reached */
4231 if (global.autoplay_leveldir == NULL) /* read level set string */
4233 global.autoplay_leveldir = str_ptr;
4234 global.autoplay_all = TRUE; /* default: play all tapes */
4236 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4237 global.autoplay_level[i] = FALSE;
4239 else /* read level number string */
4241 int level_nr = atoi(str_ptr); /* get level_nr value */
4243 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4244 global.autoplay_level[level_nr] = TRUE;
4246 global.autoplay_all = FALSE;
4249 /* advance string pointer to the next whitespace (or end of string) */
4250 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4254 else if (strncmp(command, "convert ", 8) == 0)
4256 char *str_copy = getStringCopy(&command[8]);
4257 char *str_ptr = strchr(str_copy, ' ');
4259 global.convert_leveldir = str_copy;
4260 global.convert_level_nr = -1;
4262 if (str_ptr != NULL) /* level number follows */
4264 *str_ptr++ = '\0'; /* terminate leveldir string */
4265 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4270 #if defined(TARGET_SDL)
4271 else if (strEqual(command, "SDL_ListModes"))
4276 SDL_Init(SDL_INIT_VIDEO);
4278 /* get available fullscreen/hardware modes */
4279 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4281 /* check if there are any modes available */
4284 printf("No modes available!\n");
4289 /* check if our resolution is restricted */
4290 if (modes == (SDL_Rect **)-1)
4292 printf("All resolutions available.\n");
4296 printf("Available Modes:\n");
4298 for(i = 0; modes[i]; i++)
4299 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4309 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4313 static void InitSetup()
4315 LoadSetup(); /* global setup info */
4317 /* set some options from setup file */
4319 if (setup.options.verbose)
4320 options.verbose = TRUE;
4323 static void InitGameInfo()
4325 game.restart_level = FALSE;
4328 static void InitPlayerInfo()
4332 /* choose default local player */
4333 local_player = &stored_player[0];
4335 for (i = 0; i < MAX_PLAYERS; i++)
4336 stored_player[i].connected = FALSE;
4338 local_player->connected = TRUE;
4341 static void InitArtworkInfo()
4346 static char *get_string_in_brackets(char *string)
4348 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4350 sprintf(string_in_brackets, "[%s]", string);
4352 return string_in_brackets;
4355 static char *get_level_id_suffix(int id_nr)
4357 char *id_suffix = checked_malloc(1 + 3 + 1);
4359 if (id_nr < 0 || id_nr > 999)
4362 sprintf(id_suffix, ".%03d", id_nr);
4368 static char *get_element_class_token(int element)
4370 char *element_class_name = element_info[element].class_name;
4371 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4373 sprintf(element_class_token, "[%s]", element_class_name);
4375 return element_class_token;
4378 static char *get_action_class_token(int action)
4380 char *action_class_name = &element_action_info[action].suffix[1];
4381 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4383 sprintf(action_class_token, "[%s]", action_class_name);
4385 return action_class_token;
4389 static void InitArtworkConfig()
4391 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4392 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4393 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4394 static char *action_id_suffix[NUM_ACTIONS + 1];
4395 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4396 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4397 static char *level_id_suffix[MAX_LEVELS + 1];
4398 static char *dummy[1] = { NULL };
4399 static char *ignore_generic_tokens[] =
4405 static char **ignore_image_tokens;
4406 static char **ignore_sound_tokens;
4407 static char **ignore_music_tokens;
4408 int num_ignore_generic_tokens;
4409 int num_ignore_image_tokens;
4410 int num_ignore_sound_tokens;
4411 int num_ignore_music_tokens;
4414 /* dynamically determine list of generic tokens to be ignored */
4415 num_ignore_generic_tokens = 0;
4416 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4417 num_ignore_generic_tokens++;
4419 /* dynamically determine list of image tokens to be ignored */
4420 num_ignore_image_tokens = num_ignore_generic_tokens;
4421 for (i = 0; image_config_vars[i].token != NULL; i++)
4422 num_ignore_image_tokens++;
4423 ignore_image_tokens =
4424 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4425 for (i = 0; i < num_ignore_generic_tokens; i++)
4426 ignore_image_tokens[i] = ignore_generic_tokens[i];
4427 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4428 ignore_image_tokens[num_ignore_generic_tokens + i] =
4429 image_config_vars[i].token;
4430 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4432 /* dynamically determine list of sound tokens to be ignored */
4433 num_ignore_sound_tokens = num_ignore_generic_tokens;
4434 ignore_sound_tokens =
4435 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4436 for (i = 0; i < num_ignore_generic_tokens; i++)
4437 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4438 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4440 /* dynamically determine list of music tokens to be ignored */
4441 num_ignore_music_tokens = num_ignore_generic_tokens;
4442 ignore_music_tokens =
4443 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4444 for (i = 0; i < num_ignore_generic_tokens; i++)
4445 ignore_music_tokens[i] = ignore_generic_tokens[i];
4446 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4448 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4449 image_id_prefix[i] = element_info[i].token_name;
4450 for (i = 0; i < NUM_FONTS; i++)
4451 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4452 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4454 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4455 sound_id_prefix[i] = element_info[i].token_name;
4456 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4457 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4458 get_string_in_brackets(element_info[i].class_name);
4459 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4461 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4462 music_id_prefix[i] = music_prefix_info[i].prefix;
4463 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4465 for (i = 0; i < NUM_ACTIONS; i++)
4466 action_id_suffix[i] = element_action_info[i].suffix;
4467 action_id_suffix[NUM_ACTIONS] = NULL;
4469 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4470 direction_id_suffix[i] = element_direction_info[i].suffix;
4471 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4473 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4474 special_id_suffix[i] = special_suffix_info[i].suffix;
4475 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4477 for (i = 0; i < MAX_LEVELS; i++)
4478 level_id_suffix[i] = get_level_id_suffix(i);
4479 level_id_suffix[MAX_LEVELS] = NULL;
4481 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4482 image_id_prefix, action_id_suffix, direction_id_suffix,
4483 special_id_suffix, ignore_image_tokens);
4484 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4485 sound_id_prefix, action_id_suffix, dummy,
4486 special_id_suffix, ignore_sound_tokens);
4487 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4488 music_id_prefix, special_id_suffix, level_id_suffix,
4489 dummy, ignore_music_tokens);
4492 static void InitMixer()
4500 char *filename_font_initial = NULL;
4501 Bitmap *bitmap_font_initial = NULL;
4505 /* determine settings for initial font (for displaying startup messages) */
4506 for (i = 0; image_config[i].token != NULL; i++)
4508 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4510 char font_token[128];
4513 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4514 len_font_token = strlen(font_token);
4516 if (strEqual(image_config[i].token, font_token))
4517 filename_font_initial = image_config[i].value;
4518 else if (strlen(image_config[i].token) > len_font_token &&
4519 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4521 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4522 font_initial[j].src_x = atoi(image_config[i].value);
4523 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4524 font_initial[j].src_y = atoi(image_config[i].value);
4525 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4526 font_initial[j].width = atoi(image_config[i].value);
4527 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4528 font_initial[j].height = atoi(image_config[i].value);
4533 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4535 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4536 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4539 if (filename_font_initial == NULL) /* should not happen */
4540 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4542 /* create additional image buffers for double-buffering and cross-fading */
4543 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4544 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4545 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4546 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4548 /* initialize screen properties */
4549 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4550 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4552 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4553 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4554 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4556 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4558 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4559 font_initial[j].bitmap = bitmap_font_initial;
4561 InitFontGraphicInfo();
4563 font_height = getFontHeight(FC_RED);
4565 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4566 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4567 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4569 DrawInitText("Loading graphics:", 120, FC_GREEN);
4572 void RedrawBackground()
4574 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4575 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4577 redraw_mask = REDRAW_ALL;
4580 void InitGfxBackground()
4584 drawto = backbuffer;
4585 fieldbuffer = bitmap_db_field;
4586 SetDrawtoField(DRAW_BACKBUFFER);
4590 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4591 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4593 for (x = 0; x < MAX_BUF_XSIZE; x++)
4594 for (y = 0; y < MAX_BUF_YSIZE; y++)
4597 redraw_mask = REDRAW_ALL;
4600 static void InitLevelInfo()
4602 LoadLevelInfo(); /* global level info */
4603 LoadLevelSetup_LastSeries(); /* last played series info */
4604 LoadLevelSetup_SeriesInfo(); /* last played level info */
4607 void InitLevelArtworkInfo()
4609 LoadLevelArtworkInfo();
4612 static void InitImages()
4614 setLevelArtworkDir(artwork.gfx_first);
4617 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4618 leveldir_current->identifier,
4619 artwork.gfx_current_identifier,
4620 artwork.gfx_current->identifier,
4621 leveldir_current->graphics_set,
4622 leveldir_current->graphics_path);
4625 ReloadCustomImages();
4627 LoadCustomElementDescriptions();
4628 LoadSpecialMenuDesignSettings();
4630 ReinitializeGraphics();
4633 static void InitSound(char *identifier)
4635 if (identifier == NULL)
4636 identifier = artwork.snd_current->identifier;
4638 /* set artwork path to send it to the sound server process */
4639 setLevelArtworkDir(artwork.snd_first);
4641 InitReloadCustomSounds(identifier);
4642 ReinitializeSounds();
4645 static void InitMusic(char *identifier)
4647 if (identifier == NULL)
4648 identifier = artwork.mus_current->identifier;
4650 /* set artwork path to send it to the sound server process */
4651 setLevelArtworkDir(artwork.mus_first);
4653 InitReloadCustomMusic(identifier);
4654 ReinitializeMusic();
4657 void InitNetworkServer()
4659 #if defined(NETWORK_AVALIABLE)
4663 if (!options.network)
4666 #if defined(NETWORK_AVALIABLE)
4667 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4669 if (!ConnectToServer(options.server_host, options.server_port))
4670 Error(ERR_EXIT, "cannot connect to network game server");
4672 SendToServer_PlayerName(setup.player_name);
4673 SendToServer_ProtocolVersion();
4676 SendToServer_NrWanted(nr_wanted);
4680 static char *getNewArtworkIdentifier(int type)
4682 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4683 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4684 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4685 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4686 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4687 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4688 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4689 char *leveldir_identifier = leveldir_current->identifier;
4691 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4692 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4694 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4696 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4697 char *artwork_current_identifier;
4698 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4700 /* leveldir_current may be invalid (level group, parent link) */
4701 if (!validLevelSeries(leveldir_current))
4704 /* 1st step: determine artwork set to be activated in descending order:
4705 --------------------------------------------------------------------
4706 1. setup artwork (when configured to override everything else)
4707 2. artwork set configured in "levelinfo.conf" of current level set
4708 (artwork in level directory will have priority when loading later)
4709 3. artwork in level directory (stored in artwork sub-directory)
4710 4. setup artwork (currently configured in setup menu) */
4712 if (setup_override_artwork)
4713 artwork_current_identifier = setup_artwork_set;
4714 else if (leveldir_artwork_set != NULL)
4715 artwork_current_identifier = leveldir_artwork_set;
4716 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4717 artwork_current_identifier = leveldir_identifier;
4719 artwork_current_identifier = setup_artwork_set;
4722 /* 2nd step: check if it is really needed to reload artwork set
4723 ------------------------------------------------------------ */
4726 if (type == ARTWORK_TYPE_GRAPHICS)
4727 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4728 artwork_new_identifier,
4729 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4730 artwork_current_identifier,
4731 leveldir_current->graphics_set,
4732 leveldir_current->identifier);
4735 /* ---------- reload if level set and also artwork set has changed ------- */
4736 if (leveldir_current_identifier[type] != leveldir_identifier &&
4737 (last_has_level_artwork_set[type] || has_level_artwork_set))
4738 artwork_new_identifier = artwork_current_identifier;
4740 leveldir_current_identifier[type] = leveldir_identifier;
4741 last_has_level_artwork_set[type] = has_level_artwork_set;
4744 if (type == ARTWORK_TYPE_GRAPHICS)
4745 printf("::: 1: '%s'\n", artwork_new_identifier);
4748 /* ---------- reload if "override artwork" setting has changed ----------- */
4749 if (last_override_level_artwork[type] != setup_override_artwork)
4750 artwork_new_identifier = artwork_current_identifier;
4752 last_override_level_artwork[type] = setup_override_artwork;
4755 if (type == ARTWORK_TYPE_GRAPHICS)
4756 printf("::: 2: '%s'\n", artwork_new_identifier);
4759 /* ---------- reload if current artwork identifier has changed ----------- */
4760 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4761 artwork_current_identifier))
4762 artwork_new_identifier = artwork_current_identifier;
4764 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4767 if (type == ARTWORK_TYPE_GRAPHICS)
4768 printf("::: 3: '%s'\n", artwork_new_identifier);
4771 /* ---------- do not reload directly after starting ---------------------- */
4772 if (!initialized[type])
4773 artwork_new_identifier = NULL;
4775 initialized[type] = TRUE;
4778 if (type == ARTWORK_TYPE_GRAPHICS)
4779 printf("::: 4: '%s'\n", artwork_new_identifier);
4783 if (type == ARTWORK_TYPE_GRAPHICS)
4784 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4785 artwork.gfx_current_identifier, artwork_current_identifier,
4786 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4787 artwork_new_identifier);
4790 return artwork_new_identifier;
4793 void ReloadCustomArtwork(int force_reload)
4795 char *gfx_new_identifier;
4796 char *snd_new_identifier;
4797 char *mus_new_identifier;
4798 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4799 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4800 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4801 boolean redraw_screen = FALSE;
4803 force_reload_gfx |= AdjustGraphicsForEMC();
4805 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4806 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4807 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4809 if (gfx_new_identifier != NULL || force_reload_gfx)
4812 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4813 artwork.gfx_current_identifier,
4815 artwork.gfx_current->identifier,
4816 leveldir_current->graphics_set);
4819 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4823 redraw_screen = TRUE;
4826 if (snd_new_identifier != NULL || force_reload_snd)
4828 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4830 InitSound(snd_new_identifier);
4832 redraw_screen = TRUE;
4835 if (mus_new_identifier != NULL || force_reload_mus)
4837 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4839 InitMusic(mus_new_identifier);
4841 redraw_screen = TRUE;
4848 /* force redraw of (open or closed) door graphics */
4849 SetDoorState(DOOR_OPEN_ALL);
4850 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4854 void KeyboardAutoRepeatOffUnlessAutoplay()
4856 if (global.autoplay_leveldir == NULL)
4857 KeyboardAutoRepeatOff();
4861 /* ========================================================================= */
4863 /* ========================================================================= */
4867 InitGlobal(); /* initialize some global variables */
4869 if (options.execute_command)
4870 Execute_Command(options.execute_command);
4872 if (options.serveronly)
4874 #if defined(PLATFORM_UNIX)
4875 NetworkServer(options.server_port, options.serveronly);
4877 Error(ERR_WARN, "networking only supported in Unix version");
4880 exit(0); /* never reached, server loops forever */
4887 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4888 InitArtworkConfig(); /* needed before forking sound child process */
4893 InitRND(NEW_RANDOMIZE);
4894 InitSimpleRandom(NEW_RANDOMIZE);
4899 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4902 InitEventFilter(FilterMouseMotionEvents);
4904 InitElementPropertiesStatic();
4905 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4910 InitLevelArtworkInfo();
4912 InitImages(); /* needs to know current level directory */
4913 InitSound(NULL); /* needs to know current level directory */
4914 InitMusic(NULL); /* needs to know current level directory */
4916 InitGfxBackground();
4922 if (global.autoplay_leveldir)
4927 else if (global.convert_leveldir)
4933 game_status = GAME_MODE_MAIN;
4937 InitNetworkServer();
4940 void CloseAllAndExit(int exit_value)
4945 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4953 #if defined(TARGET_SDL)
4954 if (network_server) /* terminate network server */
4955 SDL_KillThread(server_thread);
4958 CloseVideoDisplay();
4959 ClosePlatformDependentStuff();
4961 if (exit_value != 0)
4962 NotifyUserAboutErrorFile();