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 /* 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;
958 graphic_info[graphic].height = TILEY;
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;
977 /* optional x and y tile position of animation frame sequence */
978 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
979 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
980 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
981 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
983 /* optional x and y pixel position of animation frame sequence */
984 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
985 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
986 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
987 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
989 /* optional width and height of each animation frame */
990 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
991 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
992 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
993 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
995 /* optional zoom factor for scaling up the image to a larger size */
996 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
997 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
998 if (graphic_info[graphic].scale_up_factor < 1)
999 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1003 /* get final bitmap size (with scaling, but without small images) */
1004 int src_image_width = get_scaled_graphic_width(graphic);
1005 int src_image_height = get_scaled_graphic_height(graphic);
1007 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1008 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1010 graphic_info[graphic].src_image_width = src_image_width;
1011 graphic_info[graphic].src_image_height = src_image_height;
1014 /* correct x or y offset dependent of vertical or horizontal frame order */
1015 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1017 graphic_info[graphic].offset_y =
1018 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1019 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1020 anim_frames_per_line = anim_frames_per_col;
1022 else /* frames are ordered horizontally */
1024 graphic_info[graphic].offset_x =
1025 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1026 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1027 anim_frames_per_line = anim_frames_per_row;
1030 /* optionally, the x and y offset of frames can be specified directly */
1031 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1032 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1033 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1034 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1036 /* optionally, moving animations may have separate start and end graphics */
1037 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1039 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1040 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1042 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1043 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1044 graphic_info[graphic].offset2_y =
1045 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1046 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1047 else /* frames are ordered horizontally */
1048 graphic_info[graphic].offset2_x =
1049 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1050 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1052 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1053 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1055 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1056 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1058 /* optionally, the second movement tile can be specified as start tile */
1059 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1060 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1062 /* automatically determine correct number of frames, if not defined */
1063 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1065 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1066 graphic_info[graphic].anim_frames = anim_frames_per_row;
1067 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1068 graphic_info[graphic].anim_frames = anim_frames_per_col;
1070 graphic_info[graphic].anim_frames = 1;
1072 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1073 graphic_info[graphic].anim_frames = 1;
1075 graphic_info[graphic].anim_frames_per_line =
1076 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1077 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1079 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1080 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1081 graphic_info[graphic].anim_delay = 1;
1083 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1085 if (graphic_info[graphic].anim_frames == 1)
1086 graphic_info[graphic].anim_mode = ANIM_NONE;
1089 /* automatically determine correct start frame, if not defined */
1090 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1091 graphic_info[graphic].anim_start_frame = 0;
1092 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1093 graphic_info[graphic].anim_start_frame =
1094 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1096 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1098 /* animation synchronized with global frame counter, not move position */
1099 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1101 /* optional element for cloning crumble graphics */
1102 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1103 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1105 /* optional element for cloning digging graphics */
1106 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1107 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1109 /* optional border size for "crumbling" diggable graphics */
1110 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1111 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1113 /* this is only used for player "boring" and "sleeping" actions */
1114 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1115 graphic_info[graphic].anim_delay_fixed =
1116 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1117 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1118 graphic_info[graphic].anim_delay_random =
1119 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1120 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1121 graphic_info[graphic].post_delay_fixed =
1122 parameter[GFX_ARG_POST_DELAY_FIXED];
1123 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].post_delay_random =
1125 parameter[GFX_ARG_POST_DELAY_RANDOM];
1127 /* this is only used for toon animations */
1128 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1129 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1131 /* this is only used for drawing font characters */
1132 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1133 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1135 /* this is only used for drawing envelope graphics */
1136 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1138 /* optional graphic for cloning all graphics settings */
1139 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1142 /* optional settings for drawing title screens */
1143 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1144 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1145 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1146 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1147 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1148 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1151 static void set_cloned_graphic_parameters(int graphic)
1153 int fallback_graphic = IMG_CHAR_EXCLAM;
1154 int max_num_images = getImageListSize();
1155 int clone_graphic = graphic_info[graphic].clone_from;
1156 int num_references_followed = 1;
1158 while (graphic_info[clone_graphic].clone_from != -1 &&
1159 num_references_followed < max_num_images)
1161 clone_graphic = graphic_info[clone_graphic].clone_from;
1163 num_references_followed++;
1166 if (num_references_followed >= max_num_images)
1168 Error(ERR_RETURN_LINE, "-");
1169 Error(ERR_RETURN, "warning: error found in config file:");
1170 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1171 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1172 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1173 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1175 if (graphic == fallback_graphic)
1176 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1178 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1179 Error(ERR_RETURN_LINE, "-");
1181 graphic_info[graphic] = graphic_info[fallback_graphic];
1185 graphic_info[graphic] = graphic_info[clone_graphic];
1186 graphic_info[graphic].clone_from = clone_graphic;
1190 static void InitGraphicInfo()
1192 int fallback_graphic = IMG_CHAR_EXCLAM;
1193 int num_images = getImageListSize();
1196 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1197 static boolean clipmasks_initialized = FALSE;
1199 XGCValues clip_gc_values;
1200 unsigned long clip_gc_valuemask;
1201 GC copy_clipmask_gc = None;
1204 checked_free(graphic_info);
1206 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1208 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1209 if (clipmasks_initialized)
1211 for (i = 0; i < num_images; i++)
1213 if (graphic_info[i].clip_mask)
1214 XFreePixmap(display, graphic_info[i].clip_mask);
1215 if (graphic_info[i].clip_gc)
1216 XFreeGC(display, graphic_info[i].clip_gc);
1218 graphic_info[i].clip_mask = None;
1219 graphic_info[i].clip_gc = None;
1224 /* first set all graphic paramaters ... */
1225 for (i = 0; i < num_images; i++)
1226 set_graphic_parameters(i);
1228 /* ... then copy these parameters for cloned graphics */
1229 for (i = 0; i < num_images; i++)
1230 if (graphic_info[i].clone_from != -1)
1231 set_cloned_graphic_parameters(i);
1233 for (i = 0; i < num_images; i++)
1237 int first_frame, last_frame;
1238 int src_bitmap_width, src_bitmap_height;
1240 /* now check if no animation frames are outside of the loaded image */
1242 if (graphic_info[i].bitmap == NULL)
1243 continue; /* skip check for optional images that are undefined */
1245 /* get final bitmap size (with scaling, but without small images) */
1246 src_bitmap_width = graphic_info[i].src_image_width;
1247 src_bitmap_height = graphic_info[i].src_image_height;
1249 /* check if first animation frame is inside specified bitmap */
1252 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1254 if (src_x < 0 || src_y < 0 ||
1255 src_x + TILEX > src_bitmap_width ||
1256 src_y + TILEY > src_bitmap_height)
1258 Error(ERR_RETURN_LINE, "-");
1259 Error(ERR_RETURN, "warning: error found in config file:");
1260 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1261 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1262 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1264 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1265 src_x, src_y, src_bitmap_width, src_bitmap_height);
1266 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1268 if (i == fallback_graphic)
1269 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1271 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1272 Error(ERR_RETURN_LINE, "-");
1274 graphic_info[i] = graphic_info[fallback_graphic];
1277 /* check if last animation frame is inside specified bitmap */
1279 last_frame = graphic_info[i].anim_frames - 1;
1280 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1282 if (src_x < 0 || src_y < 0 ||
1283 src_x + TILEX > src_bitmap_width ||
1284 src_y + TILEY > src_bitmap_height)
1286 Error(ERR_RETURN_LINE, "-");
1287 Error(ERR_RETURN, "warning: error found in config file:");
1288 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1289 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1290 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1292 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1293 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1294 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1296 if (i == fallback_graphic)
1297 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1299 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1300 Error(ERR_RETURN_LINE, "-");
1302 graphic_info[i] = graphic_info[fallback_graphic];
1305 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1306 /* currently we only need a tile clip mask from the first frame */
1307 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1309 if (copy_clipmask_gc == None)
1311 clip_gc_values.graphics_exposures = False;
1312 clip_gc_valuemask = GCGraphicsExposures;
1313 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1314 clip_gc_valuemask, &clip_gc_values);
1317 graphic_info[i].clip_mask =
1318 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1320 src_pixmap = src_bitmap->clip_mask;
1321 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1322 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1324 clip_gc_values.graphics_exposures = False;
1325 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1326 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1328 graphic_info[i].clip_gc =
1329 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1333 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1334 if (copy_clipmask_gc)
1335 XFreeGC(display, copy_clipmask_gc);
1337 clipmasks_initialized = TRUE;
1341 static void InitElementSoundInfo()
1343 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1344 int num_property_mappings = getSoundListPropertyMappingSize();
1347 /* set values to -1 to identify later as "uninitialized" values */
1348 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1349 for (act = 0; act < NUM_ACTIONS; act++)
1350 element_info[i].sound[act] = -1;
1352 /* initialize element/sound mapping from static configuration */
1353 for (i = 0; element_to_sound[i].element > -1; i++)
1355 int element = element_to_sound[i].element;
1356 int action = element_to_sound[i].action;
1357 int sound = element_to_sound[i].sound;
1358 boolean is_class = element_to_sound[i].is_class;
1361 action = ACTION_DEFAULT;
1364 element_info[element].sound[action] = sound;
1366 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1367 if (strEqual(element_info[j].class_name,
1368 element_info[element].class_name))
1369 element_info[j].sound[action] = sound;
1372 /* initialize element class/sound mapping from dynamic configuration */
1373 for (i = 0; i < num_property_mappings; i++)
1375 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1376 int action = property_mapping[i].ext1_index;
1377 int sound = property_mapping[i].artwork_index;
1379 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1383 action = ACTION_DEFAULT;
1385 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1386 if (strEqual(element_info[j].class_name,
1387 element_info[element_class].class_name))
1388 element_info[j].sound[action] = sound;
1391 /* initialize element/sound mapping from dynamic configuration */
1392 for (i = 0; i < num_property_mappings; i++)
1394 int element = property_mapping[i].base_index;
1395 int action = property_mapping[i].ext1_index;
1396 int sound = property_mapping[i].artwork_index;
1398 if (element >= MAX_NUM_ELEMENTS)
1402 action = ACTION_DEFAULT;
1404 element_info[element].sound[action] = sound;
1407 /* now set all '-1' values to element specific default values */
1408 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1410 for (act = 0; act < NUM_ACTIONS; act++)
1412 /* generic default action sound (defined by "[default]" directive) */
1413 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1415 /* look for special default action sound (classic game specific) */
1416 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1417 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1418 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1419 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1420 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1421 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1423 /* !!! there's no such thing as a "default action sound" !!! */
1425 /* look for element specific default sound (independent from action) */
1426 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1427 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1431 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1432 /* !!! make this better !!! */
1433 if (i == EL_EMPTY_SPACE)
1434 default_action_sound = element_info[EL_DEFAULT].sound[act];
1437 /* no sound for this specific action -- use default action sound */
1438 if (element_info[i].sound[act] == -1)
1439 element_info[i].sound[act] = default_action_sound;
1443 /* copy sound settings to some elements that are only stored in level file
1444 in native R'n'D levels, but are used by game engine in native EM levels */
1445 for (i = 0; copy_properties[i][0] != -1; i++)
1446 for (j = 1; j <= 4; j++)
1447 for (act = 0; act < NUM_ACTIONS; act++)
1448 element_info[copy_properties[i][j]].sound[act] =
1449 element_info[copy_properties[i][0]].sound[act];
1452 static void InitGameModeSoundInfo()
1456 /* set values to -1 to identify later as "uninitialized" values */
1457 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1460 /* initialize gamemode/sound mapping from static configuration */
1461 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1463 int gamemode = gamemode_to_sound[i].gamemode;
1464 int sound = gamemode_to_sound[i].sound;
1467 gamemode = GAME_MODE_DEFAULT;
1469 menu.sound[gamemode] = sound;
1472 /* now set all '-1' values to levelset specific default values */
1473 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1474 if (menu.sound[i] == -1)
1475 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1478 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1479 if (menu.sound[i] != -1)
1480 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1484 static void set_sound_parameters(int sound, char **parameter_raw)
1486 int parameter[NUM_SND_ARGS];
1489 /* get integer values from string parameters */
1490 for (i = 0; i < NUM_SND_ARGS; i++)
1492 get_parameter_value(parameter_raw[i],
1493 sound_config_suffix[i].token,
1494 sound_config_suffix[i].type);
1496 /* explicit loop mode setting in configuration overrides default value */
1497 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1498 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1500 /* sound volume to change the original volume when loading the sound file */
1501 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1503 /* sound priority to give certain sounds a higher or lower priority */
1504 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1507 static void InitSoundInfo()
1509 int *sound_effect_properties;
1510 int num_sounds = getSoundListSize();
1513 checked_free(sound_info);
1515 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1516 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1518 /* initialize sound effect for all elements to "no sound" */
1519 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1520 for (j = 0; j < NUM_ACTIONS; j++)
1521 element_info[i].sound[j] = SND_UNDEFINED;
1523 for (i = 0; i < num_sounds; i++)
1525 struct FileInfo *sound = getSoundListEntry(i);
1526 int len_effect_text = strlen(sound->token);
1528 sound_effect_properties[i] = ACTION_OTHER;
1529 sound_info[i].loop = FALSE; /* default: play sound only once */
1532 printf("::: sound %d: '%s'\n", i, sound->token);
1535 /* determine all loop sounds and identify certain sound classes */
1537 for (j = 0; element_action_info[j].suffix; j++)
1539 int len_action_text = strlen(element_action_info[j].suffix);
1541 if (len_action_text < len_effect_text &&
1542 strEqual(&sound->token[len_effect_text - len_action_text],
1543 element_action_info[j].suffix))
1545 sound_effect_properties[i] = element_action_info[j].value;
1546 sound_info[i].loop = element_action_info[j].is_loop_sound;
1552 /* associate elements and some selected sound actions */
1554 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1556 if (element_info[j].class_name)
1558 int len_class_text = strlen(element_info[j].class_name);
1560 if (len_class_text + 1 < len_effect_text &&
1561 strncmp(sound->token,
1562 element_info[j].class_name, len_class_text) == 0 &&
1563 sound->token[len_class_text] == '.')
1565 int sound_action_value = sound_effect_properties[i];
1567 element_info[j].sound[sound_action_value] = i;
1572 set_sound_parameters(i, sound->parameter);
1575 free(sound_effect_properties);
1578 static void InitGameModeMusicInfo()
1580 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1581 int num_property_mappings = getMusicListPropertyMappingSize();
1582 int default_levelset_music = -1;
1585 /* set values to -1 to identify later as "uninitialized" values */
1586 for (i = 0; i < MAX_LEVELS; i++)
1587 levelset.music[i] = -1;
1588 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1591 /* initialize gamemode/music mapping from static configuration */
1592 for (i = 0; gamemode_to_music[i].music > -1; i++)
1594 int gamemode = gamemode_to_music[i].gamemode;
1595 int music = gamemode_to_music[i].music;
1598 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1602 gamemode = GAME_MODE_DEFAULT;
1604 menu.music[gamemode] = music;
1607 /* initialize gamemode/music mapping from dynamic configuration */
1608 for (i = 0; i < num_property_mappings; i++)
1610 int prefix = property_mapping[i].base_index;
1611 int gamemode = property_mapping[i].ext1_index;
1612 int level = property_mapping[i].ext2_index;
1613 int music = property_mapping[i].artwork_index;
1616 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1617 prefix, gamemode, level, music);
1620 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1624 gamemode = GAME_MODE_DEFAULT;
1626 /* level specific music only allowed for in-game music */
1627 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1628 gamemode = GAME_MODE_PLAYING;
1633 default_levelset_music = music;
1636 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1637 levelset.music[level] = music;
1638 if (gamemode != GAME_MODE_PLAYING)
1639 menu.music[gamemode] = music;
1642 /* now set all '-1' values to menu specific default values */
1643 /* (undefined values of "levelset.music[]" might stay at "-1" to
1644 allow dynamic selection of music files from music directory!) */
1645 for (i = 0; i < MAX_LEVELS; i++)
1646 if (levelset.music[i] == -1)
1647 levelset.music[i] = default_levelset_music;
1648 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1649 if (menu.music[i] == -1)
1650 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1653 for (i = 0; i < MAX_LEVELS; i++)
1654 if (levelset.music[i] != -1)
1655 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1656 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1657 if (menu.music[i] != -1)
1658 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1662 static void set_music_parameters(int music, char **parameter_raw)
1664 int parameter[NUM_MUS_ARGS];
1667 /* get integer values from string parameters */
1668 for (i = 0; i < NUM_MUS_ARGS; i++)
1670 get_parameter_value(parameter_raw[i],
1671 music_config_suffix[i].token,
1672 music_config_suffix[i].type);
1674 /* explicit loop mode setting in configuration overrides default value */
1675 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1676 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1679 static void InitMusicInfo()
1681 int num_music = getMusicListSize();
1684 checked_free(music_info);
1686 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1688 for (i = 0; i < num_music; i++)
1690 struct FileInfo *music = getMusicListEntry(i);
1691 int len_music_text = strlen(music->token);
1693 music_info[i].loop = TRUE; /* default: play music in loop mode */
1695 /* determine all loop music */
1697 for (j = 0; music_prefix_info[j].prefix; j++)
1699 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1701 if (len_prefix_text < len_music_text &&
1702 strncmp(music->token,
1703 music_prefix_info[j].prefix, len_prefix_text) == 0)
1705 music_info[i].loop = music_prefix_info[j].is_loop_music;
1711 set_music_parameters(i, music->parameter);
1715 static void ReinitializeGraphics()
1717 InitGraphicInfo(); /* graphic properties mapping */
1718 InitElementGraphicInfo(); /* element game graphic mapping */
1719 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1721 InitElementSmallImages(); /* scale elements to all needed sizes */
1722 InitScaledImages(); /* scale all other images, if needed */
1723 InitFontGraphicInfo(); /* initialize text drawing functions */
1725 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1727 SetMainBackgroundImage(IMG_BACKGROUND);
1728 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1734 static void ReinitializeSounds()
1736 InitSoundInfo(); /* sound properties mapping */
1737 InitElementSoundInfo(); /* element game sound mapping */
1738 InitGameModeSoundInfo(); /* game mode sound mapping */
1740 InitPlayLevelSound(); /* internal game sound settings */
1743 static void ReinitializeMusic()
1745 InitMusicInfo(); /* music properties mapping */
1746 InitGameModeMusicInfo(); /* game mode music mapping */
1749 static int get_special_property_bit(int element, int property_bit_nr)
1751 struct PropertyBitInfo
1757 static struct PropertyBitInfo pb_can_move_into_acid[] =
1759 /* the player may be able fall into acid when gravity is activated */
1764 { EL_SP_MURPHY, 0 },
1765 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1767 /* all elements that can move may be able to also move into acid */
1770 { EL_BUG_RIGHT, 1 },
1773 { EL_SPACESHIP, 2 },
1774 { EL_SPACESHIP_LEFT, 2 },
1775 { EL_SPACESHIP_RIGHT, 2 },
1776 { EL_SPACESHIP_UP, 2 },
1777 { EL_SPACESHIP_DOWN, 2 },
1778 { EL_BD_BUTTERFLY, 3 },
1779 { EL_BD_BUTTERFLY_LEFT, 3 },
1780 { EL_BD_BUTTERFLY_RIGHT, 3 },
1781 { EL_BD_BUTTERFLY_UP, 3 },
1782 { EL_BD_BUTTERFLY_DOWN, 3 },
1783 { EL_BD_FIREFLY, 4 },
1784 { EL_BD_FIREFLY_LEFT, 4 },
1785 { EL_BD_FIREFLY_RIGHT, 4 },
1786 { EL_BD_FIREFLY_UP, 4 },
1787 { EL_BD_FIREFLY_DOWN, 4 },
1789 { EL_YAMYAM_LEFT, 5 },
1790 { EL_YAMYAM_RIGHT, 5 },
1791 { EL_YAMYAM_UP, 5 },
1792 { EL_YAMYAM_DOWN, 5 },
1793 { EL_DARK_YAMYAM, 6 },
1796 { EL_PACMAN_LEFT, 8 },
1797 { EL_PACMAN_RIGHT, 8 },
1798 { EL_PACMAN_UP, 8 },
1799 { EL_PACMAN_DOWN, 8 },
1801 { EL_MOLE_LEFT, 9 },
1802 { EL_MOLE_RIGHT, 9 },
1804 { EL_MOLE_DOWN, 9 },
1808 { EL_SATELLITE, 13 },
1809 { EL_SP_SNIKSNAK, 14 },
1810 { EL_SP_ELECTRON, 15 },
1813 { EL_EMC_ANDROID, 18 },
1818 static struct PropertyBitInfo pb_dont_collide_with[] =
1820 { EL_SP_SNIKSNAK, 0 },
1821 { EL_SP_ELECTRON, 1 },
1829 struct PropertyBitInfo *pb_info;
1832 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1833 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1838 struct PropertyBitInfo *pb_info = NULL;
1841 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1842 if (pb_definition[i].bit_nr == property_bit_nr)
1843 pb_info = pb_definition[i].pb_info;
1845 if (pb_info == NULL)
1848 for (i = 0; pb_info[i].element != -1; i++)
1849 if (pb_info[i].element == element)
1850 return pb_info[i].bit_nr;
1855 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1856 boolean property_value)
1858 int bit_nr = get_special_property_bit(element, property_bit_nr);
1863 *bitfield |= (1 << bit_nr);
1865 *bitfield &= ~(1 << bit_nr);
1869 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1871 int bit_nr = get_special_property_bit(element, property_bit_nr);
1874 return ((*bitfield & (1 << bit_nr)) != 0);
1879 static void resolve_group_element(int group_element, int recursion_depth)
1881 static int group_nr;
1882 static struct ElementGroupInfo *group;
1883 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1886 if (actual_group == NULL) /* not yet initialized */
1889 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1891 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1892 group_element - EL_GROUP_START + 1);
1894 /* replace element which caused too deep recursion by question mark */
1895 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1900 if (recursion_depth == 0) /* initialization */
1902 group = actual_group;
1903 group_nr = group_element - EL_GROUP_START;
1905 group->num_elements_resolved = 0;
1906 group->choice_pos = 0;
1909 for (i = 0; i < actual_group->num_elements; i++)
1911 int element = actual_group->element[i];
1913 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1916 if (IS_GROUP_ELEMENT(element))
1917 resolve_group_element(element, recursion_depth + 1);
1920 group->element_resolved[group->num_elements_resolved++] = element;
1921 element_info[element].in_group[group_nr] = TRUE;
1926 void InitElementPropertiesStatic()
1928 static int ep_diggable[] =
1933 EL_SP_BUGGY_BASE_ACTIVATING,
1936 EL_INVISIBLE_SAND_ACTIVE,
1939 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1940 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1944 EL_SP_BUGGY_BASE_ACTIVE,
1951 static int ep_collectible_only[] =
1973 EL_DYNABOMB_INCREASE_NUMBER,
1974 EL_DYNABOMB_INCREASE_SIZE,
1975 EL_DYNABOMB_INCREASE_POWER,
1995 static int ep_dont_run_into[] =
1997 /* same elements as in 'ep_dont_touch' */
2003 /* same elements as in 'ep_dont_collide_with' */
2015 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2019 EL_SP_BUGGY_BASE_ACTIVE,
2026 static int ep_dont_collide_with[] =
2028 /* same elements as in 'ep_dont_touch' */
2045 static int ep_dont_touch[] =
2055 static int ep_indestructible[] =
2059 EL_ACID_POOL_TOPLEFT,
2060 EL_ACID_POOL_TOPRIGHT,
2061 EL_ACID_POOL_BOTTOMLEFT,
2062 EL_ACID_POOL_BOTTOM,
2063 EL_ACID_POOL_BOTTOMRIGHT,
2064 EL_SP_HARDWARE_GRAY,
2065 EL_SP_HARDWARE_GREEN,
2066 EL_SP_HARDWARE_BLUE,
2068 EL_SP_HARDWARE_YELLOW,
2069 EL_SP_HARDWARE_BASE_1,
2070 EL_SP_HARDWARE_BASE_2,
2071 EL_SP_HARDWARE_BASE_3,
2072 EL_SP_HARDWARE_BASE_4,
2073 EL_SP_HARDWARE_BASE_5,
2074 EL_SP_HARDWARE_BASE_6,
2075 EL_INVISIBLE_STEELWALL,
2076 EL_INVISIBLE_STEELWALL_ACTIVE,
2077 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2078 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2079 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2080 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2081 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2082 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2083 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2084 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2085 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2086 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2087 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2088 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2090 EL_LIGHT_SWITCH_ACTIVE,
2091 EL_SIGN_EXCLAMATION,
2092 EL_SIGN_RADIOACTIVITY,
2103 EL_STEELWALL_SLIPPERY,
2117 EL_GATE_1_GRAY_ACTIVE,
2118 EL_GATE_2_GRAY_ACTIVE,
2119 EL_GATE_3_GRAY_ACTIVE,
2120 EL_GATE_4_GRAY_ACTIVE,
2129 EL_EM_GATE_1_GRAY_ACTIVE,
2130 EL_EM_GATE_2_GRAY_ACTIVE,
2131 EL_EM_GATE_3_GRAY_ACTIVE,
2132 EL_EM_GATE_4_GRAY_ACTIVE,
2141 EL_EMC_GATE_5_GRAY_ACTIVE,
2142 EL_EMC_GATE_6_GRAY_ACTIVE,
2143 EL_EMC_GATE_7_GRAY_ACTIVE,
2144 EL_EMC_GATE_8_GRAY_ACTIVE,
2146 EL_SWITCHGATE_OPENING,
2147 EL_SWITCHGATE_CLOSED,
2148 EL_SWITCHGATE_CLOSING,
2150 EL_SWITCHGATE_SWITCH_UP,
2151 EL_SWITCHGATE_SWITCH_DOWN,
2154 EL_TIMEGATE_OPENING,
2156 EL_TIMEGATE_CLOSING,
2159 EL_TIMEGATE_SWITCH_ACTIVE,
2164 EL_TUBE_VERTICAL_LEFT,
2165 EL_TUBE_VERTICAL_RIGHT,
2166 EL_TUBE_HORIZONTAL_UP,
2167 EL_TUBE_HORIZONTAL_DOWN,
2176 static int ep_slippery[] =
2190 EL_ROBOT_WHEEL_ACTIVE,
2196 EL_ACID_POOL_TOPLEFT,
2197 EL_ACID_POOL_TOPRIGHT,
2207 EL_STEELWALL_SLIPPERY,
2210 EL_EMC_WALL_SLIPPERY_1,
2211 EL_EMC_WALL_SLIPPERY_2,
2212 EL_EMC_WALL_SLIPPERY_3,
2213 EL_EMC_WALL_SLIPPERY_4,
2215 EL_EMC_MAGIC_BALL_ACTIVE,
2220 static int ep_can_change[] =
2225 static int ep_can_move[] =
2227 /* same elements as in 'pb_can_move_into_acid' */
2250 static int ep_can_fall[] =
2265 EL_BD_MAGIC_WALL_FULL,
2279 static int ep_can_smash_player[] =
2305 static int ep_can_smash_enemies[] =
2314 static int ep_can_smash_everything[] =
2323 static int ep_explodes_by_fire[] =
2325 /* same elements as in 'ep_explodes_impact' */
2330 /* same elements as in 'ep_explodes_smashed' */
2340 EL_EM_DYNAMITE_ACTIVE,
2341 EL_DYNABOMB_PLAYER_1_ACTIVE,
2342 EL_DYNABOMB_PLAYER_2_ACTIVE,
2343 EL_DYNABOMB_PLAYER_3_ACTIVE,
2344 EL_DYNABOMB_PLAYER_4_ACTIVE,
2345 EL_DYNABOMB_INCREASE_NUMBER,
2346 EL_DYNABOMB_INCREASE_SIZE,
2347 EL_DYNABOMB_INCREASE_POWER,
2348 EL_SP_DISK_RED_ACTIVE,
2362 static int ep_explodes_smashed[] =
2364 /* same elements as in 'ep_explodes_impact' */
2378 static int ep_explodes_impact[] =
2387 static int ep_walkable_over[] =
2391 EL_SOKOBAN_FIELD_EMPTY,
2403 EL_GATE_1_GRAY_ACTIVE,
2404 EL_GATE_2_GRAY_ACTIVE,
2405 EL_GATE_3_GRAY_ACTIVE,
2406 EL_GATE_4_GRAY_ACTIVE,
2414 static int ep_walkable_inside[] =
2419 EL_TUBE_VERTICAL_LEFT,
2420 EL_TUBE_VERTICAL_RIGHT,
2421 EL_TUBE_HORIZONTAL_UP,
2422 EL_TUBE_HORIZONTAL_DOWN,
2431 static int ep_walkable_under[] =
2436 static int ep_passable_over[] =
2446 EL_EM_GATE_1_GRAY_ACTIVE,
2447 EL_EM_GATE_2_GRAY_ACTIVE,
2448 EL_EM_GATE_3_GRAY_ACTIVE,
2449 EL_EM_GATE_4_GRAY_ACTIVE,
2458 EL_EMC_GATE_5_GRAY_ACTIVE,
2459 EL_EMC_GATE_6_GRAY_ACTIVE,
2460 EL_EMC_GATE_7_GRAY_ACTIVE,
2461 EL_EMC_GATE_8_GRAY_ACTIVE,
2468 static int ep_passable_inside[] =
2474 EL_SP_PORT_HORIZONTAL,
2475 EL_SP_PORT_VERTICAL,
2477 EL_SP_GRAVITY_PORT_LEFT,
2478 EL_SP_GRAVITY_PORT_RIGHT,
2479 EL_SP_GRAVITY_PORT_UP,
2480 EL_SP_GRAVITY_PORT_DOWN,
2481 EL_SP_GRAVITY_ON_PORT_LEFT,
2482 EL_SP_GRAVITY_ON_PORT_RIGHT,
2483 EL_SP_GRAVITY_ON_PORT_UP,
2484 EL_SP_GRAVITY_ON_PORT_DOWN,
2485 EL_SP_GRAVITY_OFF_PORT_LEFT,
2486 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2487 EL_SP_GRAVITY_OFF_PORT_UP,
2488 EL_SP_GRAVITY_OFF_PORT_DOWN,
2493 static int ep_passable_under[] =
2498 static int ep_droppable[] =
2503 static int ep_explodes_1x1_old[] =
2508 static int ep_pushable[] =
2520 EL_SOKOBAN_FIELD_FULL,
2529 static int ep_explodes_cross_old[] =
2534 static int ep_protected[] =
2536 /* same elements as in 'ep_walkable_inside' */
2540 EL_TUBE_VERTICAL_LEFT,
2541 EL_TUBE_VERTICAL_RIGHT,
2542 EL_TUBE_HORIZONTAL_UP,
2543 EL_TUBE_HORIZONTAL_DOWN,
2549 /* same elements as in 'ep_passable_over' */
2558 EL_EM_GATE_1_GRAY_ACTIVE,
2559 EL_EM_GATE_2_GRAY_ACTIVE,
2560 EL_EM_GATE_3_GRAY_ACTIVE,
2561 EL_EM_GATE_4_GRAY_ACTIVE,
2570 EL_EMC_GATE_5_GRAY_ACTIVE,
2571 EL_EMC_GATE_6_GRAY_ACTIVE,
2572 EL_EMC_GATE_7_GRAY_ACTIVE,
2573 EL_EMC_GATE_8_GRAY_ACTIVE,
2577 /* same elements as in 'ep_passable_inside' */
2582 EL_SP_PORT_HORIZONTAL,
2583 EL_SP_PORT_VERTICAL,
2585 EL_SP_GRAVITY_PORT_LEFT,
2586 EL_SP_GRAVITY_PORT_RIGHT,
2587 EL_SP_GRAVITY_PORT_UP,
2588 EL_SP_GRAVITY_PORT_DOWN,
2589 EL_SP_GRAVITY_ON_PORT_LEFT,
2590 EL_SP_GRAVITY_ON_PORT_RIGHT,
2591 EL_SP_GRAVITY_ON_PORT_UP,
2592 EL_SP_GRAVITY_ON_PORT_DOWN,
2593 EL_SP_GRAVITY_OFF_PORT_LEFT,
2594 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2595 EL_SP_GRAVITY_OFF_PORT_UP,
2596 EL_SP_GRAVITY_OFF_PORT_DOWN,
2601 static int ep_throwable[] =
2606 static int ep_can_explode[] =
2608 /* same elements as in 'ep_explodes_impact' */
2613 /* same elements as in 'ep_explodes_smashed' */
2619 /* elements that can explode by explosion or by dragonfire */
2623 EL_EM_DYNAMITE_ACTIVE,
2624 EL_DYNABOMB_PLAYER_1_ACTIVE,
2625 EL_DYNABOMB_PLAYER_2_ACTIVE,
2626 EL_DYNABOMB_PLAYER_3_ACTIVE,
2627 EL_DYNABOMB_PLAYER_4_ACTIVE,
2628 EL_DYNABOMB_INCREASE_NUMBER,
2629 EL_DYNABOMB_INCREASE_SIZE,
2630 EL_DYNABOMB_INCREASE_POWER,
2631 EL_SP_DISK_RED_ACTIVE,
2639 /* elements that can explode only by explosion */
2645 static int ep_gravity_reachable[] =
2651 EL_INVISIBLE_SAND_ACTIVE,
2656 EL_SP_PORT_HORIZONTAL,
2657 EL_SP_PORT_VERTICAL,
2659 EL_SP_GRAVITY_PORT_LEFT,
2660 EL_SP_GRAVITY_PORT_RIGHT,
2661 EL_SP_GRAVITY_PORT_UP,
2662 EL_SP_GRAVITY_PORT_DOWN,
2663 EL_SP_GRAVITY_ON_PORT_LEFT,
2664 EL_SP_GRAVITY_ON_PORT_RIGHT,
2665 EL_SP_GRAVITY_ON_PORT_UP,
2666 EL_SP_GRAVITY_ON_PORT_DOWN,
2667 EL_SP_GRAVITY_OFF_PORT_LEFT,
2668 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2669 EL_SP_GRAVITY_OFF_PORT_UP,
2670 EL_SP_GRAVITY_OFF_PORT_DOWN,
2676 static int ep_player[] =
2683 EL_SOKOBAN_FIELD_PLAYER,
2689 static int ep_can_pass_magic_wall[] =
2703 static int ep_switchable[] =
2707 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2708 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2709 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2710 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2711 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2712 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2713 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2714 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2715 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2716 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2717 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2718 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2719 EL_SWITCHGATE_SWITCH_UP,
2720 EL_SWITCHGATE_SWITCH_DOWN,
2722 EL_LIGHT_SWITCH_ACTIVE,
2724 EL_BALLOON_SWITCH_LEFT,
2725 EL_BALLOON_SWITCH_RIGHT,
2726 EL_BALLOON_SWITCH_UP,
2727 EL_BALLOON_SWITCH_DOWN,
2728 EL_BALLOON_SWITCH_ANY,
2729 EL_BALLOON_SWITCH_NONE,
2732 EL_EMC_MAGIC_BALL_SWITCH,
2733 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2738 static int ep_bd_element[] =
2772 static int ep_sp_element[] =
2774 /* should always be valid */
2777 /* standard classic Supaplex elements */
2784 EL_SP_HARDWARE_GRAY,
2792 EL_SP_GRAVITY_PORT_RIGHT,
2793 EL_SP_GRAVITY_PORT_DOWN,
2794 EL_SP_GRAVITY_PORT_LEFT,
2795 EL_SP_GRAVITY_PORT_UP,
2800 EL_SP_PORT_VERTICAL,
2801 EL_SP_PORT_HORIZONTAL,
2807 EL_SP_HARDWARE_BASE_1,
2808 EL_SP_HARDWARE_GREEN,
2809 EL_SP_HARDWARE_BLUE,
2811 EL_SP_HARDWARE_YELLOW,
2812 EL_SP_HARDWARE_BASE_2,
2813 EL_SP_HARDWARE_BASE_3,
2814 EL_SP_HARDWARE_BASE_4,
2815 EL_SP_HARDWARE_BASE_5,
2816 EL_SP_HARDWARE_BASE_6,
2820 /* additional elements that appeared in newer Supaplex levels */
2823 /* additional gravity port elements (not switching, but setting gravity) */
2824 EL_SP_GRAVITY_ON_PORT_LEFT,
2825 EL_SP_GRAVITY_ON_PORT_RIGHT,
2826 EL_SP_GRAVITY_ON_PORT_UP,
2827 EL_SP_GRAVITY_ON_PORT_DOWN,
2828 EL_SP_GRAVITY_OFF_PORT_LEFT,
2829 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2830 EL_SP_GRAVITY_OFF_PORT_UP,
2831 EL_SP_GRAVITY_OFF_PORT_DOWN,
2833 /* more than one Murphy in a level results in an inactive clone */
2836 /* runtime Supaplex elements */
2837 EL_SP_DISK_RED_ACTIVE,
2838 EL_SP_TERMINAL_ACTIVE,
2839 EL_SP_BUGGY_BASE_ACTIVATING,
2840 EL_SP_BUGGY_BASE_ACTIVE,
2847 static int ep_sb_element[] =
2852 EL_SOKOBAN_FIELD_EMPTY,
2853 EL_SOKOBAN_FIELD_FULL,
2854 EL_SOKOBAN_FIELD_PLAYER,
2859 EL_INVISIBLE_STEELWALL,
2864 static int ep_gem[] =
2876 static int ep_food_dark_yamyam[] =
2904 static int ep_food_penguin[] =
2918 static int ep_food_pig[] =
2930 static int ep_historic_wall[] =
2941 EL_GATE_1_GRAY_ACTIVE,
2942 EL_GATE_2_GRAY_ACTIVE,
2943 EL_GATE_3_GRAY_ACTIVE,
2944 EL_GATE_4_GRAY_ACTIVE,
2953 EL_EM_GATE_1_GRAY_ACTIVE,
2954 EL_EM_GATE_2_GRAY_ACTIVE,
2955 EL_EM_GATE_3_GRAY_ACTIVE,
2956 EL_EM_GATE_4_GRAY_ACTIVE,
2963 EL_EXPANDABLE_WALL_HORIZONTAL,
2964 EL_EXPANDABLE_WALL_VERTICAL,
2965 EL_EXPANDABLE_WALL_ANY,
2966 EL_EXPANDABLE_WALL_GROWING,
2967 EL_BD_EXPANDABLE_WALL,
2974 EL_SP_HARDWARE_GRAY,
2975 EL_SP_HARDWARE_GREEN,
2976 EL_SP_HARDWARE_BLUE,
2978 EL_SP_HARDWARE_YELLOW,
2979 EL_SP_HARDWARE_BASE_1,
2980 EL_SP_HARDWARE_BASE_2,
2981 EL_SP_HARDWARE_BASE_3,
2982 EL_SP_HARDWARE_BASE_4,
2983 EL_SP_HARDWARE_BASE_5,
2984 EL_SP_HARDWARE_BASE_6,
2986 EL_SP_TERMINAL_ACTIVE,
2989 EL_INVISIBLE_STEELWALL,
2990 EL_INVISIBLE_STEELWALL_ACTIVE,
2992 EL_INVISIBLE_WALL_ACTIVE,
2993 EL_STEELWALL_SLIPPERY,
3010 static int ep_historic_solid[] =
3014 EL_EXPANDABLE_WALL_HORIZONTAL,
3015 EL_EXPANDABLE_WALL_VERTICAL,
3016 EL_EXPANDABLE_WALL_ANY,
3017 EL_BD_EXPANDABLE_WALL,
3030 EL_QUICKSAND_FILLING,
3031 EL_QUICKSAND_EMPTYING,
3033 EL_MAGIC_WALL_ACTIVE,
3034 EL_MAGIC_WALL_EMPTYING,
3035 EL_MAGIC_WALL_FILLING,
3039 EL_BD_MAGIC_WALL_ACTIVE,
3040 EL_BD_MAGIC_WALL_EMPTYING,
3041 EL_BD_MAGIC_WALL_FULL,
3042 EL_BD_MAGIC_WALL_FILLING,
3043 EL_BD_MAGIC_WALL_DEAD,
3052 EL_SP_TERMINAL_ACTIVE,
3056 EL_INVISIBLE_WALL_ACTIVE,
3057 EL_SWITCHGATE_SWITCH_UP,
3058 EL_SWITCHGATE_SWITCH_DOWN,
3060 EL_TIMEGATE_SWITCH_ACTIVE,
3072 /* the following elements are a direct copy of "indestructible" elements,
3073 except "EL_ACID", which is "indestructible", but not "solid"! */
3078 EL_ACID_POOL_TOPLEFT,
3079 EL_ACID_POOL_TOPRIGHT,
3080 EL_ACID_POOL_BOTTOMLEFT,
3081 EL_ACID_POOL_BOTTOM,
3082 EL_ACID_POOL_BOTTOMRIGHT,
3083 EL_SP_HARDWARE_GRAY,
3084 EL_SP_HARDWARE_GREEN,
3085 EL_SP_HARDWARE_BLUE,
3087 EL_SP_HARDWARE_YELLOW,
3088 EL_SP_HARDWARE_BASE_1,
3089 EL_SP_HARDWARE_BASE_2,
3090 EL_SP_HARDWARE_BASE_3,
3091 EL_SP_HARDWARE_BASE_4,
3092 EL_SP_HARDWARE_BASE_5,
3093 EL_SP_HARDWARE_BASE_6,
3094 EL_INVISIBLE_STEELWALL,
3095 EL_INVISIBLE_STEELWALL_ACTIVE,
3096 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3097 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3098 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3099 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3100 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3101 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3102 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3103 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3104 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3105 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3106 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3107 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3109 EL_LIGHT_SWITCH_ACTIVE,
3110 EL_SIGN_EXCLAMATION,
3111 EL_SIGN_RADIOACTIVITY,
3122 EL_STEELWALL_SLIPPERY,
3136 EL_GATE_1_GRAY_ACTIVE,
3137 EL_GATE_2_GRAY_ACTIVE,
3138 EL_GATE_3_GRAY_ACTIVE,
3139 EL_GATE_4_GRAY_ACTIVE,
3148 EL_EM_GATE_1_GRAY_ACTIVE,
3149 EL_EM_GATE_2_GRAY_ACTIVE,
3150 EL_EM_GATE_3_GRAY_ACTIVE,
3151 EL_EM_GATE_4_GRAY_ACTIVE,
3153 EL_SWITCHGATE_OPENING,
3154 EL_SWITCHGATE_CLOSED,
3155 EL_SWITCHGATE_CLOSING,
3157 EL_TIMEGATE_OPENING,
3159 EL_TIMEGATE_CLOSING,
3163 EL_TUBE_VERTICAL_LEFT,
3164 EL_TUBE_VERTICAL_RIGHT,
3165 EL_TUBE_HORIZONTAL_UP,
3166 EL_TUBE_HORIZONTAL_DOWN,
3175 static int ep_classic_enemy[] =
3192 static int ep_belt[] =
3194 EL_CONVEYOR_BELT_1_LEFT,
3195 EL_CONVEYOR_BELT_1_MIDDLE,
3196 EL_CONVEYOR_BELT_1_RIGHT,
3197 EL_CONVEYOR_BELT_2_LEFT,
3198 EL_CONVEYOR_BELT_2_MIDDLE,
3199 EL_CONVEYOR_BELT_2_RIGHT,
3200 EL_CONVEYOR_BELT_3_LEFT,
3201 EL_CONVEYOR_BELT_3_MIDDLE,
3202 EL_CONVEYOR_BELT_3_RIGHT,
3203 EL_CONVEYOR_BELT_4_LEFT,
3204 EL_CONVEYOR_BELT_4_MIDDLE,
3205 EL_CONVEYOR_BELT_4_RIGHT,
3210 static int ep_belt_active[] =
3212 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3213 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3214 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3215 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3216 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3217 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3218 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3219 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3220 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3221 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3222 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3223 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3228 static int ep_belt_switch[] =
3230 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3231 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3232 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3233 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3234 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3235 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3236 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3237 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3238 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3239 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3240 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3241 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3246 static int ep_tube[] =
3253 EL_TUBE_HORIZONTAL_UP,
3254 EL_TUBE_HORIZONTAL_DOWN,
3256 EL_TUBE_VERTICAL_LEFT,
3257 EL_TUBE_VERTICAL_RIGHT,
3263 static int ep_keygate[] =
3273 EL_GATE_1_GRAY_ACTIVE,
3274 EL_GATE_2_GRAY_ACTIVE,
3275 EL_GATE_3_GRAY_ACTIVE,
3276 EL_GATE_4_GRAY_ACTIVE,
3285 EL_EM_GATE_1_GRAY_ACTIVE,
3286 EL_EM_GATE_2_GRAY_ACTIVE,
3287 EL_EM_GATE_3_GRAY_ACTIVE,
3288 EL_EM_GATE_4_GRAY_ACTIVE,
3297 EL_EMC_GATE_5_GRAY_ACTIVE,
3298 EL_EMC_GATE_6_GRAY_ACTIVE,
3299 EL_EMC_GATE_7_GRAY_ACTIVE,
3300 EL_EMC_GATE_8_GRAY_ACTIVE,
3305 static int ep_amoeboid[] =
3317 static int ep_amoebalive[] =
3328 static int ep_has_editor_content[] =
3350 static int ep_can_turn_each_move[] =
3352 /* !!! do something with this one !!! */
3356 static int ep_can_grow[] =
3370 static int ep_active_bomb[] =
3373 EL_EM_DYNAMITE_ACTIVE,
3374 EL_DYNABOMB_PLAYER_1_ACTIVE,
3375 EL_DYNABOMB_PLAYER_2_ACTIVE,
3376 EL_DYNABOMB_PLAYER_3_ACTIVE,
3377 EL_DYNABOMB_PLAYER_4_ACTIVE,
3378 EL_SP_DISK_RED_ACTIVE,
3383 static int ep_inactive[] =
3415 EL_GATE_1_GRAY_ACTIVE,
3416 EL_GATE_2_GRAY_ACTIVE,
3417 EL_GATE_3_GRAY_ACTIVE,
3418 EL_GATE_4_GRAY_ACTIVE,
3427 EL_EM_GATE_1_GRAY_ACTIVE,
3428 EL_EM_GATE_2_GRAY_ACTIVE,
3429 EL_EM_GATE_3_GRAY_ACTIVE,
3430 EL_EM_GATE_4_GRAY_ACTIVE,
3439 EL_EMC_GATE_5_GRAY_ACTIVE,
3440 EL_EMC_GATE_6_GRAY_ACTIVE,
3441 EL_EMC_GATE_7_GRAY_ACTIVE,
3442 EL_EMC_GATE_8_GRAY_ACTIVE,
3445 EL_INVISIBLE_STEELWALL,
3453 EL_WALL_EMERALD_YELLOW,
3454 EL_DYNABOMB_INCREASE_NUMBER,
3455 EL_DYNABOMB_INCREASE_SIZE,
3456 EL_DYNABOMB_INCREASE_POWER,
3460 EL_SOKOBAN_FIELD_EMPTY,
3461 EL_SOKOBAN_FIELD_FULL,
3462 EL_WALL_EMERALD_RED,
3463 EL_WALL_EMERALD_PURPLE,
3464 EL_ACID_POOL_TOPLEFT,
3465 EL_ACID_POOL_TOPRIGHT,
3466 EL_ACID_POOL_BOTTOMLEFT,
3467 EL_ACID_POOL_BOTTOM,
3468 EL_ACID_POOL_BOTTOMRIGHT,
3472 EL_BD_MAGIC_WALL_DEAD,
3473 EL_AMOEBA_TO_DIAMOND,
3481 EL_SP_GRAVITY_PORT_RIGHT,
3482 EL_SP_GRAVITY_PORT_DOWN,
3483 EL_SP_GRAVITY_PORT_LEFT,
3484 EL_SP_GRAVITY_PORT_UP,
3485 EL_SP_PORT_HORIZONTAL,
3486 EL_SP_PORT_VERTICAL,
3497 EL_SP_HARDWARE_GRAY,
3498 EL_SP_HARDWARE_GREEN,
3499 EL_SP_HARDWARE_BLUE,
3501 EL_SP_HARDWARE_YELLOW,
3502 EL_SP_HARDWARE_BASE_1,
3503 EL_SP_HARDWARE_BASE_2,
3504 EL_SP_HARDWARE_BASE_3,
3505 EL_SP_HARDWARE_BASE_4,
3506 EL_SP_HARDWARE_BASE_5,
3507 EL_SP_HARDWARE_BASE_6,
3508 EL_SP_GRAVITY_ON_PORT_LEFT,
3509 EL_SP_GRAVITY_ON_PORT_RIGHT,
3510 EL_SP_GRAVITY_ON_PORT_UP,
3511 EL_SP_GRAVITY_ON_PORT_DOWN,
3512 EL_SP_GRAVITY_OFF_PORT_LEFT,
3513 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3514 EL_SP_GRAVITY_OFF_PORT_UP,
3515 EL_SP_GRAVITY_OFF_PORT_DOWN,
3516 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3519 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3525 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3528 EL_SIGN_EXCLAMATION,
3529 EL_SIGN_RADIOACTIVITY,
3540 EL_STEELWALL_SLIPPERY,
3545 EL_EMC_WALL_SLIPPERY_1,
3546 EL_EMC_WALL_SLIPPERY_2,
3547 EL_EMC_WALL_SLIPPERY_3,
3548 EL_EMC_WALL_SLIPPERY_4,
3569 static int ep_em_slippery_wall[] =
3574 static int ep_gfx_crumbled[] =
3584 static int ep_editor_cascade_active[] =
3586 EL_INTERNAL_CASCADE_BD_ACTIVE,
3587 EL_INTERNAL_CASCADE_EM_ACTIVE,
3588 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3589 EL_INTERNAL_CASCADE_RND_ACTIVE,
3590 EL_INTERNAL_CASCADE_SB_ACTIVE,
3591 EL_INTERNAL_CASCADE_SP_ACTIVE,
3592 EL_INTERNAL_CASCADE_DC_ACTIVE,
3593 EL_INTERNAL_CASCADE_DX_ACTIVE,
3594 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3595 EL_INTERNAL_CASCADE_CE_ACTIVE,
3596 EL_INTERNAL_CASCADE_GE_ACTIVE,
3597 EL_INTERNAL_CASCADE_REF_ACTIVE,
3598 EL_INTERNAL_CASCADE_USER_ACTIVE,
3599 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3604 static int ep_editor_cascade_inactive[] =
3606 EL_INTERNAL_CASCADE_BD,
3607 EL_INTERNAL_CASCADE_EM,
3608 EL_INTERNAL_CASCADE_EMC,
3609 EL_INTERNAL_CASCADE_RND,
3610 EL_INTERNAL_CASCADE_SB,
3611 EL_INTERNAL_CASCADE_SP,
3612 EL_INTERNAL_CASCADE_DC,
3613 EL_INTERNAL_CASCADE_DX,
3614 EL_INTERNAL_CASCADE_CHARS,
3615 EL_INTERNAL_CASCADE_CE,
3616 EL_INTERNAL_CASCADE_GE,
3617 EL_INTERNAL_CASCADE_REF,
3618 EL_INTERNAL_CASCADE_USER,
3619 EL_INTERNAL_CASCADE_DYNAMIC,
3624 static int ep_obsolete[] =
3628 EL_EM_KEY_1_FILE_OBSOLETE,
3629 EL_EM_KEY_2_FILE_OBSOLETE,
3630 EL_EM_KEY_3_FILE_OBSOLETE,
3631 EL_EM_KEY_4_FILE_OBSOLETE,
3632 EL_ENVELOPE_OBSOLETE,
3641 } element_properties[] =
3643 { ep_diggable, EP_DIGGABLE },
3644 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3645 { ep_dont_run_into, EP_DONT_RUN_INTO },
3646 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3647 { ep_dont_touch, EP_DONT_TOUCH },
3648 { ep_indestructible, EP_INDESTRUCTIBLE },
3649 { ep_slippery, EP_SLIPPERY },
3650 { ep_can_change, EP_CAN_CHANGE },
3651 { ep_can_move, EP_CAN_MOVE },
3652 { ep_can_fall, EP_CAN_FALL },
3653 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3654 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3655 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3656 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3657 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3658 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3659 { ep_walkable_over, EP_WALKABLE_OVER },
3660 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3661 { ep_walkable_under, EP_WALKABLE_UNDER },
3662 { ep_passable_over, EP_PASSABLE_OVER },
3663 { ep_passable_inside, EP_PASSABLE_INSIDE },
3664 { ep_passable_under, EP_PASSABLE_UNDER },
3665 { ep_droppable, EP_DROPPABLE },
3666 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3667 { ep_pushable, EP_PUSHABLE },
3668 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3669 { ep_protected, EP_PROTECTED },
3670 { ep_throwable, EP_THROWABLE },
3671 { ep_can_explode, EP_CAN_EXPLODE },
3672 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3674 { ep_player, EP_PLAYER },
3675 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3676 { ep_switchable, EP_SWITCHABLE },
3677 { ep_bd_element, EP_BD_ELEMENT },
3678 { ep_sp_element, EP_SP_ELEMENT },
3679 { ep_sb_element, EP_SB_ELEMENT },
3681 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3682 { ep_food_penguin, EP_FOOD_PENGUIN },
3683 { ep_food_pig, EP_FOOD_PIG },
3684 { ep_historic_wall, EP_HISTORIC_WALL },
3685 { ep_historic_solid, EP_HISTORIC_SOLID },
3686 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3687 { ep_belt, EP_BELT },
3688 { ep_belt_active, EP_BELT_ACTIVE },
3689 { ep_belt_switch, EP_BELT_SWITCH },
3690 { ep_tube, EP_TUBE },
3691 { ep_keygate, EP_KEYGATE },
3692 { ep_amoeboid, EP_AMOEBOID },
3693 { ep_amoebalive, EP_AMOEBALIVE },
3694 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3695 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3696 { ep_can_grow, EP_CAN_GROW },
3697 { ep_active_bomb, EP_ACTIVE_BOMB },
3698 { ep_inactive, EP_INACTIVE },
3700 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3702 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3704 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3705 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3707 { ep_obsolete, EP_OBSOLETE },
3714 /* always start with reliable default values (element has no properties) */
3715 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3716 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3717 SET_PROPERTY(i, j, FALSE);
3719 /* set all base element properties from above array definitions */
3720 for (i = 0; element_properties[i].elements != NULL; i++)
3721 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3722 SET_PROPERTY((element_properties[i].elements)[j],
3723 element_properties[i].property, TRUE);
3725 /* copy properties to some elements that are only stored in level file */
3726 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3727 for (j = 0; copy_properties[j][0] != -1; j++)
3728 if (HAS_PROPERTY(copy_properties[j][0], i))
3729 for (k = 1; k <= 4; k++)
3730 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3733 void InitElementPropertiesEngine(int engine_version)
3735 static int no_wall_properties[] =
3738 EP_COLLECTIBLE_ONLY,
3740 EP_DONT_COLLIDE_WITH,
3743 EP_CAN_SMASH_PLAYER,
3744 EP_CAN_SMASH_ENEMIES,
3745 EP_CAN_SMASH_EVERYTHING,
3750 EP_FOOD_DARK_YAMYAM,
3766 /* important: after initialization in InitElementPropertiesStatic(), the
3767 elements are not again initialized to a default value; therefore all
3768 changes have to make sure that they leave the element with a defined
3769 property (which means that conditional property changes must be set to
3770 a reliable default value before) */
3772 /* ---------- recursively resolve group elements ------------------------- */
3774 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3775 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3776 element_info[i].in_group[j] = FALSE;
3778 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3779 resolve_group_element(EL_GROUP_START + i, 0);
3781 /* set all special, combined or engine dependent element properties */
3782 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3784 /* ---------- INACTIVE ------------------------------------------------- */
3785 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3787 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3788 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3789 IS_WALKABLE_INSIDE(i) ||
3790 IS_WALKABLE_UNDER(i)));
3792 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3793 IS_PASSABLE_INSIDE(i) ||
3794 IS_PASSABLE_UNDER(i)));
3796 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3797 IS_PASSABLE_OVER(i)));
3799 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3800 IS_PASSABLE_INSIDE(i)));
3802 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3803 IS_PASSABLE_UNDER(i)));
3805 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3808 /* ---------- COLLECTIBLE ---------------------------------------------- */
3809 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3813 /* ---------- SNAPPABLE ------------------------------------------------ */
3814 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3815 IS_COLLECTIBLE(i) ||
3819 /* ---------- WALL ----------------------------------------------------- */
3820 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3822 for (j = 0; no_wall_properties[j] != -1; j++)
3823 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3824 i >= EL_FIRST_RUNTIME_UNREAL)
3825 SET_PROPERTY(i, EP_WALL, FALSE);
3827 if (IS_HISTORIC_WALL(i))
3828 SET_PROPERTY(i, EP_WALL, TRUE);
3830 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3831 if (engine_version < VERSION_IDENT(2,2,0,0))
3832 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3834 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3836 !IS_COLLECTIBLE(i)));
3838 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3840 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3841 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3843 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3844 IS_INDESTRUCTIBLE(i)));
3846 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3848 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3849 else if (engine_version < VERSION_IDENT(2,2,0,0))
3850 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3852 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3856 if (IS_CUSTOM_ELEMENT(i))
3858 /* these are additional properties which are initially false when set */
3860 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3862 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3863 if (DONT_COLLIDE_WITH(i))
3864 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3866 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3867 if (CAN_SMASH_EVERYTHING(i))
3868 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3869 if (CAN_SMASH_ENEMIES(i))
3870 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3873 /* ---------- CAN_SMASH ------------------------------------------------ */
3874 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3875 CAN_SMASH_ENEMIES(i) ||
3876 CAN_SMASH_EVERYTHING(i)));
3878 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3879 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3880 EXPLODES_BY_FIRE(i)));
3882 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3883 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3884 EXPLODES_SMASHED(i)));
3886 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3887 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3888 EXPLODES_IMPACT(i)));
3890 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3891 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3893 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3894 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3895 i == EL_BLACK_ORB));
3897 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3898 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3900 IS_CUSTOM_ELEMENT(i)));
3902 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3903 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3904 i == EL_SP_ELECTRON));
3906 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3907 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3908 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3909 getMoveIntoAcidProperty(&level, i));
3911 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3912 if (MAYBE_DONT_COLLIDE_WITH(i))
3913 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3914 getDontCollideWithProperty(&level, i));
3916 /* ---------- SP_PORT -------------------------------------------------- */
3917 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3918 IS_PASSABLE_INSIDE(i)));
3920 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3921 for (j = 0; j < level.num_android_clone_elements; j++)
3922 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3924 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3926 /* ---------- CAN_CHANGE ----------------------------------------------- */
3927 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3928 for (j = 0; j < element_info[i].num_change_pages; j++)
3929 if (element_info[i].change_page[j].can_change)
3930 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3932 /* ---------- HAS_ACTION ----------------------------------------------- */
3933 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3934 for (j = 0; j < element_info[i].num_change_pages; j++)
3935 if (element_info[i].change_page[j].has_action)
3936 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3938 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3939 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3942 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3944 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3945 element_info[i].crumbled[ACTION_DEFAULT] !=
3946 element_info[i].graphic[ACTION_DEFAULT]);
3948 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3949 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3950 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3953 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3954 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3955 IS_EDITOR_CASCADE_INACTIVE(i)));
3958 /* dynamically adjust element properties according to game engine version */
3960 static int ep_em_slippery_wall[] =
3965 EL_EXPANDABLE_WALL_HORIZONTAL,
3966 EL_EXPANDABLE_WALL_VERTICAL,
3967 EL_EXPANDABLE_WALL_ANY,
3971 /* special EM style gems behaviour */
3972 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3973 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3974 level.em_slippery_gems);
3976 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3977 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3978 (level.em_slippery_gems &&
3979 engine_version > VERSION_IDENT(2,0,1,0)));
3982 /* this is needed because some graphics depend on element properties */
3983 if (game_status == GAME_MODE_PLAYING)
3984 InitElementGraphicInfo();
3987 void InitElementPropertiesAfterLoading(int engine_version)
3991 /* set some other uninitialized values of custom elements in older levels */
3992 if (engine_version < VERSION_IDENT(3,1,0,0))
3994 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3996 int element = EL_CUSTOM_START + i;
3998 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4000 element_info[element].explosion_delay = 17;
4001 element_info[element].ignition_delay = 8;
4006 static void InitGlobal()
4010 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4012 /* check if element_name_info entry defined for each element in "main.h" */
4013 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4014 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4016 element_info[i].token_name = element_name_info[i].token_name;
4017 element_info[i].class_name = element_name_info[i].class_name;
4018 element_info[i].editor_description=element_name_info[i].editor_description;
4021 global.autoplay_leveldir = NULL;
4022 global.convert_leveldir = NULL;
4024 global.frames_per_second = 0;
4025 global.fps_slowdown = FALSE;
4026 global.fps_slowdown_factor = 1;
4029 void Execute_Command(char *command)
4033 if (strEqual(command, "print graphicsinfo.conf"))
4035 printf("# You can configure additional/alternative image files here.\n");
4036 printf("# (The entries below are default and therefore commented out.)\n");
4038 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4040 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4043 for (i = 0; image_config[i].token != NULL; i++)
4044 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4045 image_config[i].value));
4049 else if (strEqual(command, "print soundsinfo.conf"))
4051 printf("# You can configure additional/alternative sound files here.\n");
4052 printf("# (The entries below are default and therefore commented out.)\n");
4054 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4056 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4059 for (i = 0; sound_config[i].token != NULL; i++)
4060 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4061 sound_config[i].value));
4065 else if (strEqual(command, "print musicinfo.conf"))
4067 printf("# You can configure additional/alternative music files here.\n");
4068 printf("# (The entries below are default and therefore commented out.)\n");
4070 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4072 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4075 for (i = 0; music_config[i].token != NULL; i++)
4076 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4077 music_config[i].value));
4081 else if (strEqual(command, "print editorsetup.conf"))
4083 printf("# You can configure your personal editor element list here.\n");
4084 printf("# (The entries below are default and therefore commented out.)\n");
4087 /* this is needed to be able to check element list for cascade elements */
4088 InitElementPropertiesStatic();
4089 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4091 PrintEditorElementList();
4095 else if (strEqual(command, "print helpanim.conf"))
4097 printf("# You can configure different element help animations here.\n");
4098 printf("# (The entries below are default and therefore commented out.)\n");
4101 for (i = 0; helpanim_config[i].token != NULL; i++)
4103 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4104 helpanim_config[i].value));
4106 if (strEqual(helpanim_config[i].token, "end"))
4112 else if (strEqual(command, "print helptext.conf"))
4114 printf("# You can configure different element help text here.\n");
4115 printf("# (The entries below are default and therefore commented out.)\n");
4118 for (i = 0; helptext_config[i].token != NULL; i++)
4119 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4120 helptext_config[i].value));
4124 else if (strncmp(command, "dump level ", 11) == 0)
4126 char *filename = &command[11];
4128 if (!fileExists(filename))
4129 Error(ERR_EXIT, "cannot open file '%s'", filename);
4131 LoadLevelFromFilename(&level, filename);
4136 else if (strncmp(command, "dump tape ", 10) == 0)
4138 char *filename = &command[10];
4140 if (!fileExists(filename))
4141 Error(ERR_EXIT, "cannot open file '%s'", filename);
4143 LoadTapeFromFilename(filename);
4148 else if (strncmp(command, "autoplay ", 9) == 0)
4150 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4152 while (*str_ptr != '\0') /* continue parsing string */
4154 /* cut leading whitespace from string, replace it by string terminator */
4155 while (*str_ptr == ' ' || *str_ptr == '\t')
4158 if (*str_ptr == '\0') /* end of string reached */
4161 if (global.autoplay_leveldir == NULL) /* read level set string */
4163 global.autoplay_leveldir = str_ptr;
4164 global.autoplay_all = TRUE; /* default: play all tapes */
4166 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4167 global.autoplay_level[i] = FALSE;
4169 else /* read level number string */
4171 int level_nr = atoi(str_ptr); /* get level_nr value */
4173 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4174 global.autoplay_level[level_nr] = TRUE;
4176 global.autoplay_all = FALSE;
4179 /* advance string pointer to the next whitespace (or end of string) */
4180 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4184 else if (strncmp(command, "convert ", 8) == 0)
4186 char *str_copy = getStringCopy(&command[8]);
4187 char *str_ptr = strchr(str_copy, ' ');
4189 global.convert_leveldir = str_copy;
4190 global.convert_level_nr = -1;
4192 if (str_ptr != NULL) /* level number follows */
4194 *str_ptr++ = '\0'; /* terminate leveldir string */
4195 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4200 #if defined(TARGET_SDL)
4201 else if (strEqual(command, "SDL_ListModes"))
4206 SDL_Init(SDL_INIT_VIDEO);
4208 /* get available fullscreen/hardware modes */
4209 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4211 /* check if there are any modes available */
4214 printf("No modes available!\n");
4219 /* check if our resolution is restricted */
4220 if (modes == (SDL_Rect **)-1)
4222 printf("All resolutions available.\n");
4226 printf("Available Modes:\n");
4228 for(i = 0; modes[i]; i++)
4229 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4239 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4243 static void InitSetup()
4245 LoadSetup(); /* global setup info */
4247 /* set some options from setup file */
4249 if (setup.options.verbose)
4250 options.verbose = TRUE;
4253 static void InitGameInfo()
4255 game.restart_level = FALSE;
4258 static void InitPlayerInfo()
4262 /* choose default local player */
4263 local_player = &stored_player[0];
4265 for (i = 0; i < MAX_PLAYERS; i++)
4266 stored_player[i].connected = FALSE;
4268 local_player->connected = TRUE;
4271 static void InitArtworkInfo()
4276 static char *get_string_in_brackets(char *string)
4278 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4280 sprintf(string_in_brackets, "[%s]", string);
4282 return string_in_brackets;
4285 static char *get_level_id_suffix(int id_nr)
4287 char *id_suffix = checked_malloc(1 + 3 + 1);
4289 if (id_nr < 0 || id_nr > 999)
4292 sprintf(id_suffix, ".%03d", id_nr);
4298 static char *get_element_class_token(int element)
4300 char *element_class_name = element_info[element].class_name;
4301 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4303 sprintf(element_class_token, "[%s]", element_class_name);
4305 return element_class_token;
4308 static char *get_action_class_token(int action)
4310 char *action_class_name = &element_action_info[action].suffix[1];
4311 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4313 sprintf(action_class_token, "[%s]", action_class_name);
4315 return action_class_token;
4319 static void InitArtworkConfig()
4321 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4322 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4323 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4324 static char *action_id_suffix[NUM_ACTIONS + 1];
4325 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4326 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4327 static char *level_id_suffix[MAX_LEVELS + 1];
4328 static char *dummy[1] = { NULL };
4329 static char *ignore_generic_tokens[] =
4335 static char **ignore_image_tokens;
4336 static char **ignore_sound_tokens;
4337 static char **ignore_music_tokens;
4338 int num_ignore_generic_tokens;
4339 int num_ignore_image_tokens;
4340 int num_ignore_sound_tokens;
4341 int num_ignore_music_tokens;
4344 /* dynamically determine list of generic tokens to be ignored */
4345 num_ignore_generic_tokens = 0;
4346 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4347 num_ignore_generic_tokens++;
4349 /* dynamically determine list of image tokens to be ignored */
4350 num_ignore_image_tokens = num_ignore_generic_tokens;
4351 for (i = 0; image_config_vars[i].token != NULL; i++)
4352 num_ignore_image_tokens++;
4353 ignore_image_tokens =
4354 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4355 for (i = 0; i < num_ignore_generic_tokens; i++)
4356 ignore_image_tokens[i] = ignore_generic_tokens[i];
4357 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4358 ignore_image_tokens[num_ignore_generic_tokens + i] =
4359 image_config_vars[i].token;
4360 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4362 /* dynamically determine list of sound tokens to be ignored */
4363 num_ignore_sound_tokens = num_ignore_generic_tokens;
4364 ignore_sound_tokens =
4365 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4366 for (i = 0; i < num_ignore_generic_tokens; i++)
4367 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4368 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4370 /* dynamically determine list of music tokens to be ignored */
4371 num_ignore_music_tokens = num_ignore_generic_tokens;
4372 ignore_music_tokens =
4373 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4374 for (i = 0; i < num_ignore_generic_tokens; i++)
4375 ignore_music_tokens[i] = ignore_generic_tokens[i];
4376 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4378 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4379 image_id_prefix[i] = element_info[i].token_name;
4380 for (i = 0; i < NUM_FONTS; i++)
4381 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4382 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4384 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4385 sound_id_prefix[i] = element_info[i].token_name;
4386 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4387 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4388 get_string_in_brackets(element_info[i].class_name);
4389 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4391 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4392 music_id_prefix[i] = music_prefix_info[i].prefix;
4393 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4395 for (i = 0; i < NUM_ACTIONS; i++)
4396 action_id_suffix[i] = element_action_info[i].suffix;
4397 action_id_suffix[NUM_ACTIONS] = NULL;
4399 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4400 direction_id_suffix[i] = element_direction_info[i].suffix;
4401 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4403 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4404 special_id_suffix[i] = special_suffix_info[i].suffix;
4405 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4407 for (i = 0; i < MAX_LEVELS; i++)
4408 level_id_suffix[i] = get_level_id_suffix(i);
4409 level_id_suffix[MAX_LEVELS] = NULL;
4411 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4412 image_id_prefix, action_id_suffix, direction_id_suffix,
4413 special_id_suffix, ignore_image_tokens);
4414 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4415 sound_id_prefix, action_id_suffix, dummy,
4416 special_id_suffix, ignore_sound_tokens);
4417 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4418 music_id_prefix, special_id_suffix, level_id_suffix,
4419 dummy, ignore_music_tokens);
4422 static void InitMixer()
4430 char *filename_font_initial = NULL;
4431 Bitmap *bitmap_font_initial = NULL;
4435 /* determine settings for initial font (for displaying startup messages) */
4436 for (i = 0; image_config[i].token != NULL; i++)
4438 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4440 char font_token[128];
4443 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4444 len_font_token = strlen(font_token);
4446 if (strEqual(image_config[i].token, font_token))
4447 filename_font_initial = image_config[i].value;
4448 else if (strlen(image_config[i].token) > len_font_token &&
4449 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4451 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4452 font_initial[j].src_x = atoi(image_config[i].value);
4453 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4454 font_initial[j].src_y = atoi(image_config[i].value);
4455 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4456 font_initial[j].width = atoi(image_config[i].value);
4457 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4458 font_initial[j].height = atoi(image_config[i].value);
4463 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4465 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4466 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4469 if (filename_font_initial == NULL) /* should not happen */
4470 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4472 /* create additional image buffers for double-buffering and cross-fading */
4473 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4474 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4475 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4476 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4478 /* initialize screen properties */
4479 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4480 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4482 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4483 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4484 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4486 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4488 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4489 font_initial[j].bitmap = bitmap_font_initial;
4491 InitFontGraphicInfo();
4493 font_height = getFontHeight(FC_RED);
4495 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4496 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4497 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4499 DrawInitText("Loading graphics:", 120, FC_GREEN);
4502 void RedrawBackground()
4504 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4505 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4507 redraw_mask = REDRAW_ALL;
4510 void InitGfxBackground()
4514 drawto = backbuffer;
4515 fieldbuffer = bitmap_db_field;
4516 SetDrawtoField(DRAW_BACKBUFFER);
4520 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4521 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4523 for (x = 0; x < MAX_BUF_XSIZE; x++)
4524 for (y = 0; y < MAX_BUF_YSIZE; y++)
4527 redraw_mask = REDRAW_ALL;
4530 static void InitLevelInfo()
4532 LoadLevelInfo(); /* global level info */
4533 LoadLevelSetup_LastSeries(); /* last played series info */
4534 LoadLevelSetup_SeriesInfo(); /* last played level info */
4537 void InitLevelArtworkInfo()
4539 LoadLevelArtworkInfo();
4542 static void InitImages()
4544 setLevelArtworkDir(artwork.gfx_first);
4547 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4548 leveldir_current->identifier,
4549 artwork.gfx_current_identifier,
4550 artwork.gfx_current->identifier,
4551 leveldir_current->graphics_set,
4552 leveldir_current->graphics_path);
4555 ReloadCustomImages();
4557 LoadCustomElementDescriptions();
4558 LoadSpecialMenuDesignSettings();
4560 ReinitializeGraphics();
4563 static void InitSound(char *identifier)
4565 if (identifier == NULL)
4566 identifier = artwork.snd_current->identifier;
4568 /* set artwork path to send it to the sound server process */
4569 setLevelArtworkDir(artwork.snd_first);
4571 InitReloadCustomSounds(identifier);
4572 ReinitializeSounds();
4575 static void InitMusic(char *identifier)
4577 if (identifier == NULL)
4578 identifier = artwork.mus_current->identifier;
4580 /* set artwork path to send it to the sound server process */
4581 setLevelArtworkDir(artwork.mus_first);
4583 InitReloadCustomMusic(identifier);
4584 ReinitializeMusic();
4587 void InitNetworkServer()
4589 #if defined(NETWORK_AVALIABLE)
4593 if (!options.network)
4596 #if defined(NETWORK_AVALIABLE)
4597 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4599 if (!ConnectToServer(options.server_host, options.server_port))
4600 Error(ERR_EXIT, "cannot connect to network game server");
4602 SendToServer_PlayerName(setup.player_name);
4603 SendToServer_ProtocolVersion();
4606 SendToServer_NrWanted(nr_wanted);
4610 static char *getNewArtworkIdentifier(int type)
4612 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4613 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4614 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4615 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4616 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4617 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4618 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4619 char *leveldir_identifier = leveldir_current->identifier;
4621 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4622 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4624 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4626 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4627 char *artwork_current_identifier;
4628 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4630 /* leveldir_current may be invalid (level group, parent link) */
4631 if (!validLevelSeries(leveldir_current))
4634 /* 1st step: determine artwork set to be activated in descending order:
4635 --------------------------------------------------------------------
4636 1. setup artwork (when configured to override everything else)
4637 2. artwork set configured in "levelinfo.conf" of current level set
4638 (artwork in level directory will have priority when loading later)
4639 3. artwork in level directory (stored in artwork sub-directory)
4640 4. setup artwork (currently configured in setup menu) */
4642 if (setup_override_artwork)
4643 artwork_current_identifier = setup_artwork_set;
4644 else if (leveldir_artwork_set != NULL)
4645 artwork_current_identifier = leveldir_artwork_set;
4646 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4647 artwork_current_identifier = leveldir_identifier;
4649 artwork_current_identifier = setup_artwork_set;
4652 /* 2nd step: check if it is really needed to reload artwork set
4653 ------------------------------------------------------------ */
4656 if (type == ARTWORK_TYPE_GRAPHICS)
4657 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4658 artwork_new_identifier,
4659 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4660 artwork_current_identifier,
4661 leveldir_current->graphics_set,
4662 leveldir_current->identifier);
4665 /* ---------- reload if level set and also artwork set has changed ------- */
4666 if (leveldir_current_identifier[type] != leveldir_identifier &&
4667 (last_has_level_artwork_set[type] || has_level_artwork_set))
4668 artwork_new_identifier = artwork_current_identifier;
4670 leveldir_current_identifier[type] = leveldir_identifier;
4671 last_has_level_artwork_set[type] = has_level_artwork_set;
4674 if (type == ARTWORK_TYPE_GRAPHICS)
4675 printf("::: 1: '%s'\n", artwork_new_identifier);
4678 /* ---------- reload if "override artwork" setting has changed ----------- */
4679 if (last_override_level_artwork[type] != setup_override_artwork)
4680 artwork_new_identifier = artwork_current_identifier;
4682 last_override_level_artwork[type] = setup_override_artwork;
4685 if (type == ARTWORK_TYPE_GRAPHICS)
4686 printf("::: 2: '%s'\n", artwork_new_identifier);
4689 /* ---------- reload if current artwork identifier has changed ----------- */
4690 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4691 artwork_current_identifier))
4692 artwork_new_identifier = artwork_current_identifier;
4694 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4697 if (type == ARTWORK_TYPE_GRAPHICS)
4698 printf("::: 3: '%s'\n", artwork_new_identifier);
4701 /* ---------- do not reload directly after starting ---------------------- */
4702 if (!initialized[type])
4703 artwork_new_identifier = NULL;
4705 initialized[type] = TRUE;
4708 if (type == ARTWORK_TYPE_GRAPHICS)
4709 printf("::: 4: '%s'\n", artwork_new_identifier);
4713 if (type == ARTWORK_TYPE_GRAPHICS)
4714 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4715 artwork.gfx_current_identifier, artwork_current_identifier,
4716 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4717 artwork_new_identifier);
4720 return artwork_new_identifier;
4723 void ReloadCustomArtwork(int force_reload)
4725 char *gfx_new_identifier;
4726 char *snd_new_identifier;
4727 char *mus_new_identifier;
4728 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4729 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4730 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4731 boolean redraw_screen = FALSE;
4733 force_reload_gfx |= AdjustGraphicsForEMC();
4735 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4736 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4737 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4739 if (gfx_new_identifier != NULL || force_reload_gfx)
4742 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4743 artwork.gfx_current_identifier,
4745 artwork.gfx_current->identifier,
4746 leveldir_current->graphics_set);
4749 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4753 redraw_screen = TRUE;
4756 if (snd_new_identifier != NULL || force_reload_snd)
4758 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4760 InitSound(snd_new_identifier);
4762 redraw_screen = TRUE;
4765 if (mus_new_identifier != NULL || force_reload_mus)
4767 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4769 InitMusic(mus_new_identifier);
4771 redraw_screen = TRUE;
4778 /* force redraw of (open or closed) door graphics */
4779 SetDoorState(DOOR_OPEN_ALL);
4780 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4784 void KeyboardAutoRepeatOffUnlessAutoplay()
4786 if (global.autoplay_leveldir == NULL)
4787 KeyboardAutoRepeatOff();
4791 /* ========================================================================= */
4793 /* ========================================================================= */
4797 InitGlobal(); /* initialize some global variables */
4799 if (options.execute_command)
4800 Execute_Command(options.execute_command);
4802 if (options.serveronly)
4804 #if defined(PLATFORM_UNIX)
4805 NetworkServer(options.server_port, options.serveronly);
4807 Error(ERR_WARN, "networking only supported in Unix version");
4810 exit(0); /* never reached, server loops forever */
4817 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4818 InitArtworkConfig(); /* needed before forking sound child process */
4823 InitRND(NEW_RANDOMIZE);
4824 InitSimpleRandom(NEW_RANDOMIZE);
4829 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4832 InitEventFilter(FilterMouseMotionEvents);
4834 InitElementPropertiesStatic();
4835 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4840 InitLevelArtworkInfo();
4842 InitImages(); /* needs to know current level directory */
4843 InitSound(NULL); /* needs to know current level directory */
4844 InitMusic(NULL); /* needs to know current level directory */
4846 InitGfxBackground();
4852 if (global.autoplay_leveldir)
4857 else if (global.convert_leveldir)
4863 game_status = GAME_MODE_MAIN;
4867 InitNetworkServer();
4870 void CloseAllAndExit(int exit_value)
4875 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4883 #if defined(TARGET_SDL)
4884 if (network_server) /* terminate network server */
4885 SDL_KillThread(server_thread);
4888 CloseVideoDisplay();
4889 ClosePlatformDependentStuff();
4891 if (exit_value != 0)
4892 NotifyUserAboutErrorFile();