1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 gadgets_initialized = TRUE;
110 inline void InitElementSmallImagesScaledUp(int graphic)
112 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
115 void InitElementSmallImages()
117 static int special_graphics[] =
119 IMG_EDITOR_ELEMENT_BORDER,
120 IMG_EDITOR_ELEMENT_BORDER_INPUT,
121 IMG_EDITOR_CASCADE_LIST,
122 IMG_EDITOR_CASCADE_LIST_ACTIVE,
125 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126 int num_property_mappings = getImageListPropertyMappingSize();
129 /* initialize normal images from static configuration */
130 for (i = 0; element_to_graphic[i].element > -1; i++)
131 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
133 /* initialize special images from static configuration */
134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
135 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
137 /* initialize images from dynamic configuration (may be elements or other) */
138 for (i = 0; i < num_property_mappings; i++)
139 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
141 /* initialize special images from above list (non-element images) */
142 for (i = 0; special_graphics[i] > -1; i++)
143 InitElementSmallImagesScaledUp(special_graphics[i]);
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 graphic_info[graphic].anim_frames_per_line =
1022 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1023 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1025 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1026 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1027 graphic_info[graphic].anim_delay = 1;
1029 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1031 if (graphic_info[graphic].anim_frames == 1)
1032 graphic_info[graphic].anim_mode = ANIM_NONE;
1035 /* automatically determine correct start frame, if not defined */
1036 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1037 graphic_info[graphic].anim_start_frame = 0;
1038 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1039 graphic_info[graphic].anim_start_frame =
1040 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1042 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1044 /* animation synchronized with global frame counter, not move position */
1045 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1047 /* optional element for cloning crumble graphics */
1048 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1049 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1051 /* optional element for cloning digging graphics */
1052 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1055 /* optional border size for "crumbling" diggable graphics */
1056 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1057 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1059 /* this is only used for player "boring" and "sleeping" actions */
1060 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1061 graphic_info[graphic].anim_delay_fixed =
1062 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1063 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].anim_delay_random =
1065 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1066 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1067 graphic_info[graphic].post_delay_fixed =
1068 parameter[GFX_ARG_POST_DELAY_FIXED];
1069 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1070 graphic_info[graphic].post_delay_random =
1071 parameter[GFX_ARG_POST_DELAY_RANDOM];
1073 /* this is only used for toon animations */
1074 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1075 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1077 /* this is only used for drawing font characters */
1078 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1079 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1081 /* this is only used for drawing envelope graphics */
1082 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1084 /* optional graphic for cloning all graphics settings */
1085 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1086 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1089 static void set_cloned_graphic_parameters(int graphic)
1091 int fallback_graphic = IMG_CHAR_EXCLAM;
1092 int max_num_images = getImageListSize();
1093 int clone_graphic = graphic_info[graphic].clone_from;
1094 int num_references_followed = 1;
1096 while (graphic_info[clone_graphic].clone_from != -1 &&
1097 num_references_followed < max_num_images)
1099 clone_graphic = graphic_info[clone_graphic].clone_from;
1101 num_references_followed++;
1104 if (num_references_followed >= max_num_images)
1106 Error(ERR_RETURN_LINE, "-");
1107 Error(ERR_RETURN, "warning: error found in config file:");
1108 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1109 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1110 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1111 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1113 if (graphic == fallback_graphic)
1114 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1116 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1117 Error(ERR_RETURN_LINE, "-");
1119 graphic_info[graphic] = graphic_info[fallback_graphic];
1123 graphic_info[graphic] = graphic_info[clone_graphic];
1124 graphic_info[graphic].clone_from = clone_graphic;
1128 static void InitGraphicInfo()
1130 int fallback_graphic = IMG_CHAR_EXCLAM;
1131 int num_images = getImageListSize();
1134 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1135 static boolean clipmasks_initialized = FALSE;
1137 XGCValues clip_gc_values;
1138 unsigned long clip_gc_valuemask;
1139 GC copy_clipmask_gc = None;
1142 checked_free(graphic_info);
1144 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1146 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1147 if (clipmasks_initialized)
1149 for (i = 0; i < num_images; i++)
1151 if (graphic_info[i].clip_mask)
1152 XFreePixmap(display, graphic_info[i].clip_mask);
1153 if (graphic_info[i].clip_gc)
1154 XFreeGC(display, graphic_info[i].clip_gc);
1156 graphic_info[i].clip_mask = None;
1157 graphic_info[i].clip_gc = None;
1162 /* first set all graphic paramaters ... */
1163 for (i = 0; i < num_images; i++)
1164 set_graphic_parameters(i);
1166 /* ... then copy these parameters for cloned graphics */
1167 for (i = 0; i < num_images; i++)
1168 if (graphic_info[i].clone_from != -1)
1169 set_cloned_graphic_parameters(i);
1171 for (i = 0; i < num_images; i++)
1175 int first_frame, last_frame;
1176 int src_bitmap_width, src_bitmap_height;
1178 /* now check if no animation frames are outside of the loaded image */
1180 if (graphic_info[i].bitmap == NULL)
1181 continue; /* skip check for optional images that are undefined */
1183 /* get final bitmap size (with scaling, but without small images) */
1184 src_bitmap_width = graphic_info[i].src_image_width;
1185 src_bitmap_height = graphic_info[i].src_image_height;
1187 /* check if first animation frame is inside specified bitmap */
1190 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1192 if (src_x < 0 || src_y < 0 ||
1193 src_x + TILEX > src_bitmap_width ||
1194 src_y + TILEY > src_bitmap_height)
1196 Error(ERR_RETURN_LINE, "-");
1197 Error(ERR_RETURN, "warning: error found in config file:");
1198 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1199 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1200 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1202 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1203 src_x, src_y, src_bitmap_width, src_bitmap_height);
1204 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1206 if (i == fallback_graphic)
1207 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1209 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1210 Error(ERR_RETURN_LINE, "-");
1212 graphic_info[i] = graphic_info[fallback_graphic];
1215 /* check if last animation frame is inside specified bitmap */
1217 last_frame = graphic_info[i].anim_frames - 1;
1218 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1220 if (src_x < 0 || src_y < 0 ||
1221 src_x + TILEX > src_bitmap_width ||
1222 src_y + TILEY > src_bitmap_height)
1224 Error(ERR_RETURN_LINE, "-");
1225 Error(ERR_RETURN, "warning: error found in config file:");
1226 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1227 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1228 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1230 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1231 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1232 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1234 if (i == fallback_graphic)
1235 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1237 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1238 Error(ERR_RETURN_LINE, "-");
1240 graphic_info[i] = graphic_info[fallback_graphic];
1243 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1244 /* currently we only need a tile clip mask from the first frame */
1245 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1247 if (copy_clipmask_gc == None)
1249 clip_gc_values.graphics_exposures = False;
1250 clip_gc_valuemask = GCGraphicsExposures;
1251 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1252 clip_gc_valuemask, &clip_gc_values);
1255 graphic_info[i].clip_mask =
1256 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1258 src_pixmap = src_bitmap->clip_mask;
1259 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1260 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1262 clip_gc_values.graphics_exposures = False;
1263 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1264 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1266 graphic_info[i].clip_gc =
1267 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1271 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1272 if (copy_clipmask_gc)
1273 XFreeGC(display, copy_clipmask_gc);
1275 clipmasks_initialized = TRUE;
1279 static void InitElementSoundInfo()
1281 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1282 int num_property_mappings = getSoundListPropertyMappingSize();
1285 /* set values to -1 to identify later as "uninitialized" values */
1286 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1287 for (act = 0; act < NUM_ACTIONS; act++)
1288 element_info[i].sound[act] = -1;
1290 /* initialize element/sound mapping from static configuration */
1291 for (i = 0; element_to_sound[i].element > -1; i++)
1293 int element = element_to_sound[i].element;
1294 int action = element_to_sound[i].action;
1295 int sound = element_to_sound[i].sound;
1296 boolean is_class = element_to_sound[i].is_class;
1299 action = ACTION_DEFAULT;
1302 element_info[element].sound[action] = sound;
1304 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1305 if (strEqual(element_info[j].class_name,
1306 element_info[element].class_name))
1307 element_info[j].sound[action] = sound;
1310 /* initialize element class/sound mapping from dynamic configuration */
1311 for (i = 0; i < num_property_mappings; i++)
1313 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1314 int action = property_mapping[i].ext1_index;
1315 int sound = property_mapping[i].artwork_index;
1317 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1321 action = ACTION_DEFAULT;
1323 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1324 if (strEqual(element_info[j].class_name,
1325 element_info[element_class].class_name))
1326 element_info[j].sound[action] = sound;
1329 /* initialize element/sound mapping from dynamic configuration */
1330 for (i = 0; i < num_property_mappings; i++)
1332 int element = property_mapping[i].base_index;
1333 int action = property_mapping[i].ext1_index;
1334 int sound = property_mapping[i].artwork_index;
1336 if (element >= MAX_NUM_ELEMENTS)
1340 action = ACTION_DEFAULT;
1342 element_info[element].sound[action] = sound;
1345 /* now set all '-1' values to element specific default values */
1346 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1348 for (act = 0; act < NUM_ACTIONS; act++)
1350 /* generic default action sound (defined by "[default]" directive) */
1351 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1353 /* look for special default action sound (classic game specific) */
1354 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1355 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1356 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1357 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1358 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1359 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1361 /* !!! there's no such thing as a "default action sound" !!! */
1363 /* look for element specific default sound (independent from action) */
1364 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1365 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1369 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1370 /* !!! make this better !!! */
1371 if (i == EL_EMPTY_SPACE)
1372 default_action_sound = element_info[EL_DEFAULT].sound[act];
1375 /* no sound for this specific action -- use default action sound */
1376 if (element_info[i].sound[act] == -1)
1377 element_info[i].sound[act] = default_action_sound;
1381 /* copy sound settings to some elements that are only stored in level file
1382 in native R'n'D levels, but are used by game engine in native EM levels */
1383 for (i = 0; copy_properties[i][0] != -1; i++)
1384 for (j = 1; j <= 4; j++)
1385 for (act = 0; act < NUM_ACTIONS; act++)
1386 element_info[copy_properties[i][j]].sound[act] =
1387 element_info[copy_properties[i][0]].sound[act];
1390 static void InitGameModeSoundInfo()
1394 /* set values to -1 to identify later as "uninitialized" values */
1395 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1398 /* initialize gamemode/sound mapping from static configuration */
1399 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1401 int gamemode = gamemode_to_sound[i].gamemode;
1402 int sound = gamemode_to_sound[i].sound;
1405 gamemode = GAME_MODE_DEFAULT;
1407 menu.sound[gamemode] = sound;
1410 /* now set all '-1' values to levelset specific default values */
1411 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1412 if (menu.sound[i] == -1)
1413 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1416 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1417 if (menu.sound[i] != -1)
1418 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1422 static void set_sound_parameters(int sound, char **parameter_raw)
1424 int parameter[NUM_SND_ARGS];
1427 /* get integer values from string parameters */
1428 for (i = 0; i < NUM_SND_ARGS; i++)
1430 get_parameter_value(parameter_raw[i],
1431 sound_config_suffix[i].token,
1432 sound_config_suffix[i].type);
1434 /* explicit loop mode setting in configuration overrides default value */
1435 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1436 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1438 /* sound volume to change the original volume when loading the sound file */
1439 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1441 /* sound priority to give certain sounds a higher or lower priority */
1442 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1445 static void InitSoundInfo()
1447 int *sound_effect_properties;
1448 int num_sounds = getSoundListSize();
1451 checked_free(sound_info);
1453 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1454 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1456 /* initialize sound effect for all elements to "no sound" */
1457 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1458 for (j = 0; j < NUM_ACTIONS; j++)
1459 element_info[i].sound[j] = SND_UNDEFINED;
1461 for (i = 0; i < num_sounds; i++)
1463 struct FileInfo *sound = getSoundListEntry(i);
1464 int len_effect_text = strlen(sound->token);
1466 sound_effect_properties[i] = ACTION_OTHER;
1467 sound_info[i].loop = FALSE; /* default: play sound only once */
1470 printf("::: sound %d: '%s'\n", i, sound->token);
1473 /* determine all loop sounds and identify certain sound classes */
1475 for (j = 0; element_action_info[j].suffix; j++)
1477 int len_action_text = strlen(element_action_info[j].suffix);
1479 if (len_action_text < len_effect_text &&
1480 strEqual(&sound->token[len_effect_text - len_action_text],
1481 element_action_info[j].suffix))
1483 sound_effect_properties[i] = element_action_info[j].value;
1484 sound_info[i].loop = element_action_info[j].is_loop_sound;
1490 /* associate elements and some selected sound actions */
1492 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1494 if (element_info[j].class_name)
1496 int len_class_text = strlen(element_info[j].class_name);
1498 if (len_class_text + 1 < len_effect_text &&
1499 strncmp(sound->token,
1500 element_info[j].class_name, len_class_text) == 0 &&
1501 sound->token[len_class_text] == '.')
1503 int sound_action_value = sound_effect_properties[i];
1505 element_info[j].sound[sound_action_value] = i;
1510 set_sound_parameters(i, sound->parameter);
1513 free(sound_effect_properties);
1516 static void InitGameModeMusicInfo()
1518 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1519 int num_property_mappings = getMusicListPropertyMappingSize();
1520 int default_levelset_music = -1;
1523 /* set values to -1 to identify later as "uninitialized" values */
1524 for (i = 0; i < MAX_LEVELS; i++)
1525 levelset.music[i] = -1;
1526 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1529 /* initialize gamemode/music mapping from static configuration */
1530 for (i = 0; gamemode_to_music[i].music > -1; i++)
1532 int gamemode = gamemode_to_music[i].gamemode;
1533 int music = gamemode_to_music[i].music;
1536 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1540 gamemode = GAME_MODE_DEFAULT;
1542 menu.music[gamemode] = music;
1545 /* initialize gamemode/music mapping from dynamic configuration */
1546 for (i = 0; i < num_property_mappings; i++)
1548 int prefix = property_mapping[i].base_index;
1549 int gamemode = property_mapping[i].ext1_index;
1550 int level = property_mapping[i].ext2_index;
1551 int music = property_mapping[i].artwork_index;
1554 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1555 prefix, gamemode, level, music);
1558 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1562 gamemode = GAME_MODE_DEFAULT;
1564 /* level specific music only allowed for in-game music */
1565 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1566 gamemode = GAME_MODE_PLAYING;
1571 default_levelset_music = music;
1574 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1575 levelset.music[level] = music;
1576 if (gamemode != GAME_MODE_PLAYING)
1577 menu.music[gamemode] = music;
1580 /* now set all '-1' values to menu specific default values */
1581 /* (undefined values of "levelset.music[]" might stay at "-1" to
1582 allow dynamic selection of music files from music directory!) */
1583 for (i = 0; i < MAX_LEVELS; i++)
1584 if (levelset.music[i] == -1)
1585 levelset.music[i] = default_levelset_music;
1586 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1587 if (menu.music[i] == -1)
1588 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1591 for (i = 0; i < MAX_LEVELS; i++)
1592 if (levelset.music[i] != -1)
1593 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1594 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1595 if (menu.music[i] != -1)
1596 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1600 static void set_music_parameters(int music, char **parameter_raw)
1602 int parameter[NUM_MUS_ARGS];
1605 /* get integer values from string parameters */
1606 for (i = 0; i < NUM_MUS_ARGS; i++)
1608 get_parameter_value(parameter_raw[i],
1609 music_config_suffix[i].token,
1610 music_config_suffix[i].type);
1612 /* explicit loop mode setting in configuration overrides default value */
1613 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1614 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1617 static void InitMusicInfo()
1619 int num_music = getMusicListSize();
1622 checked_free(music_info);
1624 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1626 for (i = 0; i < num_music; i++)
1628 struct FileInfo *music = getMusicListEntry(i);
1629 int len_music_text = strlen(music->token);
1631 music_info[i].loop = TRUE; /* default: play music in loop mode */
1633 /* determine all loop music */
1635 for (j = 0; music_prefix_info[j].prefix; j++)
1637 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1639 if (len_prefix_text < len_music_text &&
1640 strncmp(music->token,
1641 music_prefix_info[j].prefix, len_prefix_text) == 0)
1643 music_info[i].loop = music_prefix_info[j].is_loop_music;
1649 set_music_parameters(i, music->parameter);
1653 static void ReinitializeGraphics()
1655 InitGraphicInfo(); /* graphic properties mapping */
1656 InitElementGraphicInfo(); /* element game graphic mapping */
1657 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1659 InitElementSmallImages(); /* scale elements to all needed sizes */
1660 InitScaledImages(); /* scale all other images, if needed */
1661 InitFontGraphicInfo(); /* initialize text drawing functions */
1663 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1665 SetMainBackgroundImage(IMG_BACKGROUND);
1666 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1672 static void ReinitializeSounds()
1674 InitSoundInfo(); /* sound properties mapping */
1675 InitElementSoundInfo(); /* element game sound mapping */
1676 InitGameModeSoundInfo(); /* game mode sound mapping */
1678 InitPlayLevelSound(); /* internal game sound settings */
1681 static void ReinitializeMusic()
1683 InitMusicInfo(); /* music properties mapping */
1684 InitGameModeMusicInfo(); /* game mode music mapping */
1687 static int get_special_property_bit(int element, int property_bit_nr)
1689 struct PropertyBitInfo
1695 static struct PropertyBitInfo pb_can_move_into_acid[] =
1697 /* the player may be able fall into acid when gravity is activated */
1702 { EL_SP_MURPHY, 0 },
1703 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1705 /* all elements that can move may be able to also move into acid */
1708 { EL_BUG_RIGHT, 1 },
1711 { EL_SPACESHIP, 2 },
1712 { EL_SPACESHIP_LEFT, 2 },
1713 { EL_SPACESHIP_RIGHT, 2 },
1714 { EL_SPACESHIP_UP, 2 },
1715 { EL_SPACESHIP_DOWN, 2 },
1716 { EL_BD_BUTTERFLY, 3 },
1717 { EL_BD_BUTTERFLY_LEFT, 3 },
1718 { EL_BD_BUTTERFLY_RIGHT, 3 },
1719 { EL_BD_BUTTERFLY_UP, 3 },
1720 { EL_BD_BUTTERFLY_DOWN, 3 },
1721 { EL_BD_FIREFLY, 4 },
1722 { EL_BD_FIREFLY_LEFT, 4 },
1723 { EL_BD_FIREFLY_RIGHT, 4 },
1724 { EL_BD_FIREFLY_UP, 4 },
1725 { EL_BD_FIREFLY_DOWN, 4 },
1727 { EL_YAMYAM_LEFT, 5 },
1728 { EL_YAMYAM_RIGHT, 5 },
1729 { EL_YAMYAM_UP, 5 },
1730 { EL_YAMYAM_DOWN, 5 },
1731 { EL_DARK_YAMYAM, 6 },
1734 { EL_PACMAN_LEFT, 8 },
1735 { EL_PACMAN_RIGHT, 8 },
1736 { EL_PACMAN_UP, 8 },
1737 { EL_PACMAN_DOWN, 8 },
1739 { EL_MOLE_LEFT, 9 },
1740 { EL_MOLE_RIGHT, 9 },
1742 { EL_MOLE_DOWN, 9 },
1746 { EL_SATELLITE, 13 },
1747 { EL_SP_SNIKSNAK, 14 },
1748 { EL_SP_ELECTRON, 15 },
1751 { EL_EMC_ANDROID, 18 },
1756 static struct PropertyBitInfo pb_dont_collide_with[] =
1758 { EL_SP_SNIKSNAK, 0 },
1759 { EL_SP_ELECTRON, 1 },
1767 struct PropertyBitInfo *pb_info;
1770 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1771 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1776 struct PropertyBitInfo *pb_info = NULL;
1779 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1780 if (pb_definition[i].bit_nr == property_bit_nr)
1781 pb_info = pb_definition[i].pb_info;
1783 if (pb_info == NULL)
1786 for (i = 0; pb_info[i].element != -1; i++)
1787 if (pb_info[i].element == element)
1788 return pb_info[i].bit_nr;
1793 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1794 boolean property_value)
1796 int bit_nr = get_special_property_bit(element, property_bit_nr);
1801 *bitfield |= (1 << bit_nr);
1803 *bitfield &= ~(1 << bit_nr);
1807 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1809 int bit_nr = get_special_property_bit(element, property_bit_nr);
1812 return ((*bitfield & (1 << bit_nr)) != 0);
1818 static void resolve_group_element(int group_element, int recursion_depth)
1820 static int group_nr;
1821 static struct ElementGroupInfo *group;
1822 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1825 if (actual_group == NULL) /* not yet initialized */
1828 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1830 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1831 group_element - EL_GROUP_START + 1);
1833 /* replace element which caused too deep recursion by question mark */
1834 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1839 if (recursion_depth == 0) /* initialization */
1841 group = actual_group;
1842 group_nr = group_element - EL_GROUP_START;
1844 group->num_elements_resolved = 0;
1845 group->choice_pos = 0;
1848 for (i = 0; i < actual_group->num_elements; i++)
1850 int element = actual_group->element[i];
1852 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1855 if (IS_GROUP_ELEMENT(element))
1856 resolve_group_element(element, recursion_depth + 1);
1859 group->element_resolved[group->num_elements_resolved++] = element;
1860 element_info[element].in_group[group_nr] = TRUE;
1866 void InitElementPropertiesStatic()
1868 static int ep_diggable[] =
1873 EL_SP_BUGGY_BASE_ACTIVATING,
1876 EL_INVISIBLE_SAND_ACTIVE,
1879 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1880 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1884 EL_SP_BUGGY_BASE_ACTIVE,
1891 static int ep_collectible_only[] =
1913 EL_DYNABOMB_INCREASE_NUMBER,
1914 EL_DYNABOMB_INCREASE_SIZE,
1915 EL_DYNABOMB_INCREASE_POWER,
1935 static int ep_dont_run_into[] =
1937 /* same elements as in 'ep_dont_touch' */
1943 /* same elements as in 'ep_dont_collide_with' */
1955 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1959 EL_SP_BUGGY_BASE_ACTIVE,
1966 static int ep_dont_collide_with[] =
1968 /* same elements as in 'ep_dont_touch' */
1985 static int ep_dont_touch[] =
1995 static int ep_indestructible[] =
1999 EL_ACID_POOL_TOPLEFT,
2000 EL_ACID_POOL_TOPRIGHT,
2001 EL_ACID_POOL_BOTTOMLEFT,
2002 EL_ACID_POOL_BOTTOM,
2003 EL_ACID_POOL_BOTTOMRIGHT,
2004 EL_SP_HARDWARE_GRAY,
2005 EL_SP_HARDWARE_GREEN,
2006 EL_SP_HARDWARE_BLUE,
2008 EL_SP_HARDWARE_YELLOW,
2009 EL_SP_HARDWARE_BASE_1,
2010 EL_SP_HARDWARE_BASE_2,
2011 EL_SP_HARDWARE_BASE_3,
2012 EL_SP_HARDWARE_BASE_4,
2013 EL_SP_HARDWARE_BASE_5,
2014 EL_SP_HARDWARE_BASE_6,
2015 EL_INVISIBLE_STEELWALL,
2016 EL_INVISIBLE_STEELWALL_ACTIVE,
2017 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2018 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2019 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2020 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2021 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2022 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2023 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2024 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2025 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2026 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2027 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2028 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2030 EL_LIGHT_SWITCH_ACTIVE,
2031 EL_SIGN_EXCLAMATION,
2032 EL_SIGN_RADIOACTIVITY,
2043 EL_STEELWALL_SLIPPERY,
2057 EL_GATE_1_GRAY_ACTIVE,
2058 EL_GATE_2_GRAY_ACTIVE,
2059 EL_GATE_3_GRAY_ACTIVE,
2060 EL_GATE_4_GRAY_ACTIVE,
2069 EL_EM_GATE_1_GRAY_ACTIVE,
2070 EL_EM_GATE_2_GRAY_ACTIVE,
2071 EL_EM_GATE_3_GRAY_ACTIVE,
2072 EL_EM_GATE_4_GRAY_ACTIVE,
2081 EL_EMC_GATE_5_GRAY_ACTIVE,
2082 EL_EMC_GATE_6_GRAY_ACTIVE,
2083 EL_EMC_GATE_7_GRAY_ACTIVE,
2084 EL_EMC_GATE_8_GRAY_ACTIVE,
2086 EL_SWITCHGATE_OPENING,
2087 EL_SWITCHGATE_CLOSED,
2088 EL_SWITCHGATE_CLOSING,
2090 EL_SWITCHGATE_SWITCH_UP,
2091 EL_SWITCHGATE_SWITCH_DOWN,
2094 EL_TIMEGATE_OPENING,
2096 EL_TIMEGATE_CLOSING,
2099 EL_TIMEGATE_SWITCH_ACTIVE,
2104 EL_TUBE_VERTICAL_LEFT,
2105 EL_TUBE_VERTICAL_RIGHT,
2106 EL_TUBE_HORIZONTAL_UP,
2107 EL_TUBE_HORIZONTAL_DOWN,
2116 static int ep_slippery[] =
2130 EL_ROBOT_WHEEL_ACTIVE,
2136 EL_ACID_POOL_TOPLEFT,
2137 EL_ACID_POOL_TOPRIGHT,
2147 EL_STEELWALL_SLIPPERY,
2150 EL_EMC_WALL_SLIPPERY_1,
2151 EL_EMC_WALL_SLIPPERY_2,
2152 EL_EMC_WALL_SLIPPERY_3,
2153 EL_EMC_WALL_SLIPPERY_4,
2155 EL_EMC_MAGIC_BALL_ACTIVE,
2160 static int ep_can_change[] =
2165 static int ep_can_move[] =
2167 /* same elements as in 'pb_can_move_into_acid' */
2190 static int ep_can_fall[] =
2205 EL_BD_MAGIC_WALL_FULL,
2219 static int ep_can_smash_player[] =
2245 static int ep_can_smash_enemies[] =
2254 static int ep_can_smash_everything[] =
2263 static int ep_explodes_by_fire[] =
2265 /* same elements as in 'ep_explodes_impact' */
2270 /* same elements as in 'ep_explodes_smashed' */
2280 EL_EM_DYNAMITE_ACTIVE,
2281 EL_DYNABOMB_PLAYER_1_ACTIVE,
2282 EL_DYNABOMB_PLAYER_2_ACTIVE,
2283 EL_DYNABOMB_PLAYER_3_ACTIVE,
2284 EL_DYNABOMB_PLAYER_4_ACTIVE,
2285 EL_DYNABOMB_INCREASE_NUMBER,
2286 EL_DYNABOMB_INCREASE_SIZE,
2287 EL_DYNABOMB_INCREASE_POWER,
2288 EL_SP_DISK_RED_ACTIVE,
2302 static int ep_explodes_smashed[] =
2304 /* same elements as in 'ep_explodes_impact' */
2318 static int ep_explodes_impact[] =
2327 static int ep_walkable_over[] =
2331 EL_SOKOBAN_FIELD_EMPTY,
2343 EL_GATE_1_GRAY_ACTIVE,
2344 EL_GATE_2_GRAY_ACTIVE,
2345 EL_GATE_3_GRAY_ACTIVE,
2346 EL_GATE_4_GRAY_ACTIVE,
2354 static int ep_walkable_inside[] =
2359 EL_TUBE_VERTICAL_LEFT,
2360 EL_TUBE_VERTICAL_RIGHT,
2361 EL_TUBE_HORIZONTAL_UP,
2362 EL_TUBE_HORIZONTAL_DOWN,
2371 static int ep_walkable_under[] =
2376 static int ep_passable_over[] =
2386 EL_EM_GATE_1_GRAY_ACTIVE,
2387 EL_EM_GATE_2_GRAY_ACTIVE,
2388 EL_EM_GATE_3_GRAY_ACTIVE,
2389 EL_EM_GATE_4_GRAY_ACTIVE,
2398 EL_EMC_GATE_5_GRAY_ACTIVE,
2399 EL_EMC_GATE_6_GRAY_ACTIVE,
2400 EL_EMC_GATE_7_GRAY_ACTIVE,
2401 EL_EMC_GATE_8_GRAY_ACTIVE,
2408 static int ep_passable_inside[] =
2414 EL_SP_PORT_HORIZONTAL,
2415 EL_SP_PORT_VERTICAL,
2417 EL_SP_GRAVITY_PORT_LEFT,
2418 EL_SP_GRAVITY_PORT_RIGHT,
2419 EL_SP_GRAVITY_PORT_UP,
2420 EL_SP_GRAVITY_PORT_DOWN,
2421 EL_SP_GRAVITY_ON_PORT_LEFT,
2422 EL_SP_GRAVITY_ON_PORT_RIGHT,
2423 EL_SP_GRAVITY_ON_PORT_UP,
2424 EL_SP_GRAVITY_ON_PORT_DOWN,
2425 EL_SP_GRAVITY_OFF_PORT_LEFT,
2426 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2427 EL_SP_GRAVITY_OFF_PORT_UP,
2428 EL_SP_GRAVITY_OFF_PORT_DOWN,
2433 static int ep_passable_under[] =
2438 static int ep_droppable[] =
2443 static int ep_explodes_1x1_old[] =
2448 static int ep_pushable[] =
2460 EL_SOKOBAN_FIELD_FULL,
2469 static int ep_explodes_cross_old[] =
2474 static int ep_protected[] =
2476 /* same elements as in 'ep_walkable_inside' */
2480 EL_TUBE_VERTICAL_LEFT,
2481 EL_TUBE_VERTICAL_RIGHT,
2482 EL_TUBE_HORIZONTAL_UP,
2483 EL_TUBE_HORIZONTAL_DOWN,
2489 /* same elements as in 'ep_passable_over' */
2498 EL_EM_GATE_1_GRAY_ACTIVE,
2499 EL_EM_GATE_2_GRAY_ACTIVE,
2500 EL_EM_GATE_3_GRAY_ACTIVE,
2501 EL_EM_GATE_4_GRAY_ACTIVE,
2510 EL_EMC_GATE_5_GRAY_ACTIVE,
2511 EL_EMC_GATE_6_GRAY_ACTIVE,
2512 EL_EMC_GATE_7_GRAY_ACTIVE,
2513 EL_EMC_GATE_8_GRAY_ACTIVE,
2517 /* same elements as in 'ep_passable_inside' */
2522 EL_SP_PORT_HORIZONTAL,
2523 EL_SP_PORT_VERTICAL,
2525 EL_SP_GRAVITY_PORT_LEFT,
2526 EL_SP_GRAVITY_PORT_RIGHT,
2527 EL_SP_GRAVITY_PORT_UP,
2528 EL_SP_GRAVITY_PORT_DOWN,
2529 EL_SP_GRAVITY_ON_PORT_LEFT,
2530 EL_SP_GRAVITY_ON_PORT_RIGHT,
2531 EL_SP_GRAVITY_ON_PORT_UP,
2532 EL_SP_GRAVITY_ON_PORT_DOWN,
2533 EL_SP_GRAVITY_OFF_PORT_LEFT,
2534 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2535 EL_SP_GRAVITY_OFF_PORT_UP,
2536 EL_SP_GRAVITY_OFF_PORT_DOWN,
2541 static int ep_throwable[] =
2546 static int ep_can_explode[] =
2548 /* same elements as in 'ep_explodes_impact' */
2553 /* same elements as in 'ep_explodes_smashed' */
2559 /* elements that can explode by explosion or by dragonfire */
2563 EL_EM_DYNAMITE_ACTIVE,
2564 EL_DYNABOMB_PLAYER_1_ACTIVE,
2565 EL_DYNABOMB_PLAYER_2_ACTIVE,
2566 EL_DYNABOMB_PLAYER_3_ACTIVE,
2567 EL_DYNABOMB_PLAYER_4_ACTIVE,
2568 EL_DYNABOMB_INCREASE_NUMBER,
2569 EL_DYNABOMB_INCREASE_SIZE,
2570 EL_DYNABOMB_INCREASE_POWER,
2571 EL_SP_DISK_RED_ACTIVE,
2579 /* elements that can explode only by explosion */
2585 static int ep_gravity_reachable[] =
2591 EL_INVISIBLE_SAND_ACTIVE,
2596 EL_SP_PORT_HORIZONTAL,
2597 EL_SP_PORT_VERTICAL,
2599 EL_SP_GRAVITY_PORT_LEFT,
2600 EL_SP_GRAVITY_PORT_RIGHT,
2601 EL_SP_GRAVITY_PORT_UP,
2602 EL_SP_GRAVITY_PORT_DOWN,
2603 EL_SP_GRAVITY_ON_PORT_LEFT,
2604 EL_SP_GRAVITY_ON_PORT_RIGHT,
2605 EL_SP_GRAVITY_ON_PORT_UP,
2606 EL_SP_GRAVITY_ON_PORT_DOWN,
2607 EL_SP_GRAVITY_OFF_PORT_LEFT,
2608 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2609 EL_SP_GRAVITY_OFF_PORT_UP,
2610 EL_SP_GRAVITY_OFF_PORT_DOWN,
2616 static int ep_player[] =
2623 EL_SOKOBAN_FIELD_PLAYER,
2629 static int ep_can_pass_magic_wall[] =
2643 static int ep_switchable[] =
2647 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2648 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2649 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2650 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2651 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2652 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2653 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2654 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2655 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2656 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2657 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2658 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2659 EL_SWITCHGATE_SWITCH_UP,
2660 EL_SWITCHGATE_SWITCH_DOWN,
2662 EL_LIGHT_SWITCH_ACTIVE,
2664 EL_BALLOON_SWITCH_LEFT,
2665 EL_BALLOON_SWITCH_RIGHT,
2666 EL_BALLOON_SWITCH_UP,
2667 EL_BALLOON_SWITCH_DOWN,
2668 EL_BALLOON_SWITCH_ANY,
2669 EL_BALLOON_SWITCH_NONE,
2672 EL_EMC_MAGIC_BALL_SWITCH,
2673 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2678 static int ep_bd_element[] =
2712 static int ep_sp_element[] =
2714 /* should always be valid */
2717 /* standard classic Supaplex elements */
2724 EL_SP_HARDWARE_GRAY,
2732 EL_SP_GRAVITY_PORT_RIGHT,
2733 EL_SP_GRAVITY_PORT_DOWN,
2734 EL_SP_GRAVITY_PORT_LEFT,
2735 EL_SP_GRAVITY_PORT_UP,
2740 EL_SP_PORT_VERTICAL,
2741 EL_SP_PORT_HORIZONTAL,
2747 EL_SP_HARDWARE_BASE_1,
2748 EL_SP_HARDWARE_GREEN,
2749 EL_SP_HARDWARE_BLUE,
2751 EL_SP_HARDWARE_YELLOW,
2752 EL_SP_HARDWARE_BASE_2,
2753 EL_SP_HARDWARE_BASE_3,
2754 EL_SP_HARDWARE_BASE_4,
2755 EL_SP_HARDWARE_BASE_5,
2756 EL_SP_HARDWARE_BASE_6,
2760 /* additional elements that appeared in newer Supaplex levels */
2763 /* additional gravity port elements (not switching, but setting gravity) */
2764 EL_SP_GRAVITY_ON_PORT_LEFT,
2765 EL_SP_GRAVITY_ON_PORT_RIGHT,
2766 EL_SP_GRAVITY_ON_PORT_UP,
2767 EL_SP_GRAVITY_ON_PORT_DOWN,
2768 EL_SP_GRAVITY_OFF_PORT_LEFT,
2769 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2770 EL_SP_GRAVITY_OFF_PORT_UP,
2771 EL_SP_GRAVITY_OFF_PORT_DOWN,
2773 /* more than one Murphy in a level results in an inactive clone */
2776 /* runtime Supaplex elements */
2777 EL_SP_DISK_RED_ACTIVE,
2778 EL_SP_TERMINAL_ACTIVE,
2779 EL_SP_BUGGY_BASE_ACTIVATING,
2780 EL_SP_BUGGY_BASE_ACTIVE,
2787 static int ep_sb_element[] =
2792 EL_SOKOBAN_FIELD_EMPTY,
2793 EL_SOKOBAN_FIELD_FULL,
2794 EL_SOKOBAN_FIELD_PLAYER,
2799 EL_INVISIBLE_STEELWALL,
2804 static int ep_gem[] =
2816 static int ep_food_dark_yamyam[] =
2844 static int ep_food_penguin[] =
2858 static int ep_food_pig[] =
2870 static int ep_historic_wall[] =
2881 EL_GATE_1_GRAY_ACTIVE,
2882 EL_GATE_2_GRAY_ACTIVE,
2883 EL_GATE_3_GRAY_ACTIVE,
2884 EL_GATE_4_GRAY_ACTIVE,
2893 EL_EM_GATE_1_GRAY_ACTIVE,
2894 EL_EM_GATE_2_GRAY_ACTIVE,
2895 EL_EM_GATE_3_GRAY_ACTIVE,
2896 EL_EM_GATE_4_GRAY_ACTIVE,
2903 EL_EXPANDABLE_WALL_HORIZONTAL,
2904 EL_EXPANDABLE_WALL_VERTICAL,
2905 EL_EXPANDABLE_WALL_ANY,
2906 EL_EXPANDABLE_WALL_GROWING,
2913 EL_SP_HARDWARE_GRAY,
2914 EL_SP_HARDWARE_GREEN,
2915 EL_SP_HARDWARE_BLUE,
2917 EL_SP_HARDWARE_YELLOW,
2918 EL_SP_HARDWARE_BASE_1,
2919 EL_SP_HARDWARE_BASE_2,
2920 EL_SP_HARDWARE_BASE_3,
2921 EL_SP_HARDWARE_BASE_4,
2922 EL_SP_HARDWARE_BASE_5,
2923 EL_SP_HARDWARE_BASE_6,
2925 EL_SP_TERMINAL_ACTIVE,
2928 EL_INVISIBLE_STEELWALL,
2929 EL_INVISIBLE_STEELWALL_ACTIVE,
2931 EL_INVISIBLE_WALL_ACTIVE,
2932 EL_STEELWALL_SLIPPERY,
2949 static int ep_historic_solid[] =
2953 EL_EXPANDABLE_WALL_HORIZONTAL,
2954 EL_EXPANDABLE_WALL_VERTICAL,
2955 EL_EXPANDABLE_WALL_ANY,
2968 EL_QUICKSAND_FILLING,
2969 EL_QUICKSAND_EMPTYING,
2971 EL_MAGIC_WALL_ACTIVE,
2972 EL_MAGIC_WALL_EMPTYING,
2973 EL_MAGIC_WALL_FILLING,
2977 EL_BD_MAGIC_WALL_ACTIVE,
2978 EL_BD_MAGIC_WALL_EMPTYING,
2979 EL_BD_MAGIC_WALL_FULL,
2980 EL_BD_MAGIC_WALL_FILLING,
2981 EL_BD_MAGIC_WALL_DEAD,
2990 EL_SP_TERMINAL_ACTIVE,
2994 EL_INVISIBLE_WALL_ACTIVE,
2995 EL_SWITCHGATE_SWITCH_UP,
2996 EL_SWITCHGATE_SWITCH_DOWN,
2998 EL_TIMEGATE_SWITCH_ACTIVE,
3010 /* the following elements are a direct copy of "indestructible" elements,
3011 except "EL_ACID", which is "indestructible", but not "solid"! */
3016 EL_ACID_POOL_TOPLEFT,
3017 EL_ACID_POOL_TOPRIGHT,
3018 EL_ACID_POOL_BOTTOMLEFT,
3019 EL_ACID_POOL_BOTTOM,
3020 EL_ACID_POOL_BOTTOMRIGHT,
3021 EL_SP_HARDWARE_GRAY,
3022 EL_SP_HARDWARE_GREEN,
3023 EL_SP_HARDWARE_BLUE,
3025 EL_SP_HARDWARE_YELLOW,
3026 EL_SP_HARDWARE_BASE_1,
3027 EL_SP_HARDWARE_BASE_2,
3028 EL_SP_HARDWARE_BASE_3,
3029 EL_SP_HARDWARE_BASE_4,
3030 EL_SP_HARDWARE_BASE_5,
3031 EL_SP_HARDWARE_BASE_6,
3032 EL_INVISIBLE_STEELWALL,
3033 EL_INVISIBLE_STEELWALL_ACTIVE,
3034 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3035 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3036 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3037 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3038 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3039 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3040 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3041 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3042 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3043 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3044 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3045 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3047 EL_LIGHT_SWITCH_ACTIVE,
3048 EL_SIGN_EXCLAMATION,
3049 EL_SIGN_RADIOACTIVITY,
3060 EL_STEELWALL_SLIPPERY,
3074 EL_GATE_1_GRAY_ACTIVE,
3075 EL_GATE_2_GRAY_ACTIVE,
3076 EL_GATE_3_GRAY_ACTIVE,
3077 EL_GATE_4_GRAY_ACTIVE,
3086 EL_EM_GATE_1_GRAY_ACTIVE,
3087 EL_EM_GATE_2_GRAY_ACTIVE,
3088 EL_EM_GATE_3_GRAY_ACTIVE,
3089 EL_EM_GATE_4_GRAY_ACTIVE,
3091 EL_SWITCHGATE_OPENING,
3092 EL_SWITCHGATE_CLOSED,
3093 EL_SWITCHGATE_CLOSING,
3095 EL_TIMEGATE_OPENING,
3097 EL_TIMEGATE_CLOSING,
3101 EL_TUBE_VERTICAL_LEFT,
3102 EL_TUBE_VERTICAL_RIGHT,
3103 EL_TUBE_HORIZONTAL_UP,
3104 EL_TUBE_HORIZONTAL_DOWN,
3113 static int ep_classic_enemy[] =
3130 static int ep_belt[] =
3132 EL_CONVEYOR_BELT_1_LEFT,
3133 EL_CONVEYOR_BELT_1_MIDDLE,
3134 EL_CONVEYOR_BELT_1_RIGHT,
3135 EL_CONVEYOR_BELT_2_LEFT,
3136 EL_CONVEYOR_BELT_2_MIDDLE,
3137 EL_CONVEYOR_BELT_2_RIGHT,
3138 EL_CONVEYOR_BELT_3_LEFT,
3139 EL_CONVEYOR_BELT_3_MIDDLE,
3140 EL_CONVEYOR_BELT_3_RIGHT,
3141 EL_CONVEYOR_BELT_4_LEFT,
3142 EL_CONVEYOR_BELT_4_MIDDLE,
3143 EL_CONVEYOR_BELT_4_RIGHT,
3148 static int ep_belt_active[] =
3150 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3151 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3152 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3153 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3154 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3155 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3156 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3157 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3158 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3159 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3160 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3161 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3166 static int ep_belt_switch[] =
3168 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3169 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3170 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3171 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3172 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3173 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3174 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3175 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3176 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3177 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3178 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3179 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3184 static int ep_tube[] =
3191 EL_TUBE_HORIZONTAL_UP,
3192 EL_TUBE_HORIZONTAL_DOWN,
3194 EL_TUBE_VERTICAL_LEFT,
3195 EL_TUBE_VERTICAL_RIGHT,
3201 static int ep_keygate[] =
3211 EL_GATE_1_GRAY_ACTIVE,
3212 EL_GATE_2_GRAY_ACTIVE,
3213 EL_GATE_3_GRAY_ACTIVE,
3214 EL_GATE_4_GRAY_ACTIVE,
3223 EL_EM_GATE_1_GRAY_ACTIVE,
3224 EL_EM_GATE_2_GRAY_ACTIVE,
3225 EL_EM_GATE_3_GRAY_ACTIVE,
3226 EL_EM_GATE_4_GRAY_ACTIVE,
3235 EL_EMC_GATE_5_GRAY_ACTIVE,
3236 EL_EMC_GATE_6_GRAY_ACTIVE,
3237 EL_EMC_GATE_7_GRAY_ACTIVE,
3238 EL_EMC_GATE_8_GRAY_ACTIVE,
3243 static int ep_amoeboid[] =
3255 static int ep_amoebalive[] =
3266 static int ep_has_editor_content[] =
3288 static int ep_can_turn_each_move[] =
3290 /* !!! do something with this one !!! */
3294 static int ep_can_grow[] =
3308 static int ep_active_bomb[] =
3311 EL_EM_DYNAMITE_ACTIVE,
3312 EL_DYNABOMB_PLAYER_1_ACTIVE,
3313 EL_DYNABOMB_PLAYER_2_ACTIVE,
3314 EL_DYNABOMB_PLAYER_3_ACTIVE,
3315 EL_DYNABOMB_PLAYER_4_ACTIVE,
3316 EL_SP_DISK_RED_ACTIVE,
3321 static int ep_inactive[] =
3353 EL_GATE_1_GRAY_ACTIVE,
3354 EL_GATE_2_GRAY_ACTIVE,
3355 EL_GATE_3_GRAY_ACTIVE,
3356 EL_GATE_4_GRAY_ACTIVE,
3365 EL_EM_GATE_1_GRAY_ACTIVE,
3366 EL_EM_GATE_2_GRAY_ACTIVE,
3367 EL_EM_GATE_3_GRAY_ACTIVE,
3368 EL_EM_GATE_4_GRAY_ACTIVE,
3377 EL_EMC_GATE_5_GRAY_ACTIVE,
3378 EL_EMC_GATE_6_GRAY_ACTIVE,
3379 EL_EMC_GATE_7_GRAY_ACTIVE,
3380 EL_EMC_GATE_8_GRAY_ACTIVE,
3383 EL_INVISIBLE_STEELWALL,
3391 EL_WALL_EMERALD_YELLOW,
3392 EL_DYNABOMB_INCREASE_NUMBER,
3393 EL_DYNABOMB_INCREASE_SIZE,
3394 EL_DYNABOMB_INCREASE_POWER,
3398 EL_SOKOBAN_FIELD_EMPTY,
3399 EL_SOKOBAN_FIELD_FULL,
3400 EL_WALL_EMERALD_RED,
3401 EL_WALL_EMERALD_PURPLE,
3402 EL_ACID_POOL_TOPLEFT,
3403 EL_ACID_POOL_TOPRIGHT,
3404 EL_ACID_POOL_BOTTOMLEFT,
3405 EL_ACID_POOL_BOTTOM,
3406 EL_ACID_POOL_BOTTOMRIGHT,
3410 EL_BD_MAGIC_WALL_DEAD,
3411 EL_AMOEBA_TO_DIAMOND,
3419 EL_SP_GRAVITY_PORT_RIGHT,
3420 EL_SP_GRAVITY_PORT_DOWN,
3421 EL_SP_GRAVITY_PORT_LEFT,
3422 EL_SP_GRAVITY_PORT_UP,
3423 EL_SP_PORT_HORIZONTAL,
3424 EL_SP_PORT_VERTICAL,
3435 EL_SP_HARDWARE_GRAY,
3436 EL_SP_HARDWARE_GREEN,
3437 EL_SP_HARDWARE_BLUE,
3439 EL_SP_HARDWARE_YELLOW,
3440 EL_SP_HARDWARE_BASE_1,
3441 EL_SP_HARDWARE_BASE_2,
3442 EL_SP_HARDWARE_BASE_3,
3443 EL_SP_HARDWARE_BASE_4,
3444 EL_SP_HARDWARE_BASE_5,
3445 EL_SP_HARDWARE_BASE_6,
3446 EL_SP_GRAVITY_ON_PORT_LEFT,
3447 EL_SP_GRAVITY_ON_PORT_RIGHT,
3448 EL_SP_GRAVITY_ON_PORT_UP,
3449 EL_SP_GRAVITY_ON_PORT_DOWN,
3450 EL_SP_GRAVITY_OFF_PORT_LEFT,
3451 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3452 EL_SP_GRAVITY_OFF_PORT_UP,
3453 EL_SP_GRAVITY_OFF_PORT_DOWN,
3454 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3455 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3456 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3457 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3458 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3459 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3460 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3461 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3462 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3463 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3464 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3465 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3466 EL_SIGN_EXCLAMATION,
3467 EL_SIGN_RADIOACTIVITY,
3478 EL_STEELWALL_SLIPPERY,
3483 EL_EMC_WALL_SLIPPERY_1,
3484 EL_EMC_WALL_SLIPPERY_2,
3485 EL_EMC_WALL_SLIPPERY_3,
3486 EL_EMC_WALL_SLIPPERY_4,
3507 static int ep_em_slippery_wall[] =
3512 static int ep_gfx_crumbled[] =
3522 static int ep_editor_cascade_active[] =
3524 EL_INTERNAL_CASCADE_BD_ACTIVE,
3525 EL_INTERNAL_CASCADE_EM_ACTIVE,
3526 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3527 EL_INTERNAL_CASCADE_RND_ACTIVE,
3528 EL_INTERNAL_CASCADE_SB_ACTIVE,
3529 EL_INTERNAL_CASCADE_SP_ACTIVE,
3530 EL_INTERNAL_CASCADE_DC_ACTIVE,
3531 EL_INTERNAL_CASCADE_DX_ACTIVE,
3532 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3533 EL_INTERNAL_CASCADE_CE_ACTIVE,
3534 EL_INTERNAL_CASCADE_GE_ACTIVE,
3535 EL_INTERNAL_CASCADE_USER_ACTIVE,
3536 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3537 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3542 static int ep_editor_cascade_inactive[] =
3544 EL_INTERNAL_CASCADE_BD,
3545 EL_INTERNAL_CASCADE_EM,
3546 EL_INTERNAL_CASCADE_EMC,
3547 EL_INTERNAL_CASCADE_RND,
3548 EL_INTERNAL_CASCADE_SB,
3549 EL_INTERNAL_CASCADE_SP,
3550 EL_INTERNAL_CASCADE_DC,
3551 EL_INTERNAL_CASCADE_DX,
3552 EL_INTERNAL_CASCADE_CHARS,
3553 EL_INTERNAL_CASCADE_CE,
3554 EL_INTERNAL_CASCADE_GE,
3555 EL_INTERNAL_CASCADE_USER,
3556 EL_INTERNAL_CASCADE_GENERIC,
3557 EL_INTERNAL_CASCADE_DYNAMIC,
3562 static int ep_obsolete[] =
3566 EL_EM_KEY_1_FILE_OBSOLETE,
3567 EL_EM_KEY_2_FILE_OBSOLETE,
3568 EL_EM_KEY_3_FILE_OBSOLETE,
3569 EL_EM_KEY_4_FILE_OBSOLETE,
3570 EL_ENVELOPE_OBSOLETE,
3579 } element_properties[] =
3581 { ep_diggable, EP_DIGGABLE },
3582 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3583 { ep_dont_run_into, EP_DONT_RUN_INTO },
3584 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3585 { ep_dont_touch, EP_DONT_TOUCH },
3586 { ep_indestructible, EP_INDESTRUCTIBLE },
3587 { ep_slippery, EP_SLIPPERY },
3588 { ep_can_change, EP_CAN_CHANGE },
3589 { ep_can_move, EP_CAN_MOVE },
3590 { ep_can_fall, EP_CAN_FALL },
3591 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3592 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3593 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3594 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3595 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3596 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3597 { ep_walkable_over, EP_WALKABLE_OVER },
3598 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3599 { ep_walkable_under, EP_WALKABLE_UNDER },
3600 { ep_passable_over, EP_PASSABLE_OVER },
3601 { ep_passable_inside, EP_PASSABLE_INSIDE },
3602 { ep_passable_under, EP_PASSABLE_UNDER },
3603 { ep_droppable, EP_DROPPABLE },
3604 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3605 { ep_pushable, EP_PUSHABLE },
3606 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3607 { ep_protected, EP_PROTECTED },
3608 { ep_throwable, EP_THROWABLE },
3609 { ep_can_explode, EP_CAN_EXPLODE },
3610 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3612 { ep_player, EP_PLAYER },
3613 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3614 { ep_switchable, EP_SWITCHABLE },
3615 { ep_bd_element, EP_BD_ELEMENT },
3616 { ep_sp_element, EP_SP_ELEMENT },
3617 { ep_sb_element, EP_SB_ELEMENT },
3619 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3620 { ep_food_penguin, EP_FOOD_PENGUIN },
3621 { ep_food_pig, EP_FOOD_PIG },
3622 { ep_historic_wall, EP_HISTORIC_WALL },
3623 { ep_historic_solid, EP_HISTORIC_SOLID },
3624 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3625 { ep_belt, EP_BELT },
3626 { ep_belt_active, EP_BELT_ACTIVE },
3627 { ep_belt_switch, EP_BELT_SWITCH },
3628 { ep_tube, EP_TUBE },
3629 { ep_keygate, EP_KEYGATE },
3630 { ep_amoeboid, EP_AMOEBOID },
3631 { ep_amoebalive, EP_AMOEBALIVE },
3632 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3633 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3634 { ep_can_grow, EP_CAN_GROW },
3635 { ep_active_bomb, EP_ACTIVE_BOMB },
3636 { ep_inactive, EP_INACTIVE },
3638 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3640 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3642 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3643 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3645 { ep_obsolete, EP_OBSOLETE },
3652 /* always start with reliable default values (element has no properties) */
3653 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3654 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3655 SET_PROPERTY(i, j, FALSE);
3657 /* set all base element properties from above array definitions */
3658 for (i = 0; element_properties[i].elements != NULL; i++)
3659 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3660 SET_PROPERTY((element_properties[i].elements)[j],
3661 element_properties[i].property, TRUE);
3663 /* copy properties to some elements that are only stored in level file */
3664 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3665 for (j = 0; copy_properties[j][0] != -1; j++)
3666 if (HAS_PROPERTY(copy_properties[j][0], i))
3667 for (k = 1; k <= 4; k++)
3668 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3671 void InitElementPropertiesEngine(int engine_version)
3673 static int no_wall_properties[] =
3676 EP_COLLECTIBLE_ONLY,
3678 EP_DONT_COLLIDE_WITH,
3681 EP_CAN_SMASH_PLAYER,
3682 EP_CAN_SMASH_ENEMIES,
3683 EP_CAN_SMASH_EVERYTHING,
3688 EP_FOOD_DARK_YAMYAM,
3704 /* important: after initialization in InitElementPropertiesStatic(), the
3705 elements are not again initialized to a default value; therefore all
3706 changes have to make sure that they leave the element with a defined
3707 property (which means that conditional property changes must be set to
3708 a reliable default value before) */
3711 /* ---------- recursively resolve group elements ------------------------- */
3713 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3714 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3715 element_info[i].in_group[j] = FALSE;
3717 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3718 resolve_group_element(EL_GROUP_START + i, 0);
3721 /* set all special, combined or engine dependent element properties */
3722 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3724 /* ---------- INACTIVE ------------------------------------------------- */
3725 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3727 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3728 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3729 IS_WALKABLE_INSIDE(i) ||
3730 IS_WALKABLE_UNDER(i)));
3732 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3733 IS_PASSABLE_INSIDE(i) ||
3734 IS_PASSABLE_UNDER(i)));
3736 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3737 IS_PASSABLE_OVER(i)));
3739 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3740 IS_PASSABLE_INSIDE(i)));
3742 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3743 IS_PASSABLE_UNDER(i)));
3745 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3748 /* ---------- COLLECTIBLE ---------------------------------------------- */
3749 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3753 /* ---------- SNAPPABLE ------------------------------------------------ */
3754 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3755 IS_COLLECTIBLE(i) ||
3759 /* ---------- WALL ----------------------------------------------------- */
3760 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3762 for (j = 0; no_wall_properties[j] != -1; j++)
3763 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3764 i >= EL_FIRST_RUNTIME_UNREAL)
3765 SET_PROPERTY(i, EP_WALL, FALSE);
3767 if (IS_HISTORIC_WALL(i))
3768 SET_PROPERTY(i, EP_WALL, TRUE);
3770 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3771 if (engine_version < VERSION_IDENT(2,2,0,0))
3772 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3774 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3776 !IS_COLLECTIBLE(i)));
3778 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3780 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3781 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3783 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3784 IS_INDESTRUCTIBLE(i)));
3786 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3788 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3789 else if (engine_version < VERSION_IDENT(2,2,0,0))
3790 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3792 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3796 if (IS_CUSTOM_ELEMENT(i))
3798 /* these are additional properties which are initially false when set */
3800 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3802 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3803 if (DONT_COLLIDE_WITH(i))
3804 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3806 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3807 if (CAN_SMASH_EVERYTHING(i))
3808 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3809 if (CAN_SMASH_ENEMIES(i))
3810 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3813 /* ---------- CAN_SMASH ------------------------------------------------ */
3814 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3815 CAN_SMASH_ENEMIES(i) ||
3816 CAN_SMASH_EVERYTHING(i)));
3818 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3819 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3820 EXPLODES_BY_FIRE(i)));
3822 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3823 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3824 EXPLODES_SMASHED(i)));
3826 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3827 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3828 EXPLODES_IMPACT(i)));
3830 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3831 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3833 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3834 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3835 i == EL_BLACK_ORB));
3837 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3838 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3840 IS_CUSTOM_ELEMENT(i)));
3842 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3843 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3844 i == EL_SP_ELECTRON));
3846 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3847 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3848 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3849 getMoveIntoAcidProperty(&level, i));
3851 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3852 if (MAYBE_DONT_COLLIDE_WITH(i))
3853 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3854 getDontCollideWithProperty(&level, i));
3856 /* ---------- SP_PORT -------------------------------------------------- */
3857 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3858 IS_PASSABLE_INSIDE(i)));
3860 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3861 for (j = 0; j < level.num_android_clone_elements; j++)
3862 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3864 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3866 /* ---------- CAN_CHANGE ----------------------------------------------- */
3867 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3868 for (j = 0; j < element_info[i].num_change_pages; j++)
3869 if (element_info[i].change_page[j].can_change)
3870 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3872 /* ---------- HAS_ACTION ----------------------------------------------- */
3873 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3874 for (j = 0; j < element_info[i].num_change_pages; j++)
3875 if (element_info[i].change_page[j].has_action)
3876 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3878 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3879 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3882 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3884 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3885 element_info[i].crumbled[ACTION_DEFAULT] !=
3886 element_info[i].graphic[ACTION_DEFAULT]);
3888 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3889 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3890 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3893 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3894 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3895 IS_EDITOR_CASCADE_INACTIVE(i)));
3898 /* dynamically adjust element properties according to game engine version */
3900 static int ep_em_slippery_wall[] =
3905 EL_EXPANDABLE_WALL_HORIZONTAL,
3906 EL_EXPANDABLE_WALL_VERTICAL,
3907 EL_EXPANDABLE_WALL_ANY,
3911 /* special EM style gems behaviour */
3912 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3913 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3914 level.em_slippery_gems);
3916 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3917 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3918 (level.em_slippery_gems &&
3919 engine_version > VERSION_IDENT(2,0,1,0)));
3922 /* set default push delay values (corrected since version 3.0.7-1) */
3923 if (engine_version < VERSION_IDENT(3,0,7,1))
3925 game.default_push_delay_fixed = 2;
3926 game.default_push_delay_random = 8;
3930 game.default_push_delay_fixed = 8;
3931 game.default_push_delay_random = 8;
3934 /* set uninitialized push delay values of custom elements in older levels */
3935 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3937 int element = EL_CUSTOM_START + i;
3939 if (element_info[element].push_delay_fixed == -1)
3940 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3941 if (element_info[element].push_delay_random == -1)
3942 element_info[element].push_delay_random = game.default_push_delay_random;
3945 /* set some other uninitialized values of custom elements in older levels */
3946 if (engine_version < VERSION_IDENT(3,1,0,0))
3948 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3950 int element = EL_CUSTOM_START + i;
3952 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3954 element_info[element].explosion_delay = 17;
3955 element_info[element].ignition_delay = 8;
3960 /* set element properties that were handled incorrectly in older levels */
3961 if (engine_version < VERSION_IDENT(3,1,0,0))
3963 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3964 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3968 /* this is needed because some graphics depend on element properties */
3969 if (game_status == GAME_MODE_PLAYING)
3970 InitElementGraphicInfo();
3973 static void InitGlobal()
3977 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3979 /* check if element_name_info entry defined for each element in "main.h" */
3980 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3981 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3983 element_info[i].token_name = element_name_info[i].token_name;
3984 element_info[i].class_name = element_name_info[i].class_name;
3985 element_info[i].editor_description=element_name_info[i].editor_description;
3988 global.autoplay_leveldir = NULL;
3989 global.convert_leveldir = NULL;
3991 global.frames_per_second = 0;
3992 global.fps_slowdown = FALSE;
3993 global.fps_slowdown_factor = 1;
3996 void Execute_Command(char *command)
4000 if (strEqual(command, "print graphicsinfo.conf"))
4002 printf("# You can configure additional/alternative image files here.\n");
4003 printf("# (The entries below are default and therefore commented out.)\n");
4005 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4007 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4010 for (i = 0; image_config[i].token != NULL; i++)
4011 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4012 image_config[i].value));
4016 else if (strEqual(command, "print soundsinfo.conf"))
4018 printf("# You can configure additional/alternative sound files here.\n");
4019 printf("# (The entries below are default and therefore commented out.)\n");
4021 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4023 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4026 for (i = 0; sound_config[i].token != NULL; i++)
4027 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4028 sound_config[i].value));
4032 else if (strEqual(command, "print musicinfo.conf"))
4034 printf("# You can configure additional/alternative music files here.\n");
4035 printf("# (The entries below are default and therefore commented out.)\n");
4037 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4039 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4042 for (i = 0; music_config[i].token != NULL; i++)
4043 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4044 music_config[i].value));
4048 else if (strEqual(command, "print editorsetup.conf"))
4050 printf("# You can configure your personal editor element list here.\n");
4051 printf("# (The entries below are default and therefore commented out.)\n");
4054 /* this is needed to be able to check element list for cascade elements */
4055 InitElementPropertiesStatic();
4056 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4058 PrintEditorElementList();
4062 else if (strEqual(command, "print helpanim.conf"))
4064 printf("# You can configure different element help animations here.\n");
4065 printf("# (The entries below are default and therefore commented out.)\n");
4068 for (i = 0; helpanim_config[i].token != NULL; i++)
4070 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4071 helpanim_config[i].value));
4073 if (strEqual(helpanim_config[i].token, "end"))
4079 else if (strEqual(command, "print helptext.conf"))
4081 printf("# You can configure different element help text here.\n");
4082 printf("# (The entries below are default and therefore commented out.)\n");
4085 for (i = 0; helptext_config[i].token != NULL; i++)
4086 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4087 helptext_config[i].value));
4091 else if (strncmp(command, "dump level ", 11) == 0)
4093 char *filename = &command[11];
4095 if (!fileExists(filename))
4096 Error(ERR_EXIT, "cannot open file '%s'", filename);
4098 LoadLevelFromFilename(&level, filename);
4103 else if (strncmp(command, "dump tape ", 10) == 0)
4105 char *filename = &command[10];
4107 if (!fileExists(filename))
4108 Error(ERR_EXIT, "cannot open file '%s'", filename);
4110 LoadTapeFromFilename(filename);
4115 else if (strncmp(command, "autoplay ", 9) == 0)
4117 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4119 while (*str_ptr != '\0') /* continue parsing string */
4121 /* cut leading whitespace from string, replace it by string terminator */
4122 while (*str_ptr == ' ' || *str_ptr == '\t')
4125 if (*str_ptr == '\0') /* end of string reached */
4128 if (global.autoplay_leveldir == NULL) /* read level set string */
4130 global.autoplay_leveldir = str_ptr;
4131 global.autoplay_all = TRUE; /* default: play all tapes */
4133 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4134 global.autoplay_level[i] = FALSE;
4136 else /* read level number string */
4138 int level_nr = atoi(str_ptr); /* get level_nr value */
4140 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4141 global.autoplay_level[level_nr] = TRUE;
4143 global.autoplay_all = FALSE;
4146 /* advance string pointer to the next whitespace (or end of string) */
4147 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4151 else if (strncmp(command, "convert ", 8) == 0)
4153 char *str_copy = getStringCopy(&command[8]);
4154 char *str_ptr = strchr(str_copy, ' ');
4156 global.convert_leveldir = str_copy;
4157 global.convert_level_nr = -1;
4159 if (str_ptr != NULL) /* level number follows */
4161 *str_ptr++ = '\0'; /* terminate leveldir string */
4162 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4167 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4171 static void InitSetup()
4173 LoadSetup(); /* global setup info */
4175 /* set some options from setup file */
4177 if (setup.options.verbose)
4178 options.verbose = TRUE;
4181 static void InitGameInfo()
4183 game.restart_level = FALSE;
4186 static void InitPlayerInfo()
4190 /* choose default local player */
4191 local_player = &stored_player[0];
4193 for (i = 0; i < MAX_PLAYERS; i++)
4194 stored_player[i].connected = FALSE;
4196 local_player->connected = TRUE;
4199 static void InitArtworkInfo()
4204 static char *get_string_in_brackets(char *string)
4206 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4208 sprintf(string_in_brackets, "[%s]", string);
4210 return string_in_brackets;
4213 static char *get_level_id_suffix(int id_nr)
4215 char *id_suffix = checked_malloc(1 + 3 + 1);
4217 if (id_nr < 0 || id_nr > 999)
4220 sprintf(id_suffix, ".%03d", id_nr);
4226 static char *get_element_class_token(int element)
4228 char *element_class_name = element_info[element].class_name;
4229 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4231 sprintf(element_class_token, "[%s]", element_class_name);
4233 return element_class_token;
4236 static char *get_action_class_token(int action)
4238 char *action_class_name = &element_action_info[action].suffix[1];
4239 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4241 sprintf(action_class_token, "[%s]", action_class_name);
4243 return action_class_token;
4247 static void InitArtworkConfig()
4249 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4250 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4251 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4252 static char *action_id_suffix[NUM_ACTIONS + 1];
4253 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4254 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4255 static char *level_id_suffix[MAX_LEVELS + 1];
4256 static char *dummy[1] = { NULL };
4257 static char *ignore_generic_tokens[] =
4263 static char **ignore_image_tokens;
4264 static char **ignore_sound_tokens;
4265 static char **ignore_music_tokens;
4266 int num_ignore_generic_tokens;
4267 int num_ignore_image_tokens;
4268 int num_ignore_sound_tokens;
4269 int num_ignore_music_tokens;
4272 /* dynamically determine list of generic tokens to be ignored */
4273 num_ignore_generic_tokens = 0;
4274 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4275 num_ignore_generic_tokens++;
4277 /* dynamically determine list of image tokens to be ignored */
4278 num_ignore_image_tokens = num_ignore_generic_tokens;
4279 for (i = 0; image_config_vars[i].token != NULL; i++)
4280 num_ignore_image_tokens++;
4281 ignore_image_tokens =
4282 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4283 for (i = 0; i < num_ignore_generic_tokens; i++)
4284 ignore_image_tokens[i] = ignore_generic_tokens[i];
4285 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4286 ignore_image_tokens[num_ignore_generic_tokens + i] =
4287 image_config_vars[i].token;
4288 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4290 /* dynamically determine list of sound tokens to be ignored */
4291 num_ignore_sound_tokens = num_ignore_generic_tokens;
4292 ignore_sound_tokens =
4293 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4294 for (i = 0; i < num_ignore_generic_tokens; i++)
4295 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4296 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4298 /* dynamically determine list of music tokens to be ignored */
4299 num_ignore_music_tokens = num_ignore_generic_tokens;
4300 ignore_music_tokens =
4301 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4302 for (i = 0; i < num_ignore_generic_tokens; i++)
4303 ignore_music_tokens[i] = ignore_generic_tokens[i];
4304 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4306 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4307 image_id_prefix[i] = element_info[i].token_name;
4308 for (i = 0; i < NUM_FONTS; i++)
4309 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4310 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4312 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4313 sound_id_prefix[i] = element_info[i].token_name;
4314 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4315 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4316 get_string_in_brackets(element_info[i].class_name);
4317 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4319 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4320 music_id_prefix[i] = music_prefix_info[i].prefix;
4321 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4323 for (i = 0; i < NUM_ACTIONS; i++)
4324 action_id_suffix[i] = element_action_info[i].suffix;
4325 action_id_suffix[NUM_ACTIONS] = NULL;
4327 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4328 direction_id_suffix[i] = element_direction_info[i].suffix;
4329 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4331 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4332 special_id_suffix[i] = special_suffix_info[i].suffix;
4333 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4335 for (i = 0; i < MAX_LEVELS; i++)
4336 level_id_suffix[i] = get_level_id_suffix(i);
4337 level_id_suffix[MAX_LEVELS] = NULL;
4339 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4340 image_id_prefix, action_id_suffix, direction_id_suffix,
4341 special_id_suffix, ignore_image_tokens);
4342 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4343 sound_id_prefix, action_id_suffix, dummy,
4344 special_id_suffix, ignore_sound_tokens);
4345 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4346 music_id_prefix, special_id_suffix, level_id_suffix,
4347 dummy, ignore_music_tokens);
4350 static void InitMixer()
4358 char *filename_font_initial = NULL;
4359 Bitmap *bitmap_font_initial = NULL;
4362 /* determine settings for initial font (for displaying startup messages) */
4363 for (i = 0; image_config[i].token != NULL; i++)
4365 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4367 char font_token[128];
4370 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4371 len_font_token = strlen(font_token);
4373 if (strEqual(image_config[i].token, font_token))
4374 filename_font_initial = image_config[i].value;
4375 else if (strlen(image_config[i].token) > len_font_token &&
4376 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4378 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4379 font_initial[j].src_x = atoi(image_config[i].value);
4380 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4381 font_initial[j].src_y = atoi(image_config[i].value);
4382 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4383 font_initial[j].width = atoi(image_config[i].value);
4384 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4385 font_initial[j].height = atoi(image_config[i].value);
4390 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4392 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4393 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4396 if (filename_font_initial == NULL) /* should not happen */
4397 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4399 /* create additional image buffers for double-buffering and cross-fading */
4400 bitmap_db_title = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4401 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4402 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4404 /* initialize screen properties */
4405 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4406 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4408 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4409 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4410 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4412 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4414 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4415 font_initial[j].bitmap = bitmap_font_initial;
4417 InitFontGraphicInfo();
4419 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4420 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4422 DrawInitText("Loading graphics:", 120, FC_GREEN);
4425 void RedrawBackground()
4427 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4428 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4430 redraw_mask = REDRAW_ALL;
4433 void InitGfxBackground()
4437 drawto = backbuffer;
4438 fieldbuffer = bitmap_db_field;
4439 SetDrawtoField(DRAW_BACKBUFFER);
4443 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4444 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4446 for (x = 0; x < MAX_BUF_XSIZE; x++)
4447 for (y = 0; y < MAX_BUF_YSIZE; y++)
4450 redraw_mask = REDRAW_ALL;
4453 static void InitLevelInfo()
4455 LoadLevelInfo(); /* global level info */
4456 LoadLevelSetup_LastSeries(); /* last played series info */
4457 LoadLevelSetup_SeriesInfo(); /* last played level info */
4460 void InitLevelArtworkInfo()
4462 LoadLevelArtworkInfo();
4465 static void InitImages()
4467 setLevelArtworkDir(artwork.gfx_first);
4470 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4471 leveldir_current->identifier,
4472 artwork.gfx_current_identifier,
4473 artwork.gfx_current->identifier,
4474 leveldir_current->graphics_set,
4475 leveldir_current->graphics_path);
4478 ReloadCustomImages();
4480 LoadCustomElementDescriptions();
4481 LoadSpecialMenuDesignSettings();
4483 ReinitializeGraphics();
4486 static void InitSound(char *identifier)
4488 if (identifier == NULL)
4489 identifier = artwork.snd_current->identifier;
4491 /* set artwork path to send it to the sound server process */
4492 setLevelArtworkDir(artwork.snd_first);
4494 InitReloadCustomSounds(identifier);
4495 ReinitializeSounds();
4498 static void InitMusic(char *identifier)
4500 if (identifier == NULL)
4501 identifier = artwork.mus_current->identifier;
4503 /* set artwork path to send it to the sound server process */
4504 setLevelArtworkDir(artwork.mus_first);
4506 InitReloadCustomMusic(identifier);
4507 ReinitializeMusic();
4510 void InitNetworkServer()
4512 #if defined(NETWORK_AVALIABLE)
4516 if (!options.network)
4519 #if defined(NETWORK_AVALIABLE)
4520 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4522 if (!ConnectToServer(options.server_host, options.server_port))
4523 Error(ERR_EXIT, "cannot connect to network game server");
4525 SendToServer_PlayerName(setup.player_name);
4526 SendToServer_ProtocolVersion();
4529 SendToServer_NrWanted(nr_wanted);
4533 static char *getNewArtworkIdentifier(int type)
4535 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4536 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4537 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4538 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4539 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4540 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4541 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4542 char *leveldir_identifier = leveldir_current->identifier;
4544 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4545 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4547 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4549 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4550 char *artwork_current_identifier;
4551 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4553 /* leveldir_current may be invalid (level group, parent link) */
4554 if (!validLevelSeries(leveldir_current))
4557 /* 1st step: determine artwork set to be activated in descending order:
4558 --------------------------------------------------------------------
4559 1. setup artwork (when configured to override everything else)
4560 2. artwork set configured in "levelinfo.conf" of current level set
4561 (artwork in level directory will have priority when loading later)
4562 3. artwork in level directory (stored in artwork sub-directory)
4563 4. setup artwork (currently configured in setup menu) */
4565 if (setup_override_artwork)
4566 artwork_current_identifier = setup_artwork_set;
4567 else if (leveldir_artwork_set != NULL)
4568 artwork_current_identifier = leveldir_artwork_set;
4569 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4570 artwork_current_identifier = leveldir_identifier;
4572 artwork_current_identifier = setup_artwork_set;
4575 /* 2nd step: check if it is really needed to reload artwork set
4576 ------------------------------------------------------------ */
4579 if (type == ARTWORK_TYPE_GRAPHICS)
4580 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4581 artwork_new_identifier,
4582 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4583 artwork_current_identifier,
4584 leveldir_current->graphics_set,
4585 leveldir_current->identifier);
4588 /* ---------- reload if level set and also artwork set has changed ------- */
4589 if (leveldir_current_identifier[type] != leveldir_identifier &&
4590 (last_has_level_artwork_set[type] || has_level_artwork_set))
4591 artwork_new_identifier = artwork_current_identifier;
4593 leveldir_current_identifier[type] = leveldir_identifier;
4594 last_has_level_artwork_set[type] = has_level_artwork_set;
4597 if (type == ARTWORK_TYPE_GRAPHICS)
4598 printf("::: 1: '%s'\n", artwork_new_identifier);
4601 /* ---------- reload if "override artwork" setting has changed ----------- */
4602 if (last_override_level_artwork[type] != setup_override_artwork)
4603 artwork_new_identifier = artwork_current_identifier;
4605 last_override_level_artwork[type] = setup_override_artwork;
4608 if (type == ARTWORK_TYPE_GRAPHICS)
4609 printf("::: 2: '%s'\n", artwork_new_identifier);
4612 /* ---------- reload if current artwork identifier has changed ----------- */
4613 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4614 artwork_current_identifier))
4615 artwork_new_identifier = artwork_current_identifier;
4617 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4620 if (type == ARTWORK_TYPE_GRAPHICS)
4621 printf("::: 3: '%s'\n", artwork_new_identifier);
4624 /* ---------- do not reload directly after starting ---------------------- */
4625 if (!initialized[type])
4626 artwork_new_identifier = NULL;
4628 initialized[type] = TRUE;
4631 if (type == ARTWORK_TYPE_GRAPHICS)
4632 printf("::: 4: '%s'\n", artwork_new_identifier);
4636 if (type == ARTWORK_TYPE_GRAPHICS)
4637 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4638 artwork.gfx_current_identifier, artwork_current_identifier,
4639 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4640 artwork_new_identifier);
4643 return artwork_new_identifier;
4646 void ReloadCustomArtwork(int force_reload)
4648 char *gfx_new_identifier;
4649 char *snd_new_identifier;
4650 char *mus_new_identifier;
4651 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4652 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4653 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4654 boolean redraw_screen = FALSE;
4656 force_reload_gfx |= AdjustGraphicsForEMC();
4658 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4659 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4660 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4662 if (gfx_new_identifier != NULL || force_reload_gfx)
4665 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4666 artwork.gfx_current_identifier,
4668 artwork.gfx_current->identifier,
4669 leveldir_current->graphics_set);
4672 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4676 redraw_screen = TRUE;
4679 if (snd_new_identifier != NULL || force_reload_snd)
4681 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4683 InitSound(snd_new_identifier);
4685 redraw_screen = TRUE;
4688 if (mus_new_identifier != NULL || force_reload_mus)
4690 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4692 InitMusic(mus_new_identifier);
4694 redraw_screen = TRUE;
4702 InitGfxBackground();
4705 /* force redraw of (open or closed) door graphics */
4706 SetDoorState(DOOR_OPEN_ALL);
4707 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4711 void KeyboardAutoRepeatOffUnlessAutoplay()
4713 if (global.autoplay_leveldir == NULL)
4714 KeyboardAutoRepeatOff();
4718 /* ========================================================================= */
4720 /* ========================================================================= */
4724 InitGlobal(); /* initialize some global variables */
4726 if (options.execute_command)
4727 Execute_Command(options.execute_command);
4729 if (options.serveronly)
4731 #if defined(PLATFORM_UNIX)
4732 NetworkServer(options.server_port, options.serveronly);
4734 Error(ERR_WARN, "networking only supported in Unix version");
4737 exit(0); /* never reached, server loops forever */
4744 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4745 InitArtworkConfig(); /* needed before forking sound child process */
4750 InitRND(NEW_RANDOMIZE);
4751 InitSimpleRND(NEW_RANDOMIZE);
4756 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4759 InitEventFilter(FilterMouseMotionEvents);
4761 InitElementPropertiesStatic();
4762 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4767 InitLevelArtworkInfo();
4769 InitImages(); /* needs to know current level directory */
4770 InitSound(NULL); /* needs to know current level directory */
4771 InitMusic(NULL); /* needs to know current level directory */
4773 InitGfxBackground();
4775 if (global.autoplay_leveldir)
4780 else if (global.convert_leveldir)
4786 game_status = GAME_MODE_MAIN;
4794 InitNetworkServer();
4797 void CloseAllAndExit(int exit_value)
4802 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4810 #if defined(TARGET_SDL)
4811 if (network_server) /* terminate network server */
4812 SDL_KillThread(server_thread);
4815 CloseVideoDisplay();
4816 ClosePlatformDependentStuff();