1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 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_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
82 FreeLevelEditorGadgets();
91 static boolean gadgets_initialized = FALSE;
93 if (gadgets_initialized)
96 CreateLevelEditorGadgets();
100 CreateScreenGadgets();
102 gadgets_initialized = TRUE;
105 inline void InitElementSmallImagesScaledUp(int graphic)
107 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
110 void InitElementSmallImages()
112 static int special_graphics[] =
114 IMG_EDITOR_ELEMENT_BORDER,
115 IMG_EDITOR_ELEMENT_BORDER_INPUT,
116 IMG_EDITOR_CASCADE_LIST,
117 IMG_EDITOR_CASCADE_LIST_ACTIVE,
120 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
121 int num_property_mappings = getImageListPropertyMappingSize();
124 /* initialize normal images from static configuration */
125 for (i = 0; element_to_graphic[i].element > -1; i++)
126 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
128 /* initialize special images from static configuration */
129 for (i = 0; element_to_special_graphic[i].element > -1; i++)
130 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
132 /* initialize images from dynamic configuration (may be elements or other) */
133 for (i = 0; i < num_property_mappings; i++)
134 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
136 /* initialize special images from above list (non-element images) */
137 for (i = 0; special_graphics[i] > -1; i++)
138 InitElementSmallImagesScaledUp(special_graphics[i]);
142 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
143 void SetBitmaps_EM(Bitmap **em_bitmap)
145 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
146 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
150 static int getFontBitmapID(int font_nr)
154 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
155 special = game_status;
156 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
157 special = GFX_SPECIAL_ARG_MAIN;
158 else if (game_status == GAME_MODE_PLAYING)
159 special = GFX_SPECIAL_ARG_DOOR;
162 return font_info[font_nr].special_bitmap_id[special];
167 void InitFontGraphicInfo()
169 static struct FontBitmapInfo *font_bitmap_info = NULL;
170 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
171 int num_property_mappings = getImageListPropertyMappingSize();
172 int num_font_bitmaps = NUM_FONTS;
175 if (graphic_info == NULL) /* still at startup phase */
177 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
182 /* ---------- initialize font graphic definitions ---------- */
184 /* always start with reliable default values (normal font graphics) */
185 for (i = 0; i < NUM_FONTS; i++)
186 font_info[i].graphic = IMG_FONT_INITIAL_1;
188 /* initialize normal font/graphic mapping from static configuration */
189 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
191 int font_nr = font_to_graphic[i].font_nr;
192 int special = font_to_graphic[i].special;
193 int graphic = font_to_graphic[i].graphic;
198 font_info[font_nr].graphic = graphic;
201 /* always start with reliable default values (special font graphics) */
202 for (i = 0; i < NUM_FONTS; i++)
204 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
206 font_info[i].special_graphic[j] = font_info[i].graphic;
207 font_info[i].special_bitmap_id[j] = i;
211 /* initialize special font/graphic mapping from static configuration */
212 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
214 int font_nr = font_to_graphic[i].font_nr;
215 int special = font_to_graphic[i].special;
216 int graphic = font_to_graphic[i].graphic;
217 int base_graphic = font2baseimg(font_nr);
219 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
221 boolean base_redefined =
222 getImageListEntryFromImageID(base_graphic)->redefined;
223 boolean special_redefined =
224 getImageListEntryFromImageID(graphic)->redefined;
226 /* if the base font ("font.title_1", for example) has been redefined,
227 but not the special font ("font.title_1.LEVELS", for example), do not
228 use an existing (in this case considered obsolete) special font
229 anymore, but use the automatically determined default font */
230 if (base_redefined && !special_redefined)
233 font_info[font_nr].special_graphic[special] = graphic;
234 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
239 /* initialize special element/graphic mapping from dynamic configuration */
240 for (i = 0; i < num_property_mappings; i++)
242 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
243 int special = property_mapping[i].ext3_index;
244 int graphic = property_mapping[i].artwork_index;
249 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
251 font_info[font_nr].special_graphic[special] = graphic;
252 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
257 /* ---------- initialize font bitmap array ---------- */
259 if (font_bitmap_info != NULL)
260 FreeFontInfo(font_bitmap_info);
263 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
265 /* ---------- initialize font bitmap definitions ---------- */
267 for (i = 0; i < NUM_FONTS; i++)
269 if (i < NUM_INITIAL_FONTS)
271 font_bitmap_info[i] = font_initial[i];
275 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
277 int font_bitmap_id = font_info[i].special_bitmap_id[j];
278 int graphic = font_info[i].special_graphic[j];
280 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
281 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
283 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
284 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
287 /* copy font relevant information from graphics information */
288 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
289 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
290 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
291 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
292 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
293 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
294 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
296 font_bitmap_info[font_bitmap_id].num_chars =
297 graphic_info[graphic].anim_frames;
298 font_bitmap_info[font_bitmap_id].num_chars_per_line =
299 graphic_info[graphic].anim_frames_per_line;
303 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
306 void InitElementGraphicInfo()
308 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
309 int num_property_mappings = getImageListPropertyMappingSize();
312 if (graphic_info == NULL) /* still at startup phase */
315 /* set values to -1 to identify later as "uninitialized" values */
316 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
318 for (act = 0; act < NUM_ACTIONS; act++)
320 element_info[i].graphic[act] = -1;
321 element_info[i].crumbled[act] = -1;
323 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
325 element_info[i].direction_graphic[act][dir] = -1;
326 element_info[i].direction_crumbled[act][dir] = -1;
331 /* initialize normal element/graphic mapping from static configuration */
332 for (i = 0; element_to_graphic[i].element > -1; i++)
334 int element = element_to_graphic[i].element;
335 int action = element_to_graphic[i].action;
336 int direction = element_to_graphic[i].direction;
337 boolean crumbled = element_to_graphic[i].crumbled;
338 int graphic = element_to_graphic[i].graphic;
339 int base_graphic = el2baseimg(element);
341 if (graphic_info[graphic].bitmap == NULL)
344 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
347 boolean base_redefined =
348 getImageListEntryFromImageID(base_graphic)->redefined;
349 boolean act_dir_redefined =
350 getImageListEntryFromImageID(graphic)->redefined;
352 /* if the base graphic ("emerald", for example) has been redefined,
353 but not the action graphic ("emerald.falling", for example), do not
354 use an existing (in this case considered obsolete) action graphic
355 anymore, but use the automatically determined default graphic */
356 if (base_redefined && !act_dir_redefined)
361 action = ACTION_DEFAULT;
366 element_info[element].direction_crumbled[action][direction] = graphic;
368 element_info[element].crumbled[action] = graphic;
373 element_info[element].direction_graphic[action][direction] = graphic;
375 element_info[element].graphic[action] = graphic;
379 /* initialize normal element/graphic mapping from dynamic configuration */
380 for (i = 0; i < num_property_mappings; i++)
382 int element = property_mapping[i].base_index;
383 int action = property_mapping[i].ext1_index;
384 int direction = property_mapping[i].ext2_index;
385 int special = property_mapping[i].ext3_index;
386 int graphic = property_mapping[i].artwork_index;
387 boolean crumbled = FALSE;
389 if (special == GFX_SPECIAL_ARG_CRUMBLED)
395 if (graphic_info[graphic].bitmap == NULL)
398 if (element >= MAX_NUM_ELEMENTS || special != -1)
402 action = ACTION_DEFAULT;
407 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
408 element_info[element].direction_crumbled[action][dir] = -1;
411 element_info[element].direction_crumbled[action][direction] = graphic;
413 element_info[element].crumbled[action] = graphic;
418 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
419 element_info[element].direction_graphic[action][dir] = -1;
422 element_info[element].direction_graphic[action][direction] = graphic;
424 element_info[element].graphic[action] = graphic;
428 /* now copy all graphics that are defined to be cloned from other graphics */
429 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
431 int graphic = element_info[i].graphic[ACTION_DEFAULT];
432 int crumbled_like, diggable_like;
437 crumbled_like = graphic_info[graphic].crumbled_like;
438 diggable_like = graphic_info[graphic].diggable_like;
440 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
442 for (act = 0; act < NUM_ACTIONS; act++)
443 element_info[i].crumbled[act] =
444 element_info[crumbled_like].crumbled[act];
445 for (act = 0; act < NUM_ACTIONS; act++)
446 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
447 element_info[i].direction_crumbled[act][dir] =
448 element_info[crumbled_like].direction_crumbled[act][dir];
451 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
453 element_info[i].graphic[ACTION_DIGGING] =
454 element_info[diggable_like].graphic[ACTION_DIGGING];
455 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
456 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
457 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
462 /* set hardcoded definitions for some runtime elements without graphic */
463 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
467 /* set hardcoded definitions for some internal elements without graphic */
468 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
470 if (IS_EDITOR_CASCADE_INACTIVE(i))
471 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
472 else if (IS_EDITOR_CASCADE_ACTIVE(i))
473 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
477 /* now set all undefined/invalid graphics to -1 to set to default after it */
478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
480 for (act = 0; act < NUM_ACTIONS; act++)
484 graphic = element_info[i].graphic[act];
485 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
486 element_info[i].graphic[act] = -1;
488 graphic = element_info[i].crumbled[act];
489 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
490 element_info[i].crumbled[act] = -1;
492 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
494 graphic = element_info[i].direction_graphic[act][dir];
495 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
496 element_info[i].direction_graphic[act][dir] = -1;
498 graphic = element_info[i].direction_crumbled[act][dir];
499 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
500 element_info[i].direction_crumbled[act][dir] = -1;
505 /* adjust graphics with 2nd tile for movement according to direction
506 (do this before correcting '-1' values to minimize calculations) */
507 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
509 for (act = 0; act < NUM_ACTIONS; act++)
511 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
513 int graphic = element_info[i].direction_graphic[act][dir];
514 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
516 if (act == ACTION_FALLING) /* special case */
517 graphic = element_info[i].graphic[act];
520 graphic_info[graphic].double_movement &&
521 graphic_info[graphic].swap_double_tiles != 0)
523 struct GraphicInfo *g = &graphic_info[graphic];
524 int src_x_front = g->src_x;
525 int src_y_front = g->src_y;
526 int src_x_back = g->src_x + g->offset2_x;
527 int src_y_back = g->src_y + g->offset2_y;
528 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
530 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
531 src_y_front < src_y_back);
532 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
533 boolean swap_movement_tiles_autodetected =
534 (!frames_are_ordered_diagonally &&
535 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
536 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
537 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
538 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
541 /* swap frontside and backside graphic tile coordinates, if needed */
542 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
544 /* get current (wrong) backside tile coordinates */
545 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
548 /* set frontside tile coordinates to backside tile coordinates */
549 g->src_x = src_x_back;
550 g->src_y = src_y_back;
552 /* invert tile offset to point to new backside tile coordinates */
556 /* do not swap front and backside tiles again after correction */
557 g->swap_double_tiles = 0;
564 /* now set all '-1' values to element specific default values */
565 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
567 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
568 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
569 int default_direction_graphic[NUM_DIRECTIONS_FULL];
570 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
572 if (default_graphic == -1)
573 default_graphic = IMG_UNKNOWN;
575 if (default_crumbled == -1)
576 default_crumbled = default_graphic;
578 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
579 if (default_crumbled == -1)
580 default_crumbled = IMG_EMPTY;
583 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
585 default_direction_graphic[dir] =
586 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
587 default_direction_crumbled[dir] =
588 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
590 if (default_direction_graphic[dir] == -1)
591 default_direction_graphic[dir] = default_graphic;
593 if (default_direction_crumbled[dir] == -1)
594 default_direction_crumbled[dir] = default_direction_graphic[dir];
596 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
597 if (default_direction_crumbled[dir] == -1)
598 default_direction_crumbled[dir] = default_crumbled;
602 for (act = 0; act < NUM_ACTIONS; act++)
604 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
605 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
606 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
607 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
608 act == ACTION_TURNING_FROM_RIGHT ||
609 act == ACTION_TURNING_FROM_UP ||
610 act == ACTION_TURNING_FROM_DOWN);
612 /* generic default action graphic (defined by "[default]" directive) */
613 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
614 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
615 int default_remove_graphic = IMG_EMPTY;
617 if (act_remove && default_action_graphic != -1)
618 default_remove_graphic = default_action_graphic;
620 /* look for special default action graphic (classic game specific) */
621 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
622 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
623 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
624 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
625 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
626 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
628 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
629 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
630 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
631 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
632 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
633 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
636 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
637 /* !!! make this better !!! */
638 if (i == EL_EMPTY_SPACE)
640 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
641 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
645 if (default_action_graphic == -1)
646 default_action_graphic = default_graphic;
648 if (default_action_crumbled == -1)
649 default_action_crumbled = default_action_graphic;
651 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
652 if (default_action_crumbled == -1)
653 default_action_crumbled = default_crumbled;
656 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
658 /* use action graphic as the default direction graphic, if undefined */
659 int default_action_direction_graphic = element_info[i].graphic[act];
660 int default_action_direction_crumbled = element_info[i].crumbled[act];
662 /* no graphic for current action -- use default direction graphic */
663 if (default_action_direction_graphic == -1)
664 default_action_direction_graphic =
665 (act_remove ? default_remove_graphic :
667 element_info[i].direction_graphic[ACTION_TURNING][dir] :
668 default_action_graphic != default_graphic ?
669 default_action_graphic :
670 default_direction_graphic[dir]);
672 if (element_info[i].direction_graphic[act][dir] == -1)
673 element_info[i].direction_graphic[act][dir] =
674 default_action_direction_graphic;
677 if (default_action_direction_crumbled == -1)
678 default_action_direction_crumbled =
679 element_info[i].direction_graphic[act][dir];
681 if (default_action_direction_crumbled == -1)
682 default_action_direction_crumbled =
683 (act_remove ? default_remove_graphic :
685 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
686 default_action_crumbled != default_crumbled ?
687 default_action_crumbled :
688 default_direction_crumbled[dir]);
691 if (element_info[i].direction_crumbled[act][dir] == -1)
692 element_info[i].direction_crumbled[act][dir] =
693 default_action_direction_crumbled;
696 /* no graphic for this specific action -- use default action graphic */
697 if (element_info[i].graphic[act] == -1)
698 element_info[i].graphic[act] =
699 (act_remove ? default_remove_graphic :
700 act_turning ? element_info[i].graphic[ACTION_TURNING] :
701 default_action_graphic);
703 if (element_info[i].crumbled[act] == -1)
704 element_info[i].crumbled[act] = element_info[i].graphic[act];
706 if (element_info[i].crumbled[act] == -1)
707 element_info[i].crumbled[act] =
708 (act_remove ? default_remove_graphic :
709 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
710 default_action_crumbled);
715 /* set animation mode to "none" for each graphic with only 1 frame */
716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718 for (act = 0; act < NUM_ACTIONS; act++)
720 int graphic = element_info[i].graphic[act];
721 int crumbled = element_info[i].crumbled[act];
723 if (graphic_info[graphic].anim_frames == 1)
724 graphic_info[graphic].anim_mode = ANIM_NONE;
725 if (graphic_info[crumbled].anim_frames == 1)
726 graphic_info[crumbled].anim_mode = ANIM_NONE;
728 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
730 graphic = element_info[i].direction_graphic[act][dir];
731 crumbled = element_info[i].direction_crumbled[act][dir];
733 if (graphic_info[graphic].anim_frames == 1)
734 graphic_info[graphic].anim_mode = ANIM_NONE;
735 if (graphic_info[crumbled].anim_frames == 1)
736 graphic_info[crumbled].anim_mode = ANIM_NONE;
745 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
746 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
748 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
749 element_info[i].token_name, i);
755 void InitElementSpecialGraphicInfo()
757 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
758 int num_property_mappings = getImageListPropertyMappingSize();
761 /* always start with reliable default values */
762 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
763 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
764 element_info[i].special_graphic[j] =
765 element_info[i].graphic[ACTION_DEFAULT];
767 /* initialize special element/graphic mapping from static configuration */
768 for (i = 0; element_to_special_graphic[i].element > -1; i++)
770 int element = element_to_special_graphic[i].element;
771 int special = element_to_special_graphic[i].special;
772 int graphic = element_to_special_graphic[i].graphic;
773 int base_graphic = el2baseimg(element);
774 boolean base_redefined =
775 getImageListEntryFromImageID(base_graphic)->redefined;
776 boolean special_redefined =
777 getImageListEntryFromImageID(graphic)->redefined;
779 /* if the base graphic ("emerald", for example) has been redefined,
780 but not the special graphic ("emerald.EDITOR", for example), do not
781 use an existing (in this case considered obsolete) special graphic
782 anymore, but use the automatically created (down-scaled) graphic */
783 if (base_redefined && !special_redefined)
786 element_info[element].special_graphic[special] = graphic;
789 /* initialize special element/graphic mapping from dynamic configuration */
790 for (i = 0; i < num_property_mappings; i++)
792 int element = property_mapping[i].base_index;
793 int special = property_mapping[i].ext3_index;
794 int graphic = property_mapping[i].artwork_index;
796 if (element >= MAX_NUM_ELEMENTS)
799 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
800 element_info[element].special_graphic[special] = graphic;
803 /* now set all undefined/invalid graphics to default */
804 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
805 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
806 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
807 element_info[i].special_graphic[j] =
808 element_info[i].graphic[ACTION_DEFAULT];
811 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
816 if (type != TYPE_TOKEN)
817 return get_parameter_value(value_raw, suffix, type);
819 if (strcmp(value_raw, ARG_UNDEFINED) == 0)
820 return ARG_UNDEFINED_VALUE;
822 /* !!! OPTIMIZE THIS BY USING HASH !!! */
823 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
824 if (strcmp(element_info[i].token_name, value_raw) == 0)
827 /* !!! OPTIMIZE THIS BY USING HASH !!! */
828 for (i = 0; image_config[i].token != NULL; i++)
830 int len_config_value = strlen(image_config[i].value);
832 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
833 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
834 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
837 if (strcmp(image_config[i].token, value_raw) == 0)
846 static int get_scaled_graphic_width(int graphic)
848 int original_width = getOriginalImageWidthFromImageID(graphic);
849 int scale_up_factor = graphic_info[graphic].scale_up_factor;
851 return original_width * scale_up_factor;
854 static int get_scaled_graphic_height(int graphic)
856 int original_height = getOriginalImageHeightFromImageID(graphic);
857 int scale_up_factor = graphic_info[graphic].scale_up_factor;
859 return original_height * scale_up_factor;
862 static void set_graphic_parameters(int graphic)
864 struct FileInfo *image = getImageListEntryFromImageID(graphic);
865 char **parameter_raw = image->parameter;
866 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
867 int parameter[NUM_GFX_ARGS];
868 int anim_frames_per_row = 1, anim_frames_per_col = 1;
869 int anim_frames_per_line = 1;
872 /* if fallback to default artwork is done, also use the default parameters */
873 if (image->fallback_to_default)
874 parameter_raw = image->default_parameter;
876 /* get integer values from string parameters */
877 for (i = 0; i < NUM_GFX_ARGS; i++)
878 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
879 image_config_suffix[i].token,
880 image_config_suffix[i].type);
882 graphic_info[graphic].bitmap = src_bitmap;
884 /* start with reliable default values */
885 graphic_info[graphic].src_image_width = 0;
886 graphic_info[graphic].src_image_height = 0;
887 graphic_info[graphic].src_x = 0;
888 graphic_info[graphic].src_y = 0;
889 graphic_info[graphic].width = TILEX;
890 graphic_info[graphic].height = TILEY;
891 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
892 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
893 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
894 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
895 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
896 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
897 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
898 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
899 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
900 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
901 graphic_info[graphic].anim_delay_fixed = 0;
902 graphic_info[graphic].anim_delay_random = 0;
903 graphic_info[graphic].post_delay_fixed = 0;
904 graphic_info[graphic].post_delay_random = 0;
906 /* optional x and y tile position of animation frame sequence */
907 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
908 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
909 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
910 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
912 /* optional x and y pixel position of animation frame sequence */
913 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
914 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
915 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
916 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
918 /* optional width and height of each animation frame */
919 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
920 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
921 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
922 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
924 /* optional zoom factor for scaling up the image to a larger size */
925 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
926 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
927 if (graphic_info[graphic].scale_up_factor < 1)
928 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
932 /* get final bitmap size (with scaling, but without small images) */
933 int src_image_width = get_scaled_graphic_width(graphic);
934 int src_image_height = get_scaled_graphic_height(graphic);
936 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
937 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
939 graphic_info[graphic].src_image_width = src_image_width;
940 graphic_info[graphic].src_image_height = src_image_height;
943 /* correct x or y offset dependent of vertical or horizontal frame order */
944 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
946 graphic_info[graphic].offset_y =
947 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
948 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
949 anim_frames_per_line = anim_frames_per_col;
951 else /* frames are ordered horizontally */
953 graphic_info[graphic].offset_x =
954 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
955 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
956 anim_frames_per_line = anim_frames_per_row;
959 /* optionally, the x and y offset of frames can be specified directly */
960 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
961 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
962 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
963 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
965 /* optionally, moving animations may have separate start and end graphics */
966 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
968 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
969 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
971 /* correct x or y offset2 dependent of vertical or horizontal frame order */
972 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
973 graphic_info[graphic].offset2_y =
974 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
975 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
976 else /* frames are ordered horizontally */
977 graphic_info[graphic].offset2_x =
978 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
979 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
981 /* optionally, the x and y offset of 2nd graphic can be specified directly */
982 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
983 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
984 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
985 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
987 /* optionally, the second movement tile can be specified as start tile */
988 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
989 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
991 /* automatically determine correct number of frames, if not defined */
992 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
993 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
994 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
995 graphic_info[graphic].anim_frames = anim_frames_per_row;
996 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
997 graphic_info[graphic].anim_frames = anim_frames_per_col;
999 graphic_info[graphic].anim_frames = 1;
1001 graphic_info[graphic].anim_frames_per_line =
1002 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1003 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1005 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1006 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1007 graphic_info[graphic].anim_delay = 1;
1009 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1011 if (graphic_info[graphic].anim_frames == 1)
1012 graphic_info[graphic].anim_mode = ANIM_NONE;
1015 /* automatically determine correct start frame, if not defined */
1016 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1017 graphic_info[graphic].anim_start_frame = 0;
1018 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1019 graphic_info[graphic].anim_start_frame =
1020 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1022 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1024 /* animation synchronized with global frame counter, not move position */
1025 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1027 /* optional element for cloning crumble graphics */
1028 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1031 /* optional element for cloning digging graphics */
1032 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1033 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1035 /* optional border size for "crumbling" diggable graphics */
1036 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1037 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1039 /* this is only used for player "boring" and "sleeping" actions */
1040 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1041 graphic_info[graphic].anim_delay_fixed =
1042 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1043 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1044 graphic_info[graphic].anim_delay_random =
1045 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1046 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1047 graphic_info[graphic].post_delay_fixed =
1048 parameter[GFX_ARG_POST_DELAY_FIXED];
1049 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1050 graphic_info[graphic].post_delay_random =
1051 parameter[GFX_ARG_POST_DELAY_RANDOM];
1053 /* this is only used for toon animations */
1054 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1055 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1057 /* this is only used for drawing font characters */
1058 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1059 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1061 /* this is only used for drawing envelope graphics */
1062 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1064 /* optional graphic for cloning all graphics settings */
1065 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1066 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1069 static void set_cloned_graphic_parameters(int graphic)
1071 int fallback_graphic = IMG_CHAR_EXCLAM;
1072 int max_num_images = getImageListSize();
1073 int clone_graphic = graphic_info[graphic].clone_from;
1074 int num_references_followed = 1;
1076 while (graphic_info[clone_graphic].clone_from != -1 &&
1077 num_references_followed < max_num_images)
1079 clone_graphic = graphic_info[clone_graphic].clone_from;
1081 num_references_followed++;
1084 if (num_references_followed >= max_num_images)
1086 Error(ERR_RETURN_LINE, "-");
1087 Error(ERR_RETURN, "warning: error found in config file:");
1088 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1089 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1090 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1091 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1093 if (graphic == fallback_graphic)
1094 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1096 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1097 Error(ERR_RETURN_LINE, "-");
1099 graphic_info[graphic] = graphic_info[fallback_graphic];
1103 graphic_info[graphic] = graphic_info[clone_graphic];
1104 graphic_info[graphic].clone_from = clone_graphic;
1108 static void InitGraphicInfo()
1110 int fallback_graphic = IMG_CHAR_EXCLAM;
1111 int num_images = getImageListSize();
1114 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1115 static boolean clipmasks_initialized = FALSE;
1117 XGCValues clip_gc_values;
1118 unsigned long clip_gc_valuemask;
1119 GC copy_clipmask_gc = None;
1122 checked_free(graphic_info);
1124 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1126 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1127 if (clipmasks_initialized)
1129 for (i = 0; i < num_images; i++)
1131 if (graphic_info[i].clip_mask)
1132 XFreePixmap(display, graphic_info[i].clip_mask);
1133 if (graphic_info[i].clip_gc)
1134 XFreeGC(display, graphic_info[i].clip_gc);
1136 graphic_info[i].clip_mask = None;
1137 graphic_info[i].clip_gc = None;
1142 /* first set all graphic paramaters ... */
1143 for (i = 0; i < num_images; i++)
1144 set_graphic_parameters(i);
1146 /* ... then copy these parameters for cloned graphics */
1147 for (i = 0; i < num_images; i++)
1148 if (graphic_info[i].clone_from != -1)
1149 set_cloned_graphic_parameters(i);
1151 for (i = 0; i < num_images; i++)
1155 int first_frame, last_frame;
1156 int src_bitmap_width, src_bitmap_height;
1158 /* now check if no animation frames are outside of the loaded image */
1160 if (graphic_info[i].bitmap == NULL)
1161 continue; /* skip check for optional images that are undefined */
1163 /* get final bitmap size (with scaling, but without small images) */
1164 src_bitmap_width = graphic_info[i].src_image_width;
1165 src_bitmap_height = graphic_info[i].src_image_height;
1167 /* check if first animation frame is inside specified bitmap */
1170 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1172 if (src_x < 0 || src_y < 0 ||
1173 src_x + TILEX > src_bitmap_width ||
1174 src_y + TILEY > src_bitmap_height)
1176 Error(ERR_RETURN_LINE, "-");
1177 Error(ERR_RETURN, "warning: error found in config file:");
1178 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1179 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1180 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1182 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1183 src_x, src_y, src_bitmap_width, src_bitmap_height);
1184 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1186 if (i == fallback_graphic)
1187 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1189 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1190 Error(ERR_RETURN_LINE, "-");
1192 graphic_info[i] = graphic_info[fallback_graphic];
1195 /* check if last animation frame is inside specified bitmap */
1197 last_frame = graphic_info[i].anim_frames - 1;
1198 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1200 if (src_x < 0 || src_y < 0 ||
1201 src_x + TILEX > src_bitmap_width ||
1202 src_y + TILEY > src_bitmap_height)
1204 Error(ERR_RETURN_LINE, "-");
1205 Error(ERR_RETURN, "warning: error found in config file:");
1206 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1207 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1208 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1210 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1211 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1212 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1214 if (i == fallback_graphic)
1215 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1217 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1218 Error(ERR_RETURN_LINE, "-");
1220 graphic_info[i] = graphic_info[fallback_graphic];
1223 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1224 /* currently we only need a tile clip mask from the first frame */
1225 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1227 if (copy_clipmask_gc == None)
1229 clip_gc_values.graphics_exposures = False;
1230 clip_gc_valuemask = GCGraphicsExposures;
1231 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1232 clip_gc_valuemask, &clip_gc_values);
1235 graphic_info[i].clip_mask =
1236 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1238 src_pixmap = src_bitmap->clip_mask;
1239 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1240 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1242 clip_gc_values.graphics_exposures = False;
1243 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1244 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1246 graphic_info[i].clip_gc =
1247 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1251 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1252 if (copy_clipmask_gc)
1253 XFreeGC(display, copy_clipmask_gc);
1255 clipmasks_initialized = TRUE;
1259 static void InitElementSoundInfo()
1261 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1262 int num_property_mappings = getSoundListPropertyMappingSize();
1265 /* set values to -1 to identify later as "uninitialized" values */
1266 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1267 for (act = 0; act < NUM_ACTIONS; act++)
1268 element_info[i].sound[act] = -1;
1270 /* initialize element/sound mapping from static configuration */
1271 for (i = 0; element_to_sound[i].element > -1; i++)
1273 int element = element_to_sound[i].element;
1274 int action = element_to_sound[i].action;
1275 int sound = element_to_sound[i].sound;
1276 boolean is_class = element_to_sound[i].is_class;
1279 action = ACTION_DEFAULT;
1282 element_info[element].sound[action] = sound;
1284 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1285 if (strcmp(element_info[j].class_name,
1286 element_info[element].class_name) == 0)
1287 element_info[j].sound[action] = sound;
1290 /* initialize element class/sound mapping from dynamic configuration */
1291 for (i = 0; i < num_property_mappings; i++)
1293 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1294 int action = property_mapping[i].ext1_index;
1295 int sound = property_mapping[i].artwork_index;
1297 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1301 action = ACTION_DEFAULT;
1303 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1304 if (strcmp(element_info[j].class_name,
1305 element_info[element_class].class_name) == 0)
1306 element_info[j].sound[action] = sound;
1309 /* initialize element/sound mapping from dynamic configuration */
1310 for (i = 0; i < num_property_mappings; i++)
1312 int element = property_mapping[i].base_index;
1313 int action = property_mapping[i].ext1_index;
1314 int sound = property_mapping[i].artwork_index;
1316 if (element >= MAX_NUM_ELEMENTS)
1320 action = ACTION_DEFAULT;
1322 element_info[element].sound[action] = sound;
1325 /* now set all '-1' values to element specific default values */
1326 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1328 for (act = 0; act < NUM_ACTIONS; act++)
1330 /* generic default action sound (defined by "[default]" directive) */
1331 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1333 /* look for special default action sound (classic game specific) */
1334 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1335 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1336 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1337 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1338 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1339 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1341 /* !!! there's no such thing as a "default action sound" !!! */
1343 /* look for element specific default sound (independent from action) */
1344 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1345 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1349 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1350 /* !!! make this better !!! */
1351 if (i == EL_EMPTY_SPACE)
1352 default_action_sound = element_info[EL_DEFAULT].sound[act];
1355 /* no sound for this specific action -- use default action sound */
1356 if (element_info[i].sound[act] == -1)
1357 element_info[i].sound[act] = default_action_sound;
1361 /* copy sound settings to some elements that are only stored in level file
1362 in native R'n'D levels, but are used by game engine in native EM levels */
1363 for (i = 0; copy_properties[i][0] != -1; i++)
1364 for (j = 1; j <= 4; j++)
1365 for (act = 0; act < NUM_ACTIONS; act++)
1366 element_info[copy_properties[i][j]].sound[act] =
1367 element_info[copy_properties[i][0]].sound[act];
1370 static void InitGameModeSoundInfo()
1374 /* set values to -1 to identify later as "uninitialized" values */
1375 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1378 /* initialize gamemode/sound mapping from static configuration */
1379 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1381 int gamemode = gamemode_to_sound[i].gamemode;
1382 int sound = gamemode_to_sound[i].sound;
1385 gamemode = GAME_MODE_DEFAULT;
1387 menu.sound[gamemode] = sound;
1390 /* now set all '-1' values to levelset specific default values */
1391 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1392 if (menu.sound[i] == -1)
1393 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1396 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1397 if (menu.sound[i] != -1)
1398 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1402 static void set_sound_parameters(int sound, char **parameter_raw)
1404 int parameter[NUM_SND_ARGS];
1407 /* get integer values from string parameters */
1408 for (i = 0; i < NUM_SND_ARGS; i++)
1410 get_parameter_value(parameter_raw[i],
1411 sound_config_suffix[i].token,
1412 sound_config_suffix[i].type);
1414 /* explicit loop mode setting in configuration overrides default value */
1415 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1416 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1418 /* sound volume to change the original volume when loading the sound file */
1419 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1421 /* sound priority to give certain sounds a higher or lower priority */
1422 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1425 static void InitSoundInfo()
1427 int *sound_effect_properties;
1428 int num_sounds = getSoundListSize();
1431 checked_free(sound_info);
1433 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1434 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1436 /* initialize sound effect for all elements to "no sound" */
1437 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1438 for (j = 0; j < NUM_ACTIONS; j++)
1439 element_info[i].sound[j] = SND_UNDEFINED;
1441 for (i = 0; i < num_sounds; i++)
1443 struct FileInfo *sound = getSoundListEntry(i);
1444 int len_effect_text = strlen(sound->token);
1446 sound_effect_properties[i] = ACTION_OTHER;
1447 sound_info[i].loop = FALSE; /* default: play sound only once */
1450 printf("::: sound %d: '%s'\n", i, sound->token);
1453 /* determine all loop sounds and identify certain sound classes */
1455 for (j = 0; element_action_info[j].suffix; j++)
1457 int len_action_text = strlen(element_action_info[j].suffix);
1459 if (len_action_text < len_effect_text &&
1460 strcmp(&sound->token[len_effect_text - len_action_text],
1461 element_action_info[j].suffix) == 0)
1463 sound_effect_properties[i] = element_action_info[j].value;
1464 sound_info[i].loop = element_action_info[j].is_loop_sound;
1470 /* associate elements and some selected sound actions */
1472 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1474 if (element_info[j].class_name)
1476 int len_class_text = strlen(element_info[j].class_name);
1478 if (len_class_text + 1 < len_effect_text &&
1479 strncmp(sound->token,
1480 element_info[j].class_name, len_class_text) == 0 &&
1481 sound->token[len_class_text] == '.')
1483 int sound_action_value = sound_effect_properties[i];
1485 element_info[j].sound[sound_action_value] = i;
1490 set_sound_parameters(i, sound->parameter);
1493 free(sound_effect_properties);
1496 static void InitGameModeMusicInfo()
1498 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1499 int num_property_mappings = getMusicListPropertyMappingSize();
1500 int default_levelset_music = -1;
1503 /* set values to -1 to identify later as "uninitialized" values */
1504 for (i = 0; i < MAX_LEVELS; i++)
1505 levelset.music[i] = -1;
1506 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1509 /* initialize gamemode/music mapping from static configuration */
1510 for (i = 0; gamemode_to_music[i].music > -1; i++)
1512 int gamemode = gamemode_to_music[i].gamemode;
1513 int music = gamemode_to_music[i].music;
1516 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1520 gamemode = GAME_MODE_DEFAULT;
1522 menu.music[gamemode] = music;
1525 /* initialize gamemode/music mapping from dynamic configuration */
1526 for (i = 0; i < num_property_mappings; i++)
1528 int prefix = property_mapping[i].base_index;
1529 int gamemode = property_mapping[i].ext1_index;
1530 int level = property_mapping[i].ext2_index;
1531 int music = property_mapping[i].artwork_index;
1534 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1535 prefix, gamemode, level, music);
1538 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1542 gamemode = GAME_MODE_DEFAULT;
1544 /* level specific music only allowed for in-game music */
1545 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1546 gamemode = GAME_MODE_PLAYING;
1551 default_levelset_music = music;
1554 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1555 levelset.music[level] = music;
1556 if (gamemode != GAME_MODE_PLAYING)
1557 menu.music[gamemode] = music;
1560 /* now set all '-1' values to menu specific default values */
1561 /* (undefined values of "levelset.music[]" might stay at "-1" to
1562 allow dynamic selection of music files from music directory!) */
1563 for (i = 0; i < MAX_LEVELS; i++)
1564 if (levelset.music[i] == -1)
1565 levelset.music[i] = default_levelset_music;
1566 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1567 if (menu.music[i] == -1)
1568 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1571 for (i = 0; i < MAX_LEVELS; i++)
1572 if (levelset.music[i] != -1)
1573 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1574 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1575 if (menu.music[i] != -1)
1576 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1580 static void set_music_parameters(int music, char **parameter_raw)
1582 int parameter[NUM_MUS_ARGS];
1585 /* get integer values from string parameters */
1586 for (i = 0; i < NUM_MUS_ARGS; i++)
1588 get_parameter_value(parameter_raw[i],
1589 music_config_suffix[i].token,
1590 music_config_suffix[i].type);
1592 /* explicit loop mode setting in configuration overrides default value */
1593 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1594 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1597 static void InitMusicInfo()
1599 int num_music = getMusicListSize();
1602 checked_free(music_info);
1604 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1606 for (i = 0; i < num_music; i++)
1608 struct FileInfo *music = getMusicListEntry(i);
1609 int len_music_text = strlen(music->token);
1611 music_info[i].loop = TRUE; /* default: play music in loop mode */
1613 /* determine all loop music */
1615 for (j = 0; music_prefix_info[j].prefix; j++)
1617 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1619 if (len_prefix_text < len_music_text &&
1620 strncmp(music->token,
1621 music_prefix_info[j].prefix, len_prefix_text) == 0)
1623 music_info[i].loop = music_prefix_info[j].is_loop_music;
1629 set_music_parameters(i, music->parameter);
1633 static void ReinitializeGraphics()
1635 InitGraphicInfo(); /* graphic properties mapping */
1636 InitElementGraphicInfo(); /* element game graphic mapping */
1637 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1639 InitElementSmallImages(); /* scale images to all needed sizes */
1640 InitFontGraphicInfo(); /* initialize text drawing functions */
1642 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1644 SetMainBackgroundImage(IMG_BACKGROUND);
1645 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1651 static void ReinitializeSounds()
1653 InitSoundInfo(); /* sound properties mapping */
1654 InitElementSoundInfo(); /* element game sound mapping */
1655 InitGameModeSoundInfo(); /* game mode sound mapping */
1657 InitPlayLevelSound(); /* internal game sound settings */
1660 static void ReinitializeMusic()
1662 InitMusicInfo(); /* music properties mapping */
1663 InitGameModeMusicInfo(); /* game mode music mapping */
1666 static int get_special_property_bit(int element, int property_bit_nr)
1668 struct PropertyBitInfo
1674 static struct PropertyBitInfo pb_can_move_into_acid[] =
1676 /* the player may be able fall into acid when gravity is activated */
1681 { EL_SP_MURPHY, 0 },
1682 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1684 /* all elements that can move may be able to also move into acid */
1687 { EL_BUG_RIGHT, 1 },
1690 { EL_SPACESHIP, 2 },
1691 { EL_SPACESHIP_LEFT, 2 },
1692 { EL_SPACESHIP_RIGHT, 2 },
1693 { EL_SPACESHIP_UP, 2 },
1694 { EL_SPACESHIP_DOWN, 2 },
1695 { EL_BD_BUTTERFLY, 3 },
1696 { EL_BD_BUTTERFLY_LEFT, 3 },
1697 { EL_BD_BUTTERFLY_RIGHT, 3 },
1698 { EL_BD_BUTTERFLY_UP, 3 },
1699 { EL_BD_BUTTERFLY_DOWN, 3 },
1700 { EL_BD_FIREFLY, 4 },
1701 { EL_BD_FIREFLY_LEFT, 4 },
1702 { EL_BD_FIREFLY_RIGHT, 4 },
1703 { EL_BD_FIREFLY_UP, 4 },
1704 { EL_BD_FIREFLY_DOWN, 4 },
1706 { EL_DARK_YAMYAM, 6 },
1709 { EL_PACMAN_LEFT, 8 },
1710 { EL_PACMAN_RIGHT, 8 },
1711 { EL_PACMAN_UP, 8 },
1712 { EL_PACMAN_DOWN, 8 },
1714 { EL_MOLE_LEFT, 9 },
1715 { EL_MOLE_RIGHT, 9 },
1717 { EL_MOLE_DOWN, 9 },
1721 { EL_SATELLITE, 13 },
1722 { EL_SP_SNIKSNAK, 14 },
1723 { EL_SP_ELECTRON, 15 },
1726 { EL_EMC_ANDROID, 18 },
1731 static struct PropertyBitInfo pb_dont_collide_with[] =
1733 { EL_SP_SNIKSNAK, 0 },
1734 { EL_SP_ELECTRON, 1 },
1742 struct PropertyBitInfo *pb_info;
1745 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1746 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1751 struct PropertyBitInfo *pb_info = NULL;
1754 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1755 if (pb_definition[i].bit_nr == property_bit_nr)
1756 pb_info = pb_definition[i].pb_info;
1758 if (pb_info == NULL)
1761 for (i = 0; pb_info[i].element != -1; i++)
1762 if (pb_info[i].element == element)
1763 return pb_info[i].bit_nr;
1768 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1769 boolean property_value)
1771 int bit_nr = get_special_property_bit(element, property_bit_nr);
1776 *bitfield |= (1 << bit_nr);
1778 *bitfield &= ~(1 << bit_nr);
1782 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1784 int bit_nr = get_special_property_bit(element, property_bit_nr);
1787 return ((*bitfield & (1 << bit_nr)) != 0);
1793 static void resolve_group_element(int group_element, int recursion_depth)
1795 static int group_nr;
1796 static struct ElementGroupInfo *group;
1797 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1800 if (actual_group == NULL) /* not yet initialized */
1803 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1805 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1806 group_element - EL_GROUP_START + 1);
1808 /* replace element which caused too deep recursion by question mark */
1809 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1814 if (recursion_depth == 0) /* initialization */
1816 group = actual_group;
1817 group_nr = group_element - EL_GROUP_START;
1819 group->num_elements_resolved = 0;
1820 group->choice_pos = 0;
1823 for (i = 0; i < actual_group->num_elements; i++)
1825 int element = actual_group->element[i];
1827 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1830 if (IS_GROUP_ELEMENT(element))
1831 resolve_group_element(element, recursion_depth + 1);
1834 group->element_resolved[group->num_elements_resolved++] = element;
1835 element_info[element].in_group[group_nr] = TRUE;
1841 void InitElementPropertiesStatic()
1843 static int ep_diggable[] =
1848 EL_SP_BUGGY_BASE_ACTIVATING,
1851 EL_INVISIBLE_SAND_ACTIVE,
1854 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1855 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1859 EL_SP_BUGGY_BASE_ACTIVE,
1866 static int ep_collectible_only[] =
1888 EL_DYNABOMB_INCREASE_NUMBER,
1889 EL_DYNABOMB_INCREASE_SIZE,
1890 EL_DYNABOMB_INCREASE_POWER,
1910 static int ep_dont_run_into[] =
1912 /* same elements as in 'ep_dont_touch' */
1918 /* same elements as in 'ep_dont_collide_with' */
1930 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1934 EL_SP_BUGGY_BASE_ACTIVE,
1941 static int ep_dont_collide_with[] =
1943 /* same elements as in 'ep_dont_touch' */
1960 static int ep_dont_touch[] =
1970 static int ep_indestructible[] =
1974 EL_ACID_POOL_TOPLEFT,
1975 EL_ACID_POOL_TOPRIGHT,
1976 EL_ACID_POOL_BOTTOMLEFT,
1977 EL_ACID_POOL_BOTTOM,
1978 EL_ACID_POOL_BOTTOMRIGHT,
1979 EL_SP_HARDWARE_GRAY,
1980 EL_SP_HARDWARE_GREEN,
1981 EL_SP_HARDWARE_BLUE,
1983 EL_SP_HARDWARE_YELLOW,
1984 EL_SP_HARDWARE_BASE_1,
1985 EL_SP_HARDWARE_BASE_2,
1986 EL_SP_HARDWARE_BASE_3,
1987 EL_SP_HARDWARE_BASE_4,
1988 EL_SP_HARDWARE_BASE_5,
1989 EL_SP_HARDWARE_BASE_6,
1990 EL_INVISIBLE_STEELWALL,
1991 EL_INVISIBLE_STEELWALL_ACTIVE,
1992 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1993 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1994 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1995 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1996 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1997 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1998 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1999 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2000 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2001 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2002 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2003 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2005 EL_LIGHT_SWITCH_ACTIVE,
2006 EL_SIGN_EXCLAMATION,
2007 EL_SIGN_RADIOACTIVITY,
2018 EL_STEELWALL_SLIPPERY,
2032 EL_GATE_1_GRAY_ACTIVE,
2033 EL_GATE_2_GRAY_ACTIVE,
2034 EL_GATE_3_GRAY_ACTIVE,
2035 EL_GATE_4_GRAY_ACTIVE,
2044 EL_EM_GATE_1_GRAY_ACTIVE,
2045 EL_EM_GATE_2_GRAY_ACTIVE,
2046 EL_EM_GATE_3_GRAY_ACTIVE,
2047 EL_EM_GATE_4_GRAY_ACTIVE,
2056 EL_EMC_GATE_5_GRAY_ACTIVE,
2057 EL_EMC_GATE_6_GRAY_ACTIVE,
2058 EL_EMC_GATE_7_GRAY_ACTIVE,
2059 EL_EMC_GATE_8_GRAY_ACTIVE,
2061 EL_SWITCHGATE_OPENING,
2062 EL_SWITCHGATE_CLOSED,
2063 EL_SWITCHGATE_CLOSING,
2065 EL_SWITCHGATE_SWITCH_UP,
2066 EL_SWITCHGATE_SWITCH_DOWN,
2069 EL_TIMEGATE_OPENING,
2071 EL_TIMEGATE_CLOSING,
2074 EL_TIMEGATE_SWITCH_ACTIVE,
2079 EL_TUBE_VERTICAL_LEFT,
2080 EL_TUBE_VERTICAL_RIGHT,
2081 EL_TUBE_HORIZONTAL_UP,
2082 EL_TUBE_HORIZONTAL_DOWN,
2091 static int ep_slippery[] =
2105 EL_ROBOT_WHEEL_ACTIVE,
2111 EL_ACID_POOL_TOPLEFT,
2112 EL_ACID_POOL_TOPRIGHT,
2122 EL_STEELWALL_SLIPPERY,
2125 EL_EMC_WALL_SLIPPERY_1,
2126 EL_EMC_WALL_SLIPPERY_2,
2127 EL_EMC_WALL_SLIPPERY_3,
2128 EL_EMC_WALL_SLIPPERY_4,
2130 EL_EMC_MAGIC_BALL_ACTIVE,
2135 static int ep_can_change[] =
2140 static int ep_can_move[] =
2142 /* same elements as in 'pb_can_move_into_acid' */
2165 static int ep_can_fall[] =
2180 EL_BD_MAGIC_WALL_FULL,
2194 static int ep_can_smash_player[] =
2220 static int ep_can_smash_enemies[] =
2229 static int ep_can_smash_everything[] =
2238 static int ep_explodes_by_fire[] =
2240 /* same elements as in 'ep_explodes_impact' */
2245 /* same elements as in 'ep_explodes_smashed' */
2255 EL_EM_DYNAMITE_ACTIVE,
2256 EL_DYNABOMB_PLAYER_1_ACTIVE,
2257 EL_DYNABOMB_PLAYER_2_ACTIVE,
2258 EL_DYNABOMB_PLAYER_3_ACTIVE,
2259 EL_DYNABOMB_PLAYER_4_ACTIVE,
2260 EL_DYNABOMB_INCREASE_NUMBER,
2261 EL_DYNABOMB_INCREASE_SIZE,
2262 EL_DYNABOMB_INCREASE_POWER,
2263 EL_SP_DISK_RED_ACTIVE,
2277 static int ep_explodes_smashed[] =
2279 /* same elements as in 'ep_explodes_impact' */
2293 static int ep_explodes_impact[] =
2302 static int ep_walkable_over[] =
2306 EL_SOKOBAN_FIELD_EMPTY,
2318 EL_GATE_1_GRAY_ACTIVE,
2319 EL_GATE_2_GRAY_ACTIVE,
2320 EL_GATE_3_GRAY_ACTIVE,
2321 EL_GATE_4_GRAY_ACTIVE,
2329 static int ep_walkable_inside[] =
2334 EL_TUBE_VERTICAL_LEFT,
2335 EL_TUBE_VERTICAL_RIGHT,
2336 EL_TUBE_HORIZONTAL_UP,
2337 EL_TUBE_HORIZONTAL_DOWN,
2346 static int ep_walkable_under[] =
2351 static int ep_passable_over[] =
2361 EL_EM_GATE_1_GRAY_ACTIVE,
2362 EL_EM_GATE_2_GRAY_ACTIVE,
2363 EL_EM_GATE_3_GRAY_ACTIVE,
2364 EL_EM_GATE_4_GRAY_ACTIVE,
2373 EL_EMC_GATE_5_GRAY_ACTIVE,
2374 EL_EMC_GATE_6_GRAY_ACTIVE,
2375 EL_EMC_GATE_7_GRAY_ACTIVE,
2376 EL_EMC_GATE_8_GRAY_ACTIVE,
2383 static int ep_passable_inside[] =
2389 EL_SP_PORT_HORIZONTAL,
2390 EL_SP_PORT_VERTICAL,
2392 EL_SP_GRAVITY_PORT_LEFT,
2393 EL_SP_GRAVITY_PORT_RIGHT,
2394 EL_SP_GRAVITY_PORT_UP,
2395 EL_SP_GRAVITY_PORT_DOWN,
2396 EL_SP_GRAVITY_ON_PORT_LEFT,
2397 EL_SP_GRAVITY_ON_PORT_RIGHT,
2398 EL_SP_GRAVITY_ON_PORT_UP,
2399 EL_SP_GRAVITY_ON_PORT_DOWN,
2400 EL_SP_GRAVITY_OFF_PORT_LEFT,
2401 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2402 EL_SP_GRAVITY_OFF_PORT_UP,
2403 EL_SP_GRAVITY_OFF_PORT_DOWN,
2408 static int ep_passable_under[] =
2413 static int ep_droppable[] =
2418 static int ep_explodes_1x1_old[] =
2423 static int ep_pushable[] =
2435 EL_SOKOBAN_FIELD_FULL,
2444 static int ep_explodes_cross_old[] =
2449 static int ep_protected[] =
2451 /* same elements as in 'ep_walkable_inside' */
2455 EL_TUBE_VERTICAL_LEFT,
2456 EL_TUBE_VERTICAL_RIGHT,
2457 EL_TUBE_HORIZONTAL_UP,
2458 EL_TUBE_HORIZONTAL_DOWN,
2464 /* same elements as in 'ep_passable_over' */
2473 EL_EM_GATE_1_GRAY_ACTIVE,
2474 EL_EM_GATE_2_GRAY_ACTIVE,
2475 EL_EM_GATE_3_GRAY_ACTIVE,
2476 EL_EM_GATE_4_GRAY_ACTIVE,
2485 EL_EMC_GATE_5_GRAY_ACTIVE,
2486 EL_EMC_GATE_6_GRAY_ACTIVE,
2487 EL_EMC_GATE_7_GRAY_ACTIVE,
2488 EL_EMC_GATE_8_GRAY_ACTIVE,
2492 /* same elements as in 'ep_passable_inside' */
2497 EL_SP_PORT_HORIZONTAL,
2498 EL_SP_PORT_VERTICAL,
2500 EL_SP_GRAVITY_PORT_LEFT,
2501 EL_SP_GRAVITY_PORT_RIGHT,
2502 EL_SP_GRAVITY_PORT_UP,
2503 EL_SP_GRAVITY_PORT_DOWN,
2504 EL_SP_GRAVITY_ON_PORT_LEFT,
2505 EL_SP_GRAVITY_ON_PORT_RIGHT,
2506 EL_SP_GRAVITY_ON_PORT_UP,
2507 EL_SP_GRAVITY_ON_PORT_DOWN,
2508 EL_SP_GRAVITY_OFF_PORT_LEFT,
2509 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2510 EL_SP_GRAVITY_OFF_PORT_UP,
2511 EL_SP_GRAVITY_OFF_PORT_DOWN,
2516 static int ep_throwable[] =
2521 static int ep_can_explode[] =
2523 /* same elements as in 'ep_explodes_impact' */
2528 /* same elements as in 'ep_explodes_smashed' */
2534 /* elements that can explode by explosion or by dragonfire */
2538 EL_EM_DYNAMITE_ACTIVE,
2539 EL_DYNABOMB_PLAYER_1_ACTIVE,
2540 EL_DYNABOMB_PLAYER_2_ACTIVE,
2541 EL_DYNABOMB_PLAYER_3_ACTIVE,
2542 EL_DYNABOMB_PLAYER_4_ACTIVE,
2543 EL_DYNABOMB_INCREASE_NUMBER,
2544 EL_DYNABOMB_INCREASE_SIZE,
2545 EL_DYNABOMB_INCREASE_POWER,
2546 EL_SP_DISK_RED_ACTIVE,
2554 /* elements that can explode only by explosion */
2560 static int ep_gravity_reachable[] =
2566 EL_INVISIBLE_SAND_ACTIVE,
2571 EL_SP_PORT_HORIZONTAL,
2572 EL_SP_PORT_VERTICAL,
2574 EL_SP_GRAVITY_PORT_LEFT,
2575 EL_SP_GRAVITY_PORT_RIGHT,
2576 EL_SP_GRAVITY_PORT_UP,
2577 EL_SP_GRAVITY_PORT_DOWN,
2578 EL_SP_GRAVITY_ON_PORT_LEFT,
2579 EL_SP_GRAVITY_ON_PORT_RIGHT,
2580 EL_SP_GRAVITY_ON_PORT_UP,
2581 EL_SP_GRAVITY_ON_PORT_DOWN,
2582 EL_SP_GRAVITY_OFF_PORT_LEFT,
2583 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2584 EL_SP_GRAVITY_OFF_PORT_UP,
2585 EL_SP_GRAVITY_OFF_PORT_DOWN,
2591 static int ep_player[] =
2598 EL_SOKOBAN_FIELD_PLAYER,
2604 static int ep_can_pass_magic_wall[] =
2618 static int ep_switchable[] =
2622 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2623 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2624 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2625 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2626 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2627 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2628 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2629 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2630 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2631 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2632 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2633 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2634 EL_SWITCHGATE_SWITCH_UP,
2635 EL_SWITCHGATE_SWITCH_DOWN,
2637 EL_LIGHT_SWITCH_ACTIVE,
2639 EL_BALLOON_SWITCH_LEFT,
2640 EL_BALLOON_SWITCH_RIGHT,
2641 EL_BALLOON_SWITCH_UP,
2642 EL_BALLOON_SWITCH_DOWN,
2643 EL_BALLOON_SWITCH_ANY,
2644 EL_BALLOON_SWITCH_NONE,
2647 EL_EMC_MAGIC_BALL_SWITCH,
2648 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2653 static int ep_bd_element[] =
2687 static int ep_sp_element[] =
2689 /* should always be valid */
2692 /* standard classic Supaplex elements */
2699 EL_SP_HARDWARE_GRAY,
2707 EL_SP_GRAVITY_PORT_RIGHT,
2708 EL_SP_GRAVITY_PORT_DOWN,
2709 EL_SP_GRAVITY_PORT_LEFT,
2710 EL_SP_GRAVITY_PORT_UP,
2715 EL_SP_PORT_VERTICAL,
2716 EL_SP_PORT_HORIZONTAL,
2722 EL_SP_HARDWARE_BASE_1,
2723 EL_SP_HARDWARE_GREEN,
2724 EL_SP_HARDWARE_BLUE,
2726 EL_SP_HARDWARE_YELLOW,
2727 EL_SP_HARDWARE_BASE_2,
2728 EL_SP_HARDWARE_BASE_3,
2729 EL_SP_HARDWARE_BASE_4,
2730 EL_SP_HARDWARE_BASE_5,
2731 EL_SP_HARDWARE_BASE_6,
2735 /* additional elements that appeared in newer Supaplex levels */
2738 /* additional gravity port elements (not switching, but setting gravity) */
2739 EL_SP_GRAVITY_ON_PORT_LEFT,
2740 EL_SP_GRAVITY_ON_PORT_RIGHT,
2741 EL_SP_GRAVITY_ON_PORT_UP,
2742 EL_SP_GRAVITY_ON_PORT_DOWN,
2743 EL_SP_GRAVITY_OFF_PORT_LEFT,
2744 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2745 EL_SP_GRAVITY_OFF_PORT_UP,
2746 EL_SP_GRAVITY_OFF_PORT_DOWN,
2748 /* more than one Murphy in a level results in an inactive clone */
2751 /* runtime Supaplex elements */
2752 EL_SP_DISK_RED_ACTIVE,
2753 EL_SP_TERMINAL_ACTIVE,
2754 EL_SP_BUGGY_BASE_ACTIVATING,
2755 EL_SP_BUGGY_BASE_ACTIVE,
2762 static int ep_sb_element[] =
2767 EL_SOKOBAN_FIELD_EMPTY,
2768 EL_SOKOBAN_FIELD_FULL,
2769 EL_SOKOBAN_FIELD_PLAYER,
2774 EL_INVISIBLE_STEELWALL,
2779 static int ep_gem[] =
2791 static int ep_food_dark_yamyam[] =
2819 static int ep_food_penguin[] =
2833 static int ep_food_pig[] =
2845 static int ep_historic_wall[] =
2856 EL_GATE_1_GRAY_ACTIVE,
2857 EL_GATE_2_GRAY_ACTIVE,
2858 EL_GATE_3_GRAY_ACTIVE,
2859 EL_GATE_4_GRAY_ACTIVE,
2868 EL_EM_GATE_1_GRAY_ACTIVE,
2869 EL_EM_GATE_2_GRAY_ACTIVE,
2870 EL_EM_GATE_3_GRAY_ACTIVE,
2871 EL_EM_GATE_4_GRAY_ACTIVE,
2878 EL_EXPANDABLE_WALL_HORIZONTAL,
2879 EL_EXPANDABLE_WALL_VERTICAL,
2880 EL_EXPANDABLE_WALL_ANY,
2881 EL_EXPANDABLE_WALL_GROWING,
2888 EL_SP_HARDWARE_GRAY,
2889 EL_SP_HARDWARE_GREEN,
2890 EL_SP_HARDWARE_BLUE,
2892 EL_SP_HARDWARE_YELLOW,
2893 EL_SP_HARDWARE_BASE_1,
2894 EL_SP_HARDWARE_BASE_2,
2895 EL_SP_HARDWARE_BASE_3,
2896 EL_SP_HARDWARE_BASE_4,
2897 EL_SP_HARDWARE_BASE_5,
2898 EL_SP_HARDWARE_BASE_6,
2900 EL_SP_TERMINAL_ACTIVE,
2903 EL_INVISIBLE_STEELWALL,
2904 EL_INVISIBLE_STEELWALL_ACTIVE,
2906 EL_INVISIBLE_WALL_ACTIVE,
2907 EL_STEELWALL_SLIPPERY,
2924 static int ep_historic_solid[] =
2928 EL_EXPANDABLE_WALL_HORIZONTAL,
2929 EL_EXPANDABLE_WALL_VERTICAL,
2930 EL_EXPANDABLE_WALL_ANY,
2943 EL_QUICKSAND_FILLING,
2944 EL_QUICKSAND_EMPTYING,
2946 EL_MAGIC_WALL_ACTIVE,
2947 EL_MAGIC_WALL_EMPTYING,
2948 EL_MAGIC_WALL_FILLING,
2952 EL_BD_MAGIC_WALL_ACTIVE,
2953 EL_BD_MAGIC_WALL_EMPTYING,
2954 EL_BD_MAGIC_WALL_FULL,
2955 EL_BD_MAGIC_WALL_FILLING,
2956 EL_BD_MAGIC_WALL_DEAD,
2965 EL_SP_TERMINAL_ACTIVE,
2969 EL_INVISIBLE_WALL_ACTIVE,
2970 EL_SWITCHGATE_SWITCH_UP,
2971 EL_SWITCHGATE_SWITCH_DOWN,
2973 EL_TIMEGATE_SWITCH_ACTIVE,
2985 /* the following elements are a direct copy of "indestructible" elements,
2986 except "EL_ACID", which is "indestructible", but not "solid"! */
2991 EL_ACID_POOL_TOPLEFT,
2992 EL_ACID_POOL_TOPRIGHT,
2993 EL_ACID_POOL_BOTTOMLEFT,
2994 EL_ACID_POOL_BOTTOM,
2995 EL_ACID_POOL_BOTTOMRIGHT,
2996 EL_SP_HARDWARE_GRAY,
2997 EL_SP_HARDWARE_GREEN,
2998 EL_SP_HARDWARE_BLUE,
3000 EL_SP_HARDWARE_YELLOW,
3001 EL_SP_HARDWARE_BASE_1,
3002 EL_SP_HARDWARE_BASE_2,
3003 EL_SP_HARDWARE_BASE_3,
3004 EL_SP_HARDWARE_BASE_4,
3005 EL_SP_HARDWARE_BASE_5,
3006 EL_SP_HARDWARE_BASE_6,
3007 EL_INVISIBLE_STEELWALL,
3008 EL_INVISIBLE_STEELWALL_ACTIVE,
3009 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3010 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3011 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3012 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3013 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3014 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3015 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3016 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3017 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3018 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3019 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3020 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3022 EL_LIGHT_SWITCH_ACTIVE,
3023 EL_SIGN_EXCLAMATION,
3024 EL_SIGN_RADIOACTIVITY,
3035 EL_STEELWALL_SLIPPERY,
3049 EL_GATE_1_GRAY_ACTIVE,
3050 EL_GATE_2_GRAY_ACTIVE,
3051 EL_GATE_3_GRAY_ACTIVE,
3052 EL_GATE_4_GRAY_ACTIVE,
3061 EL_EM_GATE_1_GRAY_ACTIVE,
3062 EL_EM_GATE_2_GRAY_ACTIVE,
3063 EL_EM_GATE_3_GRAY_ACTIVE,
3064 EL_EM_GATE_4_GRAY_ACTIVE,
3066 EL_SWITCHGATE_OPENING,
3067 EL_SWITCHGATE_CLOSED,
3068 EL_SWITCHGATE_CLOSING,
3070 EL_TIMEGATE_OPENING,
3072 EL_TIMEGATE_CLOSING,
3076 EL_TUBE_VERTICAL_LEFT,
3077 EL_TUBE_VERTICAL_RIGHT,
3078 EL_TUBE_HORIZONTAL_UP,
3079 EL_TUBE_HORIZONTAL_DOWN,
3088 static int ep_classic_enemy[] =
3105 static int ep_belt[] =
3107 EL_CONVEYOR_BELT_1_LEFT,
3108 EL_CONVEYOR_BELT_1_MIDDLE,
3109 EL_CONVEYOR_BELT_1_RIGHT,
3110 EL_CONVEYOR_BELT_2_LEFT,
3111 EL_CONVEYOR_BELT_2_MIDDLE,
3112 EL_CONVEYOR_BELT_2_RIGHT,
3113 EL_CONVEYOR_BELT_3_LEFT,
3114 EL_CONVEYOR_BELT_3_MIDDLE,
3115 EL_CONVEYOR_BELT_3_RIGHT,
3116 EL_CONVEYOR_BELT_4_LEFT,
3117 EL_CONVEYOR_BELT_4_MIDDLE,
3118 EL_CONVEYOR_BELT_4_RIGHT,
3123 static int ep_belt_active[] =
3125 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3126 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3127 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3128 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3129 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3130 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3131 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3132 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3133 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3134 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3135 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3136 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3141 static int ep_belt_switch[] =
3143 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3144 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3145 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3146 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3147 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3148 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3149 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3150 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3151 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3152 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3153 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3154 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3159 static int ep_tube[] =
3166 EL_TUBE_HORIZONTAL_UP,
3167 EL_TUBE_HORIZONTAL_DOWN,
3169 EL_TUBE_VERTICAL_LEFT,
3170 EL_TUBE_VERTICAL_RIGHT,
3176 static int ep_keygate[] =
3186 EL_GATE_1_GRAY_ACTIVE,
3187 EL_GATE_2_GRAY_ACTIVE,
3188 EL_GATE_3_GRAY_ACTIVE,
3189 EL_GATE_4_GRAY_ACTIVE,
3198 EL_EM_GATE_1_GRAY_ACTIVE,
3199 EL_EM_GATE_2_GRAY_ACTIVE,
3200 EL_EM_GATE_3_GRAY_ACTIVE,
3201 EL_EM_GATE_4_GRAY_ACTIVE,
3210 EL_EMC_GATE_5_GRAY_ACTIVE,
3211 EL_EMC_GATE_6_GRAY_ACTIVE,
3212 EL_EMC_GATE_7_GRAY_ACTIVE,
3213 EL_EMC_GATE_8_GRAY_ACTIVE,
3218 static int ep_amoeboid[] =
3230 static int ep_amoebalive[] =
3241 static int ep_has_editor_content[] =
3259 static int ep_can_turn_each_move[] =
3261 /* !!! do something with this one !!! */
3265 static int ep_can_grow[] =
3279 static int ep_active_bomb[] =
3282 EL_EM_DYNAMITE_ACTIVE,
3283 EL_DYNABOMB_PLAYER_1_ACTIVE,
3284 EL_DYNABOMB_PLAYER_2_ACTIVE,
3285 EL_DYNABOMB_PLAYER_3_ACTIVE,
3286 EL_DYNABOMB_PLAYER_4_ACTIVE,
3287 EL_SP_DISK_RED_ACTIVE,
3292 static int ep_inactive[] =
3324 EL_GATE_1_GRAY_ACTIVE,
3325 EL_GATE_2_GRAY_ACTIVE,
3326 EL_GATE_3_GRAY_ACTIVE,
3327 EL_GATE_4_GRAY_ACTIVE,
3336 EL_EM_GATE_1_GRAY_ACTIVE,
3337 EL_EM_GATE_2_GRAY_ACTIVE,
3338 EL_EM_GATE_3_GRAY_ACTIVE,
3339 EL_EM_GATE_4_GRAY_ACTIVE,
3348 EL_EMC_GATE_5_GRAY_ACTIVE,
3349 EL_EMC_GATE_6_GRAY_ACTIVE,
3350 EL_EMC_GATE_7_GRAY_ACTIVE,
3351 EL_EMC_GATE_8_GRAY_ACTIVE,
3354 EL_INVISIBLE_STEELWALL,
3362 EL_WALL_EMERALD_YELLOW,
3363 EL_DYNABOMB_INCREASE_NUMBER,
3364 EL_DYNABOMB_INCREASE_SIZE,
3365 EL_DYNABOMB_INCREASE_POWER,
3369 EL_SOKOBAN_FIELD_EMPTY,
3370 EL_SOKOBAN_FIELD_FULL,
3371 EL_WALL_EMERALD_RED,
3372 EL_WALL_EMERALD_PURPLE,
3373 EL_ACID_POOL_TOPLEFT,
3374 EL_ACID_POOL_TOPRIGHT,
3375 EL_ACID_POOL_BOTTOMLEFT,
3376 EL_ACID_POOL_BOTTOM,
3377 EL_ACID_POOL_BOTTOMRIGHT,
3381 EL_BD_MAGIC_WALL_DEAD,
3382 EL_AMOEBA_TO_DIAMOND,
3390 EL_SP_GRAVITY_PORT_RIGHT,
3391 EL_SP_GRAVITY_PORT_DOWN,
3392 EL_SP_GRAVITY_PORT_LEFT,
3393 EL_SP_GRAVITY_PORT_UP,
3394 EL_SP_PORT_HORIZONTAL,
3395 EL_SP_PORT_VERTICAL,
3406 EL_SP_HARDWARE_GRAY,
3407 EL_SP_HARDWARE_GREEN,
3408 EL_SP_HARDWARE_BLUE,
3410 EL_SP_HARDWARE_YELLOW,
3411 EL_SP_HARDWARE_BASE_1,
3412 EL_SP_HARDWARE_BASE_2,
3413 EL_SP_HARDWARE_BASE_3,
3414 EL_SP_HARDWARE_BASE_4,
3415 EL_SP_HARDWARE_BASE_5,
3416 EL_SP_HARDWARE_BASE_6,
3417 EL_SP_GRAVITY_ON_PORT_LEFT,
3418 EL_SP_GRAVITY_ON_PORT_RIGHT,
3419 EL_SP_GRAVITY_ON_PORT_UP,
3420 EL_SP_GRAVITY_ON_PORT_DOWN,
3421 EL_SP_GRAVITY_OFF_PORT_LEFT,
3422 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3423 EL_SP_GRAVITY_OFF_PORT_UP,
3424 EL_SP_GRAVITY_OFF_PORT_DOWN,
3425 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3426 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3427 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3428 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3429 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3430 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3431 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3432 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3433 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3434 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3435 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3436 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3437 EL_SIGN_EXCLAMATION,
3438 EL_SIGN_RADIOACTIVITY,
3449 EL_STEELWALL_SLIPPERY,
3454 EL_EMC_WALL_SLIPPERY_1,
3455 EL_EMC_WALL_SLIPPERY_2,
3456 EL_EMC_WALL_SLIPPERY_3,
3457 EL_EMC_WALL_SLIPPERY_4,
3478 static int ep_em_slippery_wall[] =
3483 static int ep_gfx_crumbled[] =
3493 static int ep_editor_cascade_active[] =
3495 EL_INTERNAL_CASCADE_BD_ACTIVE,
3496 EL_INTERNAL_CASCADE_EM_ACTIVE,
3497 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3498 EL_INTERNAL_CASCADE_RND_ACTIVE,
3499 EL_INTERNAL_CASCADE_SB_ACTIVE,
3500 EL_INTERNAL_CASCADE_SP_ACTIVE,
3501 EL_INTERNAL_CASCADE_DC_ACTIVE,
3502 EL_INTERNAL_CASCADE_DX_ACTIVE,
3503 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3504 EL_INTERNAL_CASCADE_CE_ACTIVE,
3505 EL_INTERNAL_CASCADE_GE_ACTIVE,
3506 EL_INTERNAL_CASCADE_USER_ACTIVE,
3507 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3508 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3513 static int ep_editor_cascade_inactive[] =
3515 EL_INTERNAL_CASCADE_BD,
3516 EL_INTERNAL_CASCADE_EM,
3517 EL_INTERNAL_CASCADE_EMC,
3518 EL_INTERNAL_CASCADE_RND,
3519 EL_INTERNAL_CASCADE_SB,
3520 EL_INTERNAL_CASCADE_SP,
3521 EL_INTERNAL_CASCADE_DC,
3522 EL_INTERNAL_CASCADE_DX,
3523 EL_INTERNAL_CASCADE_CHARS,
3524 EL_INTERNAL_CASCADE_CE,
3525 EL_INTERNAL_CASCADE_GE,
3526 EL_INTERNAL_CASCADE_USER,
3527 EL_INTERNAL_CASCADE_GENERIC,
3528 EL_INTERNAL_CASCADE_DYNAMIC,
3537 } element_properties[] =
3539 { ep_diggable, EP_DIGGABLE },
3540 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3541 { ep_dont_run_into, EP_DONT_RUN_INTO },
3542 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3543 { ep_dont_touch, EP_DONT_TOUCH },
3544 { ep_indestructible, EP_INDESTRUCTIBLE },
3545 { ep_slippery, EP_SLIPPERY },
3546 { ep_can_change, EP_CAN_CHANGE },
3547 { ep_can_move, EP_CAN_MOVE },
3548 { ep_can_fall, EP_CAN_FALL },
3549 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3550 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3551 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3552 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3553 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3554 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3555 { ep_walkable_over, EP_WALKABLE_OVER },
3556 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3557 { ep_walkable_under, EP_WALKABLE_UNDER },
3558 { ep_passable_over, EP_PASSABLE_OVER },
3559 { ep_passable_inside, EP_PASSABLE_INSIDE },
3560 { ep_passable_under, EP_PASSABLE_UNDER },
3561 { ep_droppable, EP_DROPPABLE },
3562 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3563 { ep_pushable, EP_PUSHABLE },
3564 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3565 { ep_protected, EP_PROTECTED },
3566 { ep_throwable, EP_THROWABLE },
3567 { ep_can_explode, EP_CAN_EXPLODE },
3568 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3570 { ep_player, EP_PLAYER },
3571 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3572 { ep_switchable, EP_SWITCHABLE },
3573 { ep_bd_element, EP_BD_ELEMENT },
3574 { ep_sp_element, EP_SP_ELEMENT },
3575 { ep_sb_element, EP_SB_ELEMENT },
3577 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3578 { ep_food_penguin, EP_FOOD_PENGUIN },
3579 { ep_food_pig, EP_FOOD_PIG },
3580 { ep_historic_wall, EP_HISTORIC_WALL },
3581 { ep_historic_solid, EP_HISTORIC_SOLID },
3582 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3583 { ep_belt, EP_BELT },
3584 { ep_belt_active, EP_BELT_ACTIVE },
3585 { ep_belt_switch, EP_BELT_SWITCH },
3586 { ep_tube, EP_TUBE },
3587 { ep_keygate, EP_KEYGATE },
3588 { ep_amoeboid, EP_AMOEBOID },
3589 { ep_amoebalive, EP_AMOEBALIVE },
3590 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3591 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3592 { ep_can_grow, EP_CAN_GROW },
3593 { ep_active_bomb, EP_ACTIVE_BOMB },
3594 { ep_inactive, EP_INACTIVE },
3596 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3598 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3600 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3601 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3608 /* always start with reliable default values (element has no properties) */
3609 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3610 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3611 SET_PROPERTY(i, j, FALSE);
3613 /* set all base element properties from above array definitions */
3614 for (i = 0; element_properties[i].elements != NULL; i++)
3615 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3616 SET_PROPERTY((element_properties[i].elements)[j],
3617 element_properties[i].property, TRUE);
3619 /* copy properties to some elements that are only stored in level file */
3620 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3621 for (j = 0; copy_properties[j][0] != -1; j++)
3622 if (HAS_PROPERTY(copy_properties[j][0], i))
3623 for (k = 1; k <= 4; k++)
3624 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3627 void InitElementPropertiesEngine(int engine_version)
3629 static int no_wall_properties[] =
3632 EP_COLLECTIBLE_ONLY,
3634 EP_DONT_COLLIDE_WITH,
3637 EP_CAN_SMASH_PLAYER,
3638 EP_CAN_SMASH_ENEMIES,
3639 EP_CAN_SMASH_EVERYTHING,
3644 EP_FOOD_DARK_YAMYAM,
3660 /* important: after initialization in InitElementPropertiesStatic(), the
3661 elements are not again initialized to a default value; therefore all
3662 changes have to make sure that they leave the element with a defined
3663 property (which means that conditional property changes must be set to
3664 a reliable default value before) */
3667 /* ---------- recursively resolve group elements ------------------------- */
3669 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3670 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3671 element_info[i].in_group[j] = FALSE;
3673 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3674 resolve_group_element(EL_GROUP_START + i, 0);
3677 /* set all special, combined or engine dependent element properties */
3678 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3680 /* ---------- INACTIVE ------------------------------------------------- */
3681 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3683 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3684 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3685 IS_WALKABLE_INSIDE(i) ||
3686 IS_WALKABLE_UNDER(i)));
3688 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3689 IS_PASSABLE_INSIDE(i) ||
3690 IS_PASSABLE_UNDER(i)));
3692 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3693 IS_PASSABLE_OVER(i)));
3695 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3696 IS_PASSABLE_INSIDE(i)));
3698 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3699 IS_PASSABLE_UNDER(i)));
3701 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3704 /* ---------- COLLECTIBLE ---------------------------------------------- */
3705 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3709 /* ---------- SNAPPABLE ------------------------------------------------ */
3710 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3711 IS_COLLECTIBLE(i) ||
3715 /* ---------- WALL ----------------------------------------------------- */
3716 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3718 for (j = 0; no_wall_properties[j] != -1; j++)
3719 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3720 i >= EL_FIRST_RUNTIME_UNREAL)
3721 SET_PROPERTY(i, EP_WALL, FALSE);
3723 if (IS_HISTORIC_WALL(i))
3724 SET_PROPERTY(i, EP_WALL, TRUE);
3726 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3727 if (engine_version < VERSION_IDENT(2,2,0,0))
3728 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3730 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3732 !IS_COLLECTIBLE(i)));
3734 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3736 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3737 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3739 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3740 IS_INDESTRUCTIBLE(i)));
3742 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3744 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3745 else if (engine_version < VERSION_IDENT(2,2,0,0))
3746 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3748 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3752 if (IS_CUSTOM_ELEMENT(i))
3754 /* these are additional properties which are initially false when set */
3756 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3758 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3759 if (DONT_COLLIDE_WITH(i))
3760 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3762 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3763 if (CAN_SMASH_EVERYTHING(i))
3764 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3765 if (CAN_SMASH_ENEMIES(i))
3766 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3769 /* ---------- CAN_SMASH ------------------------------------------------ */
3770 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3771 CAN_SMASH_ENEMIES(i) ||
3772 CAN_SMASH_EVERYTHING(i)));
3774 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3775 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3776 EXPLODES_BY_FIRE(i)));
3778 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3779 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3780 EXPLODES_SMASHED(i)));
3782 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3783 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3784 EXPLODES_IMPACT(i)));
3786 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3787 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3789 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3790 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3791 i == EL_BLACK_ORB));
3793 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3794 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3796 IS_CUSTOM_ELEMENT(i)));
3798 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3799 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3800 i == EL_SP_ELECTRON));
3802 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3803 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3804 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3805 getMoveIntoAcidProperty(&level, i));
3807 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3808 if (MAYBE_DONT_COLLIDE_WITH(i))
3809 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3810 getDontCollideWithProperty(&level, i));
3812 /* ---------- SP_PORT -------------------------------------------------- */
3813 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3814 IS_PASSABLE_INSIDE(i)));
3816 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3817 for (j = 0; j < level.num_android_clone_elements; j++)
3818 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3820 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3822 /* ---------- CAN_CHANGE ----------------------------------------------- */
3823 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3824 for (j = 0; j < element_info[i].num_change_pages; j++)
3825 if (element_info[i].change_page[j].can_change)
3826 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3828 /* ---------- HAS_ACTION ----------------------------------------------- */
3829 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3830 for (j = 0; j < element_info[i].num_change_pages; j++)
3831 if (element_info[i].change_page[j].has_action)
3832 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3834 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3835 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3838 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3840 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3841 element_info[i].crumbled[ACTION_DEFAULT] !=
3842 element_info[i].graphic[ACTION_DEFAULT]);
3844 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3845 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3846 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3849 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3850 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3851 IS_EDITOR_CASCADE_INACTIVE(i)));
3854 /* dynamically adjust element properties according to game engine version */
3856 static int ep_em_slippery_wall[] =
3861 EL_EXPANDABLE_WALL_HORIZONTAL,
3862 EL_EXPANDABLE_WALL_VERTICAL,
3863 EL_EXPANDABLE_WALL_ANY,
3867 /* special EM style gems behaviour */
3868 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3869 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3870 level.em_slippery_gems);
3872 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3873 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3874 (level.em_slippery_gems &&
3875 engine_version > VERSION_IDENT(2,0,1,0)));
3878 /* set default push delay values (corrected since version 3.0.7-1) */
3879 if (engine_version < VERSION_IDENT(3,0,7,1))
3881 game.default_push_delay_fixed = 2;
3882 game.default_push_delay_random = 8;
3886 game.default_push_delay_fixed = 8;
3887 game.default_push_delay_random = 8;
3890 /* set uninitialized push delay values of custom elements in older levels */
3891 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3893 int element = EL_CUSTOM_START + i;
3895 if (element_info[element].push_delay_fixed == -1)
3896 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3897 if (element_info[element].push_delay_random == -1)
3898 element_info[element].push_delay_random = game.default_push_delay_random;
3901 /* set some other uninitialized values of custom elements in older levels */
3902 if (engine_version < VERSION_IDENT(3,1,0,0))
3904 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3906 int element = EL_CUSTOM_START + i;
3908 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3910 element_info[element].explosion_delay = 17;
3911 element_info[element].ignition_delay = 8;
3916 /* set element properties that were handled incorrectly in older levels */
3917 if (engine_version < VERSION_IDENT(3,1,0,0))
3919 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3920 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3924 /* this is needed because some graphics depend on element properties */
3925 if (game_status == GAME_MODE_PLAYING)
3926 InitElementGraphicInfo();
3929 static void InitGlobal()
3933 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3935 /* check if element_name_info entry defined for each element in "main.h" */
3936 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3937 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3939 element_info[i].token_name = element_name_info[i].token_name;
3940 element_info[i].class_name = element_name_info[i].class_name;
3941 element_info[i].editor_description=element_name_info[i].editor_description;
3944 global.autoplay_leveldir = NULL;
3945 global.convert_leveldir = NULL;
3947 global.frames_per_second = 0;
3948 global.fps_slowdown = FALSE;
3949 global.fps_slowdown_factor = 1;
3952 void Execute_Command(char *command)
3956 if (strcmp(command, "print graphicsinfo.conf") == 0)
3958 printf("# You can configure additional/alternative image files here.\n");
3959 printf("# (The entries below are default and therefore commented out.)\n");
3961 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3963 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3966 for (i = 0; image_config[i].token != NULL; i++)
3967 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3968 image_config[i].value));
3972 else if (strcmp(command, "print soundsinfo.conf") == 0)
3974 printf("# You can configure additional/alternative sound files here.\n");
3975 printf("# (The entries below are default and therefore commented out.)\n");
3977 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3979 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3982 for (i = 0; sound_config[i].token != NULL; i++)
3983 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3984 sound_config[i].value));
3988 else if (strcmp(command, "print musicinfo.conf") == 0)
3990 printf("# You can configure additional/alternative music files here.\n");
3991 printf("# (The entries below are default and therefore commented out.)\n");
3993 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3995 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3998 for (i = 0; music_config[i].token != NULL; i++)
3999 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4000 music_config[i].value));
4004 else if (strcmp(command, "print editorsetup.conf") == 0)
4006 printf("# You can configure your personal editor element list here.\n");
4007 printf("# (The entries below are default and therefore commented out.)\n");
4010 /* this is needed to be able to check element list for cascade elements */
4011 InitElementPropertiesStatic();
4012 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4014 PrintEditorElementList();
4018 else if (strcmp(command, "print helpanim.conf") == 0)
4020 printf("# You can configure different element help animations here.\n");
4021 printf("# (The entries below are default and therefore commented out.)\n");
4024 for (i = 0; helpanim_config[i].token != NULL; i++)
4026 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4027 helpanim_config[i].value));
4029 if (strcmp(helpanim_config[i].token, "end") == 0)
4035 else if (strcmp(command, "print helptext.conf") == 0)
4037 printf("# You can configure different element help text here.\n");
4038 printf("# (The entries below are default and therefore commented out.)\n");
4041 for (i = 0; helptext_config[i].token != NULL; i++)
4042 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4043 helptext_config[i].value));
4047 else if (strncmp(command, "dump level ", 11) == 0)
4049 char *filename = &command[11];
4051 if (!fileExists(filename))
4052 Error(ERR_EXIT, "cannot open file '%s'", filename);
4054 LoadLevelFromFilename(&level, filename);
4059 else if (strncmp(command, "dump tape ", 10) == 0)
4061 char *filename = &command[10];
4063 if (!fileExists(filename))
4064 Error(ERR_EXIT, "cannot open file '%s'", filename);
4066 LoadTapeFromFilename(filename);
4071 else if (strncmp(command, "autoplay ", 9) == 0)
4073 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4075 while (*str_ptr != '\0') /* continue parsing string */
4077 /* cut leading whitespace from string, replace it by string terminator */
4078 while (*str_ptr == ' ' || *str_ptr == '\t')
4081 if (*str_ptr == '\0') /* end of string reached */
4084 if (global.autoplay_leveldir == NULL) /* read level set string */
4086 global.autoplay_leveldir = str_ptr;
4087 global.autoplay_all = TRUE; /* default: play all tapes */
4089 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4090 global.autoplay_level[i] = FALSE;
4092 else /* read level number string */
4094 int level_nr = atoi(str_ptr); /* get level_nr value */
4096 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4097 global.autoplay_level[level_nr] = TRUE;
4099 global.autoplay_all = FALSE;
4102 /* advance string pointer to the next whitespace (or end of string) */
4103 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4107 else if (strncmp(command, "convert ", 8) == 0)
4109 char *str_copy = getStringCopy(&command[8]);
4110 char *str_ptr = strchr(str_copy, ' ');
4112 global.convert_leveldir = str_copy;
4113 global.convert_level_nr = -1;
4115 if (str_ptr != NULL) /* level number follows */
4117 *str_ptr++ = '\0'; /* terminate leveldir string */
4118 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4123 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4127 static void InitSetup()
4129 LoadSetup(); /* global setup info */
4131 /* set some options from setup file */
4133 if (setup.options.verbose)
4134 options.verbose = TRUE;
4137 static void InitGameInfo()
4139 game.restart_level = FALSE;
4142 static void InitPlayerInfo()
4146 /* choose default local player */
4147 local_player = &stored_player[0];
4149 for (i = 0; i < MAX_PLAYERS; i++)
4150 stored_player[i].connected = FALSE;
4152 local_player->connected = TRUE;
4155 static void InitArtworkInfo()
4160 static char *get_string_in_brackets(char *string)
4162 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4164 sprintf(string_in_brackets, "[%s]", string);
4166 return string_in_brackets;
4169 static char *get_level_id_suffix(int id_nr)
4171 char *id_suffix = checked_malloc(1 + 3 + 1);
4173 if (id_nr < 0 || id_nr > 999)
4176 sprintf(id_suffix, ".%03d", id_nr);
4182 static char *get_element_class_token(int element)
4184 char *element_class_name = element_info[element].class_name;
4185 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4187 sprintf(element_class_token, "[%s]", element_class_name);
4189 return element_class_token;
4192 static char *get_action_class_token(int action)
4194 char *action_class_name = &element_action_info[action].suffix[1];
4195 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4197 sprintf(action_class_token, "[%s]", action_class_name);
4199 return action_class_token;
4203 static void InitArtworkConfig()
4205 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4206 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4207 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4208 static char *action_id_suffix[NUM_ACTIONS + 1];
4209 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4210 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4211 static char *level_id_suffix[MAX_LEVELS + 1];
4212 static char *dummy[1] = { NULL };
4213 static char *ignore_generic_tokens[] =
4219 static char **ignore_image_tokens;
4220 static char **ignore_sound_tokens;
4221 static char **ignore_music_tokens;
4222 int num_ignore_generic_tokens;
4223 int num_ignore_image_tokens;
4224 int num_ignore_sound_tokens;
4225 int num_ignore_music_tokens;
4228 /* dynamically determine list of generic tokens to be ignored */
4229 num_ignore_generic_tokens = 0;
4230 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4231 num_ignore_generic_tokens++;
4233 /* dynamically determine list of image tokens to be ignored */
4234 num_ignore_image_tokens = num_ignore_generic_tokens;
4235 for (i = 0; image_config_vars[i].token != NULL; i++)
4236 num_ignore_image_tokens++;
4237 ignore_image_tokens =
4238 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4239 for (i = 0; i < num_ignore_generic_tokens; i++)
4240 ignore_image_tokens[i] = ignore_generic_tokens[i];
4241 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4242 ignore_image_tokens[num_ignore_generic_tokens + i] =
4243 image_config_vars[i].token;
4244 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4246 /* dynamically determine list of sound tokens to be ignored */
4247 num_ignore_sound_tokens = num_ignore_generic_tokens;
4248 ignore_sound_tokens =
4249 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4250 for (i = 0; i < num_ignore_generic_tokens; i++)
4251 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4252 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4254 /* dynamically determine list of music tokens to be ignored */
4255 num_ignore_music_tokens = num_ignore_generic_tokens;
4256 ignore_music_tokens =
4257 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4258 for (i = 0; i < num_ignore_generic_tokens; i++)
4259 ignore_music_tokens[i] = ignore_generic_tokens[i];
4260 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4262 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4263 image_id_prefix[i] = element_info[i].token_name;
4264 for (i = 0; i < NUM_FONTS; i++)
4265 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4266 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4268 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4269 sound_id_prefix[i] = element_info[i].token_name;
4270 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4271 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4272 get_string_in_brackets(element_info[i].class_name);
4273 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4275 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4276 music_id_prefix[i] = music_prefix_info[i].prefix;
4277 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4279 for (i = 0; i < NUM_ACTIONS; i++)
4280 action_id_suffix[i] = element_action_info[i].suffix;
4281 action_id_suffix[NUM_ACTIONS] = NULL;
4283 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4284 direction_id_suffix[i] = element_direction_info[i].suffix;
4285 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4287 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4288 special_id_suffix[i] = special_suffix_info[i].suffix;
4289 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4291 for (i = 0; i < MAX_LEVELS; i++)
4292 level_id_suffix[i] = get_level_id_suffix(i);
4293 level_id_suffix[MAX_LEVELS] = NULL;
4295 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4296 image_id_prefix, action_id_suffix, direction_id_suffix,
4297 special_id_suffix, ignore_image_tokens);
4298 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4299 sound_id_prefix, action_id_suffix, dummy,
4300 special_id_suffix, ignore_sound_tokens);
4301 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4302 music_id_prefix, special_id_suffix, level_id_suffix,
4303 dummy, ignore_music_tokens);
4306 static void InitMixer()
4314 char *filename_font_initial = NULL;
4315 Bitmap *bitmap_font_initial = NULL;
4318 /* determine settings for initial font (for displaying startup messages) */
4319 for (i = 0; image_config[i].token != NULL; i++)
4321 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4323 char font_token[128];
4326 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4327 len_font_token = strlen(font_token);
4329 if (strcmp(image_config[i].token, font_token) == 0)
4330 filename_font_initial = image_config[i].value;
4331 else if (strlen(image_config[i].token) > len_font_token &&
4332 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4334 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4335 font_initial[j].src_x = atoi(image_config[i].value);
4336 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4337 font_initial[j].src_y = atoi(image_config[i].value);
4338 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4339 font_initial[j].width = atoi(image_config[i].value);
4340 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4341 font_initial[j].height = atoi(image_config[i].value);
4346 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4348 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4349 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4352 if (filename_font_initial == NULL) /* should not happen */
4353 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4355 /* create additional image buffers for double-buffering */
4356 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4357 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4359 /* initialize screen properties */
4360 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4361 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4363 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4364 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4365 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4367 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4369 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4370 font_initial[j].bitmap = bitmap_font_initial;
4372 InitFontGraphicInfo();
4374 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4375 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4377 DrawInitText("Loading graphics:", 120, FC_GREEN);
4380 void InitGfxBackground()
4384 drawto = backbuffer;
4385 fieldbuffer = bitmap_db_field;
4386 SetDrawtoField(DRAW_BACKBUFFER);
4388 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4389 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4390 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4391 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4393 for (x = 0; x < MAX_BUF_XSIZE; x++)
4394 for (y = 0; y < MAX_BUF_YSIZE; y++)
4397 redraw_mask = REDRAW_ALL;
4400 static void InitLevelInfo()
4402 LoadLevelInfo(); /* global level info */
4403 LoadLevelSetup_LastSeries(); /* last played series info */
4404 LoadLevelSetup_SeriesInfo(); /* last played level info */
4407 void InitLevelArtworkInfo()
4409 LoadLevelArtworkInfo();
4412 static void InitImages()
4414 setLevelArtworkDir(artwork.gfx_first);
4417 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4418 leveldir_current->identifier,
4419 artwork.gfx_current_identifier,
4420 artwork.gfx_current->identifier,
4421 leveldir_current->graphics_set,
4422 leveldir_current->graphics_path);
4425 ReloadCustomImages();
4427 LoadCustomElementDescriptions();
4428 LoadSpecialMenuDesignSettings();
4430 ReinitializeGraphics();
4433 static void InitSound(char *identifier)
4435 if (identifier == NULL)
4436 identifier = artwork.snd_current->identifier;
4438 /* set artwork path to send it to the sound server process */
4439 setLevelArtworkDir(artwork.snd_first);
4441 InitReloadCustomSounds(identifier);
4442 ReinitializeSounds();
4445 static void InitMusic(char *identifier)
4447 if (identifier == NULL)
4448 identifier = artwork.mus_current->identifier;
4450 /* set artwork path to send it to the sound server process */
4451 setLevelArtworkDir(artwork.mus_first);
4453 InitReloadCustomMusic(identifier);
4454 ReinitializeMusic();
4457 void InitNetworkServer()
4459 #if defined(NETWORK_AVALIABLE)
4463 if (!options.network)
4466 #if defined(NETWORK_AVALIABLE)
4467 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4469 if (!ConnectToServer(options.server_host, options.server_port))
4470 Error(ERR_EXIT, "cannot connect to network game server");
4472 SendToServer_PlayerName(setup.player_name);
4473 SendToServer_ProtocolVersion();
4476 SendToServer_NrWanted(nr_wanted);
4480 static char *getNewArtworkIdentifier(int type)
4482 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4483 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4484 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4485 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4486 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4487 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4488 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4489 char *leveldir_identifier = leveldir_current->identifier;
4491 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4492 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4494 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4496 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4497 char *artwork_current_identifier;
4498 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4500 /* leveldir_current may be invalid (level group, parent link) */
4501 if (!validLevelSeries(leveldir_current))
4504 /* 1st step: determine artwork set to be activated in descending order:
4505 --------------------------------------------------------------------
4506 1. setup artwork (when configured to override everything else)
4507 2. artwork set configured in "levelinfo.conf" of current level set
4508 (artwork in level directory will have priority when loading later)
4509 3. artwork in level directory (stored in artwork sub-directory)
4510 4. setup artwork (currently configured in setup menu) */
4512 if (setup_override_artwork)
4513 artwork_current_identifier = setup_artwork_set;
4514 else if (leveldir_artwork_set != NULL)
4515 artwork_current_identifier = leveldir_artwork_set;
4516 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4517 artwork_current_identifier = leveldir_identifier;
4519 artwork_current_identifier = setup_artwork_set;
4522 /* 2nd step: check if it is really needed to reload artwork set
4523 ------------------------------------------------------------ */
4526 if (type == ARTWORK_TYPE_GRAPHICS)
4527 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4528 artwork_new_identifier,
4529 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4530 artwork_current_identifier,
4531 leveldir_current->graphics_set,
4532 leveldir_current->identifier);
4535 /* ---------- reload if level set and also artwork set has changed ------- */
4536 if (leveldir_current_identifier[type] != leveldir_identifier &&
4537 (last_has_level_artwork_set[type] || has_level_artwork_set))
4538 artwork_new_identifier = artwork_current_identifier;
4540 leveldir_current_identifier[type] = leveldir_identifier;
4541 last_has_level_artwork_set[type] = has_level_artwork_set;
4544 if (type == ARTWORK_TYPE_GRAPHICS)
4545 printf("::: 1: '%s'\n", artwork_new_identifier);
4548 /* ---------- reload if "override artwork" setting has changed ----------- */
4549 if (last_override_level_artwork[type] != setup_override_artwork)
4550 artwork_new_identifier = artwork_current_identifier;
4552 last_override_level_artwork[type] = setup_override_artwork;
4555 if (type == ARTWORK_TYPE_GRAPHICS)
4556 printf("::: 2: '%s'\n", artwork_new_identifier);
4559 /* ---------- reload if current artwork identifier has changed ----------- */
4560 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4561 artwork_current_identifier) != 0)
4562 artwork_new_identifier = artwork_current_identifier;
4564 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4567 if (type == ARTWORK_TYPE_GRAPHICS)
4568 printf("::: 3: '%s'\n", artwork_new_identifier);
4571 /* ---------- do not reload directly after starting ---------------------- */
4572 if (!initialized[type])
4573 artwork_new_identifier = NULL;
4575 initialized[type] = TRUE;
4578 if (type == ARTWORK_TYPE_GRAPHICS)
4579 printf("::: 4: '%s'\n", artwork_new_identifier);
4583 if (type == ARTWORK_TYPE_GRAPHICS)
4584 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4585 artwork.gfx_current_identifier, artwork_current_identifier,
4586 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4587 artwork_new_identifier);
4590 return artwork_new_identifier;
4593 void ReloadCustomArtwork(int force_reload)
4595 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4596 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4597 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4598 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4599 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4600 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4601 boolean redraw_screen = FALSE;
4603 if (gfx_new_identifier != NULL || force_reload_gfx)
4606 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4607 artwork.gfx_current_identifier,
4609 artwork.gfx_current->identifier,
4610 leveldir_current->graphics_set);
4613 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4617 redraw_screen = TRUE;
4620 if (snd_new_identifier != NULL || force_reload_snd)
4622 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4624 InitSound(snd_new_identifier);
4626 redraw_screen = TRUE;
4629 if (mus_new_identifier != NULL || force_reload_mus)
4631 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4633 InitMusic(mus_new_identifier);
4635 redraw_screen = TRUE;
4640 InitGfxBackground();
4642 /* force redraw of (open or closed) door graphics */
4643 SetDoorState(DOOR_OPEN_ALL);
4644 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4648 void KeyboardAutoRepeatOffUnlessAutoplay()
4650 if (global.autoplay_leveldir == NULL)
4651 KeyboardAutoRepeatOff();
4655 /* ========================================================================= */
4657 /* ========================================================================= */
4661 InitGlobal(); /* initialize some global variables */
4663 if (options.execute_command)
4664 Execute_Command(options.execute_command);
4666 if (options.serveronly)
4668 #if defined(PLATFORM_UNIX)
4669 NetworkServer(options.server_port, options.serveronly);
4671 Error(ERR_WARN, "networking only supported in Unix version");
4674 exit(0); /* never reached, server loops forever */
4681 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4682 InitArtworkConfig(); /* needed before forking sound child process */
4687 InitRND(NEW_RANDOMIZE);
4688 InitSimpleRND(NEW_RANDOMIZE);
4693 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4696 InitEventFilter(FilterMouseMotionEvents);
4698 InitElementPropertiesStatic();
4699 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4704 InitLevelArtworkInfo();
4706 InitImages(); /* needs to know current level directory */
4707 InitSound(NULL); /* needs to know current level directory */
4708 InitMusic(NULL); /* needs to know current level directory */
4710 InitGfxBackground();
4712 if (global.autoplay_leveldir)
4717 else if (global.convert_leveldir)
4723 game_status = GAME_MODE_MAIN;
4731 InitNetworkServer();
4734 void CloseAllAndExit(int exit_value)
4739 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4747 #if defined(TARGET_SDL)
4748 if (network_server) /* terminate network server */
4749 SDL_KillThread(server_thread);
4752 CloseVideoDisplay();
4753 ClosePlatformDependentStuff();