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_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 gadgets_initialized = TRUE;
110 inline void InitElementSmallImagesScaledUp(int graphic)
112 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
115 void InitElementSmallImages()
117 static int special_graphics[] =
119 IMG_EDITOR_ELEMENT_BORDER,
120 IMG_EDITOR_ELEMENT_BORDER_INPUT,
121 IMG_EDITOR_CASCADE_LIST,
122 IMG_EDITOR_CASCADE_LIST_ACTIVE,
125 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126 int num_property_mappings = getImageListPropertyMappingSize();
129 /* initialize normal images from static configuration */
130 for (i = 0; element_to_graphic[i].element > -1; i++)
131 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
133 /* initialize special images from static configuration */
134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
135 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
137 /* initialize images from dynamic configuration (may be elements or other) */
138 for (i = 0; i < num_property_mappings; i++)
139 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
141 /* initialize special images from above list (non-element images) */
142 for (i = 0; special_graphics[i] > -1; i++)
143 InitElementSmallImagesScaledUp(special_graphics[i]);
147 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
148 void SetBitmaps_EM(Bitmap **em_bitmap)
150 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
151 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
155 static int getFontBitmapID(int font_nr)
159 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
160 special = game_status;
161 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
162 special = GFX_SPECIAL_ARG_MAIN;
163 else if (game_status == GAME_MODE_PLAYING)
164 special = GFX_SPECIAL_ARG_DOOR;
167 return font_info[font_nr].special_bitmap_id[special];
172 void InitFontGraphicInfo()
174 static struct FontBitmapInfo *font_bitmap_info = NULL;
175 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
176 int num_property_mappings = getImageListPropertyMappingSize();
177 int num_font_bitmaps = NUM_FONTS;
180 if (graphic_info == NULL) /* still at startup phase */
182 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
187 /* ---------- initialize font graphic definitions ---------- */
189 /* always start with reliable default values (normal font graphics) */
190 for (i = 0; i < NUM_FONTS; i++)
191 font_info[i].graphic = IMG_FONT_INITIAL_1;
193 /* initialize normal font/graphic mapping from static configuration */
194 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
196 int font_nr = font_to_graphic[i].font_nr;
197 int special = font_to_graphic[i].special;
198 int graphic = font_to_graphic[i].graphic;
203 font_info[font_nr].graphic = graphic;
206 /* always start with reliable default values (special font graphics) */
207 for (i = 0; i < NUM_FONTS; i++)
209 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
211 font_info[i].special_graphic[j] = font_info[i].graphic;
212 font_info[i].special_bitmap_id[j] = i;
216 /* initialize special font/graphic mapping from static configuration */
217 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
219 int font_nr = font_to_graphic[i].font_nr;
220 int special = font_to_graphic[i].special;
221 int graphic = font_to_graphic[i].graphic;
222 int base_graphic = font2baseimg(font_nr);
224 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
226 boolean base_redefined =
227 getImageListEntryFromImageID(base_graphic)->redefined;
228 boolean special_redefined =
229 getImageListEntryFromImageID(graphic)->redefined;
231 /* if the base font ("font.title_1", for example) has been redefined,
232 but not the special font ("font.title_1.LEVELS", for example), do not
233 use an existing (in this case considered obsolete) special font
234 anymore, but use the automatically determined default font */
235 if (base_redefined && !special_redefined)
238 font_info[font_nr].special_graphic[special] = graphic;
239 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
244 /* initialize special element/graphic mapping from dynamic configuration */
245 for (i = 0; i < num_property_mappings; i++)
247 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
248 int special = property_mapping[i].ext3_index;
249 int graphic = property_mapping[i].artwork_index;
254 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
256 font_info[font_nr].special_graphic[special] = graphic;
257 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
262 /* ---------- initialize font bitmap array ---------- */
264 if (font_bitmap_info != NULL)
265 FreeFontInfo(font_bitmap_info);
268 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
270 /* ---------- initialize font bitmap definitions ---------- */
272 for (i = 0; i < NUM_FONTS; i++)
274 if (i < NUM_INITIAL_FONTS)
276 font_bitmap_info[i] = font_initial[i];
280 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
282 int font_bitmap_id = font_info[i].special_bitmap_id[j];
283 int graphic = font_info[i].special_graphic[j];
285 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
286 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
288 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
289 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
292 /* copy font relevant information from graphics information */
293 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
294 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
295 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
296 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
297 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
298 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
299 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
301 font_bitmap_info[font_bitmap_id].num_chars =
302 graphic_info[graphic].anim_frames;
303 font_bitmap_info[font_bitmap_id].num_chars_per_line =
304 graphic_info[graphic].anim_frames_per_line;
308 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
311 void InitElementGraphicInfo()
313 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
314 int num_property_mappings = getImageListPropertyMappingSize();
317 if (graphic_info == NULL) /* still at startup phase */
320 /* set values to -1 to identify later as "uninitialized" values */
321 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
323 for (act = 0; act < NUM_ACTIONS; act++)
325 element_info[i].graphic[act] = -1;
326 element_info[i].crumbled[act] = -1;
328 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
330 element_info[i].direction_graphic[act][dir] = -1;
331 element_info[i].direction_crumbled[act][dir] = -1;
336 /* initialize normal element/graphic mapping from static configuration */
337 for (i = 0; element_to_graphic[i].element > -1; i++)
339 int element = element_to_graphic[i].element;
340 int action = element_to_graphic[i].action;
341 int direction = element_to_graphic[i].direction;
342 boolean crumbled = element_to_graphic[i].crumbled;
343 int graphic = element_to_graphic[i].graphic;
344 int base_graphic = el2baseimg(element);
346 if (graphic_info[graphic].bitmap == NULL)
349 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
352 boolean base_redefined =
353 getImageListEntryFromImageID(base_graphic)->redefined;
354 boolean act_dir_redefined =
355 getImageListEntryFromImageID(graphic)->redefined;
357 /* if the base graphic ("emerald", for example) has been redefined,
358 but not the action graphic ("emerald.falling", for example), do not
359 use an existing (in this case considered obsolete) action graphic
360 anymore, but use the automatically determined default graphic */
361 if (base_redefined && !act_dir_redefined)
366 action = ACTION_DEFAULT;
371 element_info[element].direction_crumbled[action][direction] = graphic;
373 element_info[element].crumbled[action] = graphic;
378 element_info[element].direction_graphic[action][direction] = graphic;
380 element_info[element].graphic[action] = graphic;
384 /* initialize normal element/graphic mapping from dynamic configuration */
385 for (i = 0; i < num_property_mappings; i++)
387 int element = property_mapping[i].base_index;
388 int action = property_mapping[i].ext1_index;
389 int direction = property_mapping[i].ext2_index;
390 int special = property_mapping[i].ext3_index;
391 int graphic = property_mapping[i].artwork_index;
392 boolean crumbled = FALSE;
394 if (special == GFX_SPECIAL_ARG_CRUMBLED)
400 if (graphic_info[graphic].bitmap == NULL)
403 if (element >= MAX_NUM_ELEMENTS || special != -1)
407 action = ACTION_DEFAULT;
412 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
413 element_info[element].direction_crumbled[action][dir] = -1;
416 element_info[element].direction_crumbled[action][direction] = graphic;
418 element_info[element].crumbled[action] = graphic;
423 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
424 element_info[element].direction_graphic[action][dir] = -1;
427 element_info[element].direction_graphic[action][direction] = graphic;
429 element_info[element].graphic[action] = graphic;
433 /* now copy all graphics that are defined to be cloned from other graphics */
434 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
436 int graphic = element_info[i].graphic[ACTION_DEFAULT];
437 int crumbled_like, diggable_like;
442 crumbled_like = graphic_info[graphic].crumbled_like;
443 diggable_like = graphic_info[graphic].diggable_like;
445 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
447 for (act = 0; act < NUM_ACTIONS; act++)
448 element_info[i].crumbled[act] =
449 element_info[crumbled_like].crumbled[act];
450 for (act = 0; act < NUM_ACTIONS; act++)
451 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
452 element_info[i].direction_crumbled[act][dir] =
453 element_info[crumbled_like].direction_crumbled[act][dir];
456 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
458 element_info[i].graphic[ACTION_DIGGING] =
459 element_info[diggable_like].graphic[ACTION_DIGGING];
460 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
461 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
462 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
467 /* set hardcoded definitions for some runtime elements without graphic */
468 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
472 /* set hardcoded definitions for some internal elements without graphic */
473 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
475 if (IS_EDITOR_CASCADE_INACTIVE(i))
476 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
477 else if (IS_EDITOR_CASCADE_ACTIVE(i))
478 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
482 /* now set all undefined/invalid graphics to -1 to set to default after it */
483 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
485 for (act = 0; act < NUM_ACTIONS; act++)
489 graphic = element_info[i].graphic[act];
490 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
491 element_info[i].graphic[act] = -1;
493 graphic = element_info[i].crumbled[act];
494 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
495 element_info[i].crumbled[act] = -1;
497 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
499 graphic = element_info[i].direction_graphic[act][dir];
500 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
501 element_info[i].direction_graphic[act][dir] = -1;
503 graphic = element_info[i].direction_crumbled[act][dir];
504 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
505 element_info[i].direction_crumbled[act][dir] = -1;
510 /* adjust graphics with 2nd tile for movement according to direction
511 (do this before correcting '-1' values to minimize calculations) */
512 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
514 for (act = 0; act < NUM_ACTIONS; act++)
516 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
518 int graphic = element_info[i].direction_graphic[act][dir];
519 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
521 if (act == ACTION_FALLING) /* special case */
522 graphic = element_info[i].graphic[act];
525 graphic_info[graphic].double_movement &&
526 graphic_info[graphic].swap_double_tiles != 0)
528 struct GraphicInfo *g = &graphic_info[graphic];
529 int src_x_front = g->src_x;
530 int src_y_front = g->src_y;
531 int src_x_back = g->src_x + g->offset2_x;
532 int src_y_back = g->src_y + g->offset2_y;
533 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
535 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
536 src_y_front < src_y_back);
537 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
538 boolean swap_movement_tiles_autodetected =
539 (!frames_are_ordered_diagonally &&
540 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
541 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
542 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
543 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
546 /* swap frontside and backside graphic tile coordinates, if needed */
547 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
549 /* get current (wrong) backside tile coordinates */
550 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
553 /* set frontside tile coordinates to backside tile coordinates */
554 g->src_x = src_x_back;
555 g->src_y = src_y_back;
557 /* invert tile offset to point to new backside tile coordinates */
561 /* do not swap front and backside tiles again after correction */
562 g->swap_double_tiles = 0;
569 /* now set all '-1' values to element specific default values */
570 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
572 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
573 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
574 int default_direction_graphic[NUM_DIRECTIONS_FULL];
575 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
577 if (default_graphic == -1)
578 default_graphic = IMG_UNKNOWN;
580 if (default_crumbled == -1)
581 default_crumbled = default_graphic;
583 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
584 if (default_crumbled == -1)
585 default_crumbled = IMG_EMPTY;
588 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
590 default_direction_graphic[dir] =
591 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
592 default_direction_crumbled[dir] =
593 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
595 if (default_direction_graphic[dir] == -1)
596 default_direction_graphic[dir] = default_graphic;
598 if (default_direction_crumbled[dir] == -1)
599 default_direction_crumbled[dir] = default_direction_graphic[dir];
601 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
602 if (default_direction_crumbled[dir] == -1)
603 default_direction_crumbled[dir] = default_crumbled;
607 for (act = 0; act < NUM_ACTIONS; act++)
609 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
610 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
611 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
612 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
613 act == ACTION_TURNING_FROM_RIGHT ||
614 act == ACTION_TURNING_FROM_UP ||
615 act == ACTION_TURNING_FROM_DOWN);
617 /* generic default action graphic (defined by "[default]" directive) */
618 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
619 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
620 int default_remove_graphic = IMG_EMPTY;
622 if (act_remove && default_action_graphic != -1)
623 default_remove_graphic = default_action_graphic;
625 /* look for special default action graphic (classic game specific) */
626 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
627 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
628 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
629 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
630 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
631 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
633 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
634 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
635 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
636 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
637 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
638 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
641 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
642 /* !!! make this better !!! */
643 if (i == EL_EMPTY_SPACE)
645 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
646 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
650 if (default_action_graphic == -1)
651 default_action_graphic = default_graphic;
653 if (default_action_crumbled == -1)
654 default_action_crumbled = default_action_graphic;
656 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
657 if (default_action_crumbled == -1)
658 default_action_crumbled = default_crumbled;
661 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
663 /* use action graphic as the default direction graphic, if undefined */
664 int default_action_direction_graphic = element_info[i].graphic[act];
665 int default_action_direction_crumbled = element_info[i].crumbled[act];
667 /* no graphic for current action -- use default direction graphic */
668 if (default_action_direction_graphic == -1)
669 default_action_direction_graphic =
670 (act_remove ? default_remove_graphic :
672 element_info[i].direction_graphic[ACTION_TURNING][dir] :
673 default_action_graphic != default_graphic ?
674 default_action_graphic :
675 default_direction_graphic[dir]);
677 if (element_info[i].direction_graphic[act][dir] == -1)
678 element_info[i].direction_graphic[act][dir] =
679 default_action_direction_graphic;
682 if (default_action_direction_crumbled == -1)
683 default_action_direction_crumbled =
684 element_info[i].direction_graphic[act][dir];
686 if (default_action_direction_crumbled == -1)
687 default_action_direction_crumbled =
688 (act_remove ? default_remove_graphic :
690 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
691 default_action_crumbled != default_crumbled ?
692 default_action_crumbled :
693 default_direction_crumbled[dir]);
696 if (element_info[i].direction_crumbled[act][dir] == -1)
697 element_info[i].direction_crumbled[act][dir] =
698 default_action_direction_crumbled;
701 /* no graphic for this specific action -- use default action graphic */
702 if (element_info[i].graphic[act] == -1)
703 element_info[i].graphic[act] =
704 (act_remove ? default_remove_graphic :
705 act_turning ? element_info[i].graphic[ACTION_TURNING] :
706 default_action_graphic);
708 if (element_info[i].crumbled[act] == -1)
709 element_info[i].crumbled[act] = element_info[i].graphic[act];
711 if (element_info[i].crumbled[act] == -1)
712 element_info[i].crumbled[act] =
713 (act_remove ? default_remove_graphic :
714 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
715 default_action_crumbled);
720 /* set animation mode to "none" for each graphic with only 1 frame */
721 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
723 for (act = 0; act < NUM_ACTIONS; act++)
725 int graphic = element_info[i].graphic[act];
726 int crumbled = element_info[i].crumbled[act];
728 if (graphic_info[graphic].anim_frames == 1)
729 graphic_info[graphic].anim_mode = ANIM_NONE;
730 if (graphic_info[crumbled].anim_frames == 1)
731 graphic_info[crumbled].anim_mode = ANIM_NONE;
733 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
735 graphic = element_info[i].direction_graphic[act][dir];
736 crumbled = element_info[i].direction_crumbled[act][dir];
738 if (graphic_info[graphic].anim_frames == 1)
739 graphic_info[graphic].anim_mode = ANIM_NONE;
740 if (graphic_info[crumbled].anim_frames == 1)
741 graphic_info[crumbled].anim_mode = ANIM_NONE;
750 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
751 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
753 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
754 element_info[i].token_name, i);
760 void InitElementSpecialGraphicInfo()
762 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
763 int num_property_mappings = getImageListPropertyMappingSize();
766 /* always start with reliable default values */
767 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
768 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
769 element_info[i].special_graphic[j] =
770 element_info[i].graphic[ACTION_DEFAULT];
772 /* initialize special element/graphic mapping from static configuration */
773 for (i = 0; element_to_special_graphic[i].element > -1; i++)
775 int element = element_to_special_graphic[i].element;
776 int special = element_to_special_graphic[i].special;
777 int graphic = element_to_special_graphic[i].graphic;
778 int base_graphic = el2baseimg(element);
779 boolean base_redefined =
780 getImageListEntryFromImageID(base_graphic)->redefined;
781 boolean special_redefined =
782 getImageListEntryFromImageID(graphic)->redefined;
784 /* if the base graphic ("emerald", for example) has been redefined,
785 but not the special graphic ("emerald.EDITOR", for example), do not
786 use an existing (in this case considered obsolete) special graphic
787 anymore, but use the automatically created (down-scaled) graphic */
788 if (base_redefined && !special_redefined)
791 element_info[element].special_graphic[special] = graphic;
794 /* initialize special element/graphic mapping from dynamic configuration */
795 for (i = 0; i < num_property_mappings; i++)
797 int element = property_mapping[i].base_index;
798 int special = property_mapping[i].ext3_index;
799 int graphic = property_mapping[i].artwork_index;
801 if (element >= MAX_NUM_ELEMENTS)
804 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
805 element_info[element].special_graphic[special] = graphic;
808 /* now set all undefined/invalid graphics to default */
809 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
810 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
811 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
812 element_info[i].special_graphic[j] =
813 element_info[i].graphic[ACTION_DEFAULT];
816 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
821 if (type != TYPE_TOKEN)
822 return get_parameter_value(value_raw, suffix, type);
824 if (strcmp(value_raw, ARG_UNDEFINED) == 0)
825 return ARG_UNDEFINED_VALUE;
827 /* !!! OPTIMIZE THIS BY USING HASH !!! */
828 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
829 if (strcmp(element_info[i].token_name, value_raw) == 0)
832 /* !!! OPTIMIZE THIS BY USING HASH !!! */
833 for (i = 0; image_config[i].token != NULL; i++)
835 int len_config_value = strlen(image_config[i].value);
837 if (strcmp(&image_config[i].value[len_config_value - 4], ".pcx") != 0 &&
838 strcmp(&image_config[i].value[len_config_value - 4], ".wav") != 0 &&
839 strcmp(image_config[i].value, UNDEFINED_FILENAME) != 0)
842 if (strcmp(image_config[i].token, value_raw) == 0)
851 static int get_scaled_graphic_width(int graphic)
853 int original_width = getOriginalImageWidthFromImageID(graphic);
854 int scale_up_factor = graphic_info[graphic].scale_up_factor;
856 return original_width * scale_up_factor;
859 static int get_scaled_graphic_height(int graphic)
861 int original_height = getOriginalImageHeightFromImageID(graphic);
862 int scale_up_factor = graphic_info[graphic].scale_up_factor;
864 return original_height * scale_up_factor;
867 static void set_graphic_parameters(int graphic)
869 struct FileInfo *image = getImageListEntryFromImageID(graphic);
870 char **parameter_raw = image->parameter;
871 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
872 int parameter[NUM_GFX_ARGS];
873 int anim_frames_per_row = 1, anim_frames_per_col = 1;
874 int anim_frames_per_line = 1;
877 /* if fallback to default artwork is done, also use the default parameters */
878 if (image->fallback_to_default)
879 parameter_raw = image->default_parameter;
881 /* get integer values from string parameters */
882 for (i = 0; i < NUM_GFX_ARGS; i++)
883 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
884 image_config_suffix[i].token,
885 image_config_suffix[i].type);
887 graphic_info[graphic].bitmap = src_bitmap;
889 /* start with reliable default values */
890 graphic_info[graphic].src_image_width = 0;
891 graphic_info[graphic].src_image_height = 0;
892 graphic_info[graphic].src_x = 0;
893 graphic_info[graphic].src_y = 0;
894 graphic_info[graphic].width = TILEX;
895 graphic_info[graphic].height = TILEY;
896 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
897 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
898 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
899 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
900 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
901 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
902 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
903 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
904 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
905 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
906 graphic_info[graphic].anim_delay_fixed = 0;
907 graphic_info[graphic].anim_delay_random = 0;
908 graphic_info[graphic].post_delay_fixed = 0;
909 graphic_info[graphic].post_delay_random = 0;
911 /* optional x and y tile position of animation frame sequence */
912 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
913 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
914 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
915 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
917 /* optional x and y pixel position of animation frame sequence */
918 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
919 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
920 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
921 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
923 /* optional width and height of each animation frame */
924 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
925 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
926 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
927 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
929 /* optional zoom factor for scaling up the image to a larger size */
930 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
931 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
932 if (graphic_info[graphic].scale_up_factor < 1)
933 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
937 /* get final bitmap size (with scaling, but without small images) */
938 int src_image_width = get_scaled_graphic_width(graphic);
939 int src_image_height = get_scaled_graphic_height(graphic);
941 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
942 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
944 graphic_info[graphic].src_image_width = src_image_width;
945 graphic_info[graphic].src_image_height = src_image_height;
948 /* correct x or y offset dependent of vertical or horizontal frame order */
949 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
951 graphic_info[graphic].offset_y =
952 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
953 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
954 anim_frames_per_line = anim_frames_per_col;
956 else /* frames are ordered horizontally */
958 graphic_info[graphic].offset_x =
959 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
960 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
961 anim_frames_per_line = anim_frames_per_row;
964 /* optionally, the x and y offset of frames can be specified directly */
965 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
966 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
967 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
968 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
970 /* optionally, moving animations may have separate start and end graphics */
971 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
973 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
974 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
976 /* correct x or y offset2 dependent of vertical or horizontal frame order */
977 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
978 graphic_info[graphic].offset2_y =
979 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
980 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
981 else /* frames are ordered horizontally */
982 graphic_info[graphic].offset2_x =
983 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
984 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
986 /* optionally, the x and y offset of 2nd graphic can be specified directly */
987 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
989 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
992 /* optionally, the second movement tile can be specified as start tile */
993 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
996 /* automatically determine correct number of frames, if not defined */
997 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
998 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
999 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1000 graphic_info[graphic].anim_frames = anim_frames_per_row;
1001 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1002 graphic_info[graphic].anim_frames = anim_frames_per_col;
1004 graphic_info[graphic].anim_frames = 1;
1006 graphic_info[graphic].anim_frames_per_line =
1007 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1008 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1010 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1011 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1012 graphic_info[graphic].anim_delay = 1;
1014 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1016 if (graphic_info[graphic].anim_frames == 1)
1017 graphic_info[graphic].anim_mode = ANIM_NONE;
1020 /* automatically determine correct start frame, if not defined */
1021 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1022 graphic_info[graphic].anim_start_frame = 0;
1023 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1024 graphic_info[graphic].anim_start_frame =
1025 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1027 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1029 /* animation synchronized with global frame counter, not move position */
1030 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1032 /* optional element for cloning crumble graphics */
1033 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1034 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1036 /* optional element for cloning digging graphics */
1037 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1038 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1040 /* optional border size for "crumbling" diggable graphics */
1041 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1042 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1044 /* this is only used for player "boring" and "sleeping" actions */
1045 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].anim_delay_fixed =
1047 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1048 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1049 graphic_info[graphic].anim_delay_random =
1050 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1051 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].post_delay_fixed =
1053 parameter[GFX_ARG_POST_DELAY_FIXED];
1054 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].post_delay_random =
1056 parameter[GFX_ARG_POST_DELAY_RANDOM];
1058 /* this is only used for toon animations */
1059 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1060 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1062 /* this is only used for drawing font characters */
1063 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1064 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1066 /* this is only used for drawing envelope graphics */
1067 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1069 /* optional graphic for cloning all graphics settings */
1070 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1071 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1074 static void set_cloned_graphic_parameters(int graphic)
1076 int fallback_graphic = IMG_CHAR_EXCLAM;
1077 int max_num_images = getImageListSize();
1078 int clone_graphic = graphic_info[graphic].clone_from;
1079 int num_references_followed = 1;
1081 while (graphic_info[clone_graphic].clone_from != -1 &&
1082 num_references_followed < max_num_images)
1084 clone_graphic = graphic_info[clone_graphic].clone_from;
1086 num_references_followed++;
1089 if (num_references_followed >= max_num_images)
1091 Error(ERR_RETURN_LINE, "-");
1092 Error(ERR_RETURN, "warning: error found in config file:");
1093 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1094 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1095 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1096 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1098 if (graphic == fallback_graphic)
1099 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1101 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1102 Error(ERR_RETURN_LINE, "-");
1104 graphic_info[graphic] = graphic_info[fallback_graphic];
1108 graphic_info[graphic] = graphic_info[clone_graphic];
1109 graphic_info[graphic].clone_from = clone_graphic;
1113 static void InitGraphicInfo()
1115 int fallback_graphic = IMG_CHAR_EXCLAM;
1116 int num_images = getImageListSize();
1119 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1120 static boolean clipmasks_initialized = FALSE;
1122 XGCValues clip_gc_values;
1123 unsigned long clip_gc_valuemask;
1124 GC copy_clipmask_gc = None;
1127 checked_free(graphic_info);
1129 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1131 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1132 if (clipmasks_initialized)
1134 for (i = 0; i < num_images; i++)
1136 if (graphic_info[i].clip_mask)
1137 XFreePixmap(display, graphic_info[i].clip_mask);
1138 if (graphic_info[i].clip_gc)
1139 XFreeGC(display, graphic_info[i].clip_gc);
1141 graphic_info[i].clip_mask = None;
1142 graphic_info[i].clip_gc = None;
1147 /* first set all graphic paramaters ... */
1148 for (i = 0; i < num_images; i++)
1149 set_graphic_parameters(i);
1151 /* ... then copy these parameters for cloned graphics */
1152 for (i = 0; i < num_images; i++)
1153 if (graphic_info[i].clone_from != -1)
1154 set_cloned_graphic_parameters(i);
1156 for (i = 0; i < num_images; i++)
1160 int first_frame, last_frame;
1161 int src_bitmap_width, src_bitmap_height;
1163 /* now check if no animation frames are outside of the loaded image */
1165 if (graphic_info[i].bitmap == NULL)
1166 continue; /* skip check for optional images that are undefined */
1168 /* get final bitmap size (with scaling, but without small images) */
1169 src_bitmap_width = graphic_info[i].src_image_width;
1170 src_bitmap_height = graphic_info[i].src_image_height;
1172 /* check if first animation frame is inside specified bitmap */
1175 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1177 if (src_x < 0 || src_y < 0 ||
1178 src_x + TILEX > src_bitmap_width ||
1179 src_y + TILEY > src_bitmap_height)
1181 Error(ERR_RETURN_LINE, "-");
1182 Error(ERR_RETURN, "warning: error found in config file:");
1183 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1184 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1185 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1187 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1188 src_x, src_y, src_bitmap_width, src_bitmap_height);
1189 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1191 if (i == fallback_graphic)
1192 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1194 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1195 Error(ERR_RETURN_LINE, "-");
1197 graphic_info[i] = graphic_info[fallback_graphic];
1200 /* check if last animation frame is inside specified bitmap */
1202 last_frame = graphic_info[i].anim_frames - 1;
1203 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1205 if (src_x < 0 || src_y < 0 ||
1206 src_x + TILEX > src_bitmap_width ||
1207 src_y + TILEY > src_bitmap_height)
1209 Error(ERR_RETURN_LINE, "-");
1210 Error(ERR_RETURN, "warning: error found in config file:");
1211 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1212 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1213 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1215 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1216 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1217 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1219 if (i == fallback_graphic)
1220 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1222 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1223 Error(ERR_RETURN_LINE, "-");
1225 graphic_info[i] = graphic_info[fallback_graphic];
1228 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1229 /* currently we only need a tile clip mask from the first frame */
1230 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1232 if (copy_clipmask_gc == None)
1234 clip_gc_values.graphics_exposures = False;
1235 clip_gc_valuemask = GCGraphicsExposures;
1236 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1237 clip_gc_valuemask, &clip_gc_values);
1240 graphic_info[i].clip_mask =
1241 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1243 src_pixmap = src_bitmap->clip_mask;
1244 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1245 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1247 clip_gc_values.graphics_exposures = False;
1248 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1249 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1251 graphic_info[i].clip_gc =
1252 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1256 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1257 if (copy_clipmask_gc)
1258 XFreeGC(display, copy_clipmask_gc);
1260 clipmasks_initialized = TRUE;
1264 static void InitElementSoundInfo()
1266 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1267 int num_property_mappings = getSoundListPropertyMappingSize();
1270 /* set values to -1 to identify later as "uninitialized" values */
1271 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1272 for (act = 0; act < NUM_ACTIONS; act++)
1273 element_info[i].sound[act] = -1;
1275 /* initialize element/sound mapping from static configuration */
1276 for (i = 0; element_to_sound[i].element > -1; i++)
1278 int element = element_to_sound[i].element;
1279 int action = element_to_sound[i].action;
1280 int sound = element_to_sound[i].sound;
1281 boolean is_class = element_to_sound[i].is_class;
1284 action = ACTION_DEFAULT;
1287 element_info[element].sound[action] = sound;
1289 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1290 if (strcmp(element_info[j].class_name,
1291 element_info[element].class_name) == 0)
1292 element_info[j].sound[action] = sound;
1295 /* initialize element class/sound mapping from dynamic configuration */
1296 for (i = 0; i < num_property_mappings; i++)
1298 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1299 int action = property_mapping[i].ext1_index;
1300 int sound = property_mapping[i].artwork_index;
1302 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1306 action = ACTION_DEFAULT;
1308 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1309 if (strcmp(element_info[j].class_name,
1310 element_info[element_class].class_name) == 0)
1311 element_info[j].sound[action] = sound;
1314 /* initialize element/sound mapping from dynamic configuration */
1315 for (i = 0; i < num_property_mappings; i++)
1317 int element = property_mapping[i].base_index;
1318 int action = property_mapping[i].ext1_index;
1319 int sound = property_mapping[i].artwork_index;
1321 if (element >= MAX_NUM_ELEMENTS)
1325 action = ACTION_DEFAULT;
1327 element_info[element].sound[action] = sound;
1330 /* now set all '-1' values to element specific default values */
1331 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1333 for (act = 0; act < NUM_ACTIONS; act++)
1335 /* generic default action sound (defined by "[default]" directive) */
1336 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1338 /* look for special default action sound (classic game specific) */
1339 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1340 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1341 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1342 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1343 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1344 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1346 /* !!! there's no such thing as a "default action sound" !!! */
1348 /* look for element specific default sound (independent from action) */
1349 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1350 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1354 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1355 /* !!! make this better !!! */
1356 if (i == EL_EMPTY_SPACE)
1357 default_action_sound = element_info[EL_DEFAULT].sound[act];
1360 /* no sound for this specific action -- use default action sound */
1361 if (element_info[i].sound[act] == -1)
1362 element_info[i].sound[act] = default_action_sound;
1366 /* copy sound settings to some elements that are only stored in level file
1367 in native R'n'D levels, but are used by game engine in native EM levels */
1368 for (i = 0; copy_properties[i][0] != -1; i++)
1369 for (j = 1; j <= 4; j++)
1370 for (act = 0; act < NUM_ACTIONS; act++)
1371 element_info[copy_properties[i][j]].sound[act] =
1372 element_info[copy_properties[i][0]].sound[act];
1375 static void InitGameModeSoundInfo()
1379 /* set values to -1 to identify later as "uninitialized" values */
1380 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1383 /* initialize gamemode/sound mapping from static configuration */
1384 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1386 int gamemode = gamemode_to_sound[i].gamemode;
1387 int sound = gamemode_to_sound[i].sound;
1390 gamemode = GAME_MODE_DEFAULT;
1392 menu.sound[gamemode] = sound;
1395 /* now set all '-1' values to levelset specific default values */
1396 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1397 if (menu.sound[i] == -1)
1398 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1401 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1402 if (menu.sound[i] != -1)
1403 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1407 static void set_sound_parameters(int sound, char **parameter_raw)
1409 int parameter[NUM_SND_ARGS];
1412 /* get integer values from string parameters */
1413 for (i = 0; i < NUM_SND_ARGS; i++)
1415 get_parameter_value(parameter_raw[i],
1416 sound_config_suffix[i].token,
1417 sound_config_suffix[i].type);
1419 /* explicit loop mode setting in configuration overrides default value */
1420 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1421 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1423 /* sound volume to change the original volume when loading the sound file */
1424 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1426 /* sound priority to give certain sounds a higher or lower priority */
1427 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1430 static void InitSoundInfo()
1432 int *sound_effect_properties;
1433 int num_sounds = getSoundListSize();
1436 checked_free(sound_info);
1438 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1439 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1441 /* initialize sound effect for all elements to "no sound" */
1442 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1443 for (j = 0; j < NUM_ACTIONS; j++)
1444 element_info[i].sound[j] = SND_UNDEFINED;
1446 for (i = 0; i < num_sounds; i++)
1448 struct FileInfo *sound = getSoundListEntry(i);
1449 int len_effect_text = strlen(sound->token);
1451 sound_effect_properties[i] = ACTION_OTHER;
1452 sound_info[i].loop = FALSE; /* default: play sound only once */
1455 printf("::: sound %d: '%s'\n", i, sound->token);
1458 /* determine all loop sounds and identify certain sound classes */
1460 for (j = 0; element_action_info[j].suffix; j++)
1462 int len_action_text = strlen(element_action_info[j].suffix);
1464 if (len_action_text < len_effect_text &&
1465 strcmp(&sound->token[len_effect_text - len_action_text],
1466 element_action_info[j].suffix) == 0)
1468 sound_effect_properties[i] = element_action_info[j].value;
1469 sound_info[i].loop = element_action_info[j].is_loop_sound;
1475 /* associate elements and some selected sound actions */
1477 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1479 if (element_info[j].class_name)
1481 int len_class_text = strlen(element_info[j].class_name);
1483 if (len_class_text + 1 < len_effect_text &&
1484 strncmp(sound->token,
1485 element_info[j].class_name, len_class_text) == 0 &&
1486 sound->token[len_class_text] == '.')
1488 int sound_action_value = sound_effect_properties[i];
1490 element_info[j].sound[sound_action_value] = i;
1495 set_sound_parameters(i, sound->parameter);
1498 free(sound_effect_properties);
1501 static void InitGameModeMusicInfo()
1503 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1504 int num_property_mappings = getMusicListPropertyMappingSize();
1505 int default_levelset_music = -1;
1508 /* set values to -1 to identify later as "uninitialized" values */
1509 for (i = 0; i < MAX_LEVELS; i++)
1510 levelset.music[i] = -1;
1511 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1514 /* initialize gamemode/music mapping from static configuration */
1515 for (i = 0; gamemode_to_music[i].music > -1; i++)
1517 int gamemode = gamemode_to_music[i].gamemode;
1518 int music = gamemode_to_music[i].music;
1521 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1525 gamemode = GAME_MODE_DEFAULT;
1527 menu.music[gamemode] = music;
1530 /* initialize gamemode/music mapping from dynamic configuration */
1531 for (i = 0; i < num_property_mappings; i++)
1533 int prefix = property_mapping[i].base_index;
1534 int gamemode = property_mapping[i].ext1_index;
1535 int level = property_mapping[i].ext2_index;
1536 int music = property_mapping[i].artwork_index;
1539 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1540 prefix, gamemode, level, music);
1543 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1547 gamemode = GAME_MODE_DEFAULT;
1549 /* level specific music only allowed for in-game music */
1550 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1551 gamemode = GAME_MODE_PLAYING;
1556 default_levelset_music = music;
1559 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1560 levelset.music[level] = music;
1561 if (gamemode != GAME_MODE_PLAYING)
1562 menu.music[gamemode] = music;
1565 /* now set all '-1' values to menu specific default values */
1566 /* (undefined values of "levelset.music[]" might stay at "-1" to
1567 allow dynamic selection of music files from music directory!) */
1568 for (i = 0; i < MAX_LEVELS; i++)
1569 if (levelset.music[i] == -1)
1570 levelset.music[i] = default_levelset_music;
1571 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1572 if (menu.music[i] == -1)
1573 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1576 for (i = 0; i < MAX_LEVELS; i++)
1577 if (levelset.music[i] != -1)
1578 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1579 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1580 if (menu.music[i] != -1)
1581 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1585 static void set_music_parameters(int music, char **parameter_raw)
1587 int parameter[NUM_MUS_ARGS];
1590 /* get integer values from string parameters */
1591 for (i = 0; i < NUM_MUS_ARGS; i++)
1593 get_parameter_value(parameter_raw[i],
1594 music_config_suffix[i].token,
1595 music_config_suffix[i].type);
1597 /* explicit loop mode setting in configuration overrides default value */
1598 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1599 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1602 static void InitMusicInfo()
1604 int num_music = getMusicListSize();
1607 checked_free(music_info);
1609 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1611 for (i = 0; i < num_music; i++)
1613 struct FileInfo *music = getMusicListEntry(i);
1614 int len_music_text = strlen(music->token);
1616 music_info[i].loop = TRUE; /* default: play music in loop mode */
1618 /* determine all loop music */
1620 for (j = 0; music_prefix_info[j].prefix; j++)
1622 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1624 if (len_prefix_text < len_music_text &&
1625 strncmp(music->token,
1626 music_prefix_info[j].prefix, len_prefix_text) == 0)
1628 music_info[i].loop = music_prefix_info[j].is_loop_music;
1634 set_music_parameters(i, music->parameter);
1638 static void ReinitializeGraphics()
1640 InitGraphicInfo(); /* graphic properties mapping */
1641 InitElementGraphicInfo(); /* element game graphic mapping */
1642 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1644 InitElementSmallImages(); /* scale images to all needed sizes */
1645 InitFontGraphicInfo(); /* initialize text drawing functions */
1647 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1649 SetMainBackgroundImage(IMG_BACKGROUND);
1650 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1656 static void ReinitializeSounds()
1658 InitSoundInfo(); /* sound properties mapping */
1659 InitElementSoundInfo(); /* element game sound mapping */
1660 InitGameModeSoundInfo(); /* game mode sound mapping */
1662 InitPlayLevelSound(); /* internal game sound settings */
1665 static void ReinitializeMusic()
1667 InitMusicInfo(); /* music properties mapping */
1668 InitGameModeMusicInfo(); /* game mode music mapping */
1671 static int get_special_property_bit(int element, int property_bit_nr)
1673 struct PropertyBitInfo
1679 static struct PropertyBitInfo pb_can_move_into_acid[] =
1681 /* the player may be able fall into acid when gravity is activated */
1686 { EL_SP_MURPHY, 0 },
1687 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1689 /* all elements that can move may be able to also move into acid */
1692 { EL_BUG_RIGHT, 1 },
1695 { EL_SPACESHIP, 2 },
1696 { EL_SPACESHIP_LEFT, 2 },
1697 { EL_SPACESHIP_RIGHT, 2 },
1698 { EL_SPACESHIP_UP, 2 },
1699 { EL_SPACESHIP_DOWN, 2 },
1700 { EL_BD_BUTTERFLY, 3 },
1701 { EL_BD_BUTTERFLY_LEFT, 3 },
1702 { EL_BD_BUTTERFLY_RIGHT, 3 },
1703 { EL_BD_BUTTERFLY_UP, 3 },
1704 { EL_BD_BUTTERFLY_DOWN, 3 },
1705 { EL_BD_FIREFLY, 4 },
1706 { EL_BD_FIREFLY_LEFT, 4 },
1707 { EL_BD_FIREFLY_RIGHT, 4 },
1708 { EL_BD_FIREFLY_UP, 4 },
1709 { EL_BD_FIREFLY_DOWN, 4 },
1711 { EL_YAMYAM_LEFT, 5 },
1712 { EL_YAMYAM_RIGHT, 5 },
1713 { EL_YAMYAM_UP, 5 },
1714 { EL_YAMYAM_DOWN, 5 },
1715 { EL_DARK_YAMYAM, 6 },
1718 { EL_PACMAN_LEFT, 8 },
1719 { EL_PACMAN_RIGHT, 8 },
1720 { EL_PACMAN_UP, 8 },
1721 { EL_PACMAN_DOWN, 8 },
1723 { EL_MOLE_LEFT, 9 },
1724 { EL_MOLE_RIGHT, 9 },
1726 { EL_MOLE_DOWN, 9 },
1730 { EL_SATELLITE, 13 },
1731 { EL_SP_SNIKSNAK, 14 },
1732 { EL_SP_ELECTRON, 15 },
1735 { EL_EMC_ANDROID, 18 },
1740 static struct PropertyBitInfo pb_dont_collide_with[] =
1742 { EL_SP_SNIKSNAK, 0 },
1743 { EL_SP_ELECTRON, 1 },
1751 struct PropertyBitInfo *pb_info;
1754 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1755 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1760 struct PropertyBitInfo *pb_info = NULL;
1763 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1764 if (pb_definition[i].bit_nr == property_bit_nr)
1765 pb_info = pb_definition[i].pb_info;
1767 if (pb_info == NULL)
1770 for (i = 0; pb_info[i].element != -1; i++)
1771 if (pb_info[i].element == element)
1772 return pb_info[i].bit_nr;
1777 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1778 boolean property_value)
1780 int bit_nr = get_special_property_bit(element, property_bit_nr);
1785 *bitfield |= (1 << bit_nr);
1787 *bitfield &= ~(1 << bit_nr);
1791 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1793 int bit_nr = get_special_property_bit(element, property_bit_nr);
1796 return ((*bitfield & (1 << bit_nr)) != 0);
1802 static void resolve_group_element(int group_element, int recursion_depth)
1804 static int group_nr;
1805 static struct ElementGroupInfo *group;
1806 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1809 if (actual_group == NULL) /* not yet initialized */
1812 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1814 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1815 group_element - EL_GROUP_START + 1);
1817 /* replace element which caused too deep recursion by question mark */
1818 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1823 if (recursion_depth == 0) /* initialization */
1825 group = actual_group;
1826 group_nr = group_element - EL_GROUP_START;
1828 group->num_elements_resolved = 0;
1829 group->choice_pos = 0;
1832 for (i = 0; i < actual_group->num_elements; i++)
1834 int element = actual_group->element[i];
1836 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1839 if (IS_GROUP_ELEMENT(element))
1840 resolve_group_element(element, recursion_depth + 1);
1843 group->element_resolved[group->num_elements_resolved++] = element;
1844 element_info[element].in_group[group_nr] = TRUE;
1850 void InitElementPropertiesStatic()
1852 static int ep_diggable[] =
1857 EL_SP_BUGGY_BASE_ACTIVATING,
1860 EL_INVISIBLE_SAND_ACTIVE,
1863 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1864 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1868 EL_SP_BUGGY_BASE_ACTIVE,
1875 static int ep_collectible_only[] =
1897 EL_DYNABOMB_INCREASE_NUMBER,
1898 EL_DYNABOMB_INCREASE_SIZE,
1899 EL_DYNABOMB_INCREASE_POWER,
1919 static int ep_dont_run_into[] =
1921 /* same elements as in 'ep_dont_touch' */
1927 /* same elements as in 'ep_dont_collide_with' */
1939 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1943 EL_SP_BUGGY_BASE_ACTIVE,
1950 static int ep_dont_collide_with[] =
1952 /* same elements as in 'ep_dont_touch' */
1969 static int ep_dont_touch[] =
1979 static int ep_indestructible[] =
1983 EL_ACID_POOL_TOPLEFT,
1984 EL_ACID_POOL_TOPRIGHT,
1985 EL_ACID_POOL_BOTTOMLEFT,
1986 EL_ACID_POOL_BOTTOM,
1987 EL_ACID_POOL_BOTTOMRIGHT,
1988 EL_SP_HARDWARE_GRAY,
1989 EL_SP_HARDWARE_GREEN,
1990 EL_SP_HARDWARE_BLUE,
1992 EL_SP_HARDWARE_YELLOW,
1993 EL_SP_HARDWARE_BASE_1,
1994 EL_SP_HARDWARE_BASE_2,
1995 EL_SP_HARDWARE_BASE_3,
1996 EL_SP_HARDWARE_BASE_4,
1997 EL_SP_HARDWARE_BASE_5,
1998 EL_SP_HARDWARE_BASE_6,
1999 EL_INVISIBLE_STEELWALL,
2000 EL_INVISIBLE_STEELWALL_ACTIVE,
2001 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2002 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2003 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2004 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2005 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2006 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2007 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2008 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2009 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2010 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2011 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2012 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2014 EL_LIGHT_SWITCH_ACTIVE,
2015 EL_SIGN_EXCLAMATION,
2016 EL_SIGN_RADIOACTIVITY,
2027 EL_STEELWALL_SLIPPERY,
2041 EL_GATE_1_GRAY_ACTIVE,
2042 EL_GATE_2_GRAY_ACTIVE,
2043 EL_GATE_3_GRAY_ACTIVE,
2044 EL_GATE_4_GRAY_ACTIVE,
2053 EL_EM_GATE_1_GRAY_ACTIVE,
2054 EL_EM_GATE_2_GRAY_ACTIVE,
2055 EL_EM_GATE_3_GRAY_ACTIVE,
2056 EL_EM_GATE_4_GRAY_ACTIVE,
2065 EL_EMC_GATE_5_GRAY_ACTIVE,
2066 EL_EMC_GATE_6_GRAY_ACTIVE,
2067 EL_EMC_GATE_7_GRAY_ACTIVE,
2068 EL_EMC_GATE_8_GRAY_ACTIVE,
2070 EL_SWITCHGATE_OPENING,
2071 EL_SWITCHGATE_CLOSED,
2072 EL_SWITCHGATE_CLOSING,
2074 EL_SWITCHGATE_SWITCH_UP,
2075 EL_SWITCHGATE_SWITCH_DOWN,
2078 EL_TIMEGATE_OPENING,
2080 EL_TIMEGATE_CLOSING,
2083 EL_TIMEGATE_SWITCH_ACTIVE,
2088 EL_TUBE_VERTICAL_LEFT,
2089 EL_TUBE_VERTICAL_RIGHT,
2090 EL_TUBE_HORIZONTAL_UP,
2091 EL_TUBE_HORIZONTAL_DOWN,
2100 static int ep_slippery[] =
2114 EL_ROBOT_WHEEL_ACTIVE,
2120 EL_ACID_POOL_TOPLEFT,
2121 EL_ACID_POOL_TOPRIGHT,
2131 EL_STEELWALL_SLIPPERY,
2134 EL_EMC_WALL_SLIPPERY_1,
2135 EL_EMC_WALL_SLIPPERY_2,
2136 EL_EMC_WALL_SLIPPERY_3,
2137 EL_EMC_WALL_SLIPPERY_4,
2139 EL_EMC_MAGIC_BALL_ACTIVE,
2144 static int ep_can_change[] =
2149 static int ep_can_move[] =
2151 /* same elements as in 'pb_can_move_into_acid' */
2174 static int ep_can_fall[] =
2189 EL_BD_MAGIC_WALL_FULL,
2203 static int ep_can_smash_player[] =
2229 static int ep_can_smash_enemies[] =
2238 static int ep_can_smash_everything[] =
2247 static int ep_explodes_by_fire[] =
2249 /* same elements as in 'ep_explodes_impact' */
2254 /* same elements as in 'ep_explodes_smashed' */
2264 EL_EM_DYNAMITE_ACTIVE,
2265 EL_DYNABOMB_PLAYER_1_ACTIVE,
2266 EL_DYNABOMB_PLAYER_2_ACTIVE,
2267 EL_DYNABOMB_PLAYER_3_ACTIVE,
2268 EL_DYNABOMB_PLAYER_4_ACTIVE,
2269 EL_DYNABOMB_INCREASE_NUMBER,
2270 EL_DYNABOMB_INCREASE_SIZE,
2271 EL_DYNABOMB_INCREASE_POWER,
2272 EL_SP_DISK_RED_ACTIVE,
2286 static int ep_explodes_smashed[] =
2288 /* same elements as in 'ep_explodes_impact' */
2302 static int ep_explodes_impact[] =
2311 static int ep_walkable_over[] =
2315 EL_SOKOBAN_FIELD_EMPTY,
2327 EL_GATE_1_GRAY_ACTIVE,
2328 EL_GATE_2_GRAY_ACTIVE,
2329 EL_GATE_3_GRAY_ACTIVE,
2330 EL_GATE_4_GRAY_ACTIVE,
2338 static int ep_walkable_inside[] =
2343 EL_TUBE_VERTICAL_LEFT,
2344 EL_TUBE_VERTICAL_RIGHT,
2345 EL_TUBE_HORIZONTAL_UP,
2346 EL_TUBE_HORIZONTAL_DOWN,
2355 static int ep_walkable_under[] =
2360 static int ep_passable_over[] =
2370 EL_EM_GATE_1_GRAY_ACTIVE,
2371 EL_EM_GATE_2_GRAY_ACTIVE,
2372 EL_EM_GATE_3_GRAY_ACTIVE,
2373 EL_EM_GATE_4_GRAY_ACTIVE,
2382 EL_EMC_GATE_5_GRAY_ACTIVE,
2383 EL_EMC_GATE_6_GRAY_ACTIVE,
2384 EL_EMC_GATE_7_GRAY_ACTIVE,
2385 EL_EMC_GATE_8_GRAY_ACTIVE,
2392 static int ep_passable_inside[] =
2398 EL_SP_PORT_HORIZONTAL,
2399 EL_SP_PORT_VERTICAL,
2401 EL_SP_GRAVITY_PORT_LEFT,
2402 EL_SP_GRAVITY_PORT_RIGHT,
2403 EL_SP_GRAVITY_PORT_UP,
2404 EL_SP_GRAVITY_PORT_DOWN,
2405 EL_SP_GRAVITY_ON_PORT_LEFT,
2406 EL_SP_GRAVITY_ON_PORT_RIGHT,
2407 EL_SP_GRAVITY_ON_PORT_UP,
2408 EL_SP_GRAVITY_ON_PORT_DOWN,
2409 EL_SP_GRAVITY_OFF_PORT_LEFT,
2410 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2411 EL_SP_GRAVITY_OFF_PORT_UP,
2412 EL_SP_GRAVITY_OFF_PORT_DOWN,
2417 static int ep_passable_under[] =
2422 static int ep_droppable[] =
2427 static int ep_explodes_1x1_old[] =
2432 static int ep_pushable[] =
2444 EL_SOKOBAN_FIELD_FULL,
2453 static int ep_explodes_cross_old[] =
2458 static int ep_protected[] =
2460 /* same elements as in 'ep_walkable_inside' */
2464 EL_TUBE_VERTICAL_LEFT,
2465 EL_TUBE_VERTICAL_RIGHT,
2466 EL_TUBE_HORIZONTAL_UP,
2467 EL_TUBE_HORIZONTAL_DOWN,
2473 /* same elements as in 'ep_passable_over' */
2482 EL_EM_GATE_1_GRAY_ACTIVE,
2483 EL_EM_GATE_2_GRAY_ACTIVE,
2484 EL_EM_GATE_3_GRAY_ACTIVE,
2485 EL_EM_GATE_4_GRAY_ACTIVE,
2494 EL_EMC_GATE_5_GRAY_ACTIVE,
2495 EL_EMC_GATE_6_GRAY_ACTIVE,
2496 EL_EMC_GATE_7_GRAY_ACTIVE,
2497 EL_EMC_GATE_8_GRAY_ACTIVE,
2501 /* same elements as in 'ep_passable_inside' */
2506 EL_SP_PORT_HORIZONTAL,
2507 EL_SP_PORT_VERTICAL,
2509 EL_SP_GRAVITY_PORT_LEFT,
2510 EL_SP_GRAVITY_PORT_RIGHT,
2511 EL_SP_GRAVITY_PORT_UP,
2512 EL_SP_GRAVITY_PORT_DOWN,
2513 EL_SP_GRAVITY_ON_PORT_LEFT,
2514 EL_SP_GRAVITY_ON_PORT_RIGHT,
2515 EL_SP_GRAVITY_ON_PORT_UP,
2516 EL_SP_GRAVITY_ON_PORT_DOWN,
2517 EL_SP_GRAVITY_OFF_PORT_LEFT,
2518 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2519 EL_SP_GRAVITY_OFF_PORT_UP,
2520 EL_SP_GRAVITY_OFF_PORT_DOWN,
2525 static int ep_throwable[] =
2530 static int ep_can_explode[] =
2532 /* same elements as in 'ep_explodes_impact' */
2537 /* same elements as in 'ep_explodes_smashed' */
2543 /* elements that can explode by explosion or by dragonfire */
2547 EL_EM_DYNAMITE_ACTIVE,
2548 EL_DYNABOMB_PLAYER_1_ACTIVE,
2549 EL_DYNABOMB_PLAYER_2_ACTIVE,
2550 EL_DYNABOMB_PLAYER_3_ACTIVE,
2551 EL_DYNABOMB_PLAYER_4_ACTIVE,
2552 EL_DYNABOMB_INCREASE_NUMBER,
2553 EL_DYNABOMB_INCREASE_SIZE,
2554 EL_DYNABOMB_INCREASE_POWER,
2555 EL_SP_DISK_RED_ACTIVE,
2563 /* elements that can explode only by explosion */
2569 static int ep_gravity_reachable[] =
2575 EL_INVISIBLE_SAND_ACTIVE,
2580 EL_SP_PORT_HORIZONTAL,
2581 EL_SP_PORT_VERTICAL,
2583 EL_SP_GRAVITY_PORT_LEFT,
2584 EL_SP_GRAVITY_PORT_RIGHT,
2585 EL_SP_GRAVITY_PORT_UP,
2586 EL_SP_GRAVITY_PORT_DOWN,
2587 EL_SP_GRAVITY_ON_PORT_LEFT,
2588 EL_SP_GRAVITY_ON_PORT_RIGHT,
2589 EL_SP_GRAVITY_ON_PORT_UP,
2590 EL_SP_GRAVITY_ON_PORT_DOWN,
2591 EL_SP_GRAVITY_OFF_PORT_LEFT,
2592 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2593 EL_SP_GRAVITY_OFF_PORT_UP,
2594 EL_SP_GRAVITY_OFF_PORT_DOWN,
2600 static int ep_player[] =
2607 EL_SOKOBAN_FIELD_PLAYER,
2613 static int ep_can_pass_magic_wall[] =
2627 static int ep_switchable[] =
2631 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2632 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2633 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2634 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2635 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2636 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2637 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2638 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2639 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2640 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2641 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2642 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2643 EL_SWITCHGATE_SWITCH_UP,
2644 EL_SWITCHGATE_SWITCH_DOWN,
2646 EL_LIGHT_SWITCH_ACTIVE,
2648 EL_BALLOON_SWITCH_LEFT,
2649 EL_BALLOON_SWITCH_RIGHT,
2650 EL_BALLOON_SWITCH_UP,
2651 EL_BALLOON_SWITCH_DOWN,
2652 EL_BALLOON_SWITCH_ANY,
2653 EL_BALLOON_SWITCH_NONE,
2656 EL_EMC_MAGIC_BALL_SWITCH,
2657 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2662 static int ep_bd_element[] =
2696 static int ep_sp_element[] =
2698 /* should always be valid */
2701 /* standard classic Supaplex elements */
2708 EL_SP_HARDWARE_GRAY,
2716 EL_SP_GRAVITY_PORT_RIGHT,
2717 EL_SP_GRAVITY_PORT_DOWN,
2718 EL_SP_GRAVITY_PORT_LEFT,
2719 EL_SP_GRAVITY_PORT_UP,
2724 EL_SP_PORT_VERTICAL,
2725 EL_SP_PORT_HORIZONTAL,
2731 EL_SP_HARDWARE_BASE_1,
2732 EL_SP_HARDWARE_GREEN,
2733 EL_SP_HARDWARE_BLUE,
2735 EL_SP_HARDWARE_YELLOW,
2736 EL_SP_HARDWARE_BASE_2,
2737 EL_SP_HARDWARE_BASE_3,
2738 EL_SP_HARDWARE_BASE_4,
2739 EL_SP_HARDWARE_BASE_5,
2740 EL_SP_HARDWARE_BASE_6,
2744 /* additional elements that appeared in newer Supaplex levels */
2747 /* additional gravity port elements (not switching, but setting gravity) */
2748 EL_SP_GRAVITY_ON_PORT_LEFT,
2749 EL_SP_GRAVITY_ON_PORT_RIGHT,
2750 EL_SP_GRAVITY_ON_PORT_UP,
2751 EL_SP_GRAVITY_ON_PORT_DOWN,
2752 EL_SP_GRAVITY_OFF_PORT_LEFT,
2753 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2754 EL_SP_GRAVITY_OFF_PORT_UP,
2755 EL_SP_GRAVITY_OFF_PORT_DOWN,
2757 /* more than one Murphy in a level results in an inactive clone */
2760 /* runtime Supaplex elements */
2761 EL_SP_DISK_RED_ACTIVE,
2762 EL_SP_TERMINAL_ACTIVE,
2763 EL_SP_BUGGY_BASE_ACTIVATING,
2764 EL_SP_BUGGY_BASE_ACTIVE,
2771 static int ep_sb_element[] =
2776 EL_SOKOBAN_FIELD_EMPTY,
2777 EL_SOKOBAN_FIELD_FULL,
2778 EL_SOKOBAN_FIELD_PLAYER,
2783 EL_INVISIBLE_STEELWALL,
2788 static int ep_gem[] =
2800 static int ep_food_dark_yamyam[] =
2828 static int ep_food_penguin[] =
2842 static int ep_food_pig[] =
2854 static int ep_historic_wall[] =
2865 EL_GATE_1_GRAY_ACTIVE,
2866 EL_GATE_2_GRAY_ACTIVE,
2867 EL_GATE_3_GRAY_ACTIVE,
2868 EL_GATE_4_GRAY_ACTIVE,
2877 EL_EM_GATE_1_GRAY_ACTIVE,
2878 EL_EM_GATE_2_GRAY_ACTIVE,
2879 EL_EM_GATE_3_GRAY_ACTIVE,
2880 EL_EM_GATE_4_GRAY_ACTIVE,
2887 EL_EXPANDABLE_WALL_HORIZONTAL,
2888 EL_EXPANDABLE_WALL_VERTICAL,
2889 EL_EXPANDABLE_WALL_ANY,
2890 EL_EXPANDABLE_WALL_GROWING,
2897 EL_SP_HARDWARE_GRAY,
2898 EL_SP_HARDWARE_GREEN,
2899 EL_SP_HARDWARE_BLUE,
2901 EL_SP_HARDWARE_YELLOW,
2902 EL_SP_HARDWARE_BASE_1,
2903 EL_SP_HARDWARE_BASE_2,
2904 EL_SP_HARDWARE_BASE_3,
2905 EL_SP_HARDWARE_BASE_4,
2906 EL_SP_HARDWARE_BASE_5,
2907 EL_SP_HARDWARE_BASE_6,
2909 EL_SP_TERMINAL_ACTIVE,
2912 EL_INVISIBLE_STEELWALL,
2913 EL_INVISIBLE_STEELWALL_ACTIVE,
2915 EL_INVISIBLE_WALL_ACTIVE,
2916 EL_STEELWALL_SLIPPERY,
2933 static int ep_historic_solid[] =
2937 EL_EXPANDABLE_WALL_HORIZONTAL,
2938 EL_EXPANDABLE_WALL_VERTICAL,
2939 EL_EXPANDABLE_WALL_ANY,
2952 EL_QUICKSAND_FILLING,
2953 EL_QUICKSAND_EMPTYING,
2955 EL_MAGIC_WALL_ACTIVE,
2956 EL_MAGIC_WALL_EMPTYING,
2957 EL_MAGIC_WALL_FILLING,
2961 EL_BD_MAGIC_WALL_ACTIVE,
2962 EL_BD_MAGIC_WALL_EMPTYING,
2963 EL_BD_MAGIC_WALL_FULL,
2964 EL_BD_MAGIC_WALL_FILLING,
2965 EL_BD_MAGIC_WALL_DEAD,
2974 EL_SP_TERMINAL_ACTIVE,
2978 EL_INVISIBLE_WALL_ACTIVE,
2979 EL_SWITCHGATE_SWITCH_UP,
2980 EL_SWITCHGATE_SWITCH_DOWN,
2982 EL_TIMEGATE_SWITCH_ACTIVE,
2994 /* the following elements are a direct copy of "indestructible" elements,
2995 except "EL_ACID", which is "indestructible", but not "solid"! */
3000 EL_ACID_POOL_TOPLEFT,
3001 EL_ACID_POOL_TOPRIGHT,
3002 EL_ACID_POOL_BOTTOMLEFT,
3003 EL_ACID_POOL_BOTTOM,
3004 EL_ACID_POOL_BOTTOMRIGHT,
3005 EL_SP_HARDWARE_GRAY,
3006 EL_SP_HARDWARE_GREEN,
3007 EL_SP_HARDWARE_BLUE,
3009 EL_SP_HARDWARE_YELLOW,
3010 EL_SP_HARDWARE_BASE_1,
3011 EL_SP_HARDWARE_BASE_2,
3012 EL_SP_HARDWARE_BASE_3,
3013 EL_SP_HARDWARE_BASE_4,
3014 EL_SP_HARDWARE_BASE_5,
3015 EL_SP_HARDWARE_BASE_6,
3016 EL_INVISIBLE_STEELWALL,
3017 EL_INVISIBLE_STEELWALL_ACTIVE,
3018 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3019 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3020 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3021 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3022 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3023 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3024 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3025 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3026 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3027 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3028 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3029 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3031 EL_LIGHT_SWITCH_ACTIVE,
3032 EL_SIGN_EXCLAMATION,
3033 EL_SIGN_RADIOACTIVITY,
3044 EL_STEELWALL_SLIPPERY,
3058 EL_GATE_1_GRAY_ACTIVE,
3059 EL_GATE_2_GRAY_ACTIVE,
3060 EL_GATE_3_GRAY_ACTIVE,
3061 EL_GATE_4_GRAY_ACTIVE,
3070 EL_EM_GATE_1_GRAY_ACTIVE,
3071 EL_EM_GATE_2_GRAY_ACTIVE,
3072 EL_EM_GATE_3_GRAY_ACTIVE,
3073 EL_EM_GATE_4_GRAY_ACTIVE,
3075 EL_SWITCHGATE_OPENING,
3076 EL_SWITCHGATE_CLOSED,
3077 EL_SWITCHGATE_CLOSING,
3079 EL_TIMEGATE_OPENING,
3081 EL_TIMEGATE_CLOSING,
3085 EL_TUBE_VERTICAL_LEFT,
3086 EL_TUBE_VERTICAL_RIGHT,
3087 EL_TUBE_HORIZONTAL_UP,
3088 EL_TUBE_HORIZONTAL_DOWN,
3097 static int ep_classic_enemy[] =
3114 static int ep_belt[] =
3116 EL_CONVEYOR_BELT_1_LEFT,
3117 EL_CONVEYOR_BELT_1_MIDDLE,
3118 EL_CONVEYOR_BELT_1_RIGHT,
3119 EL_CONVEYOR_BELT_2_LEFT,
3120 EL_CONVEYOR_BELT_2_MIDDLE,
3121 EL_CONVEYOR_BELT_2_RIGHT,
3122 EL_CONVEYOR_BELT_3_LEFT,
3123 EL_CONVEYOR_BELT_3_MIDDLE,
3124 EL_CONVEYOR_BELT_3_RIGHT,
3125 EL_CONVEYOR_BELT_4_LEFT,
3126 EL_CONVEYOR_BELT_4_MIDDLE,
3127 EL_CONVEYOR_BELT_4_RIGHT,
3132 static int ep_belt_active[] =
3134 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3135 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3136 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3137 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3138 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3139 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3140 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3141 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3142 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3143 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3144 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3145 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3150 static int ep_belt_switch[] =
3152 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3153 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3154 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3155 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3156 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3157 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3158 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3159 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3160 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3161 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3162 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3163 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3168 static int ep_tube[] =
3175 EL_TUBE_HORIZONTAL_UP,
3176 EL_TUBE_HORIZONTAL_DOWN,
3178 EL_TUBE_VERTICAL_LEFT,
3179 EL_TUBE_VERTICAL_RIGHT,
3185 static int ep_keygate[] =
3195 EL_GATE_1_GRAY_ACTIVE,
3196 EL_GATE_2_GRAY_ACTIVE,
3197 EL_GATE_3_GRAY_ACTIVE,
3198 EL_GATE_4_GRAY_ACTIVE,
3207 EL_EM_GATE_1_GRAY_ACTIVE,
3208 EL_EM_GATE_2_GRAY_ACTIVE,
3209 EL_EM_GATE_3_GRAY_ACTIVE,
3210 EL_EM_GATE_4_GRAY_ACTIVE,
3219 EL_EMC_GATE_5_GRAY_ACTIVE,
3220 EL_EMC_GATE_6_GRAY_ACTIVE,
3221 EL_EMC_GATE_7_GRAY_ACTIVE,
3222 EL_EMC_GATE_8_GRAY_ACTIVE,
3227 static int ep_amoeboid[] =
3239 static int ep_amoebalive[] =
3250 static int ep_has_editor_content[] =
3272 static int ep_can_turn_each_move[] =
3274 /* !!! do something with this one !!! */
3278 static int ep_can_grow[] =
3292 static int ep_active_bomb[] =
3295 EL_EM_DYNAMITE_ACTIVE,
3296 EL_DYNABOMB_PLAYER_1_ACTIVE,
3297 EL_DYNABOMB_PLAYER_2_ACTIVE,
3298 EL_DYNABOMB_PLAYER_3_ACTIVE,
3299 EL_DYNABOMB_PLAYER_4_ACTIVE,
3300 EL_SP_DISK_RED_ACTIVE,
3305 static int ep_inactive[] =
3337 EL_GATE_1_GRAY_ACTIVE,
3338 EL_GATE_2_GRAY_ACTIVE,
3339 EL_GATE_3_GRAY_ACTIVE,
3340 EL_GATE_4_GRAY_ACTIVE,
3349 EL_EM_GATE_1_GRAY_ACTIVE,
3350 EL_EM_GATE_2_GRAY_ACTIVE,
3351 EL_EM_GATE_3_GRAY_ACTIVE,
3352 EL_EM_GATE_4_GRAY_ACTIVE,
3361 EL_EMC_GATE_5_GRAY_ACTIVE,
3362 EL_EMC_GATE_6_GRAY_ACTIVE,
3363 EL_EMC_GATE_7_GRAY_ACTIVE,
3364 EL_EMC_GATE_8_GRAY_ACTIVE,
3367 EL_INVISIBLE_STEELWALL,
3375 EL_WALL_EMERALD_YELLOW,
3376 EL_DYNABOMB_INCREASE_NUMBER,
3377 EL_DYNABOMB_INCREASE_SIZE,
3378 EL_DYNABOMB_INCREASE_POWER,
3382 EL_SOKOBAN_FIELD_EMPTY,
3383 EL_SOKOBAN_FIELD_FULL,
3384 EL_WALL_EMERALD_RED,
3385 EL_WALL_EMERALD_PURPLE,
3386 EL_ACID_POOL_TOPLEFT,
3387 EL_ACID_POOL_TOPRIGHT,
3388 EL_ACID_POOL_BOTTOMLEFT,
3389 EL_ACID_POOL_BOTTOM,
3390 EL_ACID_POOL_BOTTOMRIGHT,
3394 EL_BD_MAGIC_WALL_DEAD,
3395 EL_AMOEBA_TO_DIAMOND,
3403 EL_SP_GRAVITY_PORT_RIGHT,
3404 EL_SP_GRAVITY_PORT_DOWN,
3405 EL_SP_GRAVITY_PORT_LEFT,
3406 EL_SP_GRAVITY_PORT_UP,
3407 EL_SP_PORT_HORIZONTAL,
3408 EL_SP_PORT_VERTICAL,
3419 EL_SP_HARDWARE_GRAY,
3420 EL_SP_HARDWARE_GREEN,
3421 EL_SP_HARDWARE_BLUE,
3423 EL_SP_HARDWARE_YELLOW,
3424 EL_SP_HARDWARE_BASE_1,
3425 EL_SP_HARDWARE_BASE_2,
3426 EL_SP_HARDWARE_BASE_3,
3427 EL_SP_HARDWARE_BASE_4,
3428 EL_SP_HARDWARE_BASE_5,
3429 EL_SP_HARDWARE_BASE_6,
3430 EL_SP_GRAVITY_ON_PORT_LEFT,
3431 EL_SP_GRAVITY_ON_PORT_RIGHT,
3432 EL_SP_GRAVITY_ON_PORT_UP,
3433 EL_SP_GRAVITY_ON_PORT_DOWN,
3434 EL_SP_GRAVITY_OFF_PORT_LEFT,
3435 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3436 EL_SP_GRAVITY_OFF_PORT_UP,
3437 EL_SP_GRAVITY_OFF_PORT_DOWN,
3438 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3439 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3440 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3441 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3442 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3443 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3444 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3445 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3446 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3447 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3448 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3449 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3450 EL_SIGN_EXCLAMATION,
3451 EL_SIGN_RADIOACTIVITY,
3462 EL_STEELWALL_SLIPPERY,
3467 EL_EMC_WALL_SLIPPERY_1,
3468 EL_EMC_WALL_SLIPPERY_2,
3469 EL_EMC_WALL_SLIPPERY_3,
3470 EL_EMC_WALL_SLIPPERY_4,
3491 static int ep_em_slippery_wall[] =
3496 static int ep_gfx_crumbled[] =
3506 static int ep_editor_cascade_active[] =
3508 EL_INTERNAL_CASCADE_BD_ACTIVE,
3509 EL_INTERNAL_CASCADE_EM_ACTIVE,
3510 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3511 EL_INTERNAL_CASCADE_RND_ACTIVE,
3512 EL_INTERNAL_CASCADE_SB_ACTIVE,
3513 EL_INTERNAL_CASCADE_SP_ACTIVE,
3514 EL_INTERNAL_CASCADE_DC_ACTIVE,
3515 EL_INTERNAL_CASCADE_DX_ACTIVE,
3516 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3517 EL_INTERNAL_CASCADE_CE_ACTIVE,
3518 EL_INTERNAL_CASCADE_GE_ACTIVE,
3519 EL_INTERNAL_CASCADE_USER_ACTIVE,
3520 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3521 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3526 static int ep_editor_cascade_inactive[] =
3528 EL_INTERNAL_CASCADE_BD,
3529 EL_INTERNAL_CASCADE_EM,
3530 EL_INTERNAL_CASCADE_EMC,
3531 EL_INTERNAL_CASCADE_RND,
3532 EL_INTERNAL_CASCADE_SB,
3533 EL_INTERNAL_CASCADE_SP,
3534 EL_INTERNAL_CASCADE_DC,
3535 EL_INTERNAL_CASCADE_DX,
3536 EL_INTERNAL_CASCADE_CHARS,
3537 EL_INTERNAL_CASCADE_CE,
3538 EL_INTERNAL_CASCADE_GE,
3539 EL_INTERNAL_CASCADE_USER,
3540 EL_INTERNAL_CASCADE_GENERIC,
3541 EL_INTERNAL_CASCADE_DYNAMIC,
3550 } element_properties[] =
3552 { ep_diggable, EP_DIGGABLE },
3553 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3554 { ep_dont_run_into, EP_DONT_RUN_INTO },
3555 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3556 { ep_dont_touch, EP_DONT_TOUCH },
3557 { ep_indestructible, EP_INDESTRUCTIBLE },
3558 { ep_slippery, EP_SLIPPERY },
3559 { ep_can_change, EP_CAN_CHANGE },
3560 { ep_can_move, EP_CAN_MOVE },
3561 { ep_can_fall, EP_CAN_FALL },
3562 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3563 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3564 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3565 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3566 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3567 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3568 { ep_walkable_over, EP_WALKABLE_OVER },
3569 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3570 { ep_walkable_under, EP_WALKABLE_UNDER },
3571 { ep_passable_over, EP_PASSABLE_OVER },
3572 { ep_passable_inside, EP_PASSABLE_INSIDE },
3573 { ep_passable_under, EP_PASSABLE_UNDER },
3574 { ep_droppable, EP_DROPPABLE },
3575 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3576 { ep_pushable, EP_PUSHABLE },
3577 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3578 { ep_protected, EP_PROTECTED },
3579 { ep_throwable, EP_THROWABLE },
3580 { ep_can_explode, EP_CAN_EXPLODE },
3581 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3583 { ep_player, EP_PLAYER },
3584 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3585 { ep_switchable, EP_SWITCHABLE },
3586 { ep_bd_element, EP_BD_ELEMENT },
3587 { ep_sp_element, EP_SP_ELEMENT },
3588 { ep_sb_element, EP_SB_ELEMENT },
3590 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3591 { ep_food_penguin, EP_FOOD_PENGUIN },
3592 { ep_food_pig, EP_FOOD_PIG },
3593 { ep_historic_wall, EP_HISTORIC_WALL },
3594 { ep_historic_solid, EP_HISTORIC_SOLID },
3595 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3596 { ep_belt, EP_BELT },
3597 { ep_belt_active, EP_BELT_ACTIVE },
3598 { ep_belt_switch, EP_BELT_SWITCH },
3599 { ep_tube, EP_TUBE },
3600 { ep_keygate, EP_KEYGATE },
3601 { ep_amoeboid, EP_AMOEBOID },
3602 { ep_amoebalive, EP_AMOEBALIVE },
3603 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3604 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3605 { ep_can_grow, EP_CAN_GROW },
3606 { ep_active_bomb, EP_ACTIVE_BOMB },
3607 { ep_inactive, EP_INACTIVE },
3609 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3611 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3613 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3614 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3621 /* always start with reliable default values (element has no properties) */
3622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3623 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3624 SET_PROPERTY(i, j, FALSE);
3626 /* set all base element properties from above array definitions */
3627 for (i = 0; element_properties[i].elements != NULL; i++)
3628 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3629 SET_PROPERTY((element_properties[i].elements)[j],
3630 element_properties[i].property, TRUE);
3632 /* copy properties to some elements that are only stored in level file */
3633 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3634 for (j = 0; copy_properties[j][0] != -1; j++)
3635 if (HAS_PROPERTY(copy_properties[j][0], i))
3636 for (k = 1; k <= 4; k++)
3637 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3640 void InitElementPropertiesEngine(int engine_version)
3642 static int no_wall_properties[] =
3645 EP_COLLECTIBLE_ONLY,
3647 EP_DONT_COLLIDE_WITH,
3650 EP_CAN_SMASH_PLAYER,
3651 EP_CAN_SMASH_ENEMIES,
3652 EP_CAN_SMASH_EVERYTHING,
3657 EP_FOOD_DARK_YAMYAM,
3673 /* important: after initialization in InitElementPropertiesStatic(), the
3674 elements are not again initialized to a default value; therefore all
3675 changes have to make sure that they leave the element with a defined
3676 property (which means that conditional property changes must be set to
3677 a reliable default value before) */
3680 /* ---------- recursively resolve group elements ------------------------- */
3682 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3683 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3684 element_info[i].in_group[j] = FALSE;
3686 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3687 resolve_group_element(EL_GROUP_START + i, 0);
3690 /* set all special, combined or engine dependent element properties */
3691 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3693 /* ---------- INACTIVE ------------------------------------------------- */
3694 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3696 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3697 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3698 IS_WALKABLE_INSIDE(i) ||
3699 IS_WALKABLE_UNDER(i)));
3701 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3702 IS_PASSABLE_INSIDE(i) ||
3703 IS_PASSABLE_UNDER(i)));
3705 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3706 IS_PASSABLE_OVER(i)));
3708 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3709 IS_PASSABLE_INSIDE(i)));
3711 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3712 IS_PASSABLE_UNDER(i)));
3714 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3717 /* ---------- COLLECTIBLE ---------------------------------------------- */
3718 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3722 /* ---------- SNAPPABLE ------------------------------------------------ */
3723 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3724 IS_COLLECTIBLE(i) ||
3728 /* ---------- WALL ----------------------------------------------------- */
3729 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3731 for (j = 0; no_wall_properties[j] != -1; j++)
3732 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3733 i >= EL_FIRST_RUNTIME_UNREAL)
3734 SET_PROPERTY(i, EP_WALL, FALSE);
3736 if (IS_HISTORIC_WALL(i))
3737 SET_PROPERTY(i, EP_WALL, TRUE);
3739 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3740 if (engine_version < VERSION_IDENT(2,2,0,0))
3741 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3743 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3745 !IS_COLLECTIBLE(i)));
3747 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3749 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3750 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3752 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3753 IS_INDESTRUCTIBLE(i)));
3755 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3757 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3758 else if (engine_version < VERSION_IDENT(2,2,0,0))
3759 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3761 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3765 if (IS_CUSTOM_ELEMENT(i))
3767 /* these are additional properties which are initially false when set */
3769 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3771 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3772 if (DONT_COLLIDE_WITH(i))
3773 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3775 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3776 if (CAN_SMASH_EVERYTHING(i))
3777 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3778 if (CAN_SMASH_ENEMIES(i))
3779 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3782 /* ---------- CAN_SMASH ------------------------------------------------ */
3783 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3784 CAN_SMASH_ENEMIES(i) ||
3785 CAN_SMASH_EVERYTHING(i)));
3787 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3788 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3789 EXPLODES_BY_FIRE(i)));
3791 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3792 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3793 EXPLODES_SMASHED(i)));
3795 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3796 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3797 EXPLODES_IMPACT(i)));
3799 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3800 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3802 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3803 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3804 i == EL_BLACK_ORB));
3806 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3807 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3809 IS_CUSTOM_ELEMENT(i)));
3811 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3812 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3813 i == EL_SP_ELECTRON));
3815 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3816 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3817 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3818 getMoveIntoAcidProperty(&level, i));
3820 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3821 if (MAYBE_DONT_COLLIDE_WITH(i))
3822 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3823 getDontCollideWithProperty(&level, i));
3825 /* ---------- SP_PORT -------------------------------------------------- */
3826 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3827 IS_PASSABLE_INSIDE(i)));
3829 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3830 for (j = 0; j < level.num_android_clone_elements; j++)
3831 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3833 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3835 /* ---------- CAN_CHANGE ----------------------------------------------- */
3836 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3837 for (j = 0; j < element_info[i].num_change_pages; j++)
3838 if (element_info[i].change_page[j].can_change)
3839 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3841 /* ---------- HAS_ACTION ----------------------------------------------- */
3842 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3843 for (j = 0; j < element_info[i].num_change_pages; j++)
3844 if (element_info[i].change_page[j].has_action)
3845 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3847 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3848 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3851 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3853 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3854 element_info[i].crumbled[ACTION_DEFAULT] !=
3855 element_info[i].graphic[ACTION_DEFAULT]);
3857 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3858 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3859 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3862 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3863 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3864 IS_EDITOR_CASCADE_INACTIVE(i)));
3867 /* dynamically adjust element properties according to game engine version */
3869 static int ep_em_slippery_wall[] =
3874 EL_EXPANDABLE_WALL_HORIZONTAL,
3875 EL_EXPANDABLE_WALL_VERTICAL,
3876 EL_EXPANDABLE_WALL_ANY,
3880 /* special EM style gems behaviour */
3881 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3882 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3883 level.em_slippery_gems);
3885 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3886 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3887 (level.em_slippery_gems &&
3888 engine_version > VERSION_IDENT(2,0,1,0)));
3891 /* set default push delay values (corrected since version 3.0.7-1) */
3892 if (engine_version < VERSION_IDENT(3,0,7,1))
3894 game.default_push_delay_fixed = 2;
3895 game.default_push_delay_random = 8;
3899 game.default_push_delay_fixed = 8;
3900 game.default_push_delay_random = 8;
3903 /* set uninitialized push delay values of custom elements in older levels */
3904 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3906 int element = EL_CUSTOM_START + i;
3908 if (element_info[element].push_delay_fixed == -1)
3909 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3910 if (element_info[element].push_delay_random == -1)
3911 element_info[element].push_delay_random = game.default_push_delay_random;
3914 /* set some other uninitialized values of custom elements in older levels */
3915 if (engine_version < VERSION_IDENT(3,1,0,0))
3917 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3919 int element = EL_CUSTOM_START + i;
3921 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3923 element_info[element].explosion_delay = 17;
3924 element_info[element].ignition_delay = 8;
3929 /* set element properties that were handled incorrectly in older levels */
3930 if (engine_version < VERSION_IDENT(3,1,0,0))
3932 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3933 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3937 /* this is needed because some graphics depend on element properties */
3938 if (game_status == GAME_MODE_PLAYING)
3939 InitElementGraphicInfo();
3942 static void InitGlobal()
3946 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3948 /* check if element_name_info entry defined for each element in "main.h" */
3949 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3950 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3952 element_info[i].token_name = element_name_info[i].token_name;
3953 element_info[i].class_name = element_name_info[i].class_name;
3954 element_info[i].editor_description=element_name_info[i].editor_description;
3957 global.autoplay_leveldir = NULL;
3958 global.convert_leveldir = NULL;
3960 global.frames_per_second = 0;
3961 global.fps_slowdown = FALSE;
3962 global.fps_slowdown_factor = 1;
3965 void Execute_Command(char *command)
3969 if (strcmp(command, "print graphicsinfo.conf") == 0)
3971 printf("# You can configure additional/alternative image files here.\n");
3972 printf("# (The entries below are default and therefore commented out.)\n");
3974 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3976 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3979 for (i = 0; image_config[i].token != NULL; i++)
3980 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3981 image_config[i].value));
3985 else if (strcmp(command, "print soundsinfo.conf") == 0)
3987 printf("# You can configure additional/alternative sound files here.\n");
3988 printf("# (The entries below are default and therefore commented out.)\n");
3990 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3992 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3995 for (i = 0; sound_config[i].token != NULL; i++)
3996 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3997 sound_config[i].value));
4001 else if (strcmp(command, "print musicinfo.conf") == 0)
4003 printf("# You can configure additional/alternative music files here.\n");
4004 printf("# (The entries below are default and therefore commented out.)\n");
4006 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4008 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4011 for (i = 0; music_config[i].token != NULL; i++)
4012 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4013 music_config[i].value));
4017 else if (strcmp(command, "print editorsetup.conf") == 0)
4019 printf("# You can configure your personal editor element list here.\n");
4020 printf("# (The entries below are default and therefore commented out.)\n");
4023 /* this is needed to be able to check element list for cascade elements */
4024 InitElementPropertiesStatic();
4025 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4027 PrintEditorElementList();
4031 else if (strcmp(command, "print helpanim.conf") == 0)
4033 printf("# You can configure different element help animations here.\n");
4034 printf("# (The entries below are default and therefore commented out.)\n");
4037 for (i = 0; helpanim_config[i].token != NULL; i++)
4039 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4040 helpanim_config[i].value));
4042 if (strcmp(helpanim_config[i].token, "end") == 0)
4048 else if (strcmp(command, "print helptext.conf") == 0)
4050 printf("# You can configure different element help text here.\n");
4051 printf("# (The entries below are default and therefore commented out.)\n");
4054 for (i = 0; helptext_config[i].token != NULL; i++)
4055 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4056 helptext_config[i].value));
4060 else if (strncmp(command, "dump level ", 11) == 0)
4062 char *filename = &command[11];
4064 if (!fileExists(filename))
4065 Error(ERR_EXIT, "cannot open file '%s'", filename);
4067 LoadLevelFromFilename(&level, filename);
4072 else if (strncmp(command, "dump tape ", 10) == 0)
4074 char *filename = &command[10];
4076 if (!fileExists(filename))
4077 Error(ERR_EXIT, "cannot open file '%s'", filename);
4079 LoadTapeFromFilename(filename);
4084 else if (strncmp(command, "autoplay ", 9) == 0)
4086 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4088 while (*str_ptr != '\0') /* continue parsing string */
4090 /* cut leading whitespace from string, replace it by string terminator */
4091 while (*str_ptr == ' ' || *str_ptr == '\t')
4094 if (*str_ptr == '\0') /* end of string reached */
4097 if (global.autoplay_leveldir == NULL) /* read level set string */
4099 global.autoplay_leveldir = str_ptr;
4100 global.autoplay_all = TRUE; /* default: play all tapes */
4102 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4103 global.autoplay_level[i] = FALSE;
4105 else /* read level number string */
4107 int level_nr = atoi(str_ptr); /* get level_nr value */
4109 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4110 global.autoplay_level[level_nr] = TRUE;
4112 global.autoplay_all = FALSE;
4115 /* advance string pointer to the next whitespace (or end of string) */
4116 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4120 else if (strncmp(command, "convert ", 8) == 0)
4122 char *str_copy = getStringCopy(&command[8]);
4123 char *str_ptr = strchr(str_copy, ' ');
4125 global.convert_leveldir = str_copy;
4126 global.convert_level_nr = -1;
4128 if (str_ptr != NULL) /* level number follows */
4130 *str_ptr++ = '\0'; /* terminate leveldir string */
4131 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4136 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4140 static void InitSetup()
4142 LoadSetup(); /* global setup info */
4144 /* set some options from setup file */
4146 if (setup.options.verbose)
4147 options.verbose = TRUE;
4150 static void InitGameInfo()
4152 game.restart_level = FALSE;
4155 static void InitPlayerInfo()
4159 /* choose default local player */
4160 local_player = &stored_player[0];
4162 for (i = 0; i < MAX_PLAYERS; i++)
4163 stored_player[i].connected = FALSE;
4165 local_player->connected = TRUE;
4168 static void InitArtworkInfo()
4173 static char *get_string_in_brackets(char *string)
4175 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4177 sprintf(string_in_brackets, "[%s]", string);
4179 return string_in_brackets;
4182 static char *get_level_id_suffix(int id_nr)
4184 char *id_suffix = checked_malloc(1 + 3 + 1);
4186 if (id_nr < 0 || id_nr > 999)
4189 sprintf(id_suffix, ".%03d", id_nr);
4195 static char *get_element_class_token(int element)
4197 char *element_class_name = element_info[element].class_name;
4198 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4200 sprintf(element_class_token, "[%s]", element_class_name);
4202 return element_class_token;
4205 static char *get_action_class_token(int action)
4207 char *action_class_name = &element_action_info[action].suffix[1];
4208 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4210 sprintf(action_class_token, "[%s]", action_class_name);
4212 return action_class_token;
4216 static void InitArtworkConfig()
4218 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4219 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4220 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4221 static char *action_id_suffix[NUM_ACTIONS + 1];
4222 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4223 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4224 static char *level_id_suffix[MAX_LEVELS + 1];
4225 static char *dummy[1] = { NULL };
4226 static char *ignore_generic_tokens[] =
4232 static char **ignore_image_tokens;
4233 static char **ignore_sound_tokens;
4234 static char **ignore_music_tokens;
4235 int num_ignore_generic_tokens;
4236 int num_ignore_image_tokens;
4237 int num_ignore_sound_tokens;
4238 int num_ignore_music_tokens;
4241 /* dynamically determine list of generic tokens to be ignored */
4242 num_ignore_generic_tokens = 0;
4243 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4244 num_ignore_generic_tokens++;
4246 /* dynamically determine list of image tokens to be ignored */
4247 num_ignore_image_tokens = num_ignore_generic_tokens;
4248 for (i = 0; image_config_vars[i].token != NULL; i++)
4249 num_ignore_image_tokens++;
4250 ignore_image_tokens =
4251 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4252 for (i = 0; i < num_ignore_generic_tokens; i++)
4253 ignore_image_tokens[i] = ignore_generic_tokens[i];
4254 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4255 ignore_image_tokens[num_ignore_generic_tokens + i] =
4256 image_config_vars[i].token;
4257 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4259 /* dynamically determine list of sound tokens to be ignored */
4260 num_ignore_sound_tokens = num_ignore_generic_tokens;
4261 ignore_sound_tokens =
4262 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4263 for (i = 0; i < num_ignore_generic_tokens; i++)
4264 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4265 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4267 /* dynamically determine list of music tokens to be ignored */
4268 num_ignore_music_tokens = num_ignore_generic_tokens;
4269 ignore_music_tokens =
4270 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4271 for (i = 0; i < num_ignore_generic_tokens; i++)
4272 ignore_music_tokens[i] = ignore_generic_tokens[i];
4273 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4275 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4276 image_id_prefix[i] = element_info[i].token_name;
4277 for (i = 0; i < NUM_FONTS; i++)
4278 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4279 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4281 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4282 sound_id_prefix[i] = element_info[i].token_name;
4283 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4284 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4285 get_string_in_brackets(element_info[i].class_name);
4286 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4288 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4289 music_id_prefix[i] = music_prefix_info[i].prefix;
4290 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4292 for (i = 0; i < NUM_ACTIONS; i++)
4293 action_id_suffix[i] = element_action_info[i].suffix;
4294 action_id_suffix[NUM_ACTIONS] = NULL;
4296 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4297 direction_id_suffix[i] = element_direction_info[i].suffix;
4298 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4300 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4301 special_id_suffix[i] = special_suffix_info[i].suffix;
4302 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4304 for (i = 0; i < MAX_LEVELS; i++)
4305 level_id_suffix[i] = get_level_id_suffix(i);
4306 level_id_suffix[MAX_LEVELS] = NULL;
4308 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4309 image_id_prefix, action_id_suffix, direction_id_suffix,
4310 special_id_suffix, ignore_image_tokens);
4311 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4312 sound_id_prefix, action_id_suffix, dummy,
4313 special_id_suffix, ignore_sound_tokens);
4314 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4315 music_id_prefix, special_id_suffix, level_id_suffix,
4316 dummy, ignore_music_tokens);
4319 static void InitMixer()
4327 char *filename_font_initial = NULL;
4328 Bitmap *bitmap_font_initial = NULL;
4331 /* determine settings for initial font (for displaying startup messages) */
4332 for (i = 0; image_config[i].token != NULL; i++)
4334 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4336 char font_token[128];
4339 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4340 len_font_token = strlen(font_token);
4342 if (strcmp(image_config[i].token, font_token) == 0)
4343 filename_font_initial = image_config[i].value;
4344 else if (strlen(image_config[i].token) > len_font_token &&
4345 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4347 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4348 font_initial[j].src_x = atoi(image_config[i].value);
4349 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4350 font_initial[j].src_y = atoi(image_config[i].value);
4351 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4352 font_initial[j].width = atoi(image_config[i].value);
4353 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4354 font_initial[j].height = atoi(image_config[i].value);
4359 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4361 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4362 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4365 if (filename_font_initial == NULL) /* should not happen */
4366 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4368 /* create additional image buffers for double-buffering */
4369 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4370 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4372 /* initialize screen properties */
4373 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4374 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4376 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4377 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4378 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4380 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4382 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4383 font_initial[j].bitmap = bitmap_font_initial;
4385 InitFontGraphicInfo();
4387 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4388 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4390 DrawInitText("Loading graphics:", 120, FC_GREEN);
4393 void InitGfxBackground()
4397 drawto = backbuffer;
4398 fieldbuffer = bitmap_db_field;
4399 SetDrawtoField(DRAW_BACKBUFFER);
4401 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4402 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4403 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4404 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4406 for (x = 0; x < MAX_BUF_XSIZE; x++)
4407 for (y = 0; y < MAX_BUF_YSIZE; y++)
4410 redraw_mask = REDRAW_ALL;
4413 static void InitLevelInfo()
4415 LoadLevelInfo(); /* global level info */
4416 LoadLevelSetup_LastSeries(); /* last played series info */
4417 LoadLevelSetup_SeriesInfo(); /* last played level info */
4420 void InitLevelArtworkInfo()
4422 LoadLevelArtworkInfo();
4425 static void InitImages()
4427 setLevelArtworkDir(artwork.gfx_first);
4430 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4431 leveldir_current->identifier,
4432 artwork.gfx_current_identifier,
4433 artwork.gfx_current->identifier,
4434 leveldir_current->graphics_set,
4435 leveldir_current->graphics_path);
4438 ReloadCustomImages();
4440 LoadCustomElementDescriptions();
4441 LoadSpecialMenuDesignSettings();
4443 ReinitializeGraphics();
4446 static void InitSound(char *identifier)
4448 if (identifier == NULL)
4449 identifier = artwork.snd_current->identifier;
4451 /* set artwork path to send it to the sound server process */
4452 setLevelArtworkDir(artwork.snd_first);
4454 InitReloadCustomSounds(identifier);
4455 ReinitializeSounds();
4458 static void InitMusic(char *identifier)
4460 if (identifier == NULL)
4461 identifier = artwork.mus_current->identifier;
4463 /* set artwork path to send it to the sound server process */
4464 setLevelArtworkDir(artwork.mus_first);
4466 InitReloadCustomMusic(identifier);
4467 ReinitializeMusic();
4470 void InitNetworkServer()
4472 #if defined(NETWORK_AVALIABLE)
4476 if (!options.network)
4479 #if defined(NETWORK_AVALIABLE)
4480 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4482 if (!ConnectToServer(options.server_host, options.server_port))
4483 Error(ERR_EXIT, "cannot connect to network game server");
4485 SendToServer_PlayerName(setup.player_name);
4486 SendToServer_ProtocolVersion();
4489 SendToServer_NrWanted(nr_wanted);
4493 static char *getNewArtworkIdentifier(int type)
4495 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4496 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4497 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4498 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4499 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4500 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4501 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4502 char *leveldir_identifier = leveldir_current->identifier;
4504 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4505 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4507 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4509 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4510 char *artwork_current_identifier;
4511 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4513 /* leveldir_current may be invalid (level group, parent link) */
4514 if (!validLevelSeries(leveldir_current))
4517 /* 1st step: determine artwork set to be activated in descending order:
4518 --------------------------------------------------------------------
4519 1. setup artwork (when configured to override everything else)
4520 2. artwork set configured in "levelinfo.conf" of current level set
4521 (artwork in level directory will have priority when loading later)
4522 3. artwork in level directory (stored in artwork sub-directory)
4523 4. setup artwork (currently configured in setup menu) */
4525 if (setup_override_artwork)
4526 artwork_current_identifier = setup_artwork_set;
4527 else if (leveldir_artwork_set != NULL)
4528 artwork_current_identifier = leveldir_artwork_set;
4529 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4530 artwork_current_identifier = leveldir_identifier;
4532 artwork_current_identifier = setup_artwork_set;
4535 /* 2nd step: check if it is really needed to reload artwork set
4536 ------------------------------------------------------------ */
4539 if (type == ARTWORK_TYPE_GRAPHICS)
4540 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4541 artwork_new_identifier,
4542 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4543 artwork_current_identifier,
4544 leveldir_current->graphics_set,
4545 leveldir_current->identifier);
4548 /* ---------- reload if level set and also artwork set has changed ------- */
4549 if (leveldir_current_identifier[type] != leveldir_identifier &&
4550 (last_has_level_artwork_set[type] || has_level_artwork_set))
4551 artwork_new_identifier = artwork_current_identifier;
4553 leveldir_current_identifier[type] = leveldir_identifier;
4554 last_has_level_artwork_set[type] = has_level_artwork_set;
4557 if (type == ARTWORK_TYPE_GRAPHICS)
4558 printf("::: 1: '%s'\n", artwork_new_identifier);
4561 /* ---------- reload if "override artwork" setting has changed ----------- */
4562 if (last_override_level_artwork[type] != setup_override_artwork)
4563 artwork_new_identifier = artwork_current_identifier;
4565 last_override_level_artwork[type] = setup_override_artwork;
4568 if (type == ARTWORK_TYPE_GRAPHICS)
4569 printf("::: 2: '%s'\n", artwork_new_identifier);
4572 /* ---------- reload if current artwork identifier has changed ----------- */
4573 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4574 artwork_current_identifier) != 0)
4575 artwork_new_identifier = artwork_current_identifier;
4577 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4580 if (type == ARTWORK_TYPE_GRAPHICS)
4581 printf("::: 3: '%s'\n", artwork_new_identifier);
4584 /* ---------- do not reload directly after starting ---------------------- */
4585 if (!initialized[type])
4586 artwork_new_identifier = NULL;
4588 initialized[type] = TRUE;
4591 if (type == ARTWORK_TYPE_GRAPHICS)
4592 printf("::: 4: '%s'\n", artwork_new_identifier);
4596 if (type == ARTWORK_TYPE_GRAPHICS)
4597 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4598 artwork.gfx_current_identifier, artwork_current_identifier,
4599 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4600 artwork_new_identifier);
4603 return artwork_new_identifier;
4606 void ReloadCustomArtwork(int force_reload)
4608 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4609 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4610 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4611 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4612 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4613 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4614 boolean redraw_screen = FALSE;
4616 if (gfx_new_identifier != NULL || force_reload_gfx)
4619 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4620 artwork.gfx_current_identifier,
4622 artwork.gfx_current->identifier,
4623 leveldir_current->graphics_set);
4626 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4630 redraw_screen = TRUE;
4633 if (snd_new_identifier != NULL || force_reload_snd)
4635 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4637 InitSound(snd_new_identifier);
4639 redraw_screen = TRUE;
4642 if (mus_new_identifier != NULL || force_reload_mus)
4644 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4646 InitMusic(mus_new_identifier);
4648 redraw_screen = TRUE;
4653 InitGfxBackground();
4655 /* force redraw of (open or closed) door graphics */
4656 SetDoorState(DOOR_OPEN_ALL);
4657 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4661 void KeyboardAutoRepeatOffUnlessAutoplay()
4663 if (global.autoplay_leveldir == NULL)
4664 KeyboardAutoRepeatOff();
4668 /* ========================================================================= */
4670 /* ========================================================================= */
4674 InitGlobal(); /* initialize some global variables */
4676 if (options.execute_command)
4677 Execute_Command(options.execute_command);
4679 if (options.serveronly)
4681 #if defined(PLATFORM_UNIX)
4682 NetworkServer(options.server_port, options.serveronly);
4684 Error(ERR_WARN, "networking only supported in Unix version");
4687 exit(0); /* never reached, server loops forever */
4694 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4695 InitArtworkConfig(); /* needed before forking sound child process */
4700 InitRND(NEW_RANDOMIZE);
4701 InitSimpleRND(NEW_RANDOMIZE);
4706 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4709 InitEventFilter(FilterMouseMotionEvents);
4711 InitElementPropertiesStatic();
4712 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4717 InitLevelArtworkInfo();
4719 InitImages(); /* needs to know current level directory */
4720 InitSound(NULL); /* needs to know current level directory */
4721 InitMusic(NULL); /* needs to know current level directory */
4723 InitGfxBackground();
4725 if (global.autoplay_leveldir)
4730 else if (global.convert_leveldir)
4736 game_status = GAME_MODE_MAIN;
4744 InitNetworkServer();
4747 void CloseAllAndExit(int exit_value)
4752 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4760 #if defined(TARGET_SDL)
4761 if (network_server) /* terminate network server */
4762 SDL_KillThread(server_thread);
4765 CloseVideoDisplay();
4766 ClosePlatformDependentStuff();