1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 gadgets_initialized = TRUE;
110 inline void InitElementSmallImagesScaledUp(int graphic)
112 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
115 void InitElementSmallImages()
117 static int special_graphics[] =
119 IMG_EDITOR_ELEMENT_BORDER,
120 IMG_EDITOR_ELEMENT_BORDER_INPUT,
121 IMG_EDITOR_CASCADE_LIST,
122 IMG_EDITOR_CASCADE_LIST_ACTIVE,
125 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126 int num_property_mappings = getImageListPropertyMappingSize();
129 /* initialize normal images from static configuration */
130 for (i = 0; element_to_graphic[i].element > -1; i++)
131 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
133 /* initialize special images from static configuration */
134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
135 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
137 /* initialize images from dynamic configuration (may be elements or other) */
138 for (i = 0; i < num_property_mappings; i++)
139 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
141 /* initialize special images from above list (non-element images) */
142 for (i = 0; special_graphics[i] > -1; i++)
143 InitElementSmallImagesScaledUp(special_graphics[i]);
146 void InitScaledImages()
150 /* scale normal images from static configuration, if not already scaled */
151 for (i = 0; i < NUM_IMAGE_FILES; i++)
152 ScaleImage(i, graphic_info[i].scale_up_factor);
156 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
157 void SetBitmaps_EM(Bitmap **em_bitmap)
159 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
160 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
164 static int getFontBitmapID(int font_nr)
168 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
169 special = game_status;
170 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
171 special = GFX_SPECIAL_ARG_MAIN;
172 else if (game_status == GAME_MODE_PLAYING)
173 special = GFX_SPECIAL_ARG_DOOR;
176 return font_info[font_nr].special_bitmap_id[special];
181 void InitFontGraphicInfo()
183 static struct FontBitmapInfo *font_bitmap_info = NULL;
184 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
185 int num_property_mappings = getImageListPropertyMappingSize();
186 int num_font_bitmaps = NUM_FONTS;
189 if (graphic_info == NULL) /* still at startup phase */
191 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
196 /* ---------- initialize font graphic definitions ---------- */
198 /* always start with reliable default values (normal font graphics) */
199 for (i = 0; i < NUM_FONTS; i++)
200 font_info[i].graphic = IMG_FONT_INITIAL_1;
202 /* initialize normal font/graphic mapping from static configuration */
203 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
205 int font_nr = font_to_graphic[i].font_nr;
206 int special = font_to_graphic[i].special;
207 int graphic = font_to_graphic[i].graphic;
212 font_info[font_nr].graphic = graphic;
215 /* always start with reliable default values (special font graphics) */
216 for (i = 0; i < NUM_FONTS; i++)
218 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
220 font_info[i].special_graphic[j] = font_info[i].graphic;
221 font_info[i].special_bitmap_id[j] = i;
225 /* initialize special font/graphic mapping from static configuration */
226 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
228 int font_nr = font_to_graphic[i].font_nr;
229 int special = font_to_graphic[i].special;
230 int graphic = font_to_graphic[i].graphic;
231 int base_graphic = font2baseimg(font_nr);
233 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
235 boolean base_redefined =
236 getImageListEntryFromImageID(base_graphic)->redefined;
237 boolean special_redefined =
238 getImageListEntryFromImageID(graphic)->redefined;
240 /* if the base font ("font.title_1", for example) has been redefined,
241 but not the special font ("font.title_1.LEVELS", for example), do not
242 use an existing (in this case considered obsolete) special font
243 anymore, but use the automatically determined default font */
244 if (base_redefined && !special_redefined)
247 font_info[font_nr].special_graphic[special] = graphic;
248 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
253 /* initialize special element/graphic mapping from dynamic configuration */
254 for (i = 0; i < num_property_mappings; i++)
256 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
257 int special = property_mapping[i].ext3_index;
258 int graphic = property_mapping[i].artwork_index;
263 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
265 font_info[font_nr].special_graphic[special] = graphic;
266 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
271 /* ---------- initialize font bitmap array ---------- */
273 if (font_bitmap_info != NULL)
274 FreeFontInfo(font_bitmap_info);
277 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
279 /* ---------- initialize font bitmap definitions ---------- */
281 for (i = 0; i < NUM_FONTS; i++)
283 if (i < NUM_INITIAL_FONTS)
285 font_bitmap_info[i] = font_initial[i];
289 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
291 int font_bitmap_id = font_info[i].special_bitmap_id[j];
292 int graphic = font_info[i].special_graphic[j];
294 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
295 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
297 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
298 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
301 /* copy font relevant information from graphics information */
302 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
303 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
304 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
305 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
306 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
308 font_bitmap_info[font_bitmap_id].draw_xoffset =
309 graphic_info[graphic].draw_xoffset;
310 font_bitmap_info[font_bitmap_id].draw_yoffset =
311 graphic_info[graphic].draw_yoffset;
313 font_bitmap_info[font_bitmap_id].num_chars =
314 graphic_info[graphic].anim_frames;
315 font_bitmap_info[font_bitmap_id].num_chars_per_line =
316 graphic_info[graphic].anim_frames_per_line;
320 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
323 void InitElementGraphicInfo()
325 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
326 int num_property_mappings = getImageListPropertyMappingSize();
329 if (graphic_info == NULL) /* still at startup phase */
332 /* set values to -1 to identify later as "uninitialized" values */
333 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
335 for (act = 0; act < NUM_ACTIONS; act++)
337 element_info[i].graphic[act] = -1;
338 element_info[i].crumbled[act] = -1;
340 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
342 element_info[i].direction_graphic[act][dir] = -1;
343 element_info[i].direction_crumbled[act][dir] = -1;
348 /* initialize normal element/graphic mapping from static configuration */
349 for (i = 0; element_to_graphic[i].element > -1; i++)
351 int element = element_to_graphic[i].element;
352 int action = element_to_graphic[i].action;
353 int direction = element_to_graphic[i].direction;
354 boolean crumbled = element_to_graphic[i].crumbled;
355 int graphic = element_to_graphic[i].graphic;
356 int base_graphic = el2baseimg(element);
358 if (graphic_info[graphic].bitmap == NULL)
361 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
364 boolean base_redefined =
365 getImageListEntryFromImageID(base_graphic)->redefined;
366 boolean act_dir_redefined =
367 getImageListEntryFromImageID(graphic)->redefined;
369 /* if the base graphic ("emerald", for example) has been redefined,
370 but not the action graphic ("emerald.falling", for example), do not
371 use an existing (in this case considered obsolete) action graphic
372 anymore, but use the automatically determined default graphic */
373 if (base_redefined && !act_dir_redefined)
378 action = ACTION_DEFAULT;
383 element_info[element].direction_crumbled[action][direction] = graphic;
385 element_info[element].crumbled[action] = graphic;
390 element_info[element].direction_graphic[action][direction] = graphic;
392 element_info[element].graphic[action] = graphic;
396 /* initialize normal element/graphic mapping from dynamic configuration */
397 for (i = 0; i < num_property_mappings; i++)
399 int element = property_mapping[i].base_index;
400 int action = property_mapping[i].ext1_index;
401 int direction = property_mapping[i].ext2_index;
402 int special = property_mapping[i].ext3_index;
403 int graphic = property_mapping[i].artwork_index;
404 boolean crumbled = FALSE;
406 if (special == GFX_SPECIAL_ARG_CRUMBLED)
412 if (graphic_info[graphic].bitmap == NULL)
415 if (element >= MAX_NUM_ELEMENTS || special != -1)
419 action = ACTION_DEFAULT;
424 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
425 element_info[element].direction_crumbled[action][dir] = -1;
428 element_info[element].direction_crumbled[action][direction] = graphic;
430 element_info[element].crumbled[action] = graphic;
435 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
436 element_info[element].direction_graphic[action][dir] = -1;
439 element_info[element].direction_graphic[action][direction] = graphic;
441 element_info[element].graphic[action] = graphic;
445 /* now copy all graphics that are defined to be cloned from other graphics */
446 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
448 int graphic = element_info[i].graphic[ACTION_DEFAULT];
449 int crumbled_like, diggable_like;
454 crumbled_like = graphic_info[graphic].crumbled_like;
455 diggable_like = graphic_info[graphic].diggable_like;
457 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
459 for (act = 0; act < NUM_ACTIONS; act++)
460 element_info[i].crumbled[act] =
461 element_info[crumbled_like].crumbled[act];
462 for (act = 0; act < NUM_ACTIONS; act++)
463 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
464 element_info[i].direction_crumbled[act][dir] =
465 element_info[crumbled_like].direction_crumbled[act][dir];
468 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
470 element_info[i].graphic[ACTION_DIGGING] =
471 element_info[diggable_like].graphic[ACTION_DIGGING];
472 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
473 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
474 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
479 /* set hardcoded definitions for some runtime elements without graphic */
480 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
484 /* set hardcoded definitions for some internal elements without graphic */
485 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
487 if (IS_EDITOR_CASCADE_INACTIVE(i))
488 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
489 else if (IS_EDITOR_CASCADE_ACTIVE(i))
490 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
494 /* now set all undefined/invalid graphics to -1 to set to default after it */
495 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
497 for (act = 0; act < NUM_ACTIONS; act++)
501 graphic = element_info[i].graphic[act];
502 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
503 element_info[i].graphic[act] = -1;
505 graphic = element_info[i].crumbled[act];
506 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
507 element_info[i].crumbled[act] = -1;
509 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
511 graphic = element_info[i].direction_graphic[act][dir];
512 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
513 element_info[i].direction_graphic[act][dir] = -1;
515 graphic = element_info[i].direction_crumbled[act][dir];
516 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
517 element_info[i].direction_crumbled[act][dir] = -1;
522 /* adjust graphics with 2nd tile for movement according to direction
523 (do this before correcting '-1' values to minimize calculations) */
524 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
526 for (act = 0; act < NUM_ACTIONS; act++)
528 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
530 int graphic = element_info[i].direction_graphic[act][dir];
531 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
533 if (act == ACTION_FALLING) /* special case */
534 graphic = element_info[i].graphic[act];
537 graphic_info[graphic].double_movement &&
538 graphic_info[graphic].swap_double_tiles != 0)
540 struct GraphicInfo *g = &graphic_info[graphic];
541 int src_x_front = g->src_x;
542 int src_y_front = g->src_y;
543 int src_x_back = g->src_x + g->offset2_x;
544 int src_y_back = g->src_y + g->offset2_y;
545 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
547 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
548 src_y_front < src_y_back);
549 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
550 boolean swap_movement_tiles_autodetected =
551 (!frames_are_ordered_diagonally &&
552 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
553 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
554 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
555 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
558 /* swap frontside and backside graphic tile coordinates, if needed */
559 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
561 /* get current (wrong) backside tile coordinates */
562 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
565 /* set frontside tile coordinates to backside tile coordinates */
566 g->src_x = src_x_back;
567 g->src_y = src_y_back;
569 /* invert tile offset to point to new backside tile coordinates */
573 /* do not swap front and backside tiles again after correction */
574 g->swap_double_tiles = 0;
581 /* now set all '-1' values to element specific default values */
582 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
584 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
585 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
586 int default_direction_graphic[NUM_DIRECTIONS_FULL];
587 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
589 if (default_graphic == -1)
590 default_graphic = IMG_UNKNOWN;
592 if (default_crumbled == -1)
593 default_crumbled = default_graphic;
595 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
596 if (default_crumbled == -1)
597 default_crumbled = IMG_EMPTY;
600 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
602 default_direction_graphic[dir] =
603 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
604 default_direction_crumbled[dir] =
605 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
607 if (default_direction_graphic[dir] == -1)
608 default_direction_graphic[dir] = default_graphic;
610 if (default_direction_crumbled[dir] == -1)
611 default_direction_crumbled[dir] = default_direction_graphic[dir];
613 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
614 if (default_direction_crumbled[dir] == -1)
615 default_direction_crumbled[dir] = default_crumbled;
619 for (act = 0; act < NUM_ACTIONS; act++)
621 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
622 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
623 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
624 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
625 act == ACTION_TURNING_FROM_RIGHT ||
626 act == ACTION_TURNING_FROM_UP ||
627 act == ACTION_TURNING_FROM_DOWN);
629 /* generic default action graphic (defined by "[default]" directive) */
630 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
631 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
632 int default_remove_graphic = IMG_EMPTY;
634 if (act_remove && default_action_graphic != -1)
635 default_remove_graphic = default_action_graphic;
637 /* look for special default action graphic (classic game specific) */
638 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
639 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
640 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
641 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
642 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
643 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
645 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
646 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
647 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
648 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
649 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
650 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
653 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
654 /* !!! make this better !!! */
655 if (i == EL_EMPTY_SPACE)
657 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
658 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
662 if (default_action_graphic == -1)
663 default_action_graphic = default_graphic;
665 if (default_action_crumbled == -1)
666 default_action_crumbled = default_action_graphic;
668 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
669 if (default_action_crumbled == -1)
670 default_action_crumbled = default_crumbled;
673 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
675 /* use action graphic as the default direction graphic, if undefined */
676 int default_action_direction_graphic = element_info[i].graphic[act];
677 int default_action_direction_crumbled = element_info[i].crumbled[act];
679 /* no graphic for current action -- use default direction graphic */
680 if (default_action_direction_graphic == -1)
681 default_action_direction_graphic =
682 (act_remove ? default_remove_graphic :
684 element_info[i].direction_graphic[ACTION_TURNING][dir] :
685 default_action_graphic != default_graphic ?
686 default_action_graphic :
687 default_direction_graphic[dir]);
689 if (element_info[i].direction_graphic[act][dir] == -1)
690 element_info[i].direction_graphic[act][dir] =
691 default_action_direction_graphic;
694 if (default_action_direction_crumbled == -1)
695 default_action_direction_crumbled =
696 element_info[i].direction_graphic[act][dir];
698 if (default_action_direction_crumbled == -1)
699 default_action_direction_crumbled =
700 (act_remove ? default_remove_graphic :
702 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
703 default_action_crumbled != default_crumbled ?
704 default_action_crumbled :
705 default_direction_crumbled[dir]);
708 if (element_info[i].direction_crumbled[act][dir] == -1)
709 element_info[i].direction_crumbled[act][dir] =
710 default_action_direction_crumbled;
713 /* no graphic for this specific action -- use default action graphic */
714 if (element_info[i].graphic[act] == -1)
715 element_info[i].graphic[act] =
716 (act_remove ? default_remove_graphic :
717 act_turning ? element_info[i].graphic[ACTION_TURNING] :
718 default_action_graphic);
720 if (element_info[i].crumbled[act] == -1)
721 element_info[i].crumbled[act] = element_info[i].graphic[act];
723 if (element_info[i].crumbled[act] == -1)
724 element_info[i].crumbled[act] =
725 (act_remove ? default_remove_graphic :
726 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
727 default_action_crumbled);
733 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
734 /* set animation mode to "none" for each graphic with only 1 frame */
735 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
737 for (act = 0; act < NUM_ACTIONS; act++)
739 int graphic = element_info[i].graphic[act];
740 int crumbled = element_info[i].crumbled[act];
742 if (graphic_info[graphic].anim_frames == 1)
743 graphic_info[graphic].anim_mode = ANIM_NONE;
744 if (graphic_info[crumbled].anim_frames == 1)
745 graphic_info[crumbled].anim_mode = ANIM_NONE;
747 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
749 graphic = element_info[i].direction_graphic[act][dir];
750 crumbled = element_info[i].direction_crumbled[act][dir];
752 if (graphic_info[graphic].anim_frames == 1)
753 graphic_info[graphic].anim_mode = ANIM_NONE;
754 if (graphic_info[crumbled].anim_frames == 1)
755 graphic_info[crumbled].anim_mode = ANIM_NONE;
765 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
766 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
768 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
769 element_info[i].token_name, i);
775 void InitElementSpecialGraphicInfo()
777 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
778 int num_property_mappings = getImageListPropertyMappingSize();
781 /* always start with reliable default values */
782 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
783 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
784 element_info[i].special_graphic[j] =
785 element_info[i].graphic[ACTION_DEFAULT];
787 /* initialize special element/graphic mapping from static configuration */
788 for (i = 0; element_to_special_graphic[i].element > -1; i++)
790 int element = element_to_special_graphic[i].element;
791 int special = element_to_special_graphic[i].special;
792 int graphic = element_to_special_graphic[i].graphic;
793 int base_graphic = el2baseimg(element);
794 boolean base_redefined =
795 getImageListEntryFromImageID(base_graphic)->redefined;
796 boolean special_redefined =
797 getImageListEntryFromImageID(graphic)->redefined;
799 /* if the base graphic ("emerald", for example) has been redefined,
800 but not the special graphic ("emerald.EDITOR", for example), do not
801 use an existing (in this case considered obsolete) special graphic
802 anymore, but use the automatically created (down-scaled) graphic */
803 if (base_redefined && !special_redefined)
806 element_info[element].special_graphic[special] = graphic;
809 /* initialize special element/graphic mapping from dynamic configuration */
810 for (i = 0; i < num_property_mappings; i++)
812 int element = property_mapping[i].base_index;
813 int special = property_mapping[i].ext3_index;
814 int graphic = property_mapping[i].artwork_index;
816 if (element >= MAX_NUM_ELEMENTS)
819 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
820 element_info[element].special_graphic[special] = graphic;
823 /* now set all undefined/invalid graphics to default */
824 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
825 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
826 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
827 element_info[i].special_graphic[j] =
828 element_info[i].graphic[ACTION_DEFAULT];
831 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
836 if (type != TYPE_TOKEN)
837 return get_parameter_value(value_raw, suffix, type);
839 if (strEqual(value_raw, ARG_UNDEFINED))
840 return ARG_UNDEFINED_VALUE;
842 /* !!! OPTIMIZE THIS BY USING HASH !!! */
843 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
844 if (strEqual(element_info[i].token_name, value_raw))
847 /* !!! OPTIMIZE THIS BY USING HASH !!! */
848 for (i = 0; image_config[i].token != NULL; i++)
850 int len_config_value = strlen(image_config[i].value);
852 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
853 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
854 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
857 if (strEqual(image_config[i].token, value_raw))
866 static int get_scaled_graphic_width(int graphic)
868 int original_width = getOriginalImageWidthFromImageID(graphic);
869 int scale_up_factor = graphic_info[graphic].scale_up_factor;
871 return original_width * scale_up_factor;
874 static int get_scaled_graphic_height(int graphic)
876 int original_height = getOriginalImageHeightFromImageID(graphic);
877 int scale_up_factor = graphic_info[graphic].scale_up_factor;
879 return original_height * scale_up_factor;
882 static void set_graphic_parameters(int graphic)
884 struct FileInfo *image = getImageListEntryFromImageID(graphic);
885 char **parameter_raw = image->parameter;
886 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
887 int parameter[NUM_GFX_ARGS];
888 int anim_frames_per_row = 1, anim_frames_per_col = 1;
889 int anim_frames_per_line = 1;
892 /* if fallback to default artwork is done, also use the default parameters */
893 if (image->fallback_to_default)
894 parameter_raw = image->default_parameter;
896 /* get integer values from string parameters */
897 for (i = 0; i < NUM_GFX_ARGS; i++)
898 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
899 image_config_suffix[i].token,
900 image_config_suffix[i].type);
902 graphic_info[graphic].bitmap = src_bitmap;
904 /* start with reliable default values */
905 graphic_info[graphic].src_image_width = 0;
906 graphic_info[graphic].src_image_height = 0;
907 graphic_info[graphic].src_x = 0;
908 graphic_info[graphic].src_y = 0;
909 graphic_info[graphic].width = TILEX;
910 graphic_info[graphic].height = TILEY;
911 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
912 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
913 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
914 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
915 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
916 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
917 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
918 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
919 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
920 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
921 graphic_info[graphic].anim_delay_fixed = 0;
922 graphic_info[graphic].anim_delay_random = 0;
923 graphic_info[graphic].post_delay_fixed = 0;
924 graphic_info[graphic].post_delay_random = 0;
926 /* optional x and y tile position of animation frame sequence */
927 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
928 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
929 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
930 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
932 /* optional x and y pixel position of animation frame sequence */
933 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
934 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
935 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
936 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
938 /* optional width and height of each animation frame */
939 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
940 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
941 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
942 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
944 /* optional zoom factor for scaling up the image to a larger size */
945 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
946 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
947 if (graphic_info[graphic].scale_up_factor < 1)
948 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
952 /* get final bitmap size (with scaling, but without small images) */
953 int src_image_width = get_scaled_graphic_width(graphic);
954 int src_image_height = get_scaled_graphic_height(graphic);
956 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
957 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
959 graphic_info[graphic].src_image_width = src_image_width;
960 graphic_info[graphic].src_image_height = src_image_height;
963 /* correct x or y offset dependent of vertical or horizontal frame order */
964 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
966 graphic_info[graphic].offset_y =
967 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
968 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
969 anim_frames_per_line = anim_frames_per_col;
971 else /* frames are ordered horizontally */
973 graphic_info[graphic].offset_x =
974 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
975 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
976 anim_frames_per_line = anim_frames_per_row;
979 /* optionally, the x and y offset of frames can be specified directly */
980 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
981 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
982 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
983 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
985 /* optionally, moving animations may have separate start and end graphics */
986 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
988 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
989 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
991 /* correct x or y offset2 dependent of vertical or horizontal frame order */
992 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
993 graphic_info[graphic].offset2_y =
994 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
995 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
996 else /* frames are ordered horizontally */
997 graphic_info[graphic].offset2_x =
998 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
999 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1001 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1002 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1003 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1004 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1005 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1007 /* optionally, the second movement tile can be specified as start tile */
1008 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1009 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1011 /* automatically determine correct number of frames, if not defined */
1012 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1013 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1014 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1015 graphic_info[graphic].anim_frames = anim_frames_per_row;
1016 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1017 graphic_info[graphic].anim_frames = anim_frames_per_col;
1019 graphic_info[graphic].anim_frames = 1;
1021 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1022 graphic_info[graphic].anim_frames = 1;
1024 graphic_info[graphic].anim_frames_per_line =
1025 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1026 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1028 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1029 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1030 graphic_info[graphic].anim_delay = 1;
1032 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1034 if (graphic_info[graphic].anim_frames == 1)
1035 graphic_info[graphic].anim_mode = ANIM_NONE;
1038 /* automatically determine correct start frame, if not defined */
1039 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1040 graphic_info[graphic].anim_start_frame = 0;
1041 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1042 graphic_info[graphic].anim_start_frame =
1043 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1045 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1047 /* animation synchronized with global frame counter, not move position */
1048 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1050 /* optional element for cloning crumble graphics */
1051 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1054 /* optional element for cloning digging graphics */
1055 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1056 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1058 /* optional border size for "crumbling" diggable graphics */
1059 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1060 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1062 /* this is only used for player "boring" and "sleeping" actions */
1063 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].anim_delay_fixed =
1065 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1066 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1067 graphic_info[graphic].anim_delay_random =
1068 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1069 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1070 graphic_info[graphic].post_delay_fixed =
1071 parameter[GFX_ARG_POST_DELAY_FIXED];
1072 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].post_delay_random =
1074 parameter[GFX_ARG_POST_DELAY_RANDOM];
1076 /* this is only used for toon animations */
1077 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1078 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1080 /* this is only used for drawing font characters */
1081 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1082 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1084 /* this is only used for drawing envelope graphics */
1085 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1087 /* optional graphic for cloning all graphics settings */
1088 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1089 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1092 static void set_cloned_graphic_parameters(int graphic)
1094 int fallback_graphic = IMG_CHAR_EXCLAM;
1095 int max_num_images = getImageListSize();
1096 int clone_graphic = graphic_info[graphic].clone_from;
1097 int num_references_followed = 1;
1099 while (graphic_info[clone_graphic].clone_from != -1 &&
1100 num_references_followed < max_num_images)
1102 clone_graphic = graphic_info[clone_graphic].clone_from;
1104 num_references_followed++;
1107 if (num_references_followed >= max_num_images)
1109 Error(ERR_RETURN_LINE, "-");
1110 Error(ERR_RETURN, "warning: error found in config file:");
1111 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1112 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1113 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1114 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1116 if (graphic == fallback_graphic)
1117 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1119 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1120 Error(ERR_RETURN_LINE, "-");
1122 graphic_info[graphic] = graphic_info[fallback_graphic];
1126 graphic_info[graphic] = graphic_info[clone_graphic];
1127 graphic_info[graphic].clone_from = clone_graphic;
1131 static void InitGraphicInfo()
1133 int fallback_graphic = IMG_CHAR_EXCLAM;
1134 int num_images = getImageListSize();
1137 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1138 static boolean clipmasks_initialized = FALSE;
1140 XGCValues clip_gc_values;
1141 unsigned long clip_gc_valuemask;
1142 GC copy_clipmask_gc = None;
1145 checked_free(graphic_info);
1147 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1149 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1150 if (clipmasks_initialized)
1152 for (i = 0; i < num_images; i++)
1154 if (graphic_info[i].clip_mask)
1155 XFreePixmap(display, graphic_info[i].clip_mask);
1156 if (graphic_info[i].clip_gc)
1157 XFreeGC(display, graphic_info[i].clip_gc);
1159 graphic_info[i].clip_mask = None;
1160 graphic_info[i].clip_gc = None;
1165 /* first set all graphic paramaters ... */
1166 for (i = 0; i < num_images; i++)
1167 set_graphic_parameters(i);
1169 /* ... then copy these parameters for cloned graphics */
1170 for (i = 0; i < num_images; i++)
1171 if (graphic_info[i].clone_from != -1)
1172 set_cloned_graphic_parameters(i);
1174 for (i = 0; i < num_images; i++)
1178 int first_frame, last_frame;
1179 int src_bitmap_width, src_bitmap_height;
1181 /* now check if no animation frames are outside of the loaded image */
1183 if (graphic_info[i].bitmap == NULL)
1184 continue; /* skip check for optional images that are undefined */
1186 /* get final bitmap size (with scaling, but without small images) */
1187 src_bitmap_width = graphic_info[i].src_image_width;
1188 src_bitmap_height = graphic_info[i].src_image_height;
1190 /* check if first animation frame is inside specified bitmap */
1193 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1195 if (src_x < 0 || src_y < 0 ||
1196 src_x + TILEX > src_bitmap_width ||
1197 src_y + TILEY > src_bitmap_height)
1199 Error(ERR_RETURN_LINE, "-");
1200 Error(ERR_RETURN, "warning: error found in config file:");
1201 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1202 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1203 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1205 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1206 src_x, src_y, src_bitmap_width, src_bitmap_height);
1207 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1209 if (i == fallback_graphic)
1210 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1212 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1213 Error(ERR_RETURN_LINE, "-");
1215 graphic_info[i] = graphic_info[fallback_graphic];
1218 /* check if last animation frame is inside specified bitmap */
1220 last_frame = graphic_info[i].anim_frames - 1;
1221 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1223 if (src_x < 0 || src_y < 0 ||
1224 src_x + TILEX > src_bitmap_width ||
1225 src_y + TILEY > src_bitmap_height)
1227 Error(ERR_RETURN_LINE, "-");
1228 Error(ERR_RETURN, "warning: error found in config file:");
1229 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1230 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1231 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1233 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1234 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1235 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1237 if (i == fallback_graphic)
1238 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1240 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1241 Error(ERR_RETURN_LINE, "-");
1243 graphic_info[i] = graphic_info[fallback_graphic];
1246 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1247 /* currently we only need a tile clip mask from the first frame */
1248 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1250 if (copy_clipmask_gc == None)
1252 clip_gc_values.graphics_exposures = False;
1253 clip_gc_valuemask = GCGraphicsExposures;
1254 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1255 clip_gc_valuemask, &clip_gc_values);
1258 graphic_info[i].clip_mask =
1259 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1261 src_pixmap = src_bitmap->clip_mask;
1262 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1263 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1265 clip_gc_values.graphics_exposures = False;
1266 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1267 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1269 graphic_info[i].clip_gc =
1270 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1274 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1275 if (copy_clipmask_gc)
1276 XFreeGC(display, copy_clipmask_gc);
1278 clipmasks_initialized = TRUE;
1282 static void InitElementSoundInfo()
1284 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1285 int num_property_mappings = getSoundListPropertyMappingSize();
1288 /* set values to -1 to identify later as "uninitialized" values */
1289 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1290 for (act = 0; act < NUM_ACTIONS; act++)
1291 element_info[i].sound[act] = -1;
1293 /* initialize element/sound mapping from static configuration */
1294 for (i = 0; element_to_sound[i].element > -1; i++)
1296 int element = element_to_sound[i].element;
1297 int action = element_to_sound[i].action;
1298 int sound = element_to_sound[i].sound;
1299 boolean is_class = element_to_sound[i].is_class;
1302 action = ACTION_DEFAULT;
1305 element_info[element].sound[action] = sound;
1307 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1308 if (strEqual(element_info[j].class_name,
1309 element_info[element].class_name))
1310 element_info[j].sound[action] = sound;
1313 /* initialize element class/sound mapping from dynamic configuration */
1314 for (i = 0; i < num_property_mappings; i++)
1316 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1317 int action = property_mapping[i].ext1_index;
1318 int sound = property_mapping[i].artwork_index;
1320 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1324 action = ACTION_DEFAULT;
1326 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1327 if (strEqual(element_info[j].class_name,
1328 element_info[element_class].class_name))
1329 element_info[j].sound[action] = sound;
1332 /* initialize element/sound mapping from dynamic configuration */
1333 for (i = 0; i < num_property_mappings; i++)
1335 int element = property_mapping[i].base_index;
1336 int action = property_mapping[i].ext1_index;
1337 int sound = property_mapping[i].artwork_index;
1339 if (element >= MAX_NUM_ELEMENTS)
1343 action = ACTION_DEFAULT;
1345 element_info[element].sound[action] = sound;
1348 /* now set all '-1' values to element specific default values */
1349 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1351 for (act = 0; act < NUM_ACTIONS; act++)
1353 /* generic default action sound (defined by "[default]" directive) */
1354 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1356 /* look for special default action sound (classic game specific) */
1357 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1358 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1359 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1360 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1361 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1362 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1364 /* !!! there's no such thing as a "default action sound" !!! */
1366 /* look for element specific default sound (independent from action) */
1367 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1368 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1372 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1373 /* !!! make this better !!! */
1374 if (i == EL_EMPTY_SPACE)
1375 default_action_sound = element_info[EL_DEFAULT].sound[act];
1378 /* no sound for this specific action -- use default action sound */
1379 if (element_info[i].sound[act] == -1)
1380 element_info[i].sound[act] = default_action_sound;
1384 /* copy sound settings to some elements that are only stored in level file
1385 in native R'n'D levels, but are used by game engine in native EM levels */
1386 for (i = 0; copy_properties[i][0] != -1; i++)
1387 for (j = 1; j <= 4; j++)
1388 for (act = 0; act < NUM_ACTIONS; act++)
1389 element_info[copy_properties[i][j]].sound[act] =
1390 element_info[copy_properties[i][0]].sound[act];
1393 static void InitGameModeSoundInfo()
1397 /* set values to -1 to identify later as "uninitialized" values */
1398 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1401 /* initialize gamemode/sound mapping from static configuration */
1402 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1404 int gamemode = gamemode_to_sound[i].gamemode;
1405 int sound = gamemode_to_sound[i].sound;
1408 gamemode = GAME_MODE_DEFAULT;
1410 menu.sound[gamemode] = sound;
1413 /* now set all '-1' values to levelset specific default values */
1414 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1415 if (menu.sound[i] == -1)
1416 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1419 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1420 if (menu.sound[i] != -1)
1421 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1425 static void set_sound_parameters(int sound, char **parameter_raw)
1427 int parameter[NUM_SND_ARGS];
1430 /* get integer values from string parameters */
1431 for (i = 0; i < NUM_SND_ARGS; i++)
1433 get_parameter_value(parameter_raw[i],
1434 sound_config_suffix[i].token,
1435 sound_config_suffix[i].type);
1437 /* explicit loop mode setting in configuration overrides default value */
1438 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1439 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1441 /* sound volume to change the original volume when loading the sound file */
1442 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1444 /* sound priority to give certain sounds a higher or lower priority */
1445 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1448 static void InitSoundInfo()
1450 int *sound_effect_properties;
1451 int num_sounds = getSoundListSize();
1454 checked_free(sound_info);
1456 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1457 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1459 /* initialize sound effect for all elements to "no sound" */
1460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1461 for (j = 0; j < NUM_ACTIONS; j++)
1462 element_info[i].sound[j] = SND_UNDEFINED;
1464 for (i = 0; i < num_sounds; i++)
1466 struct FileInfo *sound = getSoundListEntry(i);
1467 int len_effect_text = strlen(sound->token);
1469 sound_effect_properties[i] = ACTION_OTHER;
1470 sound_info[i].loop = FALSE; /* default: play sound only once */
1473 printf("::: sound %d: '%s'\n", i, sound->token);
1476 /* determine all loop sounds and identify certain sound classes */
1478 for (j = 0; element_action_info[j].suffix; j++)
1480 int len_action_text = strlen(element_action_info[j].suffix);
1482 if (len_action_text < len_effect_text &&
1483 strEqual(&sound->token[len_effect_text - len_action_text],
1484 element_action_info[j].suffix))
1486 sound_effect_properties[i] = element_action_info[j].value;
1487 sound_info[i].loop = element_action_info[j].is_loop_sound;
1493 /* associate elements and some selected sound actions */
1495 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1497 if (element_info[j].class_name)
1499 int len_class_text = strlen(element_info[j].class_name);
1501 if (len_class_text + 1 < len_effect_text &&
1502 strncmp(sound->token,
1503 element_info[j].class_name, len_class_text) == 0 &&
1504 sound->token[len_class_text] == '.')
1506 int sound_action_value = sound_effect_properties[i];
1508 element_info[j].sound[sound_action_value] = i;
1513 set_sound_parameters(i, sound->parameter);
1516 free(sound_effect_properties);
1519 static void InitGameModeMusicInfo()
1521 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1522 int num_property_mappings = getMusicListPropertyMappingSize();
1523 int default_levelset_music = -1;
1526 /* set values to -1 to identify later as "uninitialized" values */
1527 for (i = 0; i < MAX_LEVELS; i++)
1528 levelset.music[i] = -1;
1529 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1532 /* initialize gamemode/music mapping from static configuration */
1533 for (i = 0; gamemode_to_music[i].music > -1; i++)
1535 int gamemode = gamemode_to_music[i].gamemode;
1536 int music = gamemode_to_music[i].music;
1539 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1543 gamemode = GAME_MODE_DEFAULT;
1545 menu.music[gamemode] = music;
1548 /* initialize gamemode/music mapping from dynamic configuration */
1549 for (i = 0; i < num_property_mappings; i++)
1551 int prefix = property_mapping[i].base_index;
1552 int gamemode = property_mapping[i].ext1_index;
1553 int level = property_mapping[i].ext2_index;
1554 int music = property_mapping[i].artwork_index;
1557 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1558 prefix, gamemode, level, music);
1561 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1565 gamemode = GAME_MODE_DEFAULT;
1567 /* level specific music only allowed for in-game music */
1568 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1569 gamemode = GAME_MODE_PLAYING;
1574 default_levelset_music = music;
1577 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1578 levelset.music[level] = music;
1579 if (gamemode != GAME_MODE_PLAYING)
1580 menu.music[gamemode] = music;
1583 /* now set all '-1' values to menu specific default values */
1584 /* (undefined values of "levelset.music[]" might stay at "-1" to
1585 allow dynamic selection of music files from music directory!) */
1586 for (i = 0; i < MAX_LEVELS; i++)
1587 if (levelset.music[i] == -1)
1588 levelset.music[i] = default_levelset_music;
1589 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1590 if (menu.music[i] == -1)
1591 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1594 for (i = 0; i < MAX_LEVELS; i++)
1595 if (levelset.music[i] != -1)
1596 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1597 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1598 if (menu.music[i] != -1)
1599 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1603 static void set_music_parameters(int music, char **parameter_raw)
1605 int parameter[NUM_MUS_ARGS];
1608 /* get integer values from string parameters */
1609 for (i = 0; i < NUM_MUS_ARGS; i++)
1611 get_parameter_value(parameter_raw[i],
1612 music_config_suffix[i].token,
1613 music_config_suffix[i].type);
1615 /* explicit loop mode setting in configuration overrides default value */
1616 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1617 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1620 static void InitMusicInfo()
1622 int num_music = getMusicListSize();
1625 checked_free(music_info);
1627 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1629 for (i = 0; i < num_music; i++)
1631 struct FileInfo *music = getMusicListEntry(i);
1632 int len_music_text = strlen(music->token);
1634 music_info[i].loop = TRUE; /* default: play music in loop mode */
1636 /* determine all loop music */
1638 for (j = 0; music_prefix_info[j].prefix; j++)
1640 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1642 if (len_prefix_text < len_music_text &&
1643 strncmp(music->token,
1644 music_prefix_info[j].prefix, len_prefix_text) == 0)
1646 music_info[i].loop = music_prefix_info[j].is_loop_music;
1652 set_music_parameters(i, music->parameter);
1656 static void ReinitializeGraphics()
1658 InitGraphicInfo(); /* graphic properties mapping */
1659 InitElementGraphicInfo(); /* element game graphic mapping */
1660 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1662 InitElementSmallImages(); /* scale elements to all needed sizes */
1663 InitScaledImages(); /* scale all other images, if needed */
1664 InitFontGraphicInfo(); /* initialize text drawing functions */
1666 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1668 SetMainBackgroundImage(IMG_BACKGROUND);
1669 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1675 static void ReinitializeSounds()
1677 InitSoundInfo(); /* sound properties mapping */
1678 InitElementSoundInfo(); /* element game sound mapping */
1679 InitGameModeSoundInfo(); /* game mode sound mapping */
1681 InitPlayLevelSound(); /* internal game sound settings */
1684 static void ReinitializeMusic()
1686 InitMusicInfo(); /* music properties mapping */
1687 InitGameModeMusicInfo(); /* game mode music mapping */
1690 static int get_special_property_bit(int element, int property_bit_nr)
1692 struct PropertyBitInfo
1698 static struct PropertyBitInfo pb_can_move_into_acid[] =
1700 /* the player may be able fall into acid when gravity is activated */
1705 { EL_SP_MURPHY, 0 },
1706 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1708 /* all elements that can move may be able to also move into acid */
1711 { EL_BUG_RIGHT, 1 },
1714 { EL_SPACESHIP, 2 },
1715 { EL_SPACESHIP_LEFT, 2 },
1716 { EL_SPACESHIP_RIGHT, 2 },
1717 { EL_SPACESHIP_UP, 2 },
1718 { EL_SPACESHIP_DOWN, 2 },
1719 { EL_BD_BUTTERFLY, 3 },
1720 { EL_BD_BUTTERFLY_LEFT, 3 },
1721 { EL_BD_BUTTERFLY_RIGHT, 3 },
1722 { EL_BD_BUTTERFLY_UP, 3 },
1723 { EL_BD_BUTTERFLY_DOWN, 3 },
1724 { EL_BD_FIREFLY, 4 },
1725 { EL_BD_FIREFLY_LEFT, 4 },
1726 { EL_BD_FIREFLY_RIGHT, 4 },
1727 { EL_BD_FIREFLY_UP, 4 },
1728 { EL_BD_FIREFLY_DOWN, 4 },
1730 { EL_YAMYAM_LEFT, 5 },
1731 { EL_YAMYAM_RIGHT, 5 },
1732 { EL_YAMYAM_UP, 5 },
1733 { EL_YAMYAM_DOWN, 5 },
1734 { EL_DARK_YAMYAM, 6 },
1737 { EL_PACMAN_LEFT, 8 },
1738 { EL_PACMAN_RIGHT, 8 },
1739 { EL_PACMAN_UP, 8 },
1740 { EL_PACMAN_DOWN, 8 },
1742 { EL_MOLE_LEFT, 9 },
1743 { EL_MOLE_RIGHT, 9 },
1745 { EL_MOLE_DOWN, 9 },
1749 { EL_SATELLITE, 13 },
1750 { EL_SP_SNIKSNAK, 14 },
1751 { EL_SP_ELECTRON, 15 },
1754 { EL_EMC_ANDROID, 18 },
1759 static struct PropertyBitInfo pb_dont_collide_with[] =
1761 { EL_SP_SNIKSNAK, 0 },
1762 { EL_SP_ELECTRON, 1 },
1770 struct PropertyBitInfo *pb_info;
1773 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1774 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1779 struct PropertyBitInfo *pb_info = NULL;
1782 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1783 if (pb_definition[i].bit_nr == property_bit_nr)
1784 pb_info = pb_definition[i].pb_info;
1786 if (pb_info == NULL)
1789 for (i = 0; pb_info[i].element != -1; i++)
1790 if (pb_info[i].element == element)
1791 return pb_info[i].bit_nr;
1796 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1797 boolean property_value)
1799 int bit_nr = get_special_property_bit(element, property_bit_nr);
1804 *bitfield |= (1 << bit_nr);
1806 *bitfield &= ~(1 << bit_nr);
1810 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1812 int bit_nr = get_special_property_bit(element, property_bit_nr);
1815 return ((*bitfield & (1 << bit_nr)) != 0);
1820 static void resolve_group_element(int group_element, int recursion_depth)
1822 static int group_nr;
1823 static struct ElementGroupInfo *group;
1824 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1827 if (actual_group == NULL) /* not yet initialized */
1830 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1832 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1833 group_element - EL_GROUP_START + 1);
1835 /* replace element which caused too deep recursion by question mark */
1836 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1841 if (recursion_depth == 0) /* initialization */
1843 group = actual_group;
1844 group_nr = group_element - EL_GROUP_START;
1846 group->num_elements_resolved = 0;
1847 group->choice_pos = 0;
1850 for (i = 0; i < actual_group->num_elements; i++)
1852 int element = actual_group->element[i];
1854 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1857 if (IS_GROUP_ELEMENT(element))
1858 resolve_group_element(element, recursion_depth + 1);
1861 group->element_resolved[group->num_elements_resolved++] = element;
1862 element_info[element].in_group[group_nr] = TRUE;
1867 void InitElementPropertiesStatic()
1869 static int ep_diggable[] =
1874 EL_SP_BUGGY_BASE_ACTIVATING,
1877 EL_INVISIBLE_SAND_ACTIVE,
1880 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1881 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1885 EL_SP_BUGGY_BASE_ACTIVE,
1892 static int ep_collectible_only[] =
1914 EL_DYNABOMB_INCREASE_NUMBER,
1915 EL_DYNABOMB_INCREASE_SIZE,
1916 EL_DYNABOMB_INCREASE_POWER,
1936 static int ep_dont_run_into[] =
1938 /* same elements as in 'ep_dont_touch' */
1944 /* same elements as in 'ep_dont_collide_with' */
1956 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1960 EL_SP_BUGGY_BASE_ACTIVE,
1967 static int ep_dont_collide_with[] =
1969 /* same elements as in 'ep_dont_touch' */
1986 static int ep_dont_touch[] =
1996 static int ep_indestructible[] =
2000 EL_ACID_POOL_TOPLEFT,
2001 EL_ACID_POOL_TOPRIGHT,
2002 EL_ACID_POOL_BOTTOMLEFT,
2003 EL_ACID_POOL_BOTTOM,
2004 EL_ACID_POOL_BOTTOMRIGHT,
2005 EL_SP_HARDWARE_GRAY,
2006 EL_SP_HARDWARE_GREEN,
2007 EL_SP_HARDWARE_BLUE,
2009 EL_SP_HARDWARE_YELLOW,
2010 EL_SP_HARDWARE_BASE_1,
2011 EL_SP_HARDWARE_BASE_2,
2012 EL_SP_HARDWARE_BASE_3,
2013 EL_SP_HARDWARE_BASE_4,
2014 EL_SP_HARDWARE_BASE_5,
2015 EL_SP_HARDWARE_BASE_6,
2016 EL_INVISIBLE_STEELWALL,
2017 EL_INVISIBLE_STEELWALL_ACTIVE,
2018 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2019 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2020 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2021 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2022 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2023 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2024 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2025 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2026 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2027 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2028 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2029 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2031 EL_LIGHT_SWITCH_ACTIVE,
2032 EL_SIGN_EXCLAMATION,
2033 EL_SIGN_RADIOACTIVITY,
2044 EL_STEELWALL_SLIPPERY,
2058 EL_GATE_1_GRAY_ACTIVE,
2059 EL_GATE_2_GRAY_ACTIVE,
2060 EL_GATE_3_GRAY_ACTIVE,
2061 EL_GATE_4_GRAY_ACTIVE,
2070 EL_EM_GATE_1_GRAY_ACTIVE,
2071 EL_EM_GATE_2_GRAY_ACTIVE,
2072 EL_EM_GATE_3_GRAY_ACTIVE,
2073 EL_EM_GATE_4_GRAY_ACTIVE,
2082 EL_EMC_GATE_5_GRAY_ACTIVE,
2083 EL_EMC_GATE_6_GRAY_ACTIVE,
2084 EL_EMC_GATE_7_GRAY_ACTIVE,
2085 EL_EMC_GATE_8_GRAY_ACTIVE,
2087 EL_SWITCHGATE_OPENING,
2088 EL_SWITCHGATE_CLOSED,
2089 EL_SWITCHGATE_CLOSING,
2091 EL_SWITCHGATE_SWITCH_UP,
2092 EL_SWITCHGATE_SWITCH_DOWN,
2095 EL_TIMEGATE_OPENING,
2097 EL_TIMEGATE_CLOSING,
2100 EL_TIMEGATE_SWITCH_ACTIVE,
2105 EL_TUBE_VERTICAL_LEFT,
2106 EL_TUBE_VERTICAL_RIGHT,
2107 EL_TUBE_HORIZONTAL_UP,
2108 EL_TUBE_HORIZONTAL_DOWN,
2117 static int ep_slippery[] =
2131 EL_ROBOT_WHEEL_ACTIVE,
2137 EL_ACID_POOL_TOPLEFT,
2138 EL_ACID_POOL_TOPRIGHT,
2148 EL_STEELWALL_SLIPPERY,
2151 EL_EMC_WALL_SLIPPERY_1,
2152 EL_EMC_WALL_SLIPPERY_2,
2153 EL_EMC_WALL_SLIPPERY_3,
2154 EL_EMC_WALL_SLIPPERY_4,
2156 EL_EMC_MAGIC_BALL_ACTIVE,
2161 static int ep_can_change[] =
2166 static int ep_can_move[] =
2168 /* same elements as in 'pb_can_move_into_acid' */
2191 static int ep_can_fall[] =
2206 EL_BD_MAGIC_WALL_FULL,
2220 static int ep_can_smash_player[] =
2246 static int ep_can_smash_enemies[] =
2255 static int ep_can_smash_everything[] =
2264 static int ep_explodes_by_fire[] =
2266 /* same elements as in 'ep_explodes_impact' */
2271 /* same elements as in 'ep_explodes_smashed' */
2281 EL_EM_DYNAMITE_ACTIVE,
2282 EL_DYNABOMB_PLAYER_1_ACTIVE,
2283 EL_DYNABOMB_PLAYER_2_ACTIVE,
2284 EL_DYNABOMB_PLAYER_3_ACTIVE,
2285 EL_DYNABOMB_PLAYER_4_ACTIVE,
2286 EL_DYNABOMB_INCREASE_NUMBER,
2287 EL_DYNABOMB_INCREASE_SIZE,
2288 EL_DYNABOMB_INCREASE_POWER,
2289 EL_SP_DISK_RED_ACTIVE,
2303 static int ep_explodes_smashed[] =
2305 /* same elements as in 'ep_explodes_impact' */
2319 static int ep_explodes_impact[] =
2328 static int ep_walkable_over[] =
2332 EL_SOKOBAN_FIELD_EMPTY,
2344 EL_GATE_1_GRAY_ACTIVE,
2345 EL_GATE_2_GRAY_ACTIVE,
2346 EL_GATE_3_GRAY_ACTIVE,
2347 EL_GATE_4_GRAY_ACTIVE,
2355 static int ep_walkable_inside[] =
2360 EL_TUBE_VERTICAL_LEFT,
2361 EL_TUBE_VERTICAL_RIGHT,
2362 EL_TUBE_HORIZONTAL_UP,
2363 EL_TUBE_HORIZONTAL_DOWN,
2372 static int ep_walkable_under[] =
2377 static int ep_passable_over[] =
2387 EL_EM_GATE_1_GRAY_ACTIVE,
2388 EL_EM_GATE_2_GRAY_ACTIVE,
2389 EL_EM_GATE_3_GRAY_ACTIVE,
2390 EL_EM_GATE_4_GRAY_ACTIVE,
2399 EL_EMC_GATE_5_GRAY_ACTIVE,
2400 EL_EMC_GATE_6_GRAY_ACTIVE,
2401 EL_EMC_GATE_7_GRAY_ACTIVE,
2402 EL_EMC_GATE_8_GRAY_ACTIVE,
2409 static int ep_passable_inside[] =
2415 EL_SP_PORT_HORIZONTAL,
2416 EL_SP_PORT_VERTICAL,
2418 EL_SP_GRAVITY_PORT_LEFT,
2419 EL_SP_GRAVITY_PORT_RIGHT,
2420 EL_SP_GRAVITY_PORT_UP,
2421 EL_SP_GRAVITY_PORT_DOWN,
2422 EL_SP_GRAVITY_ON_PORT_LEFT,
2423 EL_SP_GRAVITY_ON_PORT_RIGHT,
2424 EL_SP_GRAVITY_ON_PORT_UP,
2425 EL_SP_GRAVITY_ON_PORT_DOWN,
2426 EL_SP_GRAVITY_OFF_PORT_LEFT,
2427 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2428 EL_SP_GRAVITY_OFF_PORT_UP,
2429 EL_SP_GRAVITY_OFF_PORT_DOWN,
2434 static int ep_passable_under[] =
2439 static int ep_droppable[] =
2444 static int ep_explodes_1x1_old[] =
2449 static int ep_pushable[] =
2461 EL_SOKOBAN_FIELD_FULL,
2470 static int ep_explodes_cross_old[] =
2475 static int ep_protected[] =
2477 /* same elements as in 'ep_walkable_inside' */
2481 EL_TUBE_VERTICAL_LEFT,
2482 EL_TUBE_VERTICAL_RIGHT,
2483 EL_TUBE_HORIZONTAL_UP,
2484 EL_TUBE_HORIZONTAL_DOWN,
2490 /* same elements as in 'ep_passable_over' */
2499 EL_EM_GATE_1_GRAY_ACTIVE,
2500 EL_EM_GATE_2_GRAY_ACTIVE,
2501 EL_EM_GATE_3_GRAY_ACTIVE,
2502 EL_EM_GATE_4_GRAY_ACTIVE,
2511 EL_EMC_GATE_5_GRAY_ACTIVE,
2512 EL_EMC_GATE_6_GRAY_ACTIVE,
2513 EL_EMC_GATE_7_GRAY_ACTIVE,
2514 EL_EMC_GATE_8_GRAY_ACTIVE,
2518 /* same elements as in 'ep_passable_inside' */
2523 EL_SP_PORT_HORIZONTAL,
2524 EL_SP_PORT_VERTICAL,
2526 EL_SP_GRAVITY_PORT_LEFT,
2527 EL_SP_GRAVITY_PORT_RIGHT,
2528 EL_SP_GRAVITY_PORT_UP,
2529 EL_SP_GRAVITY_PORT_DOWN,
2530 EL_SP_GRAVITY_ON_PORT_LEFT,
2531 EL_SP_GRAVITY_ON_PORT_RIGHT,
2532 EL_SP_GRAVITY_ON_PORT_UP,
2533 EL_SP_GRAVITY_ON_PORT_DOWN,
2534 EL_SP_GRAVITY_OFF_PORT_LEFT,
2535 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2536 EL_SP_GRAVITY_OFF_PORT_UP,
2537 EL_SP_GRAVITY_OFF_PORT_DOWN,
2542 static int ep_throwable[] =
2547 static int ep_can_explode[] =
2549 /* same elements as in 'ep_explodes_impact' */
2554 /* same elements as in 'ep_explodes_smashed' */
2560 /* elements that can explode by explosion or by dragonfire */
2564 EL_EM_DYNAMITE_ACTIVE,
2565 EL_DYNABOMB_PLAYER_1_ACTIVE,
2566 EL_DYNABOMB_PLAYER_2_ACTIVE,
2567 EL_DYNABOMB_PLAYER_3_ACTIVE,
2568 EL_DYNABOMB_PLAYER_4_ACTIVE,
2569 EL_DYNABOMB_INCREASE_NUMBER,
2570 EL_DYNABOMB_INCREASE_SIZE,
2571 EL_DYNABOMB_INCREASE_POWER,
2572 EL_SP_DISK_RED_ACTIVE,
2580 /* elements that can explode only by explosion */
2586 static int ep_gravity_reachable[] =
2592 EL_INVISIBLE_SAND_ACTIVE,
2597 EL_SP_PORT_HORIZONTAL,
2598 EL_SP_PORT_VERTICAL,
2600 EL_SP_GRAVITY_PORT_LEFT,
2601 EL_SP_GRAVITY_PORT_RIGHT,
2602 EL_SP_GRAVITY_PORT_UP,
2603 EL_SP_GRAVITY_PORT_DOWN,
2604 EL_SP_GRAVITY_ON_PORT_LEFT,
2605 EL_SP_GRAVITY_ON_PORT_RIGHT,
2606 EL_SP_GRAVITY_ON_PORT_UP,
2607 EL_SP_GRAVITY_ON_PORT_DOWN,
2608 EL_SP_GRAVITY_OFF_PORT_LEFT,
2609 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2610 EL_SP_GRAVITY_OFF_PORT_UP,
2611 EL_SP_GRAVITY_OFF_PORT_DOWN,
2617 static int ep_player[] =
2624 EL_SOKOBAN_FIELD_PLAYER,
2630 static int ep_can_pass_magic_wall[] =
2644 static int ep_switchable[] =
2648 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2649 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2650 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2651 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2652 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2653 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2654 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2655 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2656 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2657 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2658 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2659 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2660 EL_SWITCHGATE_SWITCH_UP,
2661 EL_SWITCHGATE_SWITCH_DOWN,
2663 EL_LIGHT_SWITCH_ACTIVE,
2665 EL_BALLOON_SWITCH_LEFT,
2666 EL_BALLOON_SWITCH_RIGHT,
2667 EL_BALLOON_SWITCH_UP,
2668 EL_BALLOON_SWITCH_DOWN,
2669 EL_BALLOON_SWITCH_ANY,
2670 EL_BALLOON_SWITCH_NONE,
2673 EL_EMC_MAGIC_BALL_SWITCH,
2674 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2679 static int ep_bd_element[] =
2713 static int ep_sp_element[] =
2715 /* should always be valid */
2718 /* standard classic Supaplex elements */
2725 EL_SP_HARDWARE_GRAY,
2733 EL_SP_GRAVITY_PORT_RIGHT,
2734 EL_SP_GRAVITY_PORT_DOWN,
2735 EL_SP_GRAVITY_PORT_LEFT,
2736 EL_SP_GRAVITY_PORT_UP,
2741 EL_SP_PORT_VERTICAL,
2742 EL_SP_PORT_HORIZONTAL,
2748 EL_SP_HARDWARE_BASE_1,
2749 EL_SP_HARDWARE_GREEN,
2750 EL_SP_HARDWARE_BLUE,
2752 EL_SP_HARDWARE_YELLOW,
2753 EL_SP_HARDWARE_BASE_2,
2754 EL_SP_HARDWARE_BASE_3,
2755 EL_SP_HARDWARE_BASE_4,
2756 EL_SP_HARDWARE_BASE_5,
2757 EL_SP_HARDWARE_BASE_6,
2761 /* additional elements that appeared in newer Supaplex levels */
2764 /* additional gravity port elements (not switching, but setting gravity) */
2765 EL_SP_GRAVITY_ON_PORT_LEFT,
2766 EL_SP_GRAVITY_ON_PORT_RIGHT,
2767 EL_SP_GRAVITY_ON_PORT_UP,
2768 EL_SP_GRAVITY_ON_PORT_DOWN,
2769 EL_SP_GRAVITY_OFF_PORT_LEFT,
2770 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2771 EL_SP_GRAVITY_OFF_PORT_UP,
2772 EL_SP_GRAVITY_OFF_PORT_DOWN,
2774 /* more than one Murphy in a level results in an inactive clone */
2777 /* runtime Supaplex elements */
2778 EL_SP_DISK_RED_ACTIVE,
2779 EL_SP_TERMINAL_ACTIVE,
2780 EL_SP_BUGGY_BASE_ACTIVATING,
2781 EL_SP_BUGGY_BASE_ACTIVE,
2788 static int ep_sb_element[] =
2793 EL_SOKOBAN_FIELD_EMPTY,
2794 EL_SOKOBAN_FIELD_FULL,
2795 EL_SOKOBAN_FIELD_PLAYER,
2800 EL_INVISIBLE_STEELWALL,
2805 static int ep_gem[] =
2817 static int ep_food_dark_yamyam[] =
2845 static int ep_food_penguin[] =
2859 static int ep_food_pig[] =
2871 static int ep_historic_wall[] =
2882 EL_GATE_1_GRAY_ACTIVE,
2883 EL_GATE_2_GRAY_ACTIVE,
2884 EL_GATE_3_GRAY_ACTIVE,
2885 EL_GATE_4_GRAY_ACTIVE,
2894 EL_EM_GATE_1_GRAY_ACTIVE,
2895 EL_EM_GATE_2_GRAY_ACTIVE,
2896 EL_EM_GATE_3_GRAY_ACTIVE,
2897 EL_EM_GATE_4_GRAY_ACTIVE,
2904 EL_EXPANDABLE_WALL_HORIZONTAL,
2905 EL_EXPANDABLE_WALL_VERTICAL,
2906 EL_EXPANDABLE_WALL_ANY,
2907 EL_EXPANDABLE_WALL_GROWING,
2908 EL_BD_EXPANDABLE_WALL,
2915 EL_SP_HARDWARE_GRAY,
2916 EL_SP_HARDWARE_GREEN,
2917 EL_SP_HARDWARE_BLUE,
2919 EL_SP_HARDWARE_YELLOW,
2920 EL_SP_HARDWARE_BASE_1,
2921 EL_SP_HARDWARE_BASE_2,
2922 EL_SP_HARDWARE_BASE_3,
2923 EL_SP_HARDWARE_BASE_4,
2924 EL_SP_HARDWARE_BASE_5,
2925 EL_SP_HARDWARE_BASE_6,
2927 EL_SP_TERMINAL_ACTIVE,
2930 EL_INVISIBLE_STEELWALL,
2931 EL_INVISIBLE_STEELWALL_ACTIVE,
2933 EL_INVISIBLE_WALL_ACTIVE,
2934 EL_STEELWALL_SLIPPERY,
2951 static int ep_historic_solid[] =
2955 EL_EXPANDABLE_WALL_HORIZONTAL,
2956 EL_EXPANDABLE_WALL_VERTICAL,
2957 EL_EXPANDABLE_WALL_ANY,
2958 EL_BD_EXPANDABLE_WALL,
2971 EL_QUICKSAND_FILLING,
2972 EL_QUICKSAND_EMPTYING,
2974 EL_MAGIC_WALL_ACTIVE,
2975 EL_MAGIC_WALL_EMPTYING,
2976 EL_MAGIC_WALL_FILLING,
2980 EL_BD_MAGIC_WALL_ACTIVE,
2981 EL_BD_MAGIC_WALL_EMPTYING,
2982 EL_BD_MAGIC_WALL_FULL,
2983 EL_BD_MAGIC_WALL_FILLING,
2984 EL_BD_MAGIC_WALL_DEAD,
2993 EL_SP_TERMINAL_ACTIVE,
2997 EL_INVISIBLE_WALL_ACTIVE,
2998 EL_SWITCHGATE_SWITCH_UP,
2999 EL_SWITCHGATE_SWITCH_DOWN,
3001 EL_TIMEGATE_SWITCH_ACTIVE,
3013 /* the following elements are a direct copy of "indestructible" elements,
3014 except "EL_ACID", which is "indestructible", but not "solid"! */
3019 EL_ACID_POOL_TOPLEFT,
3020 EL_ACID_POOL_TOPRIGHT,
3021 EL_ACID_POOL_BOTTOMLEFT,
3022 EL_ACID_POOL_BOTTOM,
3023 EL_ACID_POOL_BOTTOMRIGHT,
3024 EL_SP_HARDWARE_GRAY,
3025 EL_SP_HARDWARE_GREEN,
3026 EL_SP_HARDWARE_BLUE,
3028 EL_SP_HARDWARE_YELLOW,
3029 EL_SP_HARDWARE_BASE_1,
3030 EL_SP_HARDWARE_BASE_2,
3031 EL_SP_HARDWARE_BASE_3,
3032 EL_SP_HARDWARE_BASE_4,
3033 EL_SP_HARDWARE_BASE_5,
3034 EL_SP_HARDWARE_BASE_6,
3035 EL_INVISIBLE_STEELWALL,
3036 EL_INVISIBLE_STEELWALL_ACTIVE,
3037 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3038 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3039 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3040 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3041 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3042 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3043 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3044 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3045 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3046 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3047 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3048 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3050 EL_LIGHT_SWITCH_ACTIVE,
3051 EL_SIGN_EXCLAMATION,
3052 EL_SIGN_RADIOACTIVITY,
3063 EL_STEELWALL_SLIPPERY,
3077 EL_GATE_1_GRAY_ACTIVE,
3078 EL_GATE_2_GRAY_ACTIVE,
3079 EL_GATE_3_GRAY_ACTIVE,
3080 EL_GATE_4_GRAY_ACTIVE,
3089 EL_EM_GATE_1_GRAY_ACTIVE,
3090 EL_EM_GATE_2_GRAY_ACTIVE,
3091 EL_EM_GATE_3_GRAY_ACTIVE,
3092 EL_EM_GATE_4_GRAY_ACTIVE,
3094 EL_SWITCHGATE_OPENING,
3095 EL_SWITCHGATE_CLOSED,
3096 EL_SWITCHGATE_CLOSING,
3098 EL_TIMEGATE_OPENING,
3100 EL_TIMEGATE_CLOSING,
3104 EL_TUBE_VERTICAL_LEFT,
3105 EL_TUBE_VERTICAL_RIGHT,
3106 EL_TUBE_HORIZONTAL_UP,
3107 EL_TUBE_HORIZONTAL_DOWN,
3116 static int ep_classic_enemy[] =
3133 static int ep_belt[] =
3135 EL_CONVEYOR_BELT_1_LEFT,
3136 EL_CONVEYOR_BELT_1_MIDDLE,
3137 EL_CONVEYOR_BELT_1_RIGHT,
3138 EL_CONVEYOR_BELT_2_LEFT,
3139 EL_CONVEYOR_BELT_2_MIDDLE,
3140 EL_CONVEYOR_BELT_2_RIGHT,
3141 EL_CONVEYOR_BELT_3_LEFT,
3142 EL_CONVEYOR_BELT_3_MIDDLE,
3143 EL_CONVEYOR_BELT_3_RIGHT,
3144 EL_CONVEYOR_BELT_4_LEFT,
3145 EL_CONVEYOR_BELT_4_MIDDLE,
3146 EL_CONVEYOR_BELT_4_RIGHT,
3151 static int ep_belt_active[] =
3153 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3154 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3155 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3156 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3157 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3158 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3159 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3160 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3161 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3162 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3163 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3164 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3169 static int ep_belt_switch[] =
3171 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3172 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3173 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3174 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3175 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3176 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3177 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3178 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3179 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3180 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3181 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3182 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3187 static int ep_tube[] =
3194 EL_TUBE_HORIZONTAL_UP,
3195 EL_TUBE_HORIZONTAL_DOWN,
3197 EL_TUBE_VERTICAL_LEFT,
3198 EL_TUBE_VERTICAL_RIGHT,
3204 static int ep_keygate[] =
3214 EL_GATE_1_GRAY_ACTIVE,
3215 EL_GATE_2_GRAY_ACTIVE,
3216 EL_GATE_3_GRAY_ACTIVE,
3217 EL_GATE_4_GRAY_ACTIVE,
3226 EL_EM_GATE_1_GRAY_ACTIVE,
3227 EL_EM_GATE_2_GRAY_ACTIVE,
3228 EL_EM_GATE_3_GRAY_ACTIVE,
3229 EL_EM_GATE_4_GRAY_ACTIVE,
3238 EL_EMC_GATE_5_GRAY_ACTIVE,
3239 EL_EMC_GATE_6_GRAY_ACTIVE,
3240 EL_EMC_GATE_7_GRAY_ACTIVE,
3241 EL_EMC_GATE_8_GRAY_ACTIVE,
3246 static int ep_amoeboid[] =
3258 static int ep_amoebalive[] =
3269 static int ep_has_editor_content[] =
3291 static int ep_can_turn_each_move[] =
3293 /* !!! do something with this one !!! */
3297 static int ep_can_grow[] =
3311 static int ep_active_bomb[] =
3314 EL_EM_DYNAMITE_ACTIVE,
3315 EL_DYNABOMB_PLAYER_1_ACTIVE,
3316 EL_DYNABOMB_PLAYER_2_ACTIVE,
3317 EL_DYNABOMB_PLAYER_3_ACTIVE,
3318 EL_DYNABOMB_PLAYER_4_ACTIVE,
3319 EL_SP_DISK_RED_ACTIVE,
3324 static int ep_inactive[] =
3356 EL_GATE_1_GRAY_ACTIVE,
3357 EL_GATE_2_GRAY_ACTIVE,
3358 EL_GATE_3_GRAY_ACTIVE,
3359 EL_GATE_4_GRAY_ACTIVE,
3368 EL_EM_GATE_1_GRAY_ACTIVE,
3369 EL_EM_GATE_2_GRAY_ACTIVE,
3370 EL_EM_GATE_3_GRAY_ACTIVE,
3371 EL_EM_GATE_4_GRAY_ACTIVE,
3380 EL_EMC_GATE_5_GRAY_ACTIVE,
3381 EL_EMC_GATE_6_GRAY_ACTIVE,
3382 EL_EMC_GATE_7_GRAY_ACTIVE,
3383 EL_EMC_GATE_8_GRAY_ACTIVE,
3386 EL_INVISIBLE_STEELWALL,
3394 EL_WALL_EMERALD_YELLOW,
3395 EL_DYNABOMB_INCREASE_NUMBER,
3396 EL_DYNABOMB_INCREASE_SIZE,
3397 EL_DYNABOMB_INCREASE_POWER,
3401 EL_SOKOBAN_FIELD_EMPTY,
3402 EL_SOKOBAN_FIELD_FULL,
3403 EL_WALL_EMERALD_RED,
3404 EL_WALL_EMERALD_PURPLE,
3405 EL_ACID_POOL_TOPLEFT,
3406 EL_ACID_POOL_TOPRIGHT,
3407 EL_ACID_POOL_BOTTOMLEFT,
3408 EL_ACID_POOL_BOTTOM,
3409 EL_ACID_POOL_BOTTOMRIGHT,
3413 EL_BD_MAGIC_WALL_DEAD,
3414 EL_AMOEBA_TO_DIAMOND,
3422 EL_SP_GRAVITY_PORT_RIGHT,
3423 EL_SP_GRAVITY_PORT_DOWN,
3424 EL_SP_GRAVITY_PORT_LEFT,
3425 EL_SP_GRAVITY_PORT_UP,
3426 EL_SP_PORT_HORIZONTAL,
3427 EL_SP_PORT_VERTICAL,
3438 EL_SP_HARDWARE_GRAY,
3439 EL_SP_HARDWARE_GREEN,
3440 EL_SP_HARDWARE_BLUE,
3442 EL_SP_HARDWARE_YELLOW,
3443 EL_SP_HARDWARE_BASE_1,
3444 EL_SP_HARDWARE_BASE_2,
3445 EL_SP_HARDWARE_BASE_3,
3446 EL_SP_HARDWARE_BASE_4,
3447 EL_SP_HARDWARE_BASE_5,
3448 EL_SP_HARDWARE_BASE_6,
3449 EL_SP_GRAVITY_ON_PORT_LEFT,
3450 EL_SP_GRAVITY_ON_PORT_RIGHT,
3451 EL_SP_GRAVITY_ON_PORT_UP,
3452 EL_SP_GRAVITY_ON_PORT_DOWN,
3453 EL_SP_GRAVITY_OFF_PORT_LEFT,
3454 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3455 EL_SP_GRAVITY_OFF_PORT_UP,
3456 EL_SP_GRAVITY_OFF_PORT_DOWN,
3457 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3458 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3459 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3460 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3461 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3462 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3463 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3464 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3465 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3466 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3467 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3468 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3469 EL_SIGN_EXCLAMATION,
3470 EL_SIGN_RADIOACTIVITY,
3481 EL_STEELWALL_SLIPPERY,
3486 EL_EMC_WALL_SLIPPERY_1,
3487 EL_EMC_WALL_SLIPPERY_2,
3488 EL_EMC_WALL_SLIPPERY_3,
3489 EL_EMC_WALL_SLIPPERY_4,
3510 static int ep_em_slippery_wall[] =
3515 static int ep_gfx_crumbled[] =
3525 static int ep_editor_cascade_active[] =
3527 EL_INTERNAL_CASCADE_BD_ACTIVE,
3528 EL_INTERNAL_CASCADE_EM_ACTIVE,
3529 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3530 EL_INTERNAL_CASCADE_RND_ACTIVE,
3531 EL_INTERNAL_CASCADE_SB_ACTIVE,
3532 EL_INTERNAL_CASCADE_SP_ACTIVE,
3533 EL_INTERNAL_CASCADE_DC_ACTIVE,
3534 EL_INTERNAL_CASCADE_DX_ACTIVE,
3535 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3536 EL_INTERNAL_CASCADE_CE_ACTIVE,
3537 EL_INTERNAL_CASCADE_GE_ACTIVE,
3538 EL_INTERNAL_CASCADE_REF_ACTIVE,
3539 EL_INTERNAL_CASCADE_USER_ACTIVE,
3540 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3545 static int ep_editor_cascade_inactive[] =
3547 EL_INTERNAL_CASCADE_BD,
3548 EL_INTERNAL_CASCADE_EM,
3549 EL_INTERNAL_CASCADE_EMC,
3550 EL_INTERNAL_CASCADE_RND,
3551 EL_INTERNAL_CASCADE_SB,
3552 EL_INTERNAL_CASCADE_SP,
3553 EL_INTERNAL_CASCADE_DC,
3554 EL_INTERNAL_CASCADE_DX,
3555 EL_INTERNAL_CASCADE_CHARS,
3556 EL_INTERNAL_CASCADE_CE,
3557 EL_INTERNAL_CASCADE_GE,
3558 EL_INTERNAL_CASCADE_REF,
3559 EL_INTERNAL_CASCADE_USER,
3560 EL_INTERNAL_CASCADE_DYNAMIC,
3565 static int ep_obsolete[] =
3569 EL_EM_KEY_1_FILE_OBSOLETE,
3570 EL_EM_KEY_2_FILE_OBSOLETE,
3571 EL_EM_KEY_3_FILE_OBSOLETE,
3572 EL_EM_KEY_4_FILE_OBSOLETE,
3573 EL_ENVELOPE_OBSOLETE,
3582 } element_properties[] =
3584 { ep_diggable, EP_DIGGABLE },
3585 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3586 { ep_dont_run_into, EP_DONT_RUN_INTO },
3587 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3588 { ep_dont_touch, EP_DONT_TOUCH },
3589 { ep_indestructible, EP_INDESTRUCTIBLE },
3590 { ep_slippery, EP_SLIPPERY },
3591 { ep_can_change, EP_CAN_CHANGE },
3592 { ep_can_move, EP_CAN_MOVE },
3593 { ep_can_fall, EP_CAN_FALL },
3594 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3595 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3596 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3597 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3598 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3599 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3600 { ep_walkable_over, EP_WALKABLE_OVER },
3601 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3602 { ep_walkable_under, EP_WALKABLE_UNDER },
3603 { ep_passable_over, EP_PASSABLE_OVER },
3604 { ep_passable_inside, EP_PASSABLE_INSIDE },
3605 { ep_passable_under, EP_PASSABLE_UNDER },
3606 { ep_droppable, EP_DROPPABLE },
3607 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3608 { ep_pushable, EP_PUSHABLE },
3609 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3610 { ep_protected, EP_PROTECTED },
3611 { ep_throwable, EP_THROWABLE },
3612 { ep_can_explode, EP_CAN_EXPLODE },
3613 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3615 { ep_player, EP_PLAYER },
3616 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3617 { ep_switchable, EP_SWITCHABLE },
3618 { ep_bd_element, EP_BD_ELEMENT },
3619 { ep_sp_element, EP_SP_ELEMENT },
3620 { ep_sb_element, EP_SB_ELEMENT },
3622 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3623 { ep_food_penguin, EP_FOOD_PENGUIN },
3624 { ep_food_pig, EP_FOOD_PIG },
3625 { ep_historic_wall, EP_HISTORIC_WALL },
3626 { ep_historic_solid, EP_HISTORIC_SOLID },
3627 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3628 { ep_belt, EP_BELT },
3629 { ep_belt_active, EP_BELT_ACTIVE },
3630 { ep_belt_switch, EP_BELT_SWITCH },
3631 { ep_tube, EP_TUBE },
3632 { ep_keygate, EP_KEYGATE },
3633 { ep_amoeboid, EP_AMOEBOID },
3634 { ep_amoebalive, EP_AMOEBALIVE },
3635 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3636 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3637 { ep_can_grow, EP_CAN_GROW },
3638 { ep_active_bomb, EP_ACTIVE_BOMB },
3639 { ep_inactive, EP_INACTIVE },
3641 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3643 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3645 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3646 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3648 { ep_obsolete, EP_OBSOLETE },
3655 /* always start with reliable default values (element has no properties) */
3656 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3657 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3658 SET_PROPERTY(i, j, FALSE);
3660 /* set all base element properties from above array definitions */
3661 for (i = 0; element_properties[i].elements != NULL; i++)
3662 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3663 SET_PROPERTY((element_properties[i].elements)[j],
3664 element_properties[i].property, TRUE);
3666 /* copy properties to some elements that are only stored in level file */
3667 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3668 for (j = 0; copy_properties[j][0] != -1; j++)
3669 if (HAS_PROPERTY(copy_properties[j][0], i))
3670 for (k = 1; k <= 4; k++)
3671 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3674 void InitElementPropertiesEngine(int engine_version)
3676 static int no_wall_properties[] =
3679 EP_COLLECTIBLE_ONLY,
3681 EP_DONT_COLLIDE_WITH,
3684 EP_CAN_SMASH_PLAYER,
3685 EP_CAN_SMASH_ENEMIES,
3686 EP_CAN_SMASH_EVERYTHING,
3691 EP_FOOD_DARK_YAMYAM,
3707 /* important: after initialization in InitElementPropertiesStatic(), the
3708 elements are not again initialized to a default value; therefore all
3709 changes have to make sure that they leave the element with a defined
3710 property (which means that conditional property changes must be set to
3711 a reliable default value before) */
3713 /* ---------- recursively resolve group elements ------------------------- */
3715 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3716 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3717 element_info[i].in_group[j] = FALSE;
3719 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3720 resolve_group_element(EL_GROUP_START + i, 0);
3722 /* set all special, combined or engine dependent element properties */
3723 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3725 /* ---------- INACTIVE ------------------------------------------------- */
3726 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3728 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3729 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3730 IS_WALKABLE_INSIDE(i) ||
3731 IS_WALKABLE_UNDER(i)));
3733 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3734 IS_PASSABLE_INSIDE(i) ||
3735 IS_PASSABLE_UNDER(i)));
3737 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3738 IS_PASSABLE_OVER(i)));
3740 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3741 IS_PASSABLE_INSIDE(i)));
3743 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3744 IS_PASSABLE_UNDER(i)));
3746 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3749 /* ---------- COLLECTIBLE ---------------------------------------------- */
3750 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3754 /* ---------- SNAPPABLE ------------------------------------------------ */
3755 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3756 IS_COLLECTIBLE(i) ||
3760 /* ---------- WALL ----------------------------------------------------- */
3761 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3763 for (j = 0; no_wall_properties[j] != -1; j++)
3764 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3765 i >= EL_FIRST_RUNTIME_UNREAL)
3766 SET_PROPERTY(i, EP_WALL, FALSE);
3768 if (IS_HISTORIC_WALL(i))
3769 SET_PROPERTY(i, EP_WALL, TRUE);
3771 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3772 if (engine_version < VERSION_IDENT(2,2,0,0))
3773 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3775 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3777 !IS_COLLECTIBLE(i)));
3779 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3781 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3782 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3784 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3785 IS_INDESTRUCTIBLE(i)));
3787 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3789 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3790 else if (engine_version < VERSION_IDENT(2,2,0,0))
3791 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3793 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3797 if (IS_CUSTOM_ELEMENT(i))
3799 /* these are additional properties which are initially false when set */
3801 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3803 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3804 if (DONT_COLLIDE_WITH(i))
3805 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3807 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3808 if (CAN_SMASH_EVERYTHING(i))
3809 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3810 if (CAN_SMASH_ENEMIES(i))
3811 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3814 /* ---------- CAN_SMASH ------------------------------------------------ */
3815 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3816 CAN_SMASH_ENEMIES(i) ||
3817 CAN_SMASH_EVERYTHING(i)));
3819 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3820 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3821 EXPLODES_BY_FIRE(i)));
3823 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3824 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3825 EXPLODES_SMASHED(i)));
3827 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3828 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3829 EXPLODES_IMPACT(i)));
3831 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3832 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3834 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3835 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3836 i == EL_BLACK_ORB));
3838 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3839 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3841 IS_CUSTOM_ELEMENT(i)));
3843 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3844 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3845 i == EL_SP_ELECTRON));
3847 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3848 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3849 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3850 getMoveIntoAcidProperty(&level, i));
3852 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3853 if (MAYBE_DONT_COLLIDE_WITH(i))
3854 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3855 getDontCollideWithProperty(&level, i));
3857 /* ---------- SP_PORT -------------------------------------------------- */
3858 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3859 IS_PASSABLE_INSIDE(i)));
3861 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3862 for (j = 0; j < level.num_android_clone_elements; j++)
3863 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3865 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3867 /* ---------- CAN_CHANGE ----------------------------------------------- */
3868 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3869 for (j = 0; j < element_info[i].num_change_pages; j++)
3870 if (element_info[i].change_page[j].can_change)
3871 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3873 /* ---------- HAS_ACTION ----------------------------------------------- */
3874 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3875 for (j = 0; j < element_info[i].num_change_pages; j++)
3876 if (element_info[i].change_page[j].has_action)
3877 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3879 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3880 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3883 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3885 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3886 element_info[i].crumbled[ACTION_DEFAULT] !=
3887 element_info[i].graphic[ACTION_DEFAULT]);
3889 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3890 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3891 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3894 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3895 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3896 IS_EDITOR_CASCADE_INACTIVE(i)));
3899 /* dynamically adjust element properties according to game engine version */
3901 static int ep_em_slippery_wall[] =
3906 EL_EXPANDABLE_WALL_HORIZONTAL,
3907 EL_EXPANDABLE_WALL_VERTICAL,
3908 EL_EXPANDABLE_WALL_ANY,
3912 /* special EM style gems behaviour */
3913 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3914 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3915 level.em_slippery_gems);
3917 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3918 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3919 (level.em_slippery_gems &&
3920 engine_version > VERSION_IDENT(2,0,1,0)));
3923 /* this is needed because some graphics depend on element properties */
3924 if (game_status == GAME_MODE_PLAYING)
3925 InitElementGraphicInfo();
3928 void InitElementPropertiesAfterLoading(int engine_version)
3932 /* set some other uninitialized values of custom elements in older levels */
3933 if (engine_version < VERSION_IDENT(3,1,0,0))
3935 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3937 int element = EL_CUSTOM_START + i;
3939 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3941 element_info[element].explosion_delay = 17;
3942 element_info[element].ignition_delay = 8;
3947 static void InitGlobal()
3951 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3953 /* check if element_name_info entry defined for each element in "main.h" */
3954 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3955 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3957 element_info[i].token_name = element_name_info[i].token_name;
3958 element_info[i].class_name = element_name_info[i].class_name;
3959 element_info[i].editor_description=element_name_info[i].editor_description;
3962 global.autoplay_leveldir = NULL;
3963 global.convert_leveldir = NULL;
3965 global.frames_per_second = 0;
3966 global.fps_slowdown = FALSE;
3967 global.fps_slowdown_factor = 1;
3970 void Execute_Command(char *command)
3974 if (strEqual(command, "print graphicsinfo.conf"))
3976 printf("# You can configure additional/alternative image files here.\n");
3977 printf("# (The entries below are default and therefore commented out.)\n");
3979 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3981 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3984 for (i = 0; image_config[i].token != NULL; i++)
3985 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3986 image_config[i].value));
3990 else if (strEqual(command, "print soundsinfo.conf"))
3992 printf("# You can configure additional/alternative sound files here.\n");
3993 printf("# (The entries below are default and therefore commented out.)\n");
3995 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3997 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4000 for (i = 0; sound_config[i].token != NULL; i++)
4001 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4002 sound_config[i].value));
4006 else if (strEqual(command, "print musicinfo.conf"))
4008 printf("# You can configure additional/alternative music files here.\n");
4009 printf("# (The entries below are default and therefore commented out.)\n");
4011 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4013 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4016 for (i = 0; music_config[i].token != NULL; i++)
4017 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4018 music_config[i].value));
4022 else if (strEqual(command, "print editorsetup.conf"))
4024 printf("# You can configure your personal editor element list here.\n");
4025 printf("# (The entries below are default and therefore commented out.)\n");
4028 /* this is needed to be able to check element list for cascade elements */
4029 InitElementPropertiesStatic();
4030 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4032 PrintEditorElementList();
4036 else if (strEqual(command, "print helpanim.conf"))
4038 printf("# You can configure different element help animations here.\n");
4039 printf("# (The entries below are default and therefore commented out.)\n");
4042 for (i = 0; helpanim_config[i].token != NULL; i++)
4044 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4045 helpanim_config[i].value));
4047 if (strEqual(helpanim_config[i].token, "end"))
4053 else if (strEqual(command, "print helptext.conf"))
4055 printf("# You can configure different element help text here.\n");
4056 printf("# (The entries below are default and therefore commented out.)\n");
4059 for (i = 0; helptext_config[i].token != NULL; i++)
4060 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4061 helptext_config[i].value));
4065 else if (strncmp(command, "dump level ", 11) == 0)
4067 char *filename = &command[11];
4069 if (!fileExists(filename))
4070 Error(ERR_EXIT, "cannot open file '%s'", filename);
4072 LoadLevelFromFilename(&level, filename);
4077 else if (strncmp(command, "dump tape ", 10) == 0)
4079 char *filename = &command[10];
4081 if (!fileExists(filename))
4082 Error(ERR_EXIT, "cannot open file '%s'", filename);
4084 LoadTapeFromFilename(filename);
4089 else if (strncmp(command, "autoplay ", 9) == 0)
4091 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4093 while (*str_ptr != '\0') /* continue parsing string */
4095 /* cut leading whitespace from string, replace it by string terminator */
4096 while (*str_ptr == ' ' || *str_ptr == '\t')
4099 if (*str_ptr == '\0') /* end of string reached */
4102 if (global.autoplay_leveldir == NULL) /* read level set string */
4104 global.autoplay_leveldir = str_ptr;
4105 global.autoplay_all = TRUE; /* default: play all tapes */
4107 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4108 global.autoplay_level[i] = FALSE;
4110 else /* read level number string */
4112 int level_nr = atoi(str_ptr); /* get level_nr value */
4114 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4115 global.autoplay_level[level_nr] = TRUE;
4117 global.autoplay_all = FALSE;
4120 /* advance string pointer to the next whitespace (or end of string) */
4121 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4125 else if (strncmp(command, "convert ", 8) == 0)
4127 char *str_copy = getStringCopy(&command[8]);
4128 char *str_ptr = strchr(str_copy, ' ');
4130 global.convert_leveldir = str_copy;
4131 global.convert_level_nr = -1;
4133 if (str_ptr != NULL) /* level number follows */
4135 *str_ptr++ = '\0'; /* terminate leveldir string */
4136 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4141 #if defined(TARGET_SDL)
4142 else if (strEqual(command, "SDL_ListModes"))
4147 SDL_Init(SDL_INIT_VIDEO);
4149 /* get available fullscreen/hardware modes */
4150 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4152 /* check if there are any modes available */
4155 printf("No modes available!\n");
4160 /* check if our resolution is restricted */
4161 if (modes == (SDL_Rect **)-1)
4163 printf("All resolutions available.\n");
4167 printf("Available Modes:\n");
4169 for(i = 0; modes[i]; i++)
4170 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4180 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4184 static void InitSetup()
4186 LoadSetup(); /* global setup info */
4188 /* set some options from setup file */
4190 if (setup.options.verbose)
4191 options.verbose = TRUE;
4194 static void InitGameInfo()
4196 game.restart_level = FALSE;
4199 static void InitPlayerInfo()
4203 /* choose default local player */
4204 local_player = &stored_player[0];
4206 for (i = 0; i < MAX_PLAYERS; i++)
4207 stored_player[i].connected = FALSE;
4209 local_player->connected = TRUE;
4212 static void InitArtworkInfo()
4217 static char *get_string_in_brackets(char *string)
4219 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4221 sprintf(string_in_brackets, "[%s]", string);
4223 return string_in_brackets;
4226 static char *get_level_id_suffix(int id_nr)
4228 char *id_suffix = checked_malloc(1 + 3 + 1);
4230 if (id_nr < 0 || id_nr > 999)
4233 sprintf(id_suffix, ".%03d", id_nr);
4239 static char *get_element_class_token(int element)
4241 char *element_class_name = element_info[element].class_name;
4242 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4244 sprintf(element_class_token, "[%s]", element_class_name);
4246 return element_class_token;
4249 static char *get_action_class_token(int action)
4251 char *action_class_name = &element_action_info[action].suffix[1];
4252 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4254 sprintf(action_class_token, "[%s]", action_class_name);
4256 return action_class_token;
4260 static void InitArtworkConfig()
4262 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4263 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4264 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4265 static char *action_id_suffix[NUM_ACTIONS + 1];
4266 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4267 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4268 static char *level_id_suffix[MAX_LEVELS + 1];
4269 static char *dummy[1] = { NULL };
4270 static char *ignore_generic_tokens[] =
4276 static char **ignore_image_tokens;
4277 static char **ignore_sound_tokens;
4278 static char **ignore_music_tokens;
4279 int num_ignore_generic_tokens;
4280 int num_ignore_image_tokens;
4281 int num_ignore_sound_tokens;
4282 int num_ignore_music_tokens;
4285 /* dynamically determine list of generic tokens to be ignored */
4286 num_ignore_generic_tokens = 0;
4287 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4288 num_ignore_generic_tokens++;
4290 /* dynamically determine list of image tokens to be ignored */
4291 num_ignore_image_tokens = num_ignore_generic_tokens;
4292 for (i = 0; image_config_vars[i].token != NULL; i++)
4293 num_ignore_image_tokens++;
4294 ignore_image_tokens =
4295 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4296 for (i = 0; i < num_ignore_generic_tokens; i++)
4297 ignore_image_tokens[i] = ignore_generic_tokens[i];
4298 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4299 ignore_image_tokens[num_ignore_generic_tokens + i] =
4300 image_config_vars[i].token;
4301 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4303 /* dynamically determine list of sound tokens to be ignored */
4304 num_ignore_sound_tokens = num_ignore_generic_tokens;
4305 ignore_sound_tokens =
4306 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4307 for (i = 0; i < num_ignore_generic_tokens; i++)
4308 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4309 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4311 /* dynamically determine list of music tokens to be ignored */
4312 num_ignore_music_tokens = num_ignore_generic_tokens;
4313 ignore_music_tokens =
4314 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4315 for (i = 0; i < num_ignore_generic_tokens; i++)
4316 ignore_music_tokens[i] = ignore_generic_tokens[i];
4317 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4319 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4320 image_id_prefix[i] = element_info[i].token_name;
4321 for (i = 0; i < NUM_FONTS; i++)
4322 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4323 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4325 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4326 sound_id_prefix[i] = element_info[i].token_name;
4327 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4328 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4329 get_string_in_brackets(element_info[i].class_name);
4330 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4332 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4333 music_id_prefix[i] = music_prefix_info[i].prefix;
4334 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4336 for (i = 0; i < NUM_ACTIONS; i++)
4337 action_id_suffix[i] = element_action_info[i].suffix;
4338 action_id_suffix[NUM_ACTIONS] = NULL;
4340 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4341 direction_id_suffix[i] = element_direction_info[i].suffix;
4342 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4344 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4345 special_id_suffix[i] = special_suffix_info[i].suffix;
4346 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4348 for (i = 0; i < MAX_LEVELS; i++)
4349 level_id_suffix[i] = get_level_id_suffix(i);
4350 level_id_suffix[MAX_LEVELS] = NULL;
4352 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4353 image_id_prefix, action_id_suffix, direction_id_suffix,
4354 special_id_suffix, ignore_image_tokens);
4355 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4356 sound_id_prefix, action_id_suffix, dummy,
4357 special_id_suffix, ignore_sound_tokens);
4358 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4359 music_id_prefix, special_id_suffix, level_id_suffix,
4360 dummy, ignore_music_tokens);
4363 static void InitMixer()
4371 char *filename_font_initial = NULL;
4372 Bitmap *bitmap_font_initial = NULL;
4376 /* determine settings for initial font (for displaying startup messages) */
4377 for (i = 0; image_config[i].token != NULL; i++)
4379 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4381 char font_token[128];
4384 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4385 len_font_token = strlen(font_token);
4387 if (strEqual(image_config[i].token, font_token))
4388 filename_font_initial = image_config[i].value;
4389 else if (strlen(image_config[i].token) > len_font_token &&
4390 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4392 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4393 font_initial[j].src_x = atoi(image_config[i].value);
4394 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4395 font_initial[j].src_y = atoi(image_config[i].value);
4396 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4397 font_initial[j].width = atoi(image_config[i].value);
4398 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4399 font_initial[j].height = atoi(image_config[i].value);
4404 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4406 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4407 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4410 if (filename_font_initial == NULL) /* should not happen */
4411 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4413 /* create additional image buffers for double-buffering and cross-fading */
4414 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4415 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4416 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4417 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4419 /* initialize screen properties */
4420 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4421 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4423 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4424 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4425 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4427 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4429 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4430 font_initial[j].bitmap = bitmap_font_initial;
4432 InitFontGraphicInfo();
4434 font_height = getFontHeight(FC_RED);
4436 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4437 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4438 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4440 DrawInitText("Loading graphics:", 120, FC_GREEN);
4443 void RedrawBackground()
4445 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4446 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4448 redraw_mask = REDRAW_ALL;
4451 void InitGfxBackground()
4455 drawto = backbuffer;
4456 fieldbuffer = bitmap_db_field;
4457 SetDrawtoField(DRAW_BACKBUFFER);
4461 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4462 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4464 for (x = 0; x < MAX_BUF_XSIZE; x++)
4465 for (y = 0; y < MAX_BUF_YSIZE; y++)
4468 redraw_mask = REDRAW_ALL;
4471 static void InitLevelInfo()
4473 LoadLevelInfo(); /* global level info */
4474 LoadLevelSetup_LastSeries(); /* last played series info */
4475 LoadLevelSetup_SeriesInfo(); /* last played level info */
4478 void InitLevelArtworkInfo()
4480 LoadLevelArtworkInfo();
4483 static void InitImages()
4485 setLevelArtworkDir(artwork.gfx_first);
4488 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4489 leveldir_current->identifier,
4490 artwork.gfx_current_identifier,
4491 artwork.gfx_current->identifier,
4492 leveldir_current->graphics_set,
4493 leveldir_current->graphics_path);
4496 ReloadCustomImages();
4498 LoadCustomElementDescriptions();
4499 LoadSpecialMenuDesignSettings();
4501 ReinitializeGraphics();
4504 static void InitSound(char *identifier)
4506 if (identifier == NULL)
4507 identifier = artwork.snd_current->identifier;
4509 /* set artwork path to send it to the sound server process */
4510 setLevelArtworkDir(artwork.snd_first);
4512 InitReloadCustomSounds(identifier);
4513 ReinitializeSounds();
4516 static void InitMusic(char *identifier)
4518 if (identifier == NULL)
4519 identifier = artwork.mus_current->identifier;
4521 /* set artwork path to send it to the sound server process */
4522 setLevelArtworkDir(artwork.mus_first);
4524 InitReloadCustomMusic(identifier);
4525 ReinitializeMusic();
4528 void InitNetworkServer()
4530 #if defined(NETWORK_AVALIABLE)
4534 if (!options.network)
4537 #if defined(NETWORK_AVALIABLE)
4538 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4540 if (!ConnectToServer(options.server_host, options.server_port))
4541 Error(ERR_EXIT, "cannot connect to network game server");
4543 SendToServer_PlayerName(setup.player_name);
4544 SendToServer_ProtocolVersion();
4547 SendToServer_NrWanted(nr_wanted);
4551 static char *getNewArtworkIdentifier(int type)
4553 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4554 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4555 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4556 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4557 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4558 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4559 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4560 char *leveldir_identifier = leveldir_current->identifier;
4562 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4563 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4565 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4567 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4568 char *artwork_current_identifier;
4569 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4571 /* leveldir_current may be invalid (level group, parent link) */
4572 if (!validLevelSeries(leveldir_current))
4575 /* 1st step: determine artwork set to be activated in descending order:
4576 --------------------------------------------------------------------
4577 1. setup artwork (when configured to override everything else)
4578 2. artwork set configured in "levelinfo.conf" of current level set
4579 (artwork in level directory will have priority when loading later)
4580 3. artwork in level directory (stored in artwork sub-directory)
4581 4. setup artwork (currently configured in setup menu) */
4583 if (setup_override_artwork)
4584 artwork_current_identifier = setup_artwork_set;
4585 else if (leveldir_artwork_set != NULL)
4586 artwork_current_identifier = leveldir_artwork_set;
4587 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4588 artwork_current_identifier = leveldir_identifier;
4590 artwork_current_identifier = setup_artwork_set;
4593 /* 2nd step: check if it is really needed to reload artwork set
4594 ------------------------------------------------------------ */
4597 if (type == ARTWORK_TYPE_GRAPHICS)
4598 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4599 artwork_new_identifier,
4600 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4601 artwork_current_identifier,
4602 leveldir_current->graphics_set,
4603 leveldir_current->identifier);
4606 /* ---------- reload if level set and also artwork set has changed ------- */
4607 if (leveldir_current_identifier[type] != leveldir_identifier &&
4608 (last_has_level_artwork_set[type] || has_level_artwork_set))
4609 artwork_new_identifier = artwork_current_identifier;
4611 leveldir_current_identifier[type] = leveldir_identifier;
4612 last_has_level_artwork_set[type] = has_level_artwork_set;
4615 if (type == ARTWORK_TYPE_GRAPHICS)
4616 printf("::: 1: '%s'\n", artwork_new_identifier);
4619 /* ---------- reload if "override artwork" setting has changed ----------- */
4620 if (last_override_level_artwork[type] != setup_override_artwork)
4621 artwork_new_identifier = artwork_current_identifier;
4623 last_override_level_artwork[type] = setup_override_artwork;
4626 if (type == ARTWORK_TYPE_GRAPHICS)
4627 printf("::: 2: '%s'\n", artwork_new_identifier);
4630 /* ---------- reload if current artwork identifier has changed ----------- */
4631 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4632 artwork_current_identifier))
4633 artwork_new_identifier = artwork_current_identifier;
4635 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4638 if (type == ARTWORK_TYPE_GRAPHICS)
4639 printf("::: 3: '%s'\n", artwork_new_identifier);
4642 /* ---------- do not reload directly after starting ---------------------- */
4643 if (!initialized[type])
4644 artwork_new_identifier = NULL;
4646 initialized[type] = TRUE;
4649 if (type == ARTWORK_TYPE_GRAPHICS)
4650 printf("::: 4: '%s'\n", artwork_new_identifier);
4654 if (type == ARTWORK_TYPE_GRAPHICS)
4655 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4656 artwork.gfx_current_identifier, artwork_current_identifier,
4657 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4658 artwork_new_identifier);
4661 return artwork_new_identifier;
4664 void ReloadCustomArtwork(int force_reload)
4666 char *gfx_new_identifier;
4667 char *snd_new_identifier;
4668 char *mus_new_identifier;
4669 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4670 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4671 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4672 boolean redraw_screen = FALSE;
4674 force_reload_gfx |= AdjustGraphicsForEMC();
4676 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4677 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4678 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4680 if (gfx_new_identifier != NULL || force_reload_gfx)
4683 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4684 artwork.gfx_current_identifier,
4686 artwork.gfx_current->identifier,
4687 leveldir_current->graphics_set);
4690 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4694 redraw_screen = TRUE;
4697 if (snd_new_identifier != NULL || force_reload_snd)
4699 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4701 InitSound(snd_new_identifier);
4703 redraw_screen = TRUE;
4706 if (mus_new_identifier != NULL || force_reload_mus)
4708 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4710 InitMusic(mus_new_identifier);
4712 redraw_screen = TRUE;
4719 /* force redraw of (open or closed) door graphics */
4720 SetDoorState(DOOR_OPEN_ALL);
4721 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4725 void KeyboardAutoRepeatOffUnlessAutoplay()
4727 if (global.autoplay_leveldir == NULL)
4728 KeyboardAutoRepeatOff();
4732 /* ========================================================================= */
4734 /* ========================================================================= */
4738 InitGlobal(); /* initialize some global variables */
4740 if (options.execute_command)
4741 Execute_Command(options.execute_command);
4743 if (options.serveronly)
4745 #if defined(PLATFORM_UNIX)
4746 NetworkServer(options.server_port, options.serveronly);
4748 Error(ERR_WARN, "networking only supported in Unix version");
4751 exit(0); /* never reached, server loops forever */
4758 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4759 InitArtworkConfig(); /* needed before forking sound child process */
4764 InitRND(NEW_RANDOMIZE);
4765 InitSimpleRandom(NEW_RANDOMIZE);
4770 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4773 InitEventFilter(FilterMouseMotionEvents);
4775 InitElementPropertiesStatic();
4776 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4781 InitLevelArtworkInfo();
4783 InitImages(); /* needs to know current level directory */
4784 InitSound(NULL); /* needs to know current level directory */
4785 InitMusic(NULL); /* needs to know current level directory */
4787 InitGfxBackground();
4793 if (global.autoplay_leveldir)
4798 else if (global.convert_leveldir)
4804 game_status = GAME_MODE_MAIN;
4808 InitNetworkServer();
4811 void CloseAllAndExit(int exit_value)
4816 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4824 #if defined(TARGET_SDL)
4825 if (network_server) /* terminate network server */
4826 SDL_KillThread(server_thread);
4829 CloseVideoDisplay();
4830 ClosePlatformDependentStuff();
4832 if (exit_value != 0)
4833 NotifyUserAboutErrorFile();