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;
299 font_bitmap_info[font_bitmap_id].draw_xoffset =
300 graphic_info[graphic].draw_xoffset;
301 font_bitmap_info[font_bitmap_id].draw_yoffset =
302 graphic_info[graphic].draw_yoffset;
304 font_bitmap_info[font_bitmap_id].num_chars =
305 graphic_info[graphic].anim_frames;
306 font_bitmap_info[font_bitmap_id].num_chars_per_line =
307 graphic_info[graphic].anim_frames_per_line;
311 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
314 void InitElementGraphicInfo()
316 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
317 int num_property_mappings = getImageListPropertyMappingSize();
320 if (graphic_info == NULL) /* still at startup phase */
323 /* set values to -1 to identify later as "uninitialized" values */
324 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
326 for (act = 0; act < NUM_ACTIONS; act++)
328 element_info[i].graphic[act] = -1;
329 element_info[i].crumbled[act] = -1;
331 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
333 element_info[i].direction_graphic[act][dir] = -1;
334 element_info[i].direction_crumbled[act][dir] = -1;
339 /* initialize normal element/graphic mapping from static configuration */
340 for (i = 0; element_to_graphic[i].element > -1; i++)
342 int element = element_to_graphic[i].element;
343 int action = element_to_graphic[i].action;
344 int direction = element_to_graphic[i].direction;
345 boolean crumbled = element_to_graphic[i].crumbled;
346 int graphic = element_to_graphic[i].graphic;
347 int base_graphic = el2baseimg(element);
349 if (graphic_info[graphic].bitmap == NULL)
352 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
355 boolean base_redefined =
356 getImageListEntryFromImageID(base_graphic)->redefined;
357 boolean act_dir_redefined =
358 getImageListEntryFromImageID(graphic)->redefined;
360 /* if the base graphic ("emerald", for example) has been redefined,
361 but not the action graphic ("emerald.falling", for example), do not
362 use an existing (in this case considered obsolete) action graphic
363 anymore, but use the automatically determined default graphic */
364 if (base_redefined && !act_dir_redefined)
369 action = ACTION_DEFAULT;
374 element_info[element].direction_crumbled[action][direction] = graphic;
376 element_info[element].crumbled[action] = graphic;
381 element_info[element].direction_graphic[action][direction] = graphic;
383 element_info[element].graphic[action] = graphic;
387 /* initialize normal element/graphic mapping from dynamic configuration */
388 for (i = 0; i < num_property_mappings; i++)
390 int element = property_mapping[i].base_index;
391 int action = property_mapping[i].ext1_index;
392 int direction = property_mapping[i].ext2_index;
393 int special = property_mapping[i].ext3_index;
394 int graphic = property_mapping[i].artwork_index;
395 boolean crumbled = FALSE;
397 if (special == GFX_SPECIAL_ARG_CRUMBLED)
403 if (graphic_info[graphic].bitmap == NULL)
406 if (element >= MAX_NUM_ELEMENTS || special != -1)
410 action = ACTION_DEFAULT;
415 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
416 element_info[element].direction_crumbled[action][dir] = -1;
419 element_info[element].direction_crumbled[action][direction] = graphic;
421 element_info[element].crumbled[action] = graphic;
426 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
427 element_info[element].direction_graphic[action][dir] = -1;
430 element_info[element].direction_graphic[action][direction] = graphic;
432 element_info[element].graphic[action] = graphic;
436 /* now copy all graphics that are defined to be cloned from other graphics */
437 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
439 int graphic = element_info[i].graphic[ACTION_DEFAULT];
440 int crumbled_like, diggable_like;
445 crumbled_like = graphic_info[graphic].crumbled_like;
446 diggable_like = graphic_info[graphic].diggable_like;
448 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
450 for (act = 0; act < NUM_ACTIONS; act++)
451 element_info[i].crumbled[act] =
452 element_info[crumbled_like].crumbled[act];
453 for (act = 0; act < NUM_ACTIONS; act++)
454 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
455 element_info[i].direction_crumbled[act][dir] =
456 element_info[crumbled_like].direction_crumbled[act][dir];
459 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
461 element_info[i].graphic[ACTION_DIGGING] =
462 element_info[diggable_like].graphic[ACTION_DIGGING];
463 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
464 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
465 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
470 /* set hardcoded definitions for some runtime elements without graphic */
471 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
475 /* set hardcoded definitions for some internal elements without graphic */
476 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
478 if (IS_EDITOR_CASCADE_INACTIVE(i))
479 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
480 else if (IS_EDITOR_CASCADE_ACTIVE(i))
481 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
485 /* now set all undefined/invalid graphics to -1 to set to default after it */
486 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
488 for (act = 0; act < NUM_ACTIONS; act++)
492 graphic = element_info[i].graphic[act];
493 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
494 element_info[i].graphic[act] = -1;
496 graphic = element_info[i].crumbled[act];
497 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
498 element_info[i].crumbled[act] = -1;
500 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
502 graphic = element_info[i].direction_graphic[act][dir];
503 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
504 element_info[i].direction_graphic[act][dir] = -1;
506 graphic = element_info[i].direction_crumbled[act][dir];
507 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
508 element_info[i].direction_crumbled[act][dir] = -1;
513 /* adjust graphics with 2nd tile for movement according to direction
514 (do this before correcting '-1' values to minimize calculations) */
515 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
517 for (act = 0; act < NUM_ACTIONS; act++)
519 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
521 int graphic = element_info[i].direction_graphic[act][dir];
522 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
524 if (act == ACTION_FALLING) /* special case */
525 graphic = element_info[i].graphic[act];
528 graphic_info[graphic].double_movement &&
529 graphic_info[graphic].swap_double_tiles != 0)
531 struct GraphicInfo *g = &graphic_info[graphic];
532 int src_x_front = g->src_x;
533 int src_y_front = g->src_y;
534 int src_x_back = g->src_x + g->offset2_x;
535 int src_y_back = g->src_y + g->offset2_y;
536 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
538 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
539 src_y_front < src_y_back);
540 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
541 boolean swap_movement_tiles_autodetected =
542 (!frames_are_ordered_diagonally &&
543 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
544 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
545 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
546 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
549 /* swap frontside and backside graphic tile coordinates, if needed */
550 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
552 /* get current (wrong) backside tile coordinates */
553 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
556 /* set frontside tile coordinates to backside tile coordinates */
557 g->src_x = src_x_back;
558 g->src_y = src_y_back;
560 /* invert tile offset to point to new backside tile coordinates */
564 /* do not swap front and backside tiles again after correction */
565 g->swap_double_tiles = 0;
572 /* now set all '-1' values to element specific default values */
573 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
575 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
576 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
577 int default_direction_graphic[NUM_DIRECTIONS_FULL];
578 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
580 if (default_graphic == -1)
581 default_graphic = IMG_UNKNOWN;
583 if (default_crumbled == -1)
584 default_crumbled = default_graphic;
586 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
587 if (default_crumbled == -1)
588 default_crumbled = IMG_EMPTY;
591 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
593 default_direction_graphic[dir] =
594 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
595 default_direction_crumbled[dir] =
596 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
598 if (default_direction_graphic[dir] == -1)
599 default_direction_graphic[dir] = default_graphic;
601 if (default_direction_crumbled[dir] == -1)
602 default_direction_crumbled[dir] = default_direction_graphic[dir];
604 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
605 if (default_direction_crumbled[dir] == -1)
606 default_direction_crumbled[dir] = default_crumbled;
610 for (act = 0; act < NUM_ACTIONS; act++)
612 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
613 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
614 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
615 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
616 act == ACTION_TURNING_FROM_RIGHT ||
617 act == ACTION_TURNING_FROM_UP ||
618 act == ACTION_TURNING_FROM_DOWN);
620 /* generic default action graphic (defined by "[default]" directive) */
621 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
622 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
623 int default_remove_graphic = IMG_EMPTY;
625 if (act_remove && default_action_graphic != -1)
626 default_remove_graphic = default_action_graphic;
628 /* look for special default action graphic (classic game specific) */
629 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
630 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
631 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
632 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
633 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
634 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
636 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
637 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
638 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
639 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
640 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
641 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
644 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
645 /* !!! make this better !!! */
646 if (i == EL_EMPTY_SPACE)
648 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
649 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
653 if (default_action_graphic == -1)
654 default_action_graphic = default_graphic;
656 if (default_action_crumbled == -1)
657 default_action_crumbled = default_action_graphic;
659 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
660 if (default_action_crumbled == -1)
661 default_action_crumbled = default_crumbled;
664 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
666 /* use action graphic as the default direction graphic, if undefined */
667 int default_action_direction_graphic = element_info[i].graphic[act];
668 int default_action_direction_crumbled = element_info[i].crumbled[act];
670 /* no graphic for current action -- use default direction graphic */
671 if (default_action_direction_graphic == -1)
672 default_action_direction_graphic =
673 (act_remove ? default_remove_graphic :
675 element_info[i].direction_graphic[ACTION_TURNING][dir] :
676 default_action_graphic != default_graphic ?
677 default_action_graphic :
678 default_direction_graphic[dir]);
680 if (element_info[i].direction_graphic[act][dir] == -1)
681 element_info[i].direction_graphic[act][dir] =
682 default_action_direction_graphic;
685 if (default_action_direction_crumbled == -1)
686 default_action_direction_crumbled =
687 element_info[i].direction_graphic[act][dir];
689 if (default_action_direction_crumbled == -1)
690 default_action_direction_crumbled =
691 (act_remove ? default_remove_graphic :
693 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
694 default_action_crumbled != default_crumbled ?
695 default_action_crumbled :
696 default_direction_crumbled[dir]);
699 if (element_info[i].direction_crumbled[act][dir] == -1)
700 element_info[i].direction_crumbled[act][dir] =
701 default_action_direction_crumbled;
704 /* no graphic for this specific action -- use default action graphic */
705 if (element_info[i].graphic[act] == -1)
706 element_info[i].graphic[act] =
707 (act_remove ? default_remove_graphic :
708 act_turning ? element_info[i].graphic[ACTION_TURNING] :
709 default_action_graphic);
711 if (element_info[i].crumbled[act] == -1)
712 element_info[i].crumbled[act] = element_info[i].graphic[act];
714 if (element_info[i].crumbled[act] == -1)
715 element_info[i].crumbled[act] =
716 (act_remove ? default_remove_graphic :
717 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
718 default_action_crumbled);
724 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
725 /* set animation mode to "none" for each graphic with only 1 frame */
726 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
728 for (act = 0; act < NUM_ACTIONS; act++)
730 int graphic = element_info[i].graphic[act];
731 int crumbled = element_info[i].crumbled[act];
733 if (graphic_info[graphic].anim_frames == 1)
734 graphic_info[graphic].anim_mode = ANIM_NONE;
735 if (graphic_info[crumbled].anim_frames == 1)
736 graphic_info[crumbled].anim_mode = ANIM_NONE;
738 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
740 graphic = element_info[i].direction_graphic[act][dir];
741 crumbled = element_info[i].direction_crumbled[act][dir];
743 if (graphic_info[graphic].anim_frames == 1)
744 graphic_info[graphic].anim_mode = ANIM_NONE;
745 if (graphic_info[crumbled].anim_frames == 1)
746 graphic_info[crumbled].anim_mode = ANIM_NONE;
756 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
757 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
759 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
760 element_info[i].token_name, i);
766 void InitElementSpecialGraphicInfo()
768 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
769 int num_property_mappings = getImageListPropertyMappingSize();
772 /* always start with reliable default values */
773 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
774 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
775 element_info[i].special_graphic[j] =
776 element_info[i].graphic[ACTION_DEFAULT];
778 /* initialize special element/graphic mapping from static configuration */
779 for (i = 0; element_to_special_graphic[i].element > -1; i++)
781 int element = element_to_special_graphic[i].element;
782 int special = element_to_special_graphic[i].special;
783 int graphic = element_to_special_graphic[i].graphic;
784 int base_graphic = el2baseimg(element);
785 boolean base_redefined =
786 getImageListEntryFromImageID(base_graphic)->redefined;
787 boolean special_redefined =
788 getImageListEntryFromImageID(graphic)->redefined;
790 /* if the base graphic ("emerald", for example) has been redefined,
791 but not the special graphic ("emerald.EDITOR", for example), do not
792 use an existing (in this case considered obsolete) special graphic
793 anymore, but use the automatically created (down-scaled) graphic */
794 if (base_redefined && !special_redefined)
797 element_info[element].special_graphic[special] = graphic;
800 /* initialize special element/graphic mapping from dynamic configuration */
801 for (i = 0; i < num_property_mappings; i++)
803 int element = property_mapping[i].base_index;
804 int special = property_mapping[i].ext3_index;
805 int graphic = property_mapping[i].artwork_index;
807 if (element >= MAX_NUM_ELEMENTS)
810 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
811 element_info[element].special_graphic[special] = graphic;
814 /* now set all undefined/invalid graphics to default */
815 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
816 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
817 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
818 element_info[i].special_graphic[j] =
819 element_info[i].graphic[ACTION_DEFAULT];
822 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
827 if (type != TYPE_TOKEN)
828 return get_parameter_value(value_raw, suffix, type);
830 if (strEqual(value_raw, ARG_UNDEFINED))
831 return ARG_UNDEFINED_VALUE;
833 /* !!! OPTIMIZE THIS BY USING HASH !!! */
834 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
835 if (strEqual(element_info[i].token_name, value_raw))
838 /* !!! OPTIMIZE THIS BY USING HASH !!! */
839 for (i = 0; image_config[i].token != NULL; i++)
841 int len_config_value = strlen(image_config[i].value);
843 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
844 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
845 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
848 if (strEqual(image_config[i].token, value_raw))
857 static int get_scaled_graphic_width(int graphic)
859 int original_width = getOriginalImageWidthFromImageID(graphic);
860 int scale_up_factor = graphic_info[graphic].scale_up_factor;
862 return original_width * scale_up_factor;
865 static int get_scaled_graphic_height(int graphic)
867 int original_height = getOriginalImageHeightFromImageID(graphic);
868 int scale_up_factor = graphic_info[graphic].scale_up_factor;
870 return original_height * scale_up_factor;
873 static void set_graphic_parameters(int graphic)
875 struct FileInfo *image = getImageListEntryFromImageID(graphic);
876 char **parameter_raw = image->parameter;
877 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
878 int parameter[NUM_GFX_ARGS];
879 int anim_frames_per_row = 1, anim_frames_per_col = 1;
880 int anim_frames_per_line = 1;
883 /* if fallback to default artwork is done, also use the default parameters */
884 if (image->fallback_to_default)
885 parameter_raw = image->default_parameter;
887 /* get integer values from string parameters */
888 for (i = 0; i < NUM_GFX_ARGS; i++)
889 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
890 image_config_suffix[i].token,
891 image_config_suffix[i].type);
893 graphic_info[graphic].bitmap = src_bitmap;
895 /* start with reliable default values */
896 graphic_info[graphic].src_image_width = 0;
897 graphic_info[graphic].src_image_height = 0;
898 graphic_info[graphic].src_x = 0;
899 graphic_info[graphic].src_y = 0;
900 graphic_info[graphic].width = TILEX;
901 graphic_info[graphic].height = TILEY;
902 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
903 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
904 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
905 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
906 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
907 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
908 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
909 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
910 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
911 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
912 graphic_info[graphic].anim_delay_fixed = 0;
913 graphic_info[graphic].anim_delay_random = 0;
914 graphic_info[graphic].post_delay_fixed = 0;
915 graphic_info[graphic].post_delay_random = 0;
917 /* optional x and y tile position of animation frame sequence */
918 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
919 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
920 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
921 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
923 /* optional x and y pixel position of animation frame sequence */
924 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
925 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
926 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
927 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
929 /* optional width and height of each animation frame */
930 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
931 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
932 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
933 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
935 /* optional zoom factor for scaling up the image to a larger size */
936 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
937 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
938 if (graphic_info[graphic].scale_up_factor < 1)
939 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
943 /* get final bitmap size (with scaling, but without small images) */
944 int src_image_width = get_scaled_graphic_width(graphic);
945 int src_image_height = get_scaled_graphic_height(graphic);
947 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
948 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
950 graphic_info[graphic].src_image_width = src_image_width;
951 graphic_info[graphic].src_image_height = src_image_height;
954 /* correct x or y offset dependent of vertical or horizontal frame order */
955 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
957 graphic_info[graphic].offset_y =
958 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
959 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
960 anim_frames_per_line = anim_frames_per_col;
962 else /* frames are ordered horizontally */
964 graphic_info[graphic].offset_x =
965 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
966 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
967 anim_frames_per_line = anim_frames_per_row;
970 /* optionally, the x and y offset of frames can be specified directly */
971 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
972 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
973 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
974 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
976 /* optionally, moving animations may have separate start and end graphics */
977 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
979 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
980 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
982 /* correct x or y offset2 dependent of vertical or horizontal frame order */
983 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
984 graphic_info[graphic].offset2_y =
985 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
986 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
987 else /* frames are ordered horizontally */
988 graphic_info[graphic].offset2_x =
989 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
990 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
992 /* optionally, the x and y offset of 2nd graphic can be specified directly */
993 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
995 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
996 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
998 /* optionally, the second movement tile can be specified as start tile */
999 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1000 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1002 /* automatically determine correct number of frames, if not defined */
1003 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1004 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1005 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1006 graphic_info[graphic].anim_frames = anim_frames_per_row;
1007 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1008 graphic_info[graphic].anim_frames = anim_frames_per_col;
1010 graphic_info[graphic].anim_frames = 1;
1012 graphic_info[graphic].anim_frames_per_line =
1013 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1014 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1016 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1017 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1018 graphic_info[graphic].anim_delay = 1;
1020 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1022 if (graphic_info[graphic].anim_frames == 1)
1023 graphic_info[graphic].anim_mode = ANIM_NONE;
1026 /* automatically determine correct start frame, if not defined */
1027 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1028 graphic_info[graphic].anim_start_frame = 0;
1029 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1030 graphic_info[graphic].anim_start_frame =
1031 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1033 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1035 /* animation synchronized with global frame counter, not move position */
1036 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1038 /* optional element for cloning crumble graphics */
1039 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1040 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1042 /* optional element for cloning digging graphics */
1043 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1044 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1046 /* optional border size for "crumbling" diggable graphics */
1047 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1048 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1050 /* this is only used for player "boring" and "sleeping" actions */
1051 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].anim_delay_fixed =
1053 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1054 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1055 graphic_info[graphic].anim_delay_random =
1056 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1057 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1058 graphic_info[graphic].post_delay_fixed =
1059 parameter[GFX_ARG_POST_DELAY_FIXED];
1060 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1061 graphic_info[graphic].post_delay_random =
1062 parameter[GFX_ARG_POST_DELAY_RANDOM];
1064 /* this is only used for toon animations */
1065 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1066 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1068 /* this is only used for drawing font characters */
1069 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1070 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1072 /* this is only used for drawing envelope graphics */
1073 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1075 /* optional graphic for cloning all graphics settings */
1076 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1077 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1080 static void set_cloned_graphic_parameters(int graphic)
1082 int fallback_graphic = IMG_CHAR_EXCLAM;
1083 int max_num_images = getImageListSize();
1084 int clone_graphic = graphic_info[graphic].clone_from;
1085 int num_references_followed = 1;
1087 while (graphic_info[clone_graphic].clone_from != -1 &&
1088 num_references_followed < max_num_images)
1090 clone_graphic = graphic_info[clone_graphic].clone_from;
1092 num_references_followed++;
1095 if (num_references_followed >= max_num_images)
1097 Error(ERR_RETURN_LINE, "-");
1098 Error(ERR_RETURN, "warning: error found in config file:");
1099 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1100 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1101 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1102 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1104 if (graphic == fallback_graphic)
1105 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1107 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1108 Error(ERR_RETURN_LINE, "-");
1110 graphic_info[graphic] = graphic_info[fallback_graphic];
1114 graphic_info[graphic] = graphic_info[clone_graphic];
1115 graphic_info[graphic].clone_from = clone_graphic;
1119 static void InitGraphicInfo()
1121 int fallback_graphic = IMG_CHAR_EXCLAM;
1122 int num_images = getImageListSize();
1125 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1126 static boolean clipmasks_initialized = FALSE;
1128 XGCValues clip_gc_values;
1129 unsigned long clip_gc_valuemask;
1130 GC copy_clipmask_gc = None;
1133 checked_free(graphic_info);
1135 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1137 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1138 if (clipmasks_initialized)
1140 for (i = 0; i < num_images; i++)
1142 if (graphic_info[i].clip_mask)
1143 XFreePixmap(display, graphic_info[i].clip_mask);
1144 if (graphic_info[i].clip_gc)
1145 XFreeGC(display, graphic_info[i].clip_gc);
1147 graphic_info[i].clip_mask = None;
1148 graphic_info[i].clip_gc = None;
1153 /* first set all graphic paramaters ... */
1154 for (i = 0; i < num_images; i++)
1155 set_graphic_parameters(i);
1157 /* ... then copy these parameters for cloned graphics */
1158 for (i = 0; i < num_images; i++)
1159 if (graphic_info[i].clone_from != -1)
1160 set_cloned_graphic_parameters(i);
1162 for (i = 0; i < num_images; i++)
1166 int first_frame, last_frame;
1167 int src_bitmap_width, src_bitmap_height;
1169 /* now check if no animation frames are outside of the loaded image */
1171 if (graphic_info[i].bitmap == NULL)
1172 continue; /* skip check for optional images that are undefined */
1174 /* get final bitmap size (with scaling, but without small images) */
1175 src_bitmap_width = graphic_info[i].src_image_width;
1176 src_bitmap_height = graphic_info[i].src_image_height;
1178 /* check if first animation frame is inside specified bitmap */
1181 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1183 if (src_x < 0 || src_y < 0 ||
1184 src_x + TILEX > src_bitmap_width ||
1185 src_y + TILEY > src_bitmap_height)
1187 Error(ERR_RETURN_LINE, "-");
1188 Error(ERR_RETURN, "warning: error found in config file:");
1189 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1190 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1191 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1193 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1194 src_x, src_y, src_bitmap_width, src_bitmap_height);
1195 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1197 if (i == fallback_graphic)
1198 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1200 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1201 Error(ERR_RETURN_LINE, "-");
1203 graphic_info[i] = graphic_info[fallback_graphic];
1206 /* check if last animation frame is inside specified bitmap */
1208 last_frame = graphic_info[i].anim_frames - 1;
1209 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1211 if (src_x < 0 || src_y < 0 ||
1212 src_x + TILEX > src_bitmap_width ||
1213 src_y + TILEY > src_bitmap_height)
1215 Error(ERR_RETURN_LINE, "-");
1216 Error(ERR_RETURN, "warning: error found in config file:");
1217 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1218 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1219 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1221 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1222 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1223 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1225 if (i == fallback_graphic)
1226 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1228 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1229 Error(ERR_RETURN_LINE, "-");
1231 graphic_info[i] = graphic_info[fallback_graphic];
1234 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1235 /* currently we only need a tile clip mask from the first frame */
1236 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1238 if (copy_clipmask_gc == None)
1240 clip_gc_values.graphics_exposures = False;
1241 clip_gc_valuemask = GCGraphicsExposures;
1242 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1243 clip_gc_valuemask, &clip_gc_values);
1246 graphic_info[i].clip_mask =
1247 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1249 src_pixmap = src_bitmap->clip_mask;
1250 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1251 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1253 clip_gc_values.graphics_exposures = False;
1254 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1255 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1257 graphic_info[i].clip_gc =
1258 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1262 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1263 if (copy_clipmask_gc)
1264 XFreeGC(display, copy_clipmask_gc);
1266 clipmasks_initialized = TRUE;
1270 static void InitElementSoundInfo()
1272 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1273 int num_property_mappings = getSoundListPropertyMappingSize();
1276 /* set values to -1 to identify later as "uninitialized" values */
1277 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1278 for (act = 0; act < NUM_ACTIONS; act++)
1279 element_info[i].sound[act] = -1;
1281 /* initialize element/sound mapping from static configuration */
1282 for (i = 0; element_to_sound[i].element > -1; i++)
1284 int element = element_to_sound[i].element;
1285 int action = element_to_sound[i].action;
1286 int sound = element_to_sound[i].sound;
1287 boolean is_class = element_to_sound[i].is_class;
1290 action = ACTION_DEFAULT;
1293 element_info[element].sound[action] = sound;
1295 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1296 if (strEqual(element_info[j].class_name,
1297 element_info[element].class_name))
1298 element_info[j].sound[action] = sound;
1301 /* initialize element class/sound mapping from dynamic configuration */
1302 for (i = 0; i < num_property_mappings; i++)
1304 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1305 int action = property_mapping[i].ext1_index;
1306 int sound = property_mapping[i].artwork_index;
1308 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1312 action = ACTION_DEFAULT;
1314 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1315 if (strEqual(element_info[j].class_name,
1316 element_info[element_class].class_name))
1317 element_info[j].sound[action] = sound;
1320 /* initialize element/sound mapping from dynamic configuration */
1321 for (i = 0; i < num_property_mappings; i++)
1323 int element = property_mapping[i].base_index;
1324 int action = property_mapping[i].ext1_index;
1325 int sound = property_mapping[i].artwork_index;
1327 if (element >= MAX_NUM_ELEMENTS)
1331 action = ACTION_DEFAULT;
1333 element_info[element].sound[action] = sound;
1336 /* now set all '-1' values to element specific default values */
1337 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1339 for (act = 0; act < NUM_ACTIONS; act++)
1341 /* generic default action sound (defined by "[default]" directive) */
1342 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1344 /* look for special default action sound (classic game specific) */
1345 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1346 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1347 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1348 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1349 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1350 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1352 /* !!! there's no such thing as a "default action sound" !!! */
1354 /* look for element specific default sound (independent from action) */
1355 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1356 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1360 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1361 /* !!! make this better !!! */
1362 if (i == EL_EMPTY_SPACE)
1363 default_action_sound = element_info[EL_DEFAULT].sound[act];
1366 /* no sound for this specific action -- use default action sound */
1367 if (element_info[i].sound[act] == -1)
1368 element_info[i].sound[act] = default_action_sound;
1372 /* copy sound settings to some elements that are only stored in level file
1373 in native R'n'D levels, but are used by game engine in native EM levels */
1374 for (i = 0; copy_properties[i][0] != -1; i++)
1375 for (j = 1; j <= 4; j++)
1376 for (act = 0; act < NUM_ACTIONS; act++)
1377 element_info[copy_properties[i][j]].sound[act] =
1378 element_info[copy_properties[i][0]].sound[act];
1381 static void InitGameModeSoundInfo()
1385 /* set values to -1 to identify later as "uninitialized" values */
1386 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1389 /* initialize gamemode/sound mapping from static configuration */
1390 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1392 int gamemode = gamemode_to_sound[i].gamemode;
1393 int sound = gamemode_to_sound[i].sound;
1396 gamemode = GAME_MODE_DEFAULT;
1398 menu.sound[gamemode] = sound;
1401 /* now set all '-1' values to levelset specific default values */
1402 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1403 if (menu.sound[i] == -1)
1404 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1407 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1408 if (menu.sound[i] != -1)
1409 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1413 static void set_sound_parameters(int sound, char **parameter_raw)
1415 int parameter[NUM_SND_ARGS];
1418 /* get integer values from string parameters */
1419 for (i = 0; i < NUM_SND_ARGS; i++)
1421 get_parameter_value(parameter_raw[i],
1422 sound_config_suffix[i].token,
1423 sound_config_suffix[i].type);
1425 /* explicit loop mode setting in configuration overrides default value */
1426 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1427 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1429 /* sound volume to change the original volume when loading the sound file */
1430 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1432 /* sound priority to give certain sounds a higher or lower priority */
1433 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1436 static void InitSoundInfo()
1438 int *sound_effect_properties;
1439 int num_sounds = getSoundListSize();
1442 checked_free(sound_info);
1444 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1445 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1447 /* initialize sound effect for all elements to "no sound" */
1448 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1449 for (j = 0; j < NUM_ACTIONS; j++)
1450 element_info[i].sound[j] = SND_UNDEFINED;
1452 for (i = 0; i < num_sounds; i++)
1454 struct FileInfo *sound = getSoundListEntry(i);
1455 int len_effect_text = strlen(sound->token);
1457 sound_effect_properties[i] = ACTION_OTHER;
1458 sound_info[i].loop = FALSE; /* default: play sound only once */
1461 printf("::: sound %d: '%s'\n", i, sound->token);
1464 /* determine all loop sounds and identify certain sound classes */
1466 for (j = 0; element_action_info[j].suffix; j++)
1468 int len_action_text = strlen(element_action_info[j].suffix);
1470 if (len_action_text < len_effect_text &&
1471 strEqual(&sound->token[len_effect_text - len_action_text],
1472 element_action_info[j].suffix))
1474 sound_effect_properties[i] = element_action_info[j].value;
1475 sound_info[i].loop = element_action_info[j].is_loop_sound;
1481 /* associate elements and some selected sound actions */
1483 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1485 if (element_info[j].class_name)
1487 int len_class_text = strlen(element_info[j].class_name);
1489 if (len_class_text + 1 < len_effect_text &&
1490 strncmp(sound->token,
1491 element_info[j].class_name, len_class_text) == 0 &&
1492 sound->token[len_class_text] == '.')
1494 int sound_action_value = sound_effect_properties[i];
1496 element_info[j].sound[sound_action_value] = i;
1501 set_sound_parameters(i, sound->parameter);
1504 free(sound_effect_properties);
1507 static void InitGameModeMusicInfo()
1509 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1510 int num_property_mappings = getMusicListPropertyMappingSize();
1511 int default_levelset_music = -1;
1514 /* set values to -1 to identify later as "uninitialized" values */
1515 for (i = 0; i < MAX_LEVELS; i++)
1516 levelset.music[i] = -1;
1517 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1520 /* initialize gamemode/music mapping from static configuration */
1521 for (i = 0; gamemode_to_music[i].music > -1; i++)
1523 int gamemode = gamemode_to_music[i].gamemode;
1524 int music = gamemode_to_music[i].music;
1527 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1531 gamemode = GAME_MODE_DEFAULT;
1533 menu.music[gamemode] = music;
1536 /* initialize gamemode/music mapping from dynamic configuration */
1537 for (i = 0; i < num_property_mappings; i++)
1539 int prefix = property_mapping[i].base_index;
1540 int gamemode = property_mapping[i].ext1_index;
1541 int level = property_mapping[i].ext2_index;
1542 int music = property_mapping[i].artwork_index;
1545 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1546 prefix, gamemode, level, music);
1549 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1553 gamemode = GAME_MODE_DEFAULT;
1555 /* level specific music only allowed for in-game music */
1556 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1557 gamemode = GAME_MODE_PLAYING;
1562 default_levelset_music = music;
1565 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1566 levelset.music[level] = music;
1567 if (gamemode != GAME_MODE_PLAYING)
1568 menu.music[gamemode] = music;
1571 /* now set all '-1' values to menu specific default values */
1572 /* (undefined values of "levelset.music[]" might stay at "-1" to
1573 allow dynamic selection of music files from music directory!) */
1574 for (i = 0; i < MAX_LEVELS; i++)
1575 if (levelset.music[i] == -1)
1576 levelset.music[i] = default_levelset_music;
1577 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1578 if (menu.music[i] == -1)
1579 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1582 for (i = 0; i < MAX_LEVELS; i++)
1583 if (levelset.music[i] != -1)
1584 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1585 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1586 if (menu.music[i] != -1)
1587 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1591 static void set_music_parameters(int music, char **parameter_raw)
1593 int parameter[NUM_MUS_ARGS];
1596 /* get integer values from string parameters */
1597 for (i = 0; i < NUM_MUS_ARGS; i++)
1599 get_parameter_value(parameter_raw[i],
1600 music_config_suffix[i].token,
1601 music_config_suffix[i].type);
1603 /* explicit loop mode setting in configuration overrides default value */
1604 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1605 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1608 static void InitMusicInfo()
1610 int num_music = getMusicListSize();
1613 checked_free(music_info);
1615 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1617 for (i = 0; i < num_music; i++)
1619 struct FileInfo *music = getMusicListEntry(i);
1620 int len_music_text = strlen(music->token);
1622 music_info[i].loop = TRUE; /* default: play music in loop mode */
1624 /* determine all loop music */
1626 for (j = 0; music_prefix_info[j].prefix; j++)
1628 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1630 if (len_prefix_text < len_music_text &&
1631 strncmp(music->token,
1632 music_prefix_info[j].prefix, len_prefix_text) == 0)
1634 music_info[i].loop = music_prefix_info[j].is_loop_music;
1640 set_music_parameters(i, music->parameter);
1644 static void ReinitializeGraphics()
1646 InitGraphicInfo(); /* graphic properties mapping */
1647 InitElementGraphicInfo(); /* element game graphic mapping */
1648 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1650 InitElementSmallImages(); /* scale images to all needed sizes */
1651 InitFontGraphicInfo(); /* initialize text drawing functions */
1653 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1655 SetMainBackgroundImage(IMG_BACKGROUND);
1656 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1662 static void ReinitializeSounds()
1664 InitSoundInfo(); /* sound properties mapping */
1665 InitElementSoundInfo(); /* element game sound mapping */
1666 InitGameModeSoundInfo(); /* game mode sound mapping */
1668 InitPlayLevelSound(); /* internal game sound settings */
1671 static void ReinitializeMusic()
1673 InitMusicInfo(); /* music properties mapping */
1674 InitGameModeMusicInfo(); /* game mode music mapping */
1677 static int get_special_property_bit(int element, int property_bit_nr)
1679 struct PropertyBitInfo
1685 static struct PropertyBitInfo pb_can_move_into_acid[] =
1687 /* the player may be able fall into acid when gravity is activated */
1692 { EL_SP_MURPHY, 0 },
1693 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1695 /* all elements that can move may be able to also move into acid */
1698 { EL_BUG_RIGHT, 1 },
1701 { EL_SPACESHIP, 2 },
1702 { EL_SPACESHIP_LEFT, 2 },
1703 { EL_SPACESHIP_RIGHT, 2 },
1704 { EL_SPACESHIP_UP, 2 },
1705 { EL_SPACESHIP_DOWN, 2 },
1706 { EL_BD_BUTTERFLY, 3 },
1707 { EL_BD_BUTTERFLY_LEFT, 3 },
1708 { EL_BD_BUTTERFLY_RIGHT, 3 },
1709 { EL_BD_BUTTERFLY_UP, 3 },
1710 { EL_BD_BUTTERFLY_DOWN, 3 },
1711 { EL_BD_FIREFLY, 4 },
1712 { EL_BD_FIREFLY_LEFT, 4 },
1713 { EL_BD_FIREFLY_RIGHT, 4 },
1714 { EL_BD_FIREFLY_UP, 4 },
1715 { EL_BD_FIREFLY_DOWN, 4 },
1717 { EL_YAMYAM_LEFT, 5 },
1718 { EL_YAMYAM_RIGHT, 5 },
1719 { EL_YAMYAM_UP, 5 },
1720 { EL_YAMYAM_DOWN, 5 },
1721 { EL_DARK_YAMYAM, 6 },
1724 { EL_PACMAN_LEFT, 8 },
1725 { EL_PACMAN_RIGHT, 8 },
1726 { EL_PACMAN_UP, 8 },
1727 { EL_PACMAN_DOWN, 8 },
1729 { EL_MOLE_LEFT, 9 },
1730 { EL_MOLE_RIGHT, 9 },
1732 { EL_MOLE_DOWN, 9 },
1736 { EL_SATELLITE, 13 },
1737 { EL_SP_SNIKSNAK, 14 },
1738 { EL_SP_ELECTRON, 15 },
1741 { EL_EMC_ANDROID, 18 },
1746 static struct PropertyBitInfo pb_dont_collide_with[] =
1748 { EL_SP_SNIKSNAK, 0 },
1749 { EL_SP_ELECTRON, 1 },
1757 struct PropertyBitInfo *pb_info;
1760 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1761 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1766 struct PropertyBitInfo *pb_info = NULL;
1769 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1770 if (pb_definition[i].bit_nr == property_bit_nr)
1771 pb_info = pb_definition[i].pb_info;
1773 if (pb_info == NULL)
1776 for (i = 0; pb_info[i].element != -1; i++)
1777 if (pb_info[i].element == element)
1778 return pb_info[i].bit_nr;
1783 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1784 boolean property_value)
1786 int bit_nr = get_special_property_bit(element, property_bit_nr);
1791 *bitfield |= (1 << bit_nr);
1793 *bitfield &= ~(1 << bit_nr);
1797 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1799 int bit_nr = get_special_property_bit(element, property_bit_nr);
1802 return ((*bitfield & (1 << bit_nr)) != 0);
1808 static void resolve_group_element(int group_element, int recursion_depth)
1810 static int group_nr;
1811 static struct ElementGroupInfo *group;
1812 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1815 if (actual_group == NULL) /* not yet initialized */
1818 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1820 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1821 group_element - EL_GROUP_START + 1);
1823 /* replace element which caused too deep recursion by question mark */
1824 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1829 if (recursion_depth == 0) /* initialization */
1831 group = actual_group;
1832 group_nr = group_element - EL_GROUP_START;
1834 group->num_elements_resolved = 0;
1835 group->choice_pos = 0;
1838 for (i = 0; i < actual_group->num_elements; i++)
1840 int element = actual_group->element[i];
1842 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1845 if (IS_GROUP_ELEMENT(element))
1846 resolve_group_element(element, recursion_depth + 1);
1849 group->element_resolved[group->num_elements_resolved++] = element;
1850 element_info[element].in_group[group_nr] = TRUE;
1856 void InitElementPropertiesStatic()
1858 static int ep_diggable[] =
1863 EL_SP_BUGGY_BASE_ACTIVATING,
1866 EL_INVISIBLE_SAND_ACTIVE,
1869 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1870 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1874 EL_SP_BUGGY_BASE_ACTIVE,
1881 static int ep_collectible_only[] =
1903 EL_DYNABOMB_INCREASE_NUMBER,
1904 EL_DYNABOMB_INCREASE_SIZE,
1905 EL_DYNABOMB_INCREASE_POWER,
1925 static int ep_dont_run_into[] =
1927 /* same elements as in 'ep_dont_touch' */
1933 /* same elements as in 'ep_dont_collide_with' */
1945 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1949 EL_SP_BUGGY_BASE_ACTIVE,
1956 static int ep_dont_collide_with[] =
1958 /* same elements as in 'ep_dont_touch' */
1975 static int ep_dont_touch[] =
1985 static int ep_indestructible[] =
1989 EL_ACID_POOL_TOPLEFT,
1990 EL_ACID_POOL_TOPRIGHT,
1991 EL_ACID_POOL_BOTTOMLEFT,
1992 EL_ACID_POOL_BOTTOM,
1993 EL_ACID_POOL_BOTTOMRIGHT,
1994 EL_SP_HARDWARE_GRAY,
1995 EL_SP_HARDWARE_GREEN,
1996 EL_SP_HARDWARE_BLUE,
1998 EL_SP_HARDWARE_YELLOW,
1999 EL_SP_HARDWARE_BASE_1,
2000 EL_SP_HARDWARE_BASE_2,
2001 EL_SP_HARDWARE_BASE_3,
2002 EL_SP_HARDWARE_BASE_4,
2003 EL_SP_HARDWARE_BASE_5,
2004 EL_SP_HARDWARE_BASE_6,
2005 EL_INVISIBLE_STEELWALL,
2006 EL_INVISIBLE_STEELWALL_ACTIVE,
2007 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2008 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2009 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2010 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2011 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2012 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2013 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2014 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2015 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2016 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2017 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2018 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2020 EL_LIGHT_SWITCH_ACTIVE,
2021 EL_SIGN_EXCLAMATION,
2022 EL_SIGN_RADIOACTIVITY,
2033 EL_STEELWALL_SLIPPERY,
2047 EL_GATE_1_GRAY_ACTIVE,
2048 EL_GATE_2_GRAY_ACTIVE,
2049 EL_GATE_3_GRAY_ACTIVE,
2050 EL_GATE_4_GRAY_ACTIVE,
2059 EL_EM_GATE_1_GRAY_ACTIVE,
2060 EL_EM_GATE_2_GRAY_ACTIVE,
2061 EL_EM_GATE_3_GRAY_ACTIVE,
2062 EL_EM_GATE_4_GRAY_ACTIVE,
2071 EL_EMC_GATE_5_GRAY_ACTIVE,
2072 EL_EMC_GATE_6_GRAY_ACTIVE,
2073 EL_EMC_GATE_7_GRAY_ACTIVE,
2074 EL_EMC_GATE_8_GRAY_ACTIVE,
2076 EL_SWITCHGATE_OPENING,
2077 EL_SWITCHGATE_CLOSED,
2078 EL_SWITCHGATE_CLOSING,
2080 EL_SWITCHGATE_SWITCH_UP,
2081 EL_SWITCHGATE_SWITCH_DOWN,
2084 EL_TIMEGATE_OPENING,
2086 EL_TIMEGATE_CLOSING,
2089 EL_TIMEGATE_SWITCH_ACTIVE,
2094 EL_TUBE_VERTICAL_LEFT,
2095 EL_TUBE_VERTICAL_RIGHT,
2096 EL_TUBE_HORIZONTAL_UP,
2097 EL_TUBE_HORIZONTAL_DOWN,
2106 static int ep_slippery[] =
2120 EL_ROBOT_WHEEL_ACTIVE,
2126 EL_ACID_POOL_TOPLEFT,
2127 EL_ACID_POOL_TOPRIGHT,
2137 EL_STEELWALL_SLIPPERY,
2140 EL_EMC_WALL_SLIPPERY_1,
2141 EL_EMC_WALL_SLIPPERY_2,
2142 EL_EMC_WALL_SLIPPERY_3,
2143 EL_EMC_WALL_SLIPPERY_4,
2145 EL_EMC_MAGIC_BALL_ACTIVE,
2150 static int ep_can_change[] =
2155 static int ep_can_move[] =
2157 /* same elements as in 'pb_can_move_into_acid' */
2180 static int ep_can_fall[] =
2195 EL_BD_MAGIC_WALL_FULL,
2209 static int ep_can_smash_player[] =
2235 static int ep_can_smash_enemies[] =
2244 static int ep_can_smash_everything[] =
2253 static int ep_explodes_by_fire[] =
2255 /* same elements as in 'ep_explodes_impact' */
2260 /* same elements as in 'ep_explodes_smashed' */
2270 EL_EM_DYNAMITE_ACTIVE,
2271 EL_DYNABOMB_PLAYER_1_ACTIVE,
2272 EL_DYNABOMB_PLAYER_2_ACTIVE,
2273 EL_DYNABOMB_PLAYER_3_ACTIVE,
2274 EL_DYNABOMB_PLAYER_4_ACTIVE,
2275 EL_DYNABOMB_INCREASE_NUMBER,
2276 EL_DYNABOMB_INCREASE_SIZE,
2277 EL_DYNABOMB_INCREASE_POWER,
2278 EL_SP_DISK_RED_ACTIVE,
2292 static int ep_explodes_smashed[] =
2294 /* same elements as in 'ep_explodes_impact' */
2308 static int ep_explodes_impact[] =
2317 static int ep_walkable_over[] =
2321 EL_SOKOBAN_FIELD_EMPTY,
2333 EL_GATE_1_GRAY_ACTIVE,
2334 EL_GATE_2_GRAY_ACTIVE,
2335 EL_GATE_3_GRAY_ACTIVE,
2336 EL_GATE_4_GRAY_ACTIVE,
2344 static int ep_walkable_inside[] =
2349 EL_TUBE_VERTICAL_LEFT,
2350 EL_TUBE_VERTICAL_RIGHT,
2351 EL_TUBE_HORIZONTAL_UP,
2352 EL_TUBE_HORIZONTAL_DOWN,
2361 static int ep_walkable_under[] =
2366 static int ep_passable_over[] =
2376 EL_EM_GATE_1_GRAY_ACTIVE,
2377 EL_EM_GATE_2_GRAY_ACTIVE,
2378 EL_EM_GATE_3_GRAY_ACTIVE,
2379 EL_EM_GATE_4_GRAY_ACTIVE,
2388 EL_EMC_GATE_5_GRAY_ACTIVE,
2389 EL_EMC_GATE_6_GRAY_ACTIVE,
2390 EL_EMC_GATE_7_GRAY_ACTIVE,
2391 EL_EMC_GATE_8_GRAY_ACTIVE,
2398 static int ep_passable_inside[] =
2404 EL_SP_PORT_HORIZONTAL,
2405 EL_SP_PORT_VERTICAL,
2407 EL_SP_GRAVITY_PORT_LEFT,
2408 EL_SP_GRAVITY_PORT_RIGHT,
2409 EL_SP_GRAVITY_PORT_UP,
2410 EL_SP_GRAVITY_PORT_DOWN,
2411 EL_SP_GRAVITY_ON_PORT_LEFT,
2412 EL_SP_GRAVITY_ON_PORT_RIGHT,
2413 EL_SP_GRAVITY_ON_PORT_UP,
2414 EL_SP_GRAVITY_ON_PORT_DOWN,
2415 EL_SP_GRAVITY_OFF_PORT_LEFT,
2416 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2417 EL_SP_GRAVITY_OFF_PORT_UP,
2418 EL_SP_GRAVITY_OFF_PORT_DOWN,
2423 static int ep_passable_under[] =
2428 static int ep_droppable[] =
2433 static int ep_explodes_1x1_old[] =
2438 static int ep_pushable[] =
2450 EL_SOKOBAN_FIELD_FULL,
2459 static int ep_explodes_cross_old[] =
2464 static int ep_protected[] =
2466 /* same elements as in 'ep_walkable_inside' */
2470 EL_TUBE_VERTICAL_LEFT,
2471 EL_TUBE_VERTICAL_RIGHT,
2472 EL_TUBE_HORIZONTAL_UP,
2473 EL_TUBE_HORIZONTAL_DOWN,
2479 /* same elements as in 'ep_passable_over' */
2488 EL_EM_GATE_1_GRAY_ACTIVE,
2489 EL_EM_GATE_2_GRAY_ACTIVE,
2490 EL_EM_GATE_3_GRAY_ACTIVE,
2491 EL_EM_GATE_4_GRAY_ACTIVE,
2500 EL_EMC_GATE_5_GRAY_ACTIVE,
2501 EL_EMC_GATE_6_GRAY_ACTIVE,
2502 EL_EMC_GATE_7_GRAY_ACTIVE,
2503 EL_EMC_GATE_8_GRAY_ACTIVE,
2507 /* same elements as in 'ep_passable_inside' */
2512 EL_SP_PORT_HORIZONTAL,
2513 EL_SP_PORT_VERTICAL,
2515 EL_SP_GRAVITY_PORT_LEFT,
2516 EL_SP_GRAVITY_PORT_RIGHT,
2517 EL_SP_GRAVITY_PORT_UP,
2518 EL_SP_GRAVITY_PORT_DOWN,
2519 EL_SP_GRAVITY_ON_PORT_LEFT,
2520 EL_SP_GRAVITY_ON_PORT_RIGHT,
2521 EL_SP_GRAVITY_ON_PORT_UP,
2522 EL_SP_GRAVITY_ON_PORT_DOWN,
2523 EL_SP_GRAVITY_OFF_PORT_LEFT,
2524 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2525 EL_SP_GRAVITY_OFF_PORT_UP,
2526 EL_SP_GRAVITY_OFF_PORT_DOWN,
2531 static int ep_throwable[] =
2536 static int ep_can_explode[] =
2538 /* same elements as in 'ep_explodes_impact' */
2543 /* same elements as in 'ep_explodes_smashed' */
2549 /* elements that can explode by explosion or by dragonfire */
2553 EL_EM_DYNAMITE_ACTIVE,
2554 EL_DYNABOMB_PLAYER_1_ACTIVE,
2555 EL_DYNABOMB_PLAYER_2_ACTIVE,
2556 EL_DYNABOMB_PLAYER_3_ACTIVE,
2557 EL_DYNABOMB_PLAYER_4_ACTIVE,
2558 EL_DYNABOMB_INCREASE_NUMBER,
2559 EL_DYNABOMB_INCREASE_SIZE,
2560 EL_DYNABOMB_INCREASE_POWER,
2561 EL_SP_DISK_RED_ACTIVE,
2569 /* elements that can explode only by explosion */
2575 static int ep_gravity_reachable[] =
2581 EL_INVISIBLE_SAND_ACTIVE,
2586 EL_SP_PORT_HORIZONTAL,
2587 EL_SP_PORT_VERTICAL,
2589 EL_SP_GRAVITY_PORT_LEFT,
2590 EL_SP_GRAVITY_PORT_RIGHT,
2591 EL_SP_GRAVITY_PORT_UP,
2592 EL_SP_GRAVITY_PORT_DOWN,
2593 EL_SP_GRAVITY_ON_PORT_LEFT,
2594 EL_SP_GRAVITY_ON_PORT_RIGHT,
2595 EL_SP_GRAVITY_ON_PORT_UP,
2596 EL_SP_GRAVITY_ON_PORT_DOWN,
2597 EL_SP_GRAVITY_OFF_PORT_LEFT,
2598 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2599 EL_SP_GRAVITY_OFF_PORT_UP,
2600 EL_SP_GRAVITY_OFF_PORT_DOWN,
2606 static int ep_player[] =
2613 EL_SOKOBAN_FIELD_PLAYER,
2619 static int ep_can_pass_magic_wall[] =
2633 static int ep_switchable[] =
2637 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2638 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2639 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2640 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2641 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2642 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2643 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2644 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2645 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2646 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2647 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2648 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2649 EL_SWITCHGATE_SWITCH_UP,
2650 EL_SWITCHGATE_SWITCH_DOWN,
2652 EL_LIGHT_SWITCH_ACTIVE,
2654 EL_BALLOON_SWITCH_LEFT,
2655 EL_BALLOON_SWITCH_RIGHT,
2656 EL_BALLOON_SWITCH_UP,
2657 EL_BALLOON_SWITCH_DOWN,
2658 EL_BALLOON_SWITCH_ANY,
2659 EL_BALLOON_SWITCH_NONE,
2662 EL_EMC_MAGIC_BALL_SWITCH,
2663 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2668 static int ep_bd_element[] =
2702 static int ep_sp_element[] =
2704 /* should always be valid */
2707 /* standard classic Supaplex elements */
2714 EL_SP_HARDWARE_GRAY,
2722 EL_SP_GRAVITY_PORT_RIGHT,
2723 EL_SP_GRAVITY_PORT_DOWN,
2724 EL_SP_GRAVITY_PORT_LEFT,
2725 EL_SP_GRAVITY_PORT_UP,
2730 EL_SP_PORT_VERTICAL,
2731 EL_SP_PORT_HORIZONTAL,
2737 EL_SP_HARDWARE_BASE_1,
2738 EL_SP_HARDWARE_GREEN,
2739 EL_SP_HARDWARE_BLUE,
2741 EL_SP_HARDWARE_YELLOW,
2742 EL_SP_HARDWARE_BASE_2,
2743 EL_SP_HARDWARE_BASE_3,
2744 EL_SP_HARDWARE_BASE_4,
2745 EL_SP_HARDWARE_BASE_5,
2746 EL_SP_HARDWARE_BASE_6,
2750 /* additional elements that appeared in newer Supaplex levels */
2753 /* additional gravity port elements (not switching, but setting gravity) */
2754 EL_SP_GRAVITY_ON_PORT_LEFT,
2755 EL_SP_GRAVITY_ON_PORT_RIGHT,
2756 EL_SP_GRAVITY_ON_PORT_UP,
2757 EL_SP_GRAVITY_ON_PORT_DOWN,
2758 EL_SP_GRAVITY_OFF_PORT_LEFT,
2759 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2760 EL_SP_GRAVITY_OFF_PORT_UP,
2761 EL_SP_GRAVITY_OFF_PORT_DOWN,
2763 /* more than one Murphy in a level results in an inactive clone */
2766 /* runtime Supaplex elements */
2767 EL_SP_DISK_RED_ACTIVE,
2768 EL_SP_TERMINAL_ACTIVE,
2769 EL_SP_BUGGY_BASE_ACTIVATING,
2770 EL_SP_BUGGY_BASE_ACTIVE,
2777 static int ep_sb_element[] =
2782 EL_SOKOBAN_FIELD_EMPTY,
2783 EL_SOKOBAN_FIELD_FULL,
2784 EL_SOKOBAN_FIELD_PLAYER,
2789 EL_INVISIBLE_STEELWALL,
2794 static int ep_gem[] =
2806 static int ep_food_dark_yamyam[] =
2834 static int ep_food_penguin[] =
2848 static int ep_food_pig[] =
2860 static int ep_historic_wall[] =
2871 EL_GATE_1_GRAY_ACTIVE,
2872 EL_GATE_2_GRAY_ACTIVE,
2873 EL_GATE_3_GRAY_ACTIVE,
2874 EL_GATE_4_GRAY_ACTIVE,
2883 EL_EM_GATE_1_GRAY_ACTIVE,
2884 EL_EM_GATE_2_GRAY_ACTIVE,
2885 EL_EM_GATE_3_GRAY_ACTIVE,
2886 EL_EM_GATE_4_GRAY_ACTIVE,
2893 EL_EXPANDABLE_WALL_HORIZONTAL,
2894 EL_EXPANDABLE_WALL_VERTICAL,
2895 EL_EXPANDABLE_WALL_ANY,
2896 EL_EXPANDABLE_WALL_GROWING,
2903 EL_SP_HARDWARE_GRAY,
2904 EL_SP_HARDWARE_GREEN,
2905 EL_SP_HARDWARE_BLUE,
2907 EL_SP_HARDWARE_YELLOW,
2908 EL_SP_HARDWARE_BASE_1,
2909 EL_SP_HARDWARE_BASE_2,
2910 EL_SP_HARDWARE_BASE_3,
2911 EL_SP_HARDWARE_BASE_4,
2912 EL_SP_HARDWARE_BASE_5,
2913 EL_SP_HARDWARE_BASE_6,
2915 EL_SP_TERMINAL_ACTIVE,
2918 EL_INVISIBLE_STEELWALL,
2919 EL_INVISIBLE_STEELWALL_ACTIVE,
2921 EL_INVISIBLE_WALL_ACTIVE,
2922 EL_STEELWALL_SLIPPERY,
2939 static int ep_historic_solid[] =
2943 EL_EXPANDABLE_WALL_HORIZONTAL,
2944 EL_EXPANDABLE_WALL_VERTICAL,
2945 EL_EXPANDABLE_WALL_ANY,
2958 EL_QUICKSAND_FILLING,
2959 EL_QUICKSAND_EMPTYING,
2961 EL_MAGIC_WALL_ACTIVE,
2962 EL_MAGIC_WALL_EMPTYING,
2963 EL_MAGIC_WALL_FILLING,
2967 EL_BD_MAGIC_WALL_ACTIVE,
2968 EL_BD_MAGIC_WALL_EMPTYING,
2969 EL_BD_MAGIC_WALL_FULL,
2970 EL_BD_MAGIC_WALL_FILLING,
2971 EL_BD_MAGIC_WALL_DEAD,
2980 EL_SP_TERMINAL_ACTIVE,
2984 EL_INVISIBLE_WALL_ACTIVE,
2985 EL_SWITCHGATE_SWITCH_UP,
2986 EL_SWITCHGATE_SWITCH_DOWN,
2988 EL_TIMEGATE_SWITCH_ACTIVE,
3000 /* the following elements are a direct copy of "indestructible" elements,
3001 except "EL_ACID", which is "indestructible", but not "solid"! */
3006 EL_ACID_POOL_TOPLEFT,
3007 EL_ACID_POOL_TOPRIGHT,
3008 EL_ACID_POOL_BOTTOMLEFT,
3009 EL_ACID_POOL_BOTTOM,
3010 EL_ACID_POOL_BOTTOMRIGHT,
3011 EL_SP_HARDWARE_GRAY,
3012 EL_SP_HARDWARE_GREEN,
3013 EL_SP_HARDWARE_BLUE,
3015 EL_SP_HARDWARE_YELLOW,
3016 EL_SP_HARDWARE_BASE_1,
3017 EL_SP_HARDWARE_BASE_2,
3018 EL_SP_HARDWARE_BASE_3,
3019 EL_SP_HARDWARE_BASE_4,
3020 EL_SP_HARDWARE_BASE_5,
3021 EL_SP_HARDWARE_BASE_6,
3022 EL_INVISIBLE_STEELWALL,
3023 EL_INVISIBLE_STEELWALL_ACTIVE,
3024 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3025 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3026 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3027 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3028 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3029 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3030 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3031 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3032 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3033 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3034 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3035 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3037 EL_LIGHT_SWITCH_ACTIVE,
3038 EL_SIGN_EXCLAMATION,
3039 EL_SIGN_RADIOACTIVITY,
3050 EL_STEELWALL_SLIPPERY,
3064 EL_GATE_1_GRAY_ACTIVE,
3065 EL_GATE_2_GRAY_ACTIVE,
3066 EL_GATE_3_GRAY_ACTIVE,
3067 EL_GATE_4_GRAY_ACTIVE,
3076 EL_EM_GATE_1_GRAY_ACTIVE,
3077 EL_EM_GATE_2_GRAY_ACTIVE,
3078 EL_EM_GATE_3_GRAY_ACTIVE,
3079 EL_EM_GATE_4_GRAY_ACTIVE,
3081 EL_SWITCHGATE_OPENING,
3082 EL_SWITCHGATE_CLOSED,
3083 EL_SWITCHGATE_CLOSING,
3085 EL_TIMEGATE_OPENING,
3087 EL_TIMEGATE_CLOSING,
3091 EL_TUBE_VERTICAL_LEFT,
3092 EL_TUBE_VERTICAL_RIGHT,
3093 EL_TUBE_HORIZONTAL_UP,
3094 EL_TUBE_HORIZONTAL_DOWN,
3103 static int ep_classic_enemy[] =
3120 static int ep_belt[] =
3122 EL_CONVEYOR_BELT_1_LEFT,
3123 EL_CONVEYOR_BELT_1_MIDDLE,
3124 EL_CONVEYOR_BELT_1_RIGHT,
3125 EL_CONVEYOR_BELT_2_LEFT,
3126 EL_CONVEYOR_BELT_2_MIDDLE,
3127 EL_CONVEYOR_BELT_2_RIGHT,
3128 EL_CONVEYOR_BELT_3_LEFT,
3129 EL_CONVEYOR_BELT_3_MIDDLE,
3130 EL_CONVEYOR_BELT_3_RIGHT,
3131 EL_CONVEYOR_BELT_4_LEFT,
3132 EL_CONVEYOR_BELT_4_MIDDLE,
3133 EL_CONVEYOR_BELT_4_RIGHT,
3138 static int ep_belt_active[] =
3140 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3141 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3142 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3143 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3144 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3145 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3146 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3147 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3148 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3149 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3150 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3151 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3156 static int ep_belt_switch[] =
3158 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3159 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3160 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3161 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3162 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3163 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3164 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3165 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3166 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3167 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3168 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3169 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3174 static int ep_tube[] =
3181 EL_TUBE_HORIZONTAL_UP,
3182 EL_TUBE_HORIZONTAL_DOWN,
3184 EL_TUBE_VERTICAL_LEFT,
3185 EL_TUBE_VERTICAL_RIGHT,
3191 static int ep_keygate[] =
3201 EL_GATE_1_GRAY_ACTIVE,
3202 EL_GATE_2_GRAY_ACTIVE,
3203 EL_GATE_3_GRAY_ACTIVE,
3204 EL_GATE_4_GRAY_ACTIVE,
3213 EL_EM_GATE_1_GRAY_ACTIVE,
3214 EL_EM_GATE_2_GRAY_ACTIVE,
3215 EL_EM_GATE_3_GRAY_ACTIVE,
3216 EL_EM_GATE_4_GRAY_ACTIVE,
3225 EL_EMC_GATE_5_GRAY_ACTIVE,
3226 EL_EMC_GATE_6_GRAY_ACTIVE,
3227 EL_EMC_GATE_7_GRAY_ACTIVE,
3228 EL_EMC_GATE_8_GRAY_ACTIVE,
3233 static int ep_amoeboid[] =
3245 static int ep_amoebalive[] =
3256 static int ep_has_editor_content[] =
3278 static int ep_can_turn_each_move[] =
3280 /* !!! do something with this one !!! */
3284 static int ep_can_grow[] =
3298 static int ep_active_bomb[] =
3301 EL_EM_DYNAMITE_ACTIVE,
3302 EL_DYNABOMB_PLAYER_1_ACTIVE,
3303 EL_DYNABOMB_PLAYER_2_ACTIVE,
3304 EL_DYNABOMB_PLAYER_3_ACTIVE,
3305 EL_DYNABOMB_PLAYER_4_ACTIVE,
3306 EL_SP_DISK_RED_ACTIVE,
3311 static int ep_inactive[] =
3343 EL_GATE_1_GRAY_ACTIVE,
3344 EL_GATE_2_GRAY_ACTIVE,
3345 EL_GATE_3_GRAY_ACTIVE,
3346 EL_GATE_4_GRAY_ACTIVE,
3355 EL_EM_GATE_1_GRAY_ACTIVE,
3356 EL_EM_GATE_2_GRAY_ACTIVE,
3357 EL_EM_GATE_3_GRAY_ACTIVE,
3358 EL_EM_GATE_4_GRAY_ACTIVE,
3367 EL_EMC_GATE_5_GRAY_ACTIVE,
3368 EL_EMC_GATE_6_GRAY_ACTIVE,
3369 EL_EMC_GATE_7_GRAY_ACTIVE,
3370 EL_EMC_GATE_8_GRAY_ACTIVE,
3373 EL_INVISIBLE_STEELWALL,
3381 EL_WALL_EMERALD_YELLOW,
3382 EL_DYNABOMB_INCREASE_NUMBER,
3383 EL_DYNABOMB_INCREASE_SIZE,
3384 EL_DYNABOMB_INCREASE_POWER,
3388 EL_SOKOBAN_FIELD_EMPTY,
3389 EL_SOKOBAN_FIELD_FULL,
3390 EL_WALL_EMERALD_RED,
3391 EL_WALL_EMERALD_PURPLE,
3392 EL_ACID_POOL_TOPLEFT,
3393 EL_ACID_POOL_TOPRIGHT,
3394 EL_ACID_POOL_BOTTOMLEFT,
3395 EL_ACID_POOL_BOTTOM,
3396 EL_ACID_POOL_BOTTOMRIGHT,
3400 EL_BD_MAGIC_WALL_DEAD,
3401 EL_AMOEBA_TO_DIAMOND,
3409 EL_SP_GRAVITY_PORT_RIGHT,
3410 EL_SP_GRAVITY_PORT_DOWN,
3411 EL_SP_GRAVITY_PORT_LEFT,
3412 EL_SP_GRAVITY_PORT_UP,
3413 EL_SP_PORT_HORIZONTAL,
3414 EL_SP_PORT_VERTICAL,
3425 EL_SP_HARDWARE_GRAY,
3426 EL_SP_HARDWARE_GREEN,
3427 EL_SP_HARDWARE_BLUE,
3429 EL_SP_HARDWARE_YELLOW,
3430 EL_SP_HARDWARE_BASE_1,
3431 EL_SP_HARDWARE_BASE_2,
3432 EL_SP_HARDWARE_BASE_3,
3433 EL_SP_HARDWARE_BASE_4,
3434 EL_SP_HARDWARE_BASE_5,
3435 EL_SP_HARDWARE_BASE_6,
3436 EL_SP_GRAVITY_ON_PORT_LEFT,
3437 EL_SP_GRAVITY_ON_PORT_RIGHT,
3438 EL_SP_GRAVITY_ON_PORT_UP,
3439 EL_SP_GRAVITY_ON_PORT_DOWN,
3440 EL_SP_GRAVITY_OFF_PORT_LEFT,
3441 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3442 EL_SP_GRAVITY_OFF_PORT_UP,
3443 EL_SP_GRAVITY_OFF_PORT_DOWN,
3444 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3445 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3446 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3447 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3448 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3449 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3450 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3451 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3452 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3453 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3454 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3455 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3456 EL_SIGN_EXCLAMATION,
3457 EL_SIGN_RADIOACTIVITY,
3468 EL_STEELWALL_SLIPPERY,
3473 EL_EMC_WALL_SLIPPERY_1,
3474 EL_EMC_WALL_SLIPPERY_2,
3475 EL_EMC_WALL_SLIPPERY_3,
3476 EL_EMC_WALL_SLIPPERY_4,
3497 static int ep_em_slippery_wall[] =
3502 static int ep_gfx_crumbled[] =
3512 static int ep_editor_cascade_active[] =
3514 EL_INTERNAL_CASCADE_BD_ACTIVE,
3515 EL_INTERNAL_CASCADE_EM_ACTIVE,
3516 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3517 EL_INTERNAL_CASCADE_RND_ACTIVE,
3518 EL_INTERNAL_CASCADE_SB_ACTIVE,
3519 EL_INTERNAL_CASCADE_SP_ACTIVE,
3520 EL_INTERNAL_CASCADE_DC_ACTIVE,
3521 EL_INTERNAL_CASCADE_DX_ACTIVE,
3522 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3523 EL_INTERNAL_CASCADE_CE_ACTIVE,
3524 EL_INTERNAL_CASCADE_GE_ACTIVE,
3525 EL_INTERNAL_CASCADE_USER_ACTIVE,
3526 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3527 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3532 static int ep_editor_cascade_inactive[] =
3534 EL_INTERNAL_CASCADE_BD,
3535 EL_INTERNAL_CASCADE_EM,
3536 EL_INTERNAL_CASCADE_EMC,
3537 EL_INTERNAL_CASCADE_RND,
3538 EL_INTERNAL_CASCADE_SB,
3539 EL_INTERNAL_CASCADE_SP,
3540 EL_INTERNAL_CASCADE_DC,
3541 EL_INTERNAL_CASCADE_DX,
3542 EL_INTERNAL_CASCADE_CHARS,
3543 EL_INTERNAL_CASCADE_CE,
3544 EL_INTERNAL_CASCADE_GE,
3545 EL_INTERNAL_CASCADE_USER,
3546 EL_INTERNAL_CASCADE_GENERIC,
3547 EL_INTERNAL_CASCADE_DYNAMIC,
3556 } element_properties[] =
3558 { ep_diggable, EP_DIGGABLE },
3559 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3560 { ep_dont_run_into, EP_DONT_RUN_INTO },
3561 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3562 { ep_dont_touch, EP_DONT_TOUCH },
3563 { ep_indestructible, EP_INDESTRUCTIBLE },
3564 { ep_slippery, EP_SLIPPERY },
3565 { ep_can_change, EP_CAN_CHANGE },
3566 { ep_can_move, EP_CAN_MOVE },
3567 { ep_can_fall, EP_CAN_FALL },
3568 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3569 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3570 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3571 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3572 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3573 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3574 { ep_walkable_over, EP_WALKABLE_OVER },
3575 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3576 { ep_walkable_under, EP_WALKABLE_UNDER },
3577 { ep_passable_over, EP_PASSABLE_OVER },
3578 { ep_passable_inside, EP_PASSABLE_INSIDE },
3579 { ep_passable_under, EP_PASSABLE_UNDER },
3580 { ep_droppable, EP_DROPPABLE },
3581 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3582 { ep_pushable, EP_PUSHABLE },
3583 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3584 { ep_protected, EP_PROTECTED },
3585 { ep_throwable, EP_THROWABLE },
3586 { ep_can_explode, EP_CAN_EXPLODE },
3587 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3589 { ep_player, EP_PLAYER },
3590 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3591 { ep_switchable, EP_SWITCHABLE },
3592 { ep_bd_element, EP_BD_ELEMENT },
3593 { ep_sp_element, EP_SP_ELEMENT },
3594 { ep_sb_element, EP_SB_ELEMENT },
3596 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3597 { ep_food_penguin, EP_FOOD_PENGUIN },
3598 { ep_food_pig, EP_FOOD_PIG },
3599 { ep_historic_wall, EP_HISTORIC_WALL },
3600 { ep_historic_solid, EP_HISTORIC_SOLID },
3601 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3602 { ep_belt, EP_BELT },
3603 { ep_belt_active, EP_BELT_ACTIVE },
3604 { ep_belt_switch, EP_BELT_SWITCH },
3605 { ep_tube, EP_TUBE },
3606 { ep_keygate, EP_KEYGATE },
3607 { ep_amoeboid, EP_AMOEBOID },
3608 { ep_amoebalive, EP_AMOEBALIVE },
3609 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3610 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3611 { ep_can_grow, EP_CAN_GROW },
3612 { ep_active_bomb, EP_ACTIVE_BOMB },
3613 { ep_inactive, EP_INACTIVE },
3615 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3617 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3619 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3620 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3627 /* always start with reliable default values (element has no properties) */
3628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3629 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3630 SET_PROPERTY(i, j, FALSE);
3632 /* set all base element properties from above array definitions */
3633 for (i = 0; element_properties[i].elements != NULL; i++)
3634 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3635 SET_PROPERTY((element_properties[i].elements)[j],
3636 element_properties[i].property, TRUE);
3638 /* copy properties to some elements that are only stored in level file */
3639 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3640 for (j = 0; copy_properties[j][0] != -1; j++)
3641 if (HAS_PROPERTY(copy_properties[j][0], i))
3642 for (k = 1; k <= 4; k++)
3643 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3646 void InitElementPropertiesEngine(int engine_version)
3648 static int no_wall_properties[] =
3651 EP_COLLECTIBLE_ONLY,
3653 EP_DONT_COLLIDE_WITH,
3656 EP_CAN_SMASH_PLAYER,
3657 EP_CAN_SMASH_ENEMIES,
3658 EP_CAN_SMASH_EVERYTHING,
3663 EP_FOOD_DARK_YAMYAM,
3679 /* important: after initialization in InitElementPropertiesStatic(), the
3680 elements are not again initialized to a default value; therefore all
3681 changes have to make sure that they leave the element with a defined
3682 property (which means that conditional property changes must be set to
3683 a reliable default value before) */
3686 /* ---------- recursively resolve group elements ------------------------- */
3688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3689 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3690 element_info[i].in_group[j] = FALSE;
3692 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3693 resolve_group_element(EL_GROUP_START + i, 0);
3696 /* set all special, combined or engine dependent element properties */
3697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3699 /* ---------- INACTIVE ------------------------------------------------- */
3700 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3702 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3703 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3704 IS_WALKABLE_INSIDE(i) ||
3705 IS_WALKABLE_UNDER(i)));
3707 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3708 IS_PASSABLE_INSIDE(i) ||
3709 IS_PASSABLE_UNDER(i)));
3711 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3712 IS_PASSABLE_OVER(i)));
3714 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3715 IS_PASSABLE_INSIDE(i)));
3717 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3718 IS_PASSABLE_UNDER(i)));
3720 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3723 /* ---------- COLLECTIBLE ---------------------------------------------- */
3724 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3728 /* ---------- SNAPPABLE ------------------------------------------------ */
3729 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3730 IS_COLLECTIBLE(i) ||
3734 /* ---------- WALL ----------------------------------------------------- */
3735 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3737 for (j = 0; no_wall_properties[j] != -1; j++)
3738 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3739 i >= EL_FIRST_RUNTIME_UNREAL)
3740 SET_PROPERTY(i, EP_WALL, FALSE);
3742 if (IS_HISTORIC_WALL(i))
3743 SET_PROPERTY(i, EP_WALL, TRUE);
3745 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3746 if (engine_version < VERSION_IDENT(2,2,0,0))
3747 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3749 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3751 !IS_COLLECTIBLE(i)));
3753 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3755 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3756 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3758 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3759 IS_INDESTRUCTIBLE(i)));
3761 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3763 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3764 else if (engine_version < VERSION_IDENT(2,2,0,0))
3765 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3767 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3771 if (IS_CUSTOM_ELEMENT(i))
3773 /* these are additional properties which are initially false when set */
3775 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3777 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3778 if (DONT_COLLIDE_WITH(i))
3779 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3781 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3782 if (CAN_SMASH_EVERYTHING(i))
3783 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3784 if (CAN_SMASH_ENEMIES(i))
3785 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3788 /* ---------- CAN_SMASH ------------------------------------------------ */
3789 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3790 CAN_SMASH_ENEMIES(i) ||
3791 CAN_SMASH_EVERYTHING(i)));
3793 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3794 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3795 EXPLODES_BY_FIRE(i)));
3797 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3798 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3799 EXPLODES_SMASHED(i)));
3801 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3802 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3803 EXPLODES_IMPACT(i)));
3805 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3806 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3808 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3809 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3810 i == EL_BLACK_ORB));
3812 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3813 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3815 IS_CUSTOM_ELEMENT(i)));
3817 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3818 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3819 i == EL_SP_ELECTRON));
3821 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3822 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3823 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3824 getMoveIntoAcidProperty(&level, i));
3826 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3827 if (MAYBE_DONT_COLLIDE_WITH(i))
3828 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3829 getDontCollideWithProperty(&level, i));
3831 /* ---------- SP_PORT -------------------------------------------------- */
3832 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3833 IS_PASSABLE_INSIDE(i)));
3835 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3836 for (j = 0; j < level.num_android_clone_elements; j++)
3837 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3839 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3841 /* ---------- CAN_CHANGE ----------------------------------------------- */
3842 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3843 for (j = 0; j < element_info[i].num_change_pages; j++)
3844 if (element_info[i].change_page[j].can_change)
3845 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3847 /* ---------- HAS_ACTION ----------------------------------------------- */
3848 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3849 for (j = 0; j < element_info[i].num_change_pages; j++)
3850 if (element_info[i].change_page[j].has_action)
3851 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3853 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3854 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3857 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3859 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3860 element_info[i].crumbled[ACTION_DEFAULT] !=
3861 element_info[i].graphic[ACTION_DEFAULT]);
3863 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3864 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3865 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3868 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3869 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3870 IS_EDITOR_CASCADE_INACTIVE(i)));
3873 /* dynamically adjust element properties according to game engine version */
3875 static int ep_em_slippery_wall[] =
3880 EL_EXPANDABLE_WALL_HORIZONTAL,
3881 EL_EXPANDABLE_WALL_VERTICAL,
3882 EL_EXPANDABLE_WALL_ANY,
3886 /* special EM style gems behaviour */
3887 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3888 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3889 level.em_slippery_gems);
3891 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3892 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3893 (level.em_slippery_gems &&
3894 engine_version > VERSION_IDENT(2,0,1,0)));
3897 /* set default push delay values (corrected since version 3.0.7-1) */
3898 if (engine_version < VERSION_IDENT(3,0,7,1))
3900 game.default_push_delay_fixed = 2;
3901 game.default_push_delay_random = 8;
3905 game.default_push_delay_fixed = 8;
3906 game.default_push_delay_random = 8;
3909 /* set uninitialized push delay values of custom elements in older levels */
3910 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3912 int element = EL_CUSTOM_START + i;
3914 if (element_info[element].push_delay_fixed == -1)
3915 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3916 if (element_info[element].push_delay_random == -1)
3917 element_info[element].push_delay_random = game.default_push_delay_random;
3920 /* set some other uninitialized values of custom elements in older levels */
3921 if (engine_version < VERSION_IDENT(3,1,0,0))
3923 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3925 int element = EL_CUSTOM_START + i;
3927 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3929 element_info[element].explosion_delay = 17;
3930 element_info[element].ignition_delay = 8;
3935 /* set element properties that were handled incorrectly in older levels */
3936 if (engine_version < VERSION_IDENT(3,1,0,0))
3938 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3939 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3943 /* this is needed because some graphics depend on element properties */
3944 if (game_status == GAME_MODE_PLAYING)
3945 InitElementGraphicInfo();
3948 static void InitGlobal()
3952 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3954 /* check if element_name_info entry defined for each element in "main.h" */
3955 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3956 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3958 element_info[i].token_name = element_name_info[i].token_name;
3959 element_info[i].class_name = element_name_info[i].class_name;
3960 element_info[i].editor_description=element_name_info[i].editor_description;
3963 global.autoplay_leveldir = NULL;
3964 global.convert_leveldir = NULL;
3966 global.frames_per_second = 0;
3967 global.fps_slowdown = FALSE;
3968 global.fps_slowdown_factor = 1;
3971 void Execute_Command(char *command)
3975 if (strEqual(command, "print graphicsinfo.conf"))
3977 printf("# You can configure additional/alternative image files here.\n");
3978 printf("# (The entries below are default and therefore commented out.)\n");
3980 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3982 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3985 for (i = 0; image_config[i].token != NULL; i++)
3986 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3987 image_config[i].value));
3991 else if (strEqual(command, "print soundsinfo.conf"))
3993 printf("# You can configure additional/alternative sound files here.\n");
3994 printf("# (The entries below are default and therefore commented out.)\n");
3996 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3998 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4001 for (i = 0; sound_config[i].token != NULL; i++)
4002 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4003 sound_config[i].value));
4007 else if (strEqual(command, "print musicinfo.conf"))
4009 printf("# You can configure additional/alternative music files here.\n");
4010 printf("# (The entries below are default and therefore commented out.)\n");
4012 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4014 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4017 for (i = 0; music_config[i].token != NULL; i++)
4018 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4019 music_config[i].value));
4023 else if (strEqual(command, "print editorsetup.conf"))
4025 printf("# You can configure your personal editor element list here.\n");
4026 printf("# (The entries below are default and therefore commented out.)\n");
4029 /* this is needed to be able to check element list for cascade elements */
4030 InitElementPropertiesStatic();
4031 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4033 PrintEditorElementList();
4037 else if (strEqual(command, "print helpanim.conf"))
4039 printf("# You can configure different element help animations here.\n");
4040 printf("# (The entries below are default and therefore commented out.)\n");
4043 for (i = 0; helpanim_config[i].token != NULL; i++)
4045 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4046 helpanim_config[i].value));
4048 if (strEqual(helpanim_config[i].token, "end"))
4054 else if (strEqual(command, "print helptext.conf"))
4056 printf("# You can configure different element help text here.\n");
4057 printf("# (The entries below are default and therefore commented out.)\n");
4060 for (i = 0; helptext_config[i].token != NULL; i++)
4061 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4062 helptext_config[i].value));
4066 else if (strncmp(command, "dump level ", 11) == 0)
4068 char *filename = &command[11];
4070 if (!fileExists(filename))
4071 Error(ERR_EXIT, "cannot open file '%s'", filename);
4073 LoadLevelFromFilename(&level, filename);
4078 else if (strncmp(command, "dump tape ", 10) == 0)
4080 char *filename = &command[10];
4082 if (!fileExists(filename))
4083 Error(ERR_EXIT, "cannot open file '%s'", filename);
4085 LoadTapeFromFilename(filename);
4090 else if (strncmp(command, "autoplay ", 9) == 0)
4092 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4094 while (*str_ptr != '\0') /* continue parsing string */
4096 /* cut leading whitespace from string, replace it by string terminator */
4097 while (*str_ptr == ' ' || *str_ptr == '\t')
4100 if (*str_ptr == '\0') /* end of string reached */
4103 if (global.autoplay_leveldir == NULL) /* read level set string */
4105 global.autoplay_leveldir = str_ptr;
4106 global.autoplay_all = TRUE; /* default: play all tapes */
4108 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4109 global.autoplay_level[i] = FALSE;
4111 else /* read level number string */
4113 int level_nr = atoi(str_ptr); /* get level_nr value */
4115 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4116 global.autoplay_level[level_nr] = TRUE;
4118 global.autoplay_all = FALSE;
4121 /* advance string pointer to the next whitespace (or end of string) */
4122 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4126 else if (strncmp(command, "convert ", 8) == 0)
4128 char *str_copy = getStringCopy(&command[8]);
4129 char *str_ptr = strchr(str_copy, ' ');
4131 global.convert_leveldir = str_copy;
4132 global.convert_level_nr = -1;
4134 if (str_ptr != NULL) /* level number follows */
4136 *str_ptr++ = '\0'; /* terminate leveldir string */
4137 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4142 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4146 static void InitSetup()
4148 LoadSetup(); /* global setup info */
4150 /* set some options from setup file */
4152 if (setup.options.verbose)
4153 options.verbose = TRUE;
4156 static void InitGameInfo()
4158 game.restart_level = FALSE;
4161 static void InitPlayerInfo()
4165 /* choose default local player */
4166 local_player = &stored_player[0];
4168 for (i = 0; i < MAX_PLAYERS; i++)
4169 stored_player[i].connected = FALSE;
4171 local_player->connected = TRUE;
4174 static void InitArtworkInfo()
4179 static char *get_string_in_brackets(char *string)
4181 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4183 sprintf(string_in_brackets, "[%s]", string);
4185 return string_in_brackets;
4188 static char *get_level_id_suffix(int id_nr)
4190 char *id_suffix = checked_malloc(1 + 3 + 1);
4192 if (id_nr < 0 || id_nr > 999)
4195 sprintf(id_suffix, ".%03d", id_nr);
4201 static char *get_element_class_token(int element)
4203 char *element_class_name = element_info[element].class_name;
4204 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4206 sprintf(element_class_token, "[%s]", element_class_name);
4208 return element_class_token;
4211 static char *get_action_class_token(int action)
4213 char *action_class_name = &element_action_info[action].suffix[1];
4214 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4216 sprintf(action_class_token, "[%s]", action_class_name);
4218 return action_class_token;
4222 static void InitArtworkConfig()
4224 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4225 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4226 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4227 static char *action_id_suffix[NUM_ACTIONS + 1];
4228 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4229 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4230 static char *level_id_suffix[MAX_LEVELS + 1];
4231 static char *dummy[1] = { NULL };
4232 static char *ignore_generic_tokens[] =
4238 static char **ignore_image_tokens;
4239 static char **ignore_sound_tokens;
4240 static char **ignore_music_tokens;
4241 int num_ignore_generic_tokens;
4242 int num_ignore_image_tokens;
4243 int num_ignore_sound_tokens;
4244 int num_ignore_music_tokens;
4247 /* dynamically determine list of generic tokens to be ignored */
4248 num_ignore_generic_tokens = 0;
4249 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4250 num_ignore_generic_tokens++;
4252 /* dynamically determine list of image tokens to be ignored */
4253 num_ignore_image_tokens = num_ignore_generic_tokens;
4254 for (i = 0; image_config_vars[i].token != NULL; i++)
4255 num_ignore_image_tokens++;
4256 ignore_image_tokens =
4257 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4258 for (i = 0; i < num_ignore_generic_tokens; i++)
4259 ignore_image_tokens[i] = ignore_generic_tokens[i];
4260 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4261 ignore_image_tokens[num_ignore_generic_tokens + i] =
4262 image_config_vars[i].token;
4263 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4265 /* dynamically determine list of sound tokens to be ignored */
4266 num_ignore_sound_tokens = num_ignore_generic_tokens;
4267 ignore_sound_tokens =
4268 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4269 for (i = 0; i < num_ignore_generic_tokens; i++)
4270 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4271 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4273 /* dynamically determine list of music tokens to be ignored */
4274 num_ignore_music_tokens = num_ignore_generic_tokens;
4275 ignore_music_tokens =
4276 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4277 for (i = 0; i < num_ignore_generic_tokens; i++)
4278 ignore_music_tokens[i] = ignore_generic_tokens[i];
4279 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4281 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4282 image_id_prefix[i] = element_info[i].token_name;
4283 for (i = 0; i < NUM_FONTS; i++)
4284 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4285 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4287 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4288 sound_id_prefix[i] = element_info[i].token_name;
4289 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4290 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4291 get_string_in_brackets(element_info[i].class_name);
4292 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4294 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4295 music_id_prefix[i] = music_prefix_info[i].prefix;
4296 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4298 for (i = 0; i < NUM_ACTIONS; i++)
4299 action_id_suffix[i] = element_action_info[i].suffix;
4300 action_id_suffix[NUM_ACTIONS] = NULL;
4302 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4303 direction_id_suffix[i] = element_direction_info[i].suffix;
4304 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4306 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4307 special_id_suffix[i] = special_suffix_info[i].suffix;
4308 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4310 for (i = 0; i < MAX_LEVELS; i++)
4311 level_id_suffix[i] = get_level_id_suffix(i);
4312 level_id_suffix[MAX_LEVELS] = NULL;
4314 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4315 image_id_prefix, action_id_suffix, direction_id_suffix,
4316 special_id_suffix, ignore_image_tokens);
4317 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4318 sound_id_prefix, action_id_suffix, dummy,
4319 special_id_suffix, ignore_sound_tokens);
4320 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4321 music_id_prefix, special_id_suffix, level_id_suffix,
4322 dummy, ignore_music_tokens);
4325 static void InitMixer()
4333 char *filename_font_initial = NULL;
4334 Bitmap *bitmap_font_initial = NULL;
4337 /* determine settings for initial font (for displaying startup messages) */
4338 for (i = 0; image_config[i].token != NULL; i++)
4340 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4342 char font_token[128];
4345 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4346 len_font_token = strlen(font_token);
4348 if (strEqual(image_config[i].token, font_token))
4349 filename_font_initial = image_config[i].value;
4350 else if (strlen(image_config[i].token) > len_font_token &&
4351 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4353 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4354 font_initial[j].src_x = atoi(image_config[i].value);
4355 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4356 font_initial[j].src_y = atoi(image_config[i].value);
4357 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4358 font_initial[j].width = atoi(image_config[i].value);
4359 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4360 font_initial[j].height = atoi(image_config[i].value);
4365 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4367 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4368 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4371 if (filename_font_initial == NULL) /* should not happen */
4372 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4374 /* create additional image buffers for double-buffering */
4375 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4376 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4378 /* initialize screen properties */
4379 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4380 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4382 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4383 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4384 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4386 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4388 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4389 font_initial[j].bitmap = bitmap_font_initial;
4391 InitFontGraphicInfo();
4393 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4394 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4396 DrawInitText("Loading graphics:", 120, FC_GREEN);
4399 void InitGfxBackground()
4403 drawto = backbuffer;
4404 fieldbuffer = bitmap_db_field;
4405 SetDrawtoField(DRAW_BACKBUFFER);
4407 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4408 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4409 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4410 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4412 for (x = 0; x < MAX_BUF_XSIZE; x++)
4413 for (y = 0; y < MAX_BUF_YSIZE; y++)
4416 redraw_mask = REDRAW_ALL;
4419 static void InitLevelInfo()
4421 LoadLevelInfo(); /* global level info */
4422 LoadLevelSetup_LastSeries(); /* last played series info */
4423 LoadLevelSetup_SeriesInfo(); /* last played level info */
4426 void InitLevelArtworkInfo()
4428 LoadLevelArtworkInfo();
4431 static void InitImages()
4433 setLevelArtworkDir(artwork.gfx_first);
4436 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4437 leveldir_current->identifier,
4438 artwork.gfx_current_identifier,
4439 artwork.gfx_current->identifier,
4440 leveldir_current->graphics_set,
4441 leveldir_current->graphics_path);
4444 ReloadCustomImages();
4446 LoadCustomElementDescriptions();
4447 LoadSpecialMenuDesignSettings();
4449 ReinitializeGraphics();
4452 static void InitSound(char *identifier)
4454 if (identifier == NULL)
4455 identifier = artwork.snd_current->identifier;
4457 /* set artwork path to send it to the sound server process */
4458 setLevelArtworkDir(artwork.snd_first);
4460 InitReloadCustomSounds(identifier);
4461 ReinitializeSounds();
4464 static void InitMusic(char *identifier)
4466 if (identifier == NULL)
4467 identifier = artwork.mus_current->identifier;
4469 /* set artwork path to send it to the sound server process */
4470 setLevelArtworkDir(artwork.mus_first);
4472 InitReloadCustomMusic(identifier);
4473 ReinitializeMusic();
4476 void InitNetworkServer()
4478 #if defined(NETWORK_AVALIABLE)
4482 if (!options.network)
4485 #if defined(NETWORK_AVALIABLE)
4486 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4488 if (!ConnectToServer(options.server_host, options.server_port))
4489 Error(ERR_EXIT, "cannot connect to network game server");
4491 SendToServer_PlayerName(setup.player_name);
4492 SendToServer_ProtocolVersion();
4495 SendToServer_NrWanted(nr_wanted);
4499 static char *getNewArtworkIdentifier(int type)
4501 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4502 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4503 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4504 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4505 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4506 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4507 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4508 char *leveldir_identifier = leveldir_current->identifier;
4510 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4511 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4513 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4515 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4516 char *artwork_current_identifier;
4517 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4519 /* leveldir_current may be invalid (level group, parent link) */
4520 if (!validLevelSeries(leveldir_current))
4523 /* 1st step: determine artwork set to be activated in descending order:
4524 --------------------------------------------------------------------
4525 1. setup artwork (when configured to override everything else)
4526 2. artwork set configured in "levelinfo.conf" of current level set
4527 (artwork in level directory will have priority when loading later)
4528 3. artwork in level directory (stored in artwork sub-directory)
4529 4. setup artwork (currently configured in setup menu) */
4531 if (setup_override_artwork)
4532 artwork_current_identifier = setup_artwork_set;
4533 else if (leveldir_artwork_set != NULL)
4534 artwork_current_identifier = leveldir_artwork_set;
4535 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4536 artwork_current_identifier = leveldir_identifier;
4538 artwork_current_identifier = setup_artwork_set;
4541 /* 2nd step: check if it is really needed to reload artwork set
4542 ------------------------------------------------------------ */
4545 if (type == ARTWORK_TYPE_GRAPHICS)
4546 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4547 artwork_new_identifier,
4548 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4549 artwork_current_identifier,
4550 leveldir_current->graphics_set,
4551 leveldir_current->identifier);
4554 /* ---------- reload if level set and also artwork set has changed ------- */
4555 if (leveldir_current_identifier[type] != leveldir_identifier &&
4556 (last_has_level_artwork_set[type] || has_level_artwork_set))
4557 artwork_new_identifier = artwork_current_identifier;
4559 leveldir_current_identifier[type] = leveldir_identifier;
4560 last_has_level_artwork_set[type] = has_level_artwork_set;
4563 if (type == ARTWORK_TYPE_GRAPHICS)
4564 printf("::: 1: '%s'\n", artwork_new_identifier);
4567 /* ---------- reload if "override artwork" setting has changed ----------- */
4568 if (last_override_level_artwork[type] != setup_override_artwork)
4569 artwork_new_identifier = artwork_current_identifier;
4571 last_override_level_artwork[type] = setup_override_artwork;
4574 if (type == ARTWORK_TYPE_GRAPHICS)
4575 printf("::: 2: '%s'\n", artwork_new_identifier);
4578 /* ---------- reload if current artwork identifier has changed ----------- */
4579 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4580 artwork_current_identifier))
4581 artwork_new_identifier = artwork_current_identifier;
4583 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4586 if (type == ARTWORK_TYPE_GRAPHICS)
4587 printf("::: 3: '%s'\n", artwork_new_identifier);
4590 /* ---------- do not reload directly after starting ---------------------- */
4591 if (!initialized[type])
4592 artwork_new_identifier = NULL;
4594 initialized[type] = TRUE;
4597 if (type == ARTWORK_TYPE_GRAPHICS)
4598 printf("::: 4: '%s'\n", artwork_new_identifier);
4602 if (type == ARTWORK_TYPE_GRAPHICS)
4603 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4604 artwork.gfx_current_identifier, artwork_current_identifier,
4605 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4606 artwork_new_identifier);
4609 return artwork_new_identifier;
4612 void ReloadCustomArtwork(int force_reload)
4614 char *gfx_new_identifier;
4615 char *snd_new_identifier;
4616 char *mus_new_identifier;
4617 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4618 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4619 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4620 boolean redraw_screen = FALSE;
4622 force_reload_gfx |= AdjustGraphicsForEMC();
4624 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4625 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4626 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4628 if (gfx_new_identifier != NULL || force_reload_gfx)
4631 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4632 artwork.gfx_current_identifier,
4634 artwork.gfx_current->identifier,
4635 leveldir_current->graphics_set);
4638 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4642 redraw_screen = TRUE;
4645 if (snd_new_identifier != NULL || force_reload_snd)
4647 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4649 InitSound(snd_new_identifier);
4651 redraw_screen = TRUE;
4654 if (mus_new_identifier != NULL || force_reload_mus)
4656 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4658 InitMusic(mus_new_identifier);
4660 redraw_screen = TRUE;
4665 InitGfxBackground();
4667 /* force redraw of (open or closed) door graphics */
4668 SetDoorState(DOOR_OPEN_ALL);
4669 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4673 void KeyboardAutoRepeatOffUnlessAutoplay()
4675 if (global.autoplay_leveldir == NULL)
4676 KeyboardAutoRepeatOff();
4680 /* ========================================================================= */
4682 /* ========================================================================= */
4686 InitGlobal(); /* initialize some global variables */
4688 if (options.execute_command)
4689 Execute_Command(options.execute_command);
4691 if (options.serveronly)
4693 #if defined(PLATFORM_UNIX)
4694 NetworkServer(options.server_port, options.serveronly);
4696 Error(ERR_WARN, "networking only supported in Unix version");
4699 exit(0); /* never reached, server loops forever */
4706 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4707 InitArtworkConfig(); /* needed before forking sound child process */
4712 InitRND(NEW_RANDOMIZE);
4713 InitSimpleRND(NEW_RANDOMIZE);
4718 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4721 InitEventFilter(FilterMouseMotionEvents);
4723 InitElementPropertiesStatic();
4724 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4729 InitLevelArtworkInfo();
4731 InitImages(); /* needs to know current level directory */
4732 InitSound(NULL); /* needs to know current level directory */
4733 InitMusic(NULL); /* needs to know current level directory */
4735 InitGfxBackground();
4737 if (global.autoplay_leveldir)
4742 else if (global.convert_leveldir)
4748 game_status = GAME_MODE_MAIN;
4756 InitNetworkServer();
4759 void CloseAllAndExit(int exit_value)
4764 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4772 #if defined(TARGET_SDL)
4773 if (network_server) /* terminate network server */
4774 SDL_KillThread(server_thread);
4777 CloseVideoDisplay();
4778 ClosePlatformDependentStuff();