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 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1022 graphic_info[graphic].anim_frames = 1;
1024 graphic_info[graphic].anim_frames_per_line =
1025 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1026 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1028 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1029 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1030 graphic_info[graphic].anim_delay = 1;
1032 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1034 if (graphic_info[graphic].anim_frames == 1)
1035 graphic_info[graphic].anim_mode = ANIM_NONE;
1038 /* automatically determine correct start frame, if not defined */
1039 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1040 graphic_info[graphic].anim_start_frame = 0;
1041 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1042 graphic_info[graphic].anim_start_frame =
1043 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1045 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1047 /* animation synchronized with global frame counter, not move position */
1048 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1050 /* optional element for cloning crumble graphics */
1051 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1054 /* optional element for cloning digging graphics */
1055 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1056 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1058 /* optional border size for "crumbling" diggable graphics */
1059 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1060 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1062 /* this is only used for player "boring" and "sleeping" actions */
1063 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].anim_delay_fixed =
1065 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1066 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1067 graphic_info[graphic].anim_delay_random =
1068 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1069 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1070 graphic_info[graphic].post_delay_fixed =
1071 parameter[GFX_ARG_POST_DELAY_FIXED];
1072 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].post_delay_random =
1074 parameter[GFX_ARG_POST_DELAY_RANDOM];
1076 /* this is only used for toon animations */
1077 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1078 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1080 /* this is only used for drawing font characters */
1081 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1082 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1084 /* this is only used for drawing envelope graphics */
1085 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1087 /* optional graphic for cloning all graphics settings */
1088 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1089 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1092 static void set_cloned_graphic_parameters(int graphic)
1094 int fallback_graphic = IMG_CHAR_EXCLAM;
1095 int max_num_images = getImageListSize();
1096 int clone_graphic = graphic_info[graphic].clone_from;
1097 int num_references_followed = 1;
1099 while (graphic_info[clone_graphic].clone_from != -1 &&
1100 num_references_followed < max_num_images)
1102 clone_graphic = graphic_info[clone_graphic].clone_from;
1104 num_references_followed++;
1107 if (num_references_followed >= max_num_images)
1109 Error(ERR_RETURN_LINE, "-");
1110 Error(ERR_RETURN, "warning: error found in config file:");
1111 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1112 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1113 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1114 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1116 if (graphic == fallback_graphic)
1117 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1119 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1120 Error(ERR_RETURN_LINE, "-");
1122 graphic_info[graphic] = graphic_info[fallback_graphic];
1126 graphic_info[graphic] = graphic_info[clone_graphic];
1127 graphic_info[graphic].clone_from = clone_graphic;
1131 static void InitGraphicInfo()
1133 int fallback_graphic = IMG_CHAR_EXCLAM;
1134 int num_images = getImageListSize();
1137 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1138 static boolean clipmasks_initialized = FALSE;
1140 XGCValues clip_gc_values;
1141 unsigned long clip_gc_valuemask;
1142 GC copy_clipmask_gc = None;
1145 checked_free(graphic_info);
1147 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1149 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1150 if (clipmasks_initialized)
1152 for (i = 0; i < num_images; i++)
1154 if (graphic_info[i].clip_mask)
1155 XFreePixmap(display, graphic_info[i].clip_mask);
1156 if (graphic_info[i].clip_gc)
1157 XFreeGC(display, graphic_info[i].clip_gc);
1159 graphic_info[i].clip_mask = None;
1160 graphic_info[i].clip_gc = None;
1165 /* first set all graphic paramaters ... */
1166 for (i = 0; i < num_images; i++)
1167 set_graphic_parameters(i);
1169 /* ... then copy these parameters for cloned graphics */
1170 for (i = 0; i < num_images; i++)
1171 if (graphic_info[i].clone_from != -1)
1172 set_cloned_graphic_parameters(i);
1174 for (i = 0; i < num_images; i++)
1178 int first_frame, last_frame;
1179 int src_bitmap_width, src_bitmap_height;
1181 /* now check if no animation frames are outside of the loaded image */
1183 if (graphic_info[i].bitmap == NULL)
1184 continue; /* skip check for optional images that are undefined */
1186 /* get final bitmap size (with scaling, but without small images) */
1187 src_bitmap_width = graphic_info[i].src_image_width;
1188 src_bitmap_height = graphic_info[i].src_image_height;
1190 /* check if first animation frame is inside specified bitmap */
1193 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1195 if (src_x < 0 || src_y < 0 ||
1196 src_x + TILEX > src_bitmap_width ||
1197 src_y + TILEY > src_bitmap_height)
1199 Error(ERR_RETURN_LINE, "-");
1200 Error(ERR_RETURN, "warning: error found in config file:");
1201 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1202 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1203 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1205 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1206 src_x, src_y, src_bitmap_width, src_bitmap_height);
1207 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1209 if (i == fallback_graphic)
1210 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1212 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1213 Error(ERR_RETURN_LINE, "-");
1215 graphic_info[i] = graphic_info[fallback_graphic];
1218 /* check if last animation frame is inside specified bitmap */
1220 last_frame = graphic_info[i].anim_frames - 1;
1221 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1223 if (src_x < 0 || src_y < 0 ||
1224 src_x + TILEX > src_bitmap_width ||
1225 src_y + TILEY > src_bitmap_height)
1227 Error(ERR_RETURN_LINE, "-");
1228 Error(ERR_RETURN, "warning: error found in config file:");
1229 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1230 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1231 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1233 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1234 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1235 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1237 if (i == fallback_graphic)
1238 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1240 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1241 Error(ERR_RETURN_LINE, "-");
1243 graphic_info[i] = graphic_info[fallback_graphic];
1246 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1247 /* currently we only need a tile clip mask from the first frame */
1248 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1250 if (copy_clipmask_gc == None)
1252 clip_gc_values.graphics_exposures = False;
1253 clip_gc_valuemask = GCGraphicsExposures;
1254 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1255 clip_gc_valuemask, &clip_gc_values);
1258 graphic_info[i].clip_mask =
1259 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1261 src_pixmap = src_bitmap->clip_mask;
1262 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1263 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1265 clip_gc_values.graphics_exposures = False;
1266 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1267 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1269 graphic_info[i].clip_gc =
1270 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1274 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1275 if (copy_clipmask_gc)
1276 XFreeGC(display, copy_clipmask_gc);
1278 clipmasks_initialized = TRUE;
1282 static void InitElementSoundInfo()
1284 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1285 int num_property_mappings = getSoundListPropertyMappingSize();
1288 /* set values to -1 to identify later as "uninitialized" values */
1289 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1290 for (act = 0; act < NUM_ACTIONS; act++)
1291 element_info[i].sound[act] = -1;
1293 /* initialize element/sound mapping from static configuration */
1294 for (i = 0; element_to_sound[i].element > -1; i++)
1296 int element = element_to_sound[i].element;
1297 int action = element_to_sound[i].action;
1298 int sound = element_to_sound[i].sound;
1299 boolean is_class = element_to_sound[i].is_class;
1302 action = ACTION_DEFAULT;
1305 element_info[element].sound[action] = sound;
1307 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1308 if (strEqual(element_info[j].class_name,
1309 element_info[element].class_name))
1310 element_info[j].sound[action] = sound;
1313 /* initialize element class/sound mapping from dynamic configuration */
1314 for (i = 0; i < num_property_mappings; i++)
1316 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1317 int action = property_mapping[i].ext1_index;
1318 int sound = property_mapping[i].artwork_index;
1320 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1324 action = ACTION_DEFAULT;
1326 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1327 if (strEqual(element_info[j].class_name,
1328 element_info[element_class].class_name))
1329 element_info[j].sound[action] = sound;
1332 /* initialize element/sound mapping from dynamic configuration */
1333 for (i = 0; i < num_property_mappings; i++)
1335 int element = property_mapping[i].base_index;
1336 int action = property_mapping[i].ext1_index;
1337 int sound = property_mapping[i].artwork_index;
1339 if (element >= MAX_NUM_ELEMENTS)
1343 action = ACTION_DEFAULT;
1345 element_info[element].sound[action] = sound;
1348 /* now set all '-1' values to element specific default values */
1349 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1351 for (act = 0; act < NUM_ACTIONS; act++)
1353 /* generic default action sound (defined by "[default]" directive) */
1354 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1356 /* look for special default action sound (classic game specific) */
1357 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1358 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1359 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1360 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1361 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1362 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1364 /* !!! there's no such thing as a "default action sound" !!! */
1366 /* look for element specific default sound (independent from action) */
1367 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1368 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1372 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1373 /* !!! make this better !!! */
1374 if (i == EL_EMPTY_SPACE)
1375 default_action_sound = element_info[EL_DEFAULT].sound[act];
1378 /* no sound for this specific action -- use default action sound */
1379 if (element_info[i].sound[act] == -1)
1380 element_info[i].sound[act] = default_action_sound;
1384 /* copy sound settings to some elements that are only stored in level file
1385 in native R'n'D levels, but are used by game engine in native EM levels */
1386 for (i = 0; copy_properties[i][0] != -1; i++)
1387 for (j = 1; j <= 4; j++)
1388 for (act = 0; act < NUM_ACTIONS; act++)
1389 element_info[copy_properties[i][j]].sound[act] =
1390 element_info[copy_properties[i][0]].sound[act];
1393 static void InitGameModeSoundInfo()
1397 /* set values to -1 to identify later as "uninitialized" values */
1398 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1401 /* initialize gamemode/sound mapping from static configuration */
1402 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1404 int gamemode = gamemode_to_sound[i].gamemode;
1405 int sound = gamemode_to_sound[i].sound;
1408 gamemode = GAME_MODE_DEFAULT;
1410 menu.sound[gamemode] = sound;
1413 /* now set all '-1' values to levelset specific default values */
1414 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1415 if (menu.sound[i] == -1)
1416 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1419 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1420 if (menu.sound[i] != -1)
1421 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1425 static void set_sound_parameters(int sound, char **parameter_raw)
1427 int parameter[NUM_SND_ARGS];
1430 /* get integer values from string parameters */
1431 for (i = 0; i < NUM_SND_ARGS; i++)
1433 get_parameter_value(parameter_raw[i],
1434 sound_config_suffix[i].token,
1435 sound_config_suffix[i].type);
1437 /* explicit loop mode setting in configuration overrides default value */
1438 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1439 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1441 /* sound volume to change the original volume when loading the sound file */
1442 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1444 /* sound priority to give certain sounds a higher or lower priority */
1445 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1448 static void InitSoundInfo()
1450 int *sound_effect_properties;
1451 int num_sounds = getSoundListSize();
1454 checked_free(sound_info);
1456 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1457 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1459 /* initialize sound effect for all elements to "no sound" */
1460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1461 for (j = 0; j < NUM_ACTIONS; j++)
1462 element_info[i].sound[j] = SND_UNDEFINED;
1464 for (i = 0; i < num_sounds; i++)
1466 struct FileInfo *sound = getSoundListEntry(i);
1467 int len_effect_text = strlen(sound->token);
1469 sound_effect_properties[i] = ACTION_OTHER;
1470 sound_info[i].loop = FALSE; /* default: play sound only once */
1473 printf("::: sound %d: '%s'\n", i, sound->token);
1476 /* determine all loop sounds and identify certain sound classes */
1478 for (j = 0; element_action_info[j].suffix; j++)
1480 int len_action_text = strlen(element_action_info[j].suffix);
1482 if (len_action_text < len_effect_text &&
1483 strEqual(&sound->token[len_effect_text - len_action_text],
1484 element_action_info[j].suffix))
1486 sound_effect_properties[i] = element_action_info[j].value;
1487 sound_info[i].loop = element_action_info[j].is_loop_sound;
1493 /* associate elements and some selected sound actions */
1495 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1497 if (element_info[j].class_name)
1499 int len_class_text = strlen(element_info[j].class_name);
1501 if (len_class_text + 1 < len_effect_text &&
1502 strncmp(sound->token,
1503 element_info[j].class_name, len_class_text) == 0 &&
1504 sound->token[len_class_text] == '.')
1506 int sound_action_value = sound_effect_properties[i];
1508 element_info[j].sound[sound_action_value] = i;
1513 set_sound_parameters(i, sound->parameter);
1516 free(sound_effect_properties);
1519 static void InitGameModeMusicInfo()
1521 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1522 int num_property_mappings = getMusicListPropertyMappingSize();
1523 int default_levelset_music = -1;
1526 /* set values to -1 to identify later as "uninitialized" values */
1527 for (i = 0; i < MAX_LEVELS; i++)
1528 levelset.music[i] = -1;
1529 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1532 /* initialize gamemode/music mapping from static configuration */
1533 for (i = 0; gamemode_to_music[i].music > -1; i++)
1535 int gamemode = gamemode_to_music[i].gamemode;
1536 int music = gamemode_to_music[i].music;
1539 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1543 gamemode = GAME_MODE_DEFAULT;
1545 menu.music[gamemode] = music;
1548 /* initialize gamemode/music mapping from dynamic configuration */
1549 for (i = 0; i < num_property_mappings; i++)
1551 int prefix = property_mapping[i].base_index;
1552 int gamemode = property_mapping[i].ext1_index;
1553 int level = property_mapping[i].ext2_index;
1554 int music = property_mapping[i].artwork_index;
1557 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1558 prefix, gamemode, level, music);
1561 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1565 gamemode = GAME_MODE_DEFAULT;
1567 /* level specific music only allowed for in-game music */
1568 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1569 gamemode = GAME_MODE_PLAYING;
1574 default_levelset_music = music;
1577 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1578 levelset.music[level] = music;
1579 if (gamemode != GAME_MODE_PLAYING)
1580 menu.music[gamemode] = music;
1583 /* now set all '-1' values to menu specific default values */
1584 /* (undefined values of "levelset.music[]" might stay at "-1" to
1585 allow dynamic selection of music files from music directory!) */
1586 for (i = 0; i < MAX_LEVELS; i++)
1587 if (levelset.music[i] == -1)
1588 levelset.music[i] = default_levelset_music;
1589 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1590 if (menu.music[i] == -1)
1591 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1594 for (i = 0; i < MAX_LEVELS; i++)
1595 if (levelset.music[i] != -1)
1596 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1597 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1598 if (menu.music[i] != -1)
1599 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1603 static void set_music_parameters(int music, char **parameter_raw)
1605 int parameter[NUM_MUS_ARGS];
1608 /* get integer values from string parameters */
1609 for (i = 0; i < NUM_MUS_ARGS; i++)
1611 get_parameter_value(parameter_raw[i],
1612 music_config_suffix[i].token,
1613 music_config_suffix[i].type);
1615 /* explicit loop mode setting in configuration overrides default value */
1616 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1617 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1620 static void InitMusicInfo()
1622 int num_music = getMusicListSize();
1625 checked_free(music_info);
1627 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1629 for (i = 0; i < num_music; i++)
1631 struct FileInfo *music = getMusicListEntry(i);
1632 int len_music_text = strlen(music->token);
1634 music_info[i].loop = TRUE; /* default: play music in loop mode */
1636 /* determine all loop music */
1638 for (j = 0; music_prefix_info[j].prefix; j++)
1640 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1642 if (len_prefix_text < len_music_text &&
1643 strncmp(music->token,
1644 music_prefix_info[j].prefix, len_prefix_text) == 0)
1646 music_info[i].loop = music_prefix_info[j].is_loop_music;
1652 set_music_parameters(i, music->parameter);
1656 static void ReinitializeGraphics()
1658 InitGraphicInfo(); /* graphic properties mapping */
1659 InitElementGraphicInfo(); /* element game graphic mapping */
1660 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1662 InitElementSmallImages(); /* scale elements to all needed sizes */
1663 InitScaledImages(); /* scale all other images, if needed */
1664 InitFontGraphicInfo(); /* initialize text drawing functions */
1666 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1668 SetMainBackgroundImage(IMG_BACKGROUND);
1669 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1675 static void ReinitializeSounds()
1677 InitSoundInfo(); /* sound properties mapping */
1678 InitElementSoundInfo(); /* element game sound mapping */
1679 InitGameModeSoundInfo(); /* game mode sound mapping */
1681 InitPlayLevelSound(); /* internal game sound settings */
1684 static void ReinitializeMusic()
1686 InitMusicInfo(); /* music properties mapping */
1687 InitGameModeMusicInfo(); /* game mode music mapping */
1690 static int get_special_property_bit(int element, int property_bit_nr)
1692 struct PropertyBitInfo
1698 static struct PropertyBitInfo pb_can_move_into_acid[] =
1700 /* the player may be able fall into acid when gravity is activated */
1705 { EL_SP_MURPHY, 0 },
1706 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1708 /* all elements that can move may be able to also move into acid */
1711 { EL_BUG_RIGHT, 1 },
1714 { EL_SPACESHIP, 2 },
1715 { EL_SPACESHIP_LEFT, 2 },
1716 { EL_SPACESHIP_RIGHT, 2 },
1717 { EL_SPACESHIP_UP, 2 },
1718 { EL_SPACESHIP_DOWN, 2 },
1719 { EL_BD_BUTTERFLY, 3 },
1720 { EL_BD_BUTTERFLY_LEFT, 3 },
1721 { EL_BD_BUTTERFLY_RIGHT, 3 },
1722 { EL_BD_BUTTERFLY_UP, 3 },
1723 { EL_BD_BUTTERFLY_DOWN, 3 },
1724 { EL_BD_FIREFLY, 4 },
1725 { EL_BD_FIREFLY_LEFT, 4 },
1726 { EL_BD_FIREFLY_RIGHT, 4 },
1727 { EL_BD_FIREFLY_UP, 4 },
1728 { EL_BD_FIREFLY_DOWN, 4 },
1730 { EL_YAMYAM_LEFT, 5 },
1731 { EL_YAMYAM_RIGHT, 5 },
1732 { EL_YAMYAM_UP, 5 },
1733 { EL_YAMYAM_DOWN, 5 },
1734 { EL_DARK_YAMYAM, 6 },
1737 { EL_PACMAN_LEFT, 8 },
1738 { EL_PACMAN_RIGHT, 8 },
1739 { EL_PACMAN_UP, 8 },
1740 { EL_PACMAN_DOWN, 8 },
1742 { EL_MOLE_LEFT, 9 },
1743 { EL_MOLE_RIGHT, 9 },
1745 { EL_MOLE_DOWN, 9 },
1749 { EL_SATELLITE, 13 },
1750 { EL_SP_SNIKSNAK, 14 },
1751 { EL_SP_ELECTRON, 15 },
1754 { EL_EMC_ANDROID, 18 },
1759 static struct PropertyBitInfo pb_dont_collide_with[] =
1761 { EL_SP_SNIKSNAK, 0 },
1762 { EL_SP_ELECTRON, 1 },
1770 struct PropertyBitInfo *pb_info;
1773 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1774 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1779 struct PropertyBitInfo *pb_info = NULL;
1782 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1783 if (pb_definition[i].bit_nr == property_bit_nr)
1784 pb_info = pb_definition[i].pb_info;
1786 if (pb_info == NULL)
1789 for (i = 0; pb_info[i].element != -1; i++)
1790 if (pb_info[i].element == element)
1791 return pb_info[i].bit_nr;
1796 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1797 boolean property_value)
1799 int bit_nr = get_special_property_bit(element, property_bit_nr);
1804 *bitfield |= (1 << bit_nr);
1806 *bitfield &= ~(1 << bit_nr);
1810 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1812 int bit_nr = get_special_property_bit(element, property_bit_nr);
1815 return ((*bitfield & (1 << bit_nr)) != 0);
1821 static void resolve_group_element(int group_element, int recursion_depth)
1823 static int group_nr;
1824 static struct ElementGroupInfo *group;
1825 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1828 if (actual_group == NULL) /* not yet initialized */
1831 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1833 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1834 group_element - EL_GROUP_START + 1);
1836 /* replace element which caused too deep recursion by question mark */
1837 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1842 if (recursion_depth == 0) /* initialization */
1844 group = actual_group;
1845 group_nr = group_element - EL_GROUP_START;
1847 group->num_elements_resolved = 0;
1848 group->choice_pos = 0;
1851 for (i = 0; i < actual_group->num_elements; i++)
1853 int element = actual_group->element[i];
1855 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1858 if (IS_GROUP_ELEMENT(element))
1859 resolve_group_element(element, recursion_depth + 1);
1862 group->element_resolved[group->num_elements_resolved++] = element;
1863 element_info[element].in_group[group_nr] = TRUE;
1869 void InitElementPropertiesStatic()
1871 static int ep_diggable[] =
1876 EL_SP_BUGGY_BASE_ACTIVATING,
1879 EL_INVISIBLE_SAND_ACTIVE,
1882 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1883 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1887 EL_SP_BUGGY_BASE_ACTIVE,
1894 static int ep_collectible_only[] =
1916 EL_DYNABOMB_INCREASE_NUMBER,
1917 EL_DYNABOMB_INCREASE_SIZE,
1918 EL_DYNABOMB_INCREASE_POWER,
1938 static int ep_dont_run_into[] =
1940 /* same elements as in 'ep_dont_touch' */
1946 /* same elements as in 'ep_dont_collide_with' */
1958 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1962 EL_SP_BUGGY_BASE_ACTIVE,
1969 static int ep_dont_collide_with[] =
1971 /* same elements as in 'ep_dont_touch' */
1988 static int ep_dont_touch[] =
1998 static int ep_indestructible[] =
2002 EL_ACID_POOL_TOPLEFT,
2003 EL_ACID_POOL_TOPRIGHT,
2004 EL_ACID_POOL_BOTTOMLEFT,
2005 EL_ACID_POOL_BOTTOM,
2006 EL_ACID_POOL_BOTTOMRIGHT,
2007 EL_SP_HARDWARE_GRAY,
2008 EL_SP_HARDWARE_GREEN,
2009 EL_SP_HARDWARE_BLUE,
2011 EL_SP_HARDWARE_YELLOW,
2012 EL_SP_HARDWARE_BASE_1,
2013 EL_SP_HARDWARE_BASE_2,
2014 EL_SP_HARDWARE_BASE_3,
2015 EL_SP_HARDWARE_BASE_4,
2016 EL_SP_HARDWARE_BASE_5,
2017 EL_SP_HARDWARE_BASE_6,
2018 EL_INVISIBLE_STEELWALL,
2019 EL_INVISIBLE_STEELWALL_ACTIVE,
2020 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2021 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2022 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2023 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2024 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2025 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2026 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2027 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2028 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2029 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2030 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2031 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2033 EL_LIGHT_SWITCH_ACTIVE,
2034 EL_SIGN_EXCLAMATION,
2035 EL_SIGN_RADIOACTIVITY,
2046 EL_STEELWALL_SLIPPERY,
2060 EL_GATE_1_GRAY_ACTIVE,
2061 EL_GATE_2_GRAY_ACTIVE,
2062 EL_GATE_3_GRAY_ACTIVE,
2063 EL_GATE_4_GRAY_ACTIVE,
2072 EL_EM_GATE_1_GRAY_ACTIVE,
2073 EL_EM_GATE_2_GRAY_ACTIVE,
2074 EL_EM_GATE_3_GRAY_ACTIVE,
2075 EL_EM_GATE_4_GRAY_ACTIVE,
2084 EL_EMC_GATE_5_GRAY_ACTIVE,
2085 EL_EMC_GATE_6_GRAY_ACTIVE,
2086 EL_EMC_GATE_7_GRAY_ACTIVE,
2087 EL_EMC_GATE_8_GRAY_ACTIVE,
2089 EL_SWITCHGATE_OPENING,
2090 EL_SWITCHGATE_CLOSED,
2091 EL_SWITCHGATE_CLOSING,
2093 EL_SWITCHGATE_SWITCH_UP,
2094 EL_SWITCHGATE_SWITCH_DOWN,
2097 EL_TIMEGATE_OPENING,
2099 EL_TIMEGATE_CLOSING,
2102 EL_TIMEGATE_SWITCH_ACTIVE,
2107 EL_TUBE_VERTICAL_LEFT,
2108 EL_TUBE_VERTICAL_RIGHT,
2109 EL_TUBE_HORIZONTAL_UP,
2110 EL_TUBE_HORIZONTAL_DOWN,
2119 static int ep_slippery[] =
2133 EL_ROBOT_WHEEL_ACTIVE,
2139 EL_ACID_POOL_TOPLEFT,
2140 EL_ACID_POOL_TOPRIGHT,
2150 EL_STEELWALL_SLIPPERY,
2153 EL_EMC_WALL_SLIPPERY_1,
2154 EL_EMC_WALL_SLIPPERY_2,
2155 EL_EMC_WALL_SLIPPERY_3,
2156 EL_EMC_WALL_SLIPPERY_4,
2158 EL_EMC_MAGIC_BALL_ACTIVE,
2163 static int ep_can_change[] =
2168 static int ep_can_move[] =
2170 /* same elements as in 'pb_can_move_into_acid' */
2193 static int ep_can_fall[] =
2208 EL_BD_MAGIC_WALL_FULL,
2222 static int ep_can_smash_player[] =
2248 static int ep_can_smash_enemies[] =
2257 static int ep_can_smash_everything[] =
2266 static int ep_explodes_by_fire[] =
2268 /* same elements as in 'ep_explodes_impact' */
2273 /* same elements as in 'ep_explodes_smashed' */
2283 EL_EM_DYNAMITE_ACTIVE,
2284 EL_DYNABOMB_PLAYER_1_ACTIVE,
2285 EL_DYNABOMB_PLAYER_2_ACTIVE,
2286 EL_DYNABOMB_PLAYER_3_ACTIVE,
2287 EL_DYNABOMB_PLAYER_4_ACTIVE,
2288 EL_DYNABOMB_INCREASE_NUMBER,
2289 EL_DYNABOMB_INCREASE_SIZE,
2290 EL_DYNABOMB_INCREASE_POWER,
2291 EL_SP_DISK_RED_ACTIVE,
2305 static int ep_explodes_smashed[] =
2307 /* same elements as in 'ep_explodes_impact' */
2321 static int ep_explodes_impact[] =
2330 static int ep_walkable_over[] =
2334 EL_SOKOBAN_FIELD_EMPTY,
2346 EL_GATE_1_GRAY_ACTIVE,
2347 EL_GATE_2_GRAY_ACTIVE,
2348 EL_GATE_3_GRAY_ACTIVE,
2349 EL_GATE_4_GRAY_ACTIVE,
2357 static int ep_walkable_inside[] =
2362 EL_TUBE_VERTICAL_LEFT,
2363 EL_TUBE_VERTICAL_RIGHT,
2364 EL_TUBE_HORIZONTAL_UP,
2365 EL_TUBE_HORIZONTAL_DOWN,
2374 static int ep_walkable_under[] =
2379 static int ep_passable_over[] =
2389 EL_EM_GATE_1_GRAY_ACTIVE,
2390 EL_EM_GATE_2_GRAY_ACTIVE,
2391 EL_EM_GATE_3_GRAY_ACTIVE,
2392 EL_EM_GATE_4_GRAY_ACTIVE,
2401 EL_EMC_GATE_5_GRAY_ACTIVE,
2402 EL_EMC_GATE_6_GRAY_ACTIVE,
2403 EL_EMC_GATE_7_GRAY_ACTIVE,
2404 EL_EMC_GATE_8_GRAY_ACTIVE,
2411 static int ep_passable_inside[] =
2417 EL_SP_PORT_HORIZONTAL,
2418 EL_SP_PORT_VERTICAL,
2420 EL_SP_GRAVITY_PORT_LEFT,
2421 EL_SP_GRAVITY_PORT_RIGHT,
2422 EL_SP_GRAVITY_PORT_UP,
2423 EL_SP_GRAVITY_PORT_DOWN,
2424 EL_SP_GRAVITY_ON_PORT_LEFT,
2425 EL_SP_GRAVITY_ON_PORT_RIGHT,
2426 EL_SP_GRAVITY_ON_PORT_UP,
2427 EL_SP_GRAVITY_ON_PORT_DOWN,
2428 EL_SP_GRAVITY_OFF_PORT_LEFT,
2429 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2430 EL_SP_GRAVITY_OFF_PORT_UP,
2431 EL_SP_GRAVITY_OFF_PORT_DOWN,
2436 static int ep_passable_under[] =
2441 static int ep_droppable[] =
2446 static int ep_explodes_1x1_old[] =
2451 static int ep_pushable[] =
2463 EL_SOKOBAN_FIELD_FULL,
2472 static int ep_explodes_cross_old[] =
2477 static int ep_protected[] =
2479 /* same elements as in 'ep_walkable_inside' */
2483 EL_TUBE_VERTICAL_LEFT,
2484 EL_TUBE_VERTICAL_RIGHT,
2485 EL_TUBE_HORIZONTAL_UP,
2486 EL_TUBE_HORIZONTAL_DOWN,
2492 /* same elements as in 'ep_passable_over' */
2501 EL_EM_GATE_1_GRAY_ACTIVE,
2502 EL_EM_GATE_2_GRAY_ACTIVE,
2503 EL_EM_GATE_3_GRAY_ACTIVE,
2504 EL_EM_GATE_4_GRAY_ACTIVE,
2513 EL_EMC_GATE_5_GRAY_ACTIVE,
2514 EL_EMC_GATE_6_GRAY_ACTIVE,
2515 EL_EMC_GATE_7_GRAY_ACTIVE,
2516 EL_EMC_GATE_8_GRAY_ACTIVE,
2520 /* same elements as in 'ep_passable_inside' */
2525 EL_SP_PORT_HORIZONTAL,
2526 EL_SP_PORT_VERTICAL,
2528 EL_SP_GRAVITY_PORT_LEFT,
2529 EL_SP_GRAVITY_PORT_RIGHT,
2530 EL_SP_GRAVITY_PORT_UP,
2531 EL_SP_GRAVITY_PORT_DOWN,
2532 EL_SP_GRAVITY_ON_PORT_LEFT,
2533 EL_SP_GRAVITY_ON_PORT_RIGHT,
2534 EL_SP_GRAVITY_ON_PORT_UP,
2535 EL_SP_GRAVITY_ON_PORT_DOWN,
2536 EL_SP_GRAVITY_OFF_PORT_LEFT,
2537 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2538 EL_SP_GRAVITY_OFF_PORT_UP,
2539 EL_SP_GRAVITY_OFF_PORT_DOWN,
2544 static int ep_throwable[] =
2549 static int ep_can_explode[] =
2551 /* same elements as in 'ep_explodes_impact' */
2556 /* same elements as in 'ep_explodes_smashed' */
2562 /* elements that can explode by explosion or by dragonfire */
2566 EL_EM_DYNAMITE_ACTIVE,
2567 EL_DYNABOMB_PLAYER_1_ACTIVE,
2568 EL_DYNABOMB_PLAYER_2_ACTIVE,
2569 EL_DYNABOMB_PLAYER_3_ACTIVE,
2570 EL_DYNABOMB_PLAYER_4_ACTIVE,
2571 EL_DYNABOMB_INCREASE_NUMBER,
2572 EL_DYNABOMB_INCREASE_SIZE,
2573 EL_DYNABOMB_INCREASE_POWER,
2574 EL_SP_DISK_RED_ACTIVE,
2582 /* elements that can explode only by explosion */
2588 static int ep_gravity_reachable[] =
2594 EL_INVISIBLE_SAND_ACTIVE,
2599 EL_SP_PORT_HORIZONTAL,
2600 EL_SP_PORT_VERTICAL,
2602 EL_SP_GRAVITY_PORT_LEFT,
2603 EL_SP_GRAVITY_PORT_RIGHT,
2604 EL_SP_GRAVITY_PORT_UP,
2605 EL_SP_GRAVITY_PORT_DOWN,
2606 EL_SP_GRAVITY_ON_PORT_LEFT,
2607 EL_SP_GRAVITY_ON_PORT_RIGHT,
2608 EL_SP_GRAVITY_ON_PORT_UP,
2609 EL_SP_GRAVITY_ON_PORT_DOWN,
2610 EL_SP_GRAVITY_OFF_PORT_LEFT,
2611 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2612 EL_SP_GRAVITY_OFF_PORT_UP,
2613 EL_SP_GRAVITY_OFF_PORT_DOWN,
2619 static int ep_player[] =
2626 EL_SOKOBAN_FIELD_PLAYER,
2632 static int ep_can_pass_magic_wall[] =
2646 static int ep_switchable[] =
2650 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2651 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2652 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2653 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2654 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2655 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2656 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2657 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2658 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2659 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2660 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2661 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2662 EL_SWITCHGATE_SWITCH_UP,
2663 EL_SWITCHGATE_SWITCH_DOWN,
2665 EL_LIGHT_SWITCH_ACTIVE,
2667 EL_BALLOON_SWITCH_LEFT,
2668 EL_BALLOON_SWITCH_RIGHT,
2669 EL_BALLOON_SWITCH_UP,
2670 EL_BALLOON_SWITCH_DOWN,
2671 EL_BALLOON_SWITCH_ANY,
2672 EL_BALLOON_SWITCH_NONE,
2675 EL_EMC_MAGIC_BALL_SWITCH,
2676 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2681 static int ep_bd_element[] =
2715 static int ep_sp_element[] =
2717 /* should always be valid */
2720 /* standard classic Supaplex elements */
2727 EL_SP_HARDWARE_GRAY,
2735 EL_SP_GRAVITY_PORT_RIGHT,
2736 EL_SP_GRAVITY_PORT_DOWN,
2737 EL_SP_GRAVITY_PORT_LEFT,
2738 EL_SP_GRAVITY_PORT_UP,
2743 EL_SP_PORT_VERTICAL,
2744 EL_SP_PORT_HORIZONTAL,
2750 EL_SP_HARDWARE_BASE_1,
2751 EL_SP_HARDWARE_GREEN,
2752 EL_SP_HARDWARE_BLUE,
2754 EL_SP_HARDWARE_YELLOW,
2755 EL_SP_HARDWARE_BASE_2,
2756 EL_SP_HARDWARE_BASE_3,
2757 EL_SP_HARDWARE_BASE_4,
2758 EL_SP_HARDWARE_BASE_5,
2759 EL_SP_HARDWARE_BASE_6,
2763 /* additional elements that appeared in newer Supaplex levels */
2766 /* additional gravity port elements (not switching, but setting gravity) */
2767 EL_SP_GRAVITY_ON_PORT_LEFT,
2768 EL_SP_GRAVITY_ON_PORT_RIGHT,
2769 EL_SP_GRAVITY_ON_PORT_UP,
2770 EL_SP_GRAVITY_ON_PORT_DOWN,
2771 EL_SP_GRAVITY_OFF_PORT_LEFT,
2772 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2773 EL_SP_GRAVITY_OFF_PORT_UP,
2774 EL_SP_GRAVITY_OFF_PORT_DOWN,
2776 /* more than one Murphy in a level results in an inactive clone */
2779 /* runtime Supaplex elements */
2780 EL_SP_DISK_RED_ACTIVE,
2781 EL_SP_TERMINAL_ACTIVE,
2782 EL_SP_BUGGY_BASE_ACTIVATING,
2783 EL_SP_BUGGY_BASE_ACTIVE,
2790 static int ep_sb_element[] =
2795 EL_SOKOBAN_FIELD_EMPTY,
2796 EL_SOKOBAN_FIELD_FULL,
2797 EL_SOKOBAN_FIELD_PLAYER,
2802 EL_INVISIBLE_STEELWALL,
2807 static int ep_gem[] =
2819 static int ep_food_dark_yamyam[] =
2847 static int ep_food_penguin[] =
2861 static int ep_food_pig[] =
2873 static int ep_historic_wall[] =
2884 EL_GATE_1_GRAY_ACTIVE,
2885 EL_GATE_2_GRAY_ACTIVE,
2886 EL_GATE_3_GRAY_ACTIVE,
2887 EL_GATE_4_GRAY_ACTIVE,
2896 EL_EM_GATE_1_GRAY_ACTIVE,
2897 EL_EM_GATE_2_GRAY_ACTIVE,
2898 EL_EM_GATE_3_GRAY_ACTIVE,
2899 EL_EM_GATE_4_GRAY_ACTIVE,
2906 EL_EXPANDABLE_WALL_HORIZONTAL,
2907 EL_EXPANDABLE_WALL_VERTICAL,
2908 EL_EXPANDABLE_WALL_ANY,
2909 EL_EXPANDABLE_WALL_GROWING,
2910 EL_BD_EXPANDABLE_WALL,
2917 EL_SP_HARDWARE_GRAY,
2918 EL_SP_HARDWARE_GREEN,
2919 EL_SP_HARDWARE_BLUE,
2921 EL_SP_HARDWARE_YELLOW,
2922 EL_SP_HARDWARE_BASE_1,
2923 EL_SP_HARDWARE_BASE_2,
2924 EL_SP_HARDWARE_BASE_3,
2925 EL_SP_HARDWARE_BASE_4,
2926 EL_SP_HARDWARE_BASE_5,
2927 EL_SP_HARDWARE_BASE_6,
2929 EL_SP_TERMINAL_ACTIVE,
2932 EL_INVISIBLE_STEELWALL,
2933 EL_INVISIBLE_STEELWALL_ACTIVE,
2935 EL_INVISIBLE_WALL_ACTIVE,
2936 EL_STEELWALL_SLIPPERY,
2953 static int ep_historic_solid[] =
2957 EL_EXPANDABLE_WALL_HORIZONTAL,
2958 EL_EXPANDABLE_WALL_VERTICAL,
2959 EL_EXPANDABLE_WALL_ANY,
2960 EL_BD_EXPANDABLE_WALL,
2973 EL_QUICKSAND_FILLING,
2974 EL_QUICKSAND_EMPTYING,
2976 EL_MAGIC_WALL_ACTIVE,
2977 EL_MAGIC_WALL_EMPTYING,
2978 EL_MAGIC_WALL_FILLING,
2982 EL_BD_MAGIC_WALL_ACTIVE,
2983 EL_BD_MAGIC_WALL_EMPTYING,
2984 EL_BD_MAGIC_WALL_FULL,
2985 EL_BD_MAGIC_WALL_FILLING,
2986 EL_BD_MAGIC_WALL_DEAD,
2995 EL_SP_TERMINAL_ACTIVE,
2999 EL_INVISIBLE_WALL_ACTIVE,
3000 EL_SWITCHGATE_SWITCH_UP,
3001 EL_SWITCHGATE_SWITCH_DOWN,
3003 EL_TIMEGATE_SWITCH_ACTIVE,
3015 /* the following elements are a direct copy of "indestructible" elements,
3016 except "EL_ACID", which is "indestructible", but not "solid"! */
3021 EL_ACID_POOL_TOPLEFT,
3022 EL_ACID_POOL_TOPRIGHT,
3023 EL_ACID_POOL_BOTTOMLEFT,
3024 EL_ACID_POOL_BOTTOM,
3025 EL_ACID_POOL_BOTTOMRIGHT,
3026 EL_SP_HARDWARE_GRAY,
3027 EL_SP_HARDWARE_GREEN,
3028 EL_SP_HARDWARE_BLUE,
3030 EL_SP_HARDWARE_YELLOW,
3031 EL_SP_HARDWARE_BASE_1,
3032 EL_SP_HARDWARE_BASE_2,
3033 EL_SP_HARDWARE_BASE_3,
3034 EL_SP_HARDWARE_BASE_4,
3035 EL_SP_HARDWARE_BASE_5,
3036 EL_SP_HARDWARE_BASE_6,
3037 EL_INVISIBLE_STEELWALL,
3038 EL_INVISIBLE_STEELWALL_ACTIVE,
3039 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3040 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3041 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3042 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3043 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3044 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3045 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3046 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3047 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3048 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3049 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3050 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3052 EL_LIGHT_SWITCH_ACTIVE,
3053 EL_SIGN_EXCLAMATION,
3054 EL_SIGN_RADIOACTIVITY,
3065 EL_STEELWALL_SLIPPERY,
3079 EL_GATE_1_GRAY_ACTIVE,
3080 EL_GATE_2_GRAY_ACTIVE,
3081 EL_GATE_3_GRAY_ACTIVE,
3082 EL_GATE_4_GRAY_ACTIVE,
3091 EL_EM_GATE_1_GRAY_ACTIVE,
3092 EL_EM_GATE_2_GRAY_ACTIVE,
3093 EL_EM_GATE_3_GRAY_ACTIVE,
3094 EL_EM_GATE_4_GRAY_ACTIVE,
3096 EL_SWITCHGATE_OPENING,
3097 EL_SWITCHGATE_CLOSED,
3098 EL_SWITCHGATE_CLOSING,
3100 EL_TIMEGATE_OPENING,
3102 EL_TIMEGATE_CLOSING,
3106 EL_TUBE_VERTICAL_LEFT,
3107 EL_TUBE_VERTICAL_RIGHT,
3108 EL_TUBE_HORIZONTAL_UP,
3109 EL_TUBE_HORIZONTAL_DOWN,
3118 static int ep_classic_enemy[] =
3135 static int ep_belt[] =
3137 EL_CONVEYOR_BELT_1_LEFT,
3138 EL_CONVEYOR_BELT_1_MIDDLE,
3139 EL_CONVEYOR_BELT_1_RIGHT,
3140 EL_CONVEYOR_BELT_2_LEFT,
3141 EL_CONVEYOR_BELT_2_MIDDLE,
3142 EL_CONVEYOR_BELT_2_RIGHT,
3143 EL_CONVEYOR_BELT_3_LEFT,
3144 EL_CONVEYOR_BELT_3_MIDDLE,
3145 EL_CONVEYOR_BELT_3_RIGHT,
3146 EL_CONVEYOR_BELT_4_LEFT,
3147 EL_CONVEYOR_BELT_4_MIDDLE,
3148 EL_CONVEYOR_BELT_4_RIGHT,
3153 static int ep_belt_active[] =
3155 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3156 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3157 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3158 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3159 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3160 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3161 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3162 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3163 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3164 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3165 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3166 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3171 static int ep_belt_switch[] =
3173 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3174 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3175 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3176 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3177 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3178 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3179 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3180 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3181 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3182 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3183 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3184 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3189 static int ep_tube[] =
3196 EL_TUBE_HORIZONTAL_UP,
3197 EL_TUBE_HORIZONTAL_DOWN,
3199 EL_TUBE_VERTICAL_LEFT,
3200 EL_TUBE_VERTICAL_RIGHT,
3206 static int ep_keygate[] =
3216 EL_GATE_1_GRAY_ACTIVE,
3217 EL_GATE_2_GRAY_ACTIVE,
3218 EL_GATE_3_GRAY_ACTIVE,
3219 EL_GATE_4_GRAY_ACTIVE,
3228 EL_EM_GATE_1_GRAY_ACTIVE,
3229 EL_EM_GATE_2_GRAY_ACTIVE,
3230 EL_EM_GATE_3_GRAY_ACTIVE,
3231 EL_EM_GATE_4_GRAY_ACTIVE,
3240 EL_EMC_GATE_5_GRAY_ACTIVE,
3241 EL_EMC_GATE_6_GRAY_ACTIVE,
3242 EL_EMC_GATE_7_GRAY_ACTIVE,
3243 EL_EMC_GATE_8_GRAY_ACTIVE,
3248 static int ep_amoeboid[] =
3260 static int ep_amoebalive[] =
3271 static int ep_has_editor_content[] =
3293 static int ep_can_turn_each_move[] =
3295 /* !!! do something with this one !!! */
3299 static int ep_can_grow[] =
3313 static int ep_active_bomb[] =
3316 EL_EM_DYNAMITE_ACTIVE,
3317 EL_DYNABOMB_PLAYER_1_ACTIVE,
3318 EL_DYNABOMB_PLAYER_2_ACTIVE,
3319 EL_DYNABOMB_PLAYER_3_ACTIVE,
3320 EL_DYNABOMB_PLAYER_4_ACTIVE,
3321 EL_SP_DISK_RED_ACTIVE,
3326 static int ep_inactive[] =
3358 EL_GATE_1_GRAY_ACTIVE,
3359 EL_GATE_2_GRAY_ACTIVE,
3360 EL_GATE_3_GRAY_ACTIVE,
3361 EL_GATE_4_GRAY_ACTIVE,
3370 EL_EM_GATE_1_GRAY_ACTIVE,
3371 EL_EM_GATE_2_GRAY_ACTIVE,
3372 EL_EM_GATE_3_GRAY_ACTIVE,
3373 EL_EM_GATE_4_GRAY_ACTIVE,
3382 EL_EMC_GATE_5_GRAY_ACTIVE,
3383 EL_EMC_GATE_6_GRAY_ACTIVE,
3384 EL_EMC_GATE_7_GRAY_ACTIVE,
3385 EL_EMC_GATE_8_GRAY_ACTIVE,
3388 EL_INVISIBLE_STEELWALL,
3396 EL_WALL_EMERALD_YELLOW,
3397 EL_DYNABOMB_INCREASE_NUMBER,
3398 EL_DYNABOMB_INCREASE_SIZE,
3399 EL_DYNABOMB_INCREASE_POWER,
3403 EL_SOKOBAN_FIELD_EMPTY,
3404 EL_SOKOBAN_FIELD_FULL,
3405 EL_WALL_EMERALD_RED,
3406 EL_WALL_EMERALD_PURPLE,
3407 EL_ACID_POOL_TOPLEFT,
3408 EL_ACID_POOL_TOPRIGHT,
3409 EL_ACID_POOL_BOTTOMLEFT,
3410 EL_ACID_POOL_BOTTOM,
3411 EL_ACID_POOL_BOTTOMRIGHT,
3415 EL_BD_MAGIC_WALL_DEAD,
3416 EL_AMOEBA_TO_DIAMOND,
3424 EL_SP_GRAVITY_PORT_RIGHT,
3425 EL_SP_GRAVITY_PORT_DOWN,
3426 EL_SP_GRAVITY_PORT_LEFT,
3427 EL_SP_GRAVITY_PORT_UP,
3428 EL_SP_PORT_HORIZONTAL,
3429 EL_SP_PORT_VERTICAL,
3440 EL_SP_HARDWARE_GRAY,
3441 EL_SP_HARDWARE_GREEN,
3442 EL_SP_HARDWARE_BLUE,
3444 EL_SP_HARDWARE_YELLOW,
3445 EL_SP_HARDWARE_BASE_1,
3446 EL_SP_HARDWARE_BASE_2,
3447 EL_SP_HARDWARE_BASE_3,
3448 EL_SP_HARDWARE_BASE_4,
3449 EL_SP_HARDWARE_BASE_5,
3450 EL_SP_HARDWARE_BASE_6,
3451 EL_SP_GRAVITY_ON_PORT_LEFT,
3452 EL_SP_GRAVITY_ON_PORT_RIGHT,
3453 EL_SP_GRAVITY_ON_PORT_UP,
3454 EL_SP_GRAVITY_ON_PORT_DOWN,
3455 EL_SP_GRAVITY_OFF_PORT_LEFT,
3456 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3457 EL_SP_GRAVITY_OFF_PORT_UP,
3458 EL_SP_GRAVITY_OFF_PORT_DOWN,
3459 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3460 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3461 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3462 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3463 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3464 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3465 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3466 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3467 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3468 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3469 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3470 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3471 EL_SIGN_EXCLAMATION,
3472 EL_SIGN_RADIOACTIVITY,
3483 EL_STEELWALL_SLIPPERY,
3488 EL_EMC_WALL_SLIPPERY_1,
3489 EL_EMC_WALL_SLIPPERY_2,
3490 EL_EMC_WALL_SLIPPERY_3,
3491 EL_EMC_WALL_SLIPPERY_4,
3512 static int ep_em_slippery_wall[] =
3517 static int ep_gfx_crumbled[] =
3527 static int ep_editor_cascade_active[] =
3529 EL_INTERNAL_CASCADE_BD_ACTIVE,
3530 EL_INTERNAL_CASCADE_EM_ACTIVE,
3531 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3532 EL_INTERNAL_CASCADE_RND_ACTIVE,
3533 EL_INTERNAL_CASCADE_SB_ACTIVE,
3534 EL_INTERNAL_CASCADE_SP_ACTIVE,
3535 EL_INTERNAL_CASCADE_DC_ACTIVE,
3536 EL_INTERNAL_CASCADE_DX_ACTIVE,
3537 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3538 EL_INTERNAL_CASCADE_CE_ACTIVE,
3539 EL_INTERNAL_CASCADE_GE_ACTIVE,
3540 EL_INTERNAL_CASCADE_USER_ACTIVE,
3541 EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3542 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3547 static int ep_editor_cascade_inactive[] =
3549 EL_INTERNAL_CASCADE_BD,
3550 EL_INTERNAL_CASCADE_EM,
3551 EL_INTERNAL_CASCADE_EMC,
3552 EL_INTERNAL_CASCADE_RND,
3553 EL_INTERNAL_CASCADE_SB,
3554 EL_INTERNAL_CASCADE_SP,
3555 EL_INTERNAL_CASCADE_DC,
3556 EL_INTERNAL_CASCADE_DX,
3557 EL_INTERNAL_CASCADE_CHARS,
3558 EL_INTERNAL_CASCADE_CE,
3559 EL_INTERNAL_CASCADE_GE,
3560 EL_INTERNAL_CASCADE_USER,
3561 EL_INTERNAL_CASCADE_GENERIC,
3562 EL_INTERNAL_CASCADE_DYNAMIC,
3567 static int ep_obsolete[] =
3571 EL_EM_KEY_1_FILE_OBSOLETE,
3572 EL_EM_KEY_2_FILE_OBSOLETE,
3573 EL_EM_KEY_3_FILE_OBSOLETE,
3574 EL_EM_KEY_4_FILE_OBSOLETE,
3575 EL_ENVELOPE_OBSOLETE,
3584 } element_properties[] =
3586 { ep_diggable, EP_DIGGABLE },
3587 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3588 { ep_dont_run_into, EP_DONT_RUN_INTO },
3589 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3590 { ep_dont_touch, EP_DONT_TOUCH },
3591 { ep_indestructible, EP_INDESTRUCTIBLE },
3592 { ep_slippery, EP_SLIPPERY },
3593 { ep_can_change, EP_CAN_CHANGE },
3594 { ep_can_move, EP_CAN_MOVE },
3595 { ep_can_fall, EP_CAN_FALL },
3596 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3597 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3598 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3599 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3600 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3601 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3602 { ep_walkable_over, EP_WALKABLE_OVER },
3603 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3604 { ep_walkable_under, EP_WALKABLE_UNDER },
3605 { ep_passable_over, EP_PASSABLE_OVER },
3606 { ep_passable_inside, EP_PASSABLE_INSIDE },
3607 { ep_passable_under, EP_PASSABLE_UNDER },
3608 { ep_droppable, EP_DROPPABLE },
3609 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3610 { ep_pushable, EP_PUSHABLE },
3611 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3612 { ep_protected, EP_PROTECTED },
3613 { ep_throwable, EP_THROWABLE },
3614 { ep_can_explode, EP_CAN_EXPLODE },
3615 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3617 { ep_player, EP_PLAYER },
3618 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3619 { ep_switchable, EP_SWITCHABLE },
3620 { ep_bd_element, EP_BD_ELEMENT },
3621 { ep_sp_element, EP_SP_ELEMENT },
3622 { ep_sb_element, EP_SB_ELEMENT },
3624 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3625 { ep_food_penguin, EP_FOOD_PENGUIN },
3626 { ep_food_pig, EP_FOOD_PIG },
3627 { ep_historic_wall, EP_HISTORIC_WALL },
3628 { ep_historic_solid, EP_HISTORIC_SOLID },
3629 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3630 { ep_belt, EP_BELT },
3631 { ep_belt_active, EP_BELT_ACTIVE },
3632 { ep_belt_switch, EP_BELT_SWITCH },
3633 { ep_tube, EP_TUBE },
3634 { ep_keygate, EP_KEYGATE },
3635 { ep_amoeboid, EP_AMOEBOID },
3636 { ep_amoebalive, EP_AMOEBALIVE },
3637 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3638 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3639 { ep_can_grow, EP_CAN_GROW },
3640 { ep_active_bomb, EP_ACTIVE_BOMB },
3641 { ep_inactive, EP_INACTIVE },
3643 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3645 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3647 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3648 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3650 { ep_obsolete, EP_OBSOLETE },
3657 /* always start with reliable default values (element has no properties) */
3658 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3659 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3660 SET_PROPERTY(i, j, FALSE);
3662 /* set all base element properties from above array definitions */
3663 for (i = 0; element_properties[i].elements != NULL; i++)
3664 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3665 SET_PROPERTY((element_properties[i].elements)[j],
3666 element_properties[i].property, TRUE);
3668 /* copy properties to some elements that are only stored in level file */
3669 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3670 for (j = 0; copy_properties[j][0] != -1; j++)
3671 if (HAS_PROPERTY(copy_properties[j][0], i))
3672 for (k = 1; k <= 4; k++)
3673 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3676 void InitElementPropertiesEngine(int engine_version)
3678 static int no_wall_properties[] =
3681 EP_COLLECTIBLE_ONLY,
3683 EP_DONT_COLLIDE_WITH,
3686 EP_CAN_SMASH_PLAYER,
3687 EP_CAN_SMASH_ENEMIES,
3688 EP_CAN_SMASH_EVERYTHING,
3693 EP_FOOD_DARK_YAMYAM,
3709 /* important: after initialization in InitElementPropertiesStatic(), the
3710 elements are not again initialized to a default value; therefore all
3711 changes have to make sure that they leave the element with a defined
3712 property (which means that conditional property changes must be set to
3713 a reliable default value before) */
3716 /* ---------- recursively resolve group elements ------------------------- */
3718 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3719 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3720 element_info[i].in_group[j] = FALSE;
3722 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3723 resolve_group_element(EL_GROUP_START + i, 0);
3726 /* set all special, combined or engine dependent element properties */
3727 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3729 /* ---------- INACTIVE ------------------------------------------------- */
3730 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3732 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3733 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3734 IS_WALKABLE_INSIDE(i) ||
3735 IS_WALKABLE_UNDER(i)));
3737 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3738 IS_PASSABLE_INSIDE(i) ||
3739 IS_PASSABLE_UNDER(i)));
3741 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3742 IS_PASSABLE_OVER(i)));
3744 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3745 IS_PASSABLE_INSIDE(i)));
3747 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3748 IS_PASSABLE_UNDER(i)));
3750 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3753 /* ---------- COLLECTIBLE ---------------------------------------------- */
3754 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3758 /* ---------- SNAPPABLE ------------------------------------------------ */
3759 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3760 IS_COLLECTIBLE(i) ||
3764 /* ---------- WALL ----------------------------------------------------- */
3765 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3767 for (j = 0; no_wall_properties[j] != -1; j++)
3768 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3769 i >= EL_FIRST_RUNTIME_UNREAL)
3770 SET_PROPERTY(i, EP_WALL, FALSE);
3772 if (IS_HISTORIC_WALL(i))
3773 SET_PROPERTY(i, EP_WALL, TRUE);
3775 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3776 if (engine_version < VERSION_IDENT(2,2,0,0))
3777 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3779 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3781 !IS_COLLECTIBLE(i)));
3783 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3785 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3786 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3788 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3789 IS_INDESTRUCTIBLE(i)));
3791 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3793 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3794 else if (engine_version < VERSION_IDENT(2,2,0,0))
3795 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3797 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3801 if (IS_CUSTOM_ELEMENT(i))
3803 /* these are additional properties which are initially false when set */
3805 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3807 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3808 if (DONT_COLLIDE_WITH(i))
3809 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3811 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3812 if (CAN_SMASH_EVERYTHING(i))
3813 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3814 if (CAN_SMASH_ENEMIES(i))
3815 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3818 /* ---------- CAN_SMASH ------------------------------------------------ */
3819 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3820 CAN_SMASH_ENEMIES(i) ||
3821 CAN_SMASH_EVERYTHING(i)));
3823 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3824 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3825 EXPLODES_BY_FIRE(i)));
3827 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3828 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3829 EXPLODES_SMASHED(i)));
3831 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3832 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3833 EXPLODES_IMPACT(i)));
3835 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3836 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3838 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3839 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3840 i == EL_BLACK_ORB));
3842 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3843 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3845 IS_CUSTOM_ELEMENT(i)));
3847 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3848 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3849 i == EL_SP_ELECTRON));
3851 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3852 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3853 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3854 getMoveIntoAcidProperty(&level, i));
3856 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3857 if (MAYBE_DONT_COLLIDE_WITH(i))
3858 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3859 getDontCollideWithProperty(&level, i));
3861 /* ---------- SP_PORT -------------------------------------------------- */
3862 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3863 IS_PASSABLE_INSIDE(i)));
3865 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3866 for (j = 0; j < level.num_android_clone_elements; j++)
3867 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3869 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3871 /* ---------- CAN_CHANGE ----------------------------------------------- */
3872 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3873 for (j = 0; j < element_info[i].num_change_pages; j++)
3874 if (element_info[i].change_page[j].can_change)
3875 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3877 /* ---------- HAS_ACTION ----------------------------------------------- */
3878 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3879 for (j = 0; j < element_info[i].num_change_pages; j++)
3880 if (element_info[i].change_page[j].has_action)
3881 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3883 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3884 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3887 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3889 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3890 element_info[i].crumbled[ACTION_DEFAULT] !=
3891 element_info[i].graphic[ACTION_DEFAULT]);
3893 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3894 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3895 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3898 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3899 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3900 IS_EDITOR_CASCADE_INACTIVE(i)));
3903 /* dynamically adjust element properties according to game engine version */
3905 static int ep_em_slippery_wall[] =
3910 EL_EXPANDABLE_WALL_HORIZONTAL,
3911 EL_EXPANDABLE_WALL_VERTICAL,
3912 EL_EXPANDABLE_WALL_ANY,
3916 /* special EM style gems behaviour */
3917 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3918 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3919 level.em_slippery_gems);
3921 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3922 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3923 (level.em_slippery_gems &&
3924 engine_version > VERSION_IDENT(2,0,1,0)));
3928 /* set default push delay values (corrected since version 3.0.7-1) */
3929 if (engine_version < VERSION_IDENT(3,0,7,1))
3931 game.default_push_delay_fixed = 2;
3932 game.default_push_delay_random = 8;
3936 game.default_push_delay_fixed = 8;
3937 game.default_push_delay_random = 8;
3942 /* set uninitialized push delay values of custom elements in older levels */
3943 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3945 int element = EL_CUSTOM_START + i;
3947 if (element_info[element].push_delay_fixed == -1)
3948 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3949 if (element_info[element].push_delay_random == -1)
3950 element_info[element].push_delay_random = game.default_push_delay_random;
3955 /* set some other uninitialized values of custom elements in older levels */
3956 if (engine_version < VERSION_IDENT(3,1,0,0))
3958 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3960 int element = EL_CUSTOM_START + i;
3962 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3964 element_info[element].explosion_delay = 17;
3965 element_info[element].ignition_delay = 8;
3971 /* set element properties that were handled incorrectly in older levels */
3972 if (engine_version < VERSION_IDENT(3,1,0,0))
3974 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3975 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3979 /* this is needed because some graphics depend on element properties */
3980 if (game_status == GAME_MODE_PLAYING)
3981 InitElementGraphicInfo();
3984 void InitElementPropertiesAfterLoading(int engine_version)
3989 /* set default push delay values (corrected since version 3.0.7-1) */
3990 if (engine_version < VERSION_IDENT(3,0,7,1))
3992 game.default_push_delay_fixed = 2;
3993 game.default_push_delay_random = 8;
3997 game.default_push_delay_fixed = 8;
3998 game.default_push_delay_random = 8;
4003 /* set uninitialized push delay values of custom elements in older levels */
4004 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4006 int element = EL_CUSTOM_START + i;
4008 if (element_info[element].push_delay_fixed == -1)
4009 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4010 if (element_info[element].push_delay_random == -1)
4011 element_info[element].push_delay_random = game.default_push_delay_random;
4016 /* set some other uninitialized values of custom elements in older levels */
4017 if (engine_version < VERSION_IDENT(3,1,0,0))
4019 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4021 int element = EL_CUSTOM_START + i;
4023 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4025 element_info[element].explosion_delay = 17;
4026 element_info[element].ignition_delay = 8;
4032 static void InitGlobal()
4036 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4038 /* check if element_name_info entry defined for each element in "main.h" */
4039 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4040 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4042 element_info[i].token_name = element_name_info[i].token_name;
4043 element_info[i].class_name = element_name_info[i].class_name;
4044 element_info[i].editor_description=element_name_info[i].editor_description;
4047 global.autoplay_leveldir = NULL;
4048 global.convert_leveldir = NULL;
4050 global.frames_per_second = 0;
4051 global.fps_slowdown = FALSE;
4052 global.fps_slowdown_factor = 1;
4055 void Execute_Command(char *command)
4059 if (strEqual(command, "print graphicsinfo.conf"))
4061 printf("# You can configure additional/alternative image files here.\n");
4062 printf("# (The entries below are default and therefore commented out.)\n");
4064 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4066 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4069 for (i = 0; image_config[i].token != NULL; i++)
4070 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4071 image_config[i].value));
4075 else if (strEqual(command, "print soundsinfo.conf"))
4077 printf("# You can configure additional/alternative sound files here.\n");
4078 printf("# (The entries below are default and therefore commented out.)\n");
4080 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4082 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4085 for (i = 0; sound_config[i].token != NULL; i++)
4086 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4087 sound_config[i].value));
4091 else if (strEqual(command, "print musicinfo.conf"))
4093 printf("# You can configure additional/alternative music files here.\n");
4094 printf("# (The entries below are default and therefore commented out.)\n");
4096 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4098 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4101 for (i = 0; music_config[i].token != NULL; i++)
4102 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4103 music_config[i].value));
4107 else if (strEqual(command, "print editorsetup.conf"))
4109 printf("# You can configure your personal editor element list here.\n");
4110 printf("# (The entries below are default and therefore commented out.)\n");
4113 /* this is needed to be able to check element list for cascade elements */
4114 InitElementPropertiesStatic();
4115 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4117 PrintEditorElementList();
4121 else if (strEqual(command, "print helpanim.conf"))
4123 printf("# You can configure different element help animations here.\n");
4124 printf("# (The entries below are default and therefore commented out.)\n");
4127 for (i = 0; helpanim_config[i].token != NULL; i++)
4129 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4130 helpanim_config[i].value));
4132 if (strEqual(helpanim_config[i].token, "end"))
4138 else if (strEqual(command, "print helptext.conf"))
4140 printf("# You can configure different element help text here.\n");
4141 printf("# (The entries below are default and therefore commented out.)\n");
4144 for (i = 0; helptext_config[i].token != NULL; i++)
4145 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4146 helptext_config[i].value));
4150 else if (strncmp(command, "dump level ", 11) == 0)
4152 char *filename = &command[11];
4154 if (!fileExists(filename))
4155 Error(ERR_EXIT, "cannot open file '%s'", filename);
4157 LoadLevelFromFilename(&level, filename);
4162 else if (strncmp(command, "dump tape ", 10) == 0)
4164 char *filename = &command[10];
4166 if (!fileExists(filename))
4167 Error(ERR_EXIT, "cannot open file '%s'", filename);
4169 LoadTapeFromFilename(filename);
4174 else if (strncmp(command, "autoplay ", 9) == 0)
4176 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4178 while (*str_ptr != '\0') /* continue parsing string */
4180 /* cut leading whitespace from string, replace it by string terminator */
4181 while (*str_ptr == ' ' || *str_ptr == '\t')
4184 if (*str_ptr == '\0') /* end of string reached */
4187 if (global.autoplay_leveldir == NULL) /* read level set string */
4189 global.autoplay_leveldir = str_ptr;
4190 global.autoplay_all = TRUE; /* default: play all tapes */
4192 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4193 global.autoplay_level[i] = FALSE;
4195 else /* read level number string */
4197 int level_nr = atoi(str_ptr); /* get level_nr value */
4199 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4200 global.autoplay_level[level_nr] = TRUE;
4202 global.autoplay_all = FALSE;
4205 /* advance string pointer to the next whitespace (or end of string) */
4206 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4210 else if (strncmp(command, "convert ", 8) == 0)
4212 char *str_copy = getStringCopy(&command[8]);
4213 char *str_ptr = strchr(str_copy, ' ');
4215 global.convert_leveldir = str_copy;
4216 global.convert_level_nr = -1;
4218 if (str_ptr != NULL) /* level number follows */
4220 *str_ptr++ = '\0'; /* terminate leveldir string */
4221 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4226 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4230 static void InitSetup()
4232 LoadSetup(); /* global setup info */
4234 /* set some options from setup file */
4236 if (setup.options.verbose)
4237 options.verbose = TRUE;
4240 static void InitGameInfo()
4242 game.restart_level = FALSE;
4245 static void InitPlayerInfo()
4249 /* choose default local player */
4250 local_player = &stored_player[0];
4252 for (i = 0; i < MAX_PLAYERS; i++)
4253 stored_player[i].connected = FALSE;
4255 local_player->connected = TRUE;
4258 static void InitArtworkInfo()
4263 static char *get_string_in_brackets(char *string)
4265 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4267 sprintf(string_in_brackets, "[%s]", string);
4269 return string_in_brackets;
4272 static char *get_level_id_suffix(int id_nr)
4274 char *id_suffix = checked_malloc(1 + 3 + 1);
4276 if (id_nr < 0 || id_nr > 999)
4279 sprintf(id_suffix, ".%03d", id_nr);
4285 static char *get_element_class_token(int element)
4287 char *element_class_name = element_info[element].class_name;
4288 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4290 sprintf(element_class_token, "[%s]", element_class_name);
4292 return element_class_token;
4295 static char *get_action_class_token(int action)
4297 char *action_class_name = &element_action_info[action].suffix[1];
4298 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4300 sprintf(action_class_token, "[%s]", action_class_name);
4302 return action_class_token;
4306 static void InitArtworkConfig()
4308 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4309 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4310 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4311 static char *action_id_suffix[NUM_ACTIONS + 1];
4312 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4313 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4314 static char *level_id_suffix[MAX_LEVELS + 1];
4315 static char *dummy[1] = { NULL };
4316 static char *ignore_generic_tokens[] =
4322 static char **ignore_image_tokens;
4323 static char **ignore_sound_tokens;
4324 static char **ignore_music_tokens;
4325 int num_ignore_generic_tokens;
4326 int num_ignore_image_tokens;
4327 int num_ignore_sound_tokens;
4328 int num_ignore_music_tokens;
4331 /* dynamically determine list of generic tokens to be ignored */
4332 num_ignore_generic_tokens = 0;
4333 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4334 num_ignore_generic_tokens++;
4336 /* dynamically determine list of image tokens to be ignored */
4337 num_ignore_image_tokens = num_ignore_generic_tokens;
4338 for (i = 0; image_config_vars[i].token != NULL; i++)
4339 num_ignore_image_tokens++;
4340 ignore_image_tokens =
4341 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4342 for (i = 0; i < num_ignore_generic_tokens; i++)
4343 ignore_image_tokens[i] = ignore_generic_tokens[i];
4344 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4345 ignore_image_tokens[num_ignore_generic_tokens + i] =
4346 image_config_vars[i].token;
4347 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4349 /* dynamically determine list of sound tokens to be ignored */
4350 num_ignore_sound_tokens = num_ignore_generic_tokens;
4351 ignore_sound_tokens =
4352 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4353 for (i = 0; i < num_ignore_generic_tokens; i++)
4354 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4355 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4357 /* dynamically determine list of music tokens to be ignored */
4358 num_ignore_music_tokens = num_ignore_generic_tokens;
4359 ignore_music_tokens =
4360 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4361 for (i = 0; i < num_ignore_generic_tokens; i++)
4362 ignore_music_tokens[i] = ignore_generic_tokens[i];
4363 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4365 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4366 image_id_prefix[i] = element_info[i].token_name;
4367 for (i = 0; i < NUM_FONTS; i++)
4368 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4369 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4371 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4372 sound_id_prefix[i] = element_info[i].token_name;
4373 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4374 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4375 get_string_in_brackets(element_info[i].class_name);
4376 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4378 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4379 music_id_prefix[i] = music_prefix_info[i].prefix;
4380 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4382 for (i = 0; i < NUM_ACTIONS; i++)
4383 action_id_suffix[i] = element_action_info[i].suffix;
4384 action_id_suffix[NUM_ACTIONS] = NULL;
4386 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4387 direction_id_suffix[i] = element_direction_info[i].suffix;
4388 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4390 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4391 special_id_suffix[i] = special_suffix_info[i].suffix;
4392 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4394 for (i = 0; i < MAX_LEVELS; i++)
4395 level_id_suffix[i] = get_level_id_suffix(i);
4396 level_id_suffix[MAX_LEVELS] = NULL;
4398 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4399 image_id_prefix, action_id_suffix, direction_id_suffix,
4400 special_id_suffix, ignore_image_tokens);
4401 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4402 sound_id_prefix, action_id_suffix, dummy,
4403 special_id_suffix, ignore_sound_tokens);
4404 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4405 music_id_prefix, special_id_suffix, level_id_suffix,
4406 dummy, ignore_music_tokens);
4409 static void InitMixer()
4417 char *filename_font_initial = NULL;
4418 Bitmap *bitmap_font_initial = NULL;
4421 /* determine settings for initial font (for displaying startup messages) */
4422 for (i = 0; image_config[i].token != NULL; i++)
4424 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4426 char font_token[128];
4429 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4430 len_font_token = strlen(font_token);
4432 if (strEqual(image_config[i].token, font_token))
4433 filename_font_initial = image_config[i].value;
4434 else if (strlen(image_config[i].token) > len_font_token &&
4435 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4437 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4438 font_initial[j].src_x = atoi(image_config[i].value);
4439 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4440 font_initial[j].src_y = atoi(image_config[i].value);
4441 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4442 font_initial[j].width = atoi(image_config[i].value);
4443 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4444 font_initial[j].height = atoi(image_config[i].value);
4449 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4451 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4452 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4455 if (filename_font_initial == NULL) /* should not happen */
4456 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4458 /* create additional image buffers for double-buffering and cross-fading */
4459 bitmap_db_title = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4460 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4461 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4463 /* initialize screen properties */
4464 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4465 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4467 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4468 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4469 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4471 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4473 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4474 font_initial[j].bitmap = bitmap_font_initial;
4476 InitFontGraphicInfo();
4478 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4479 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4481 DrawInitText("Loading graphics:", 120, FC_GREEN);
4484 void RedrawBackground()
4486 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4487 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4489 redraw_mask = REDRAW_ALL;
4492 void InitGfxBackground()
4496 drawto = backbuffer;
4497 fieldbuffer = bitmap_db_field;
4498 SetDrawtoField(DRAW_BACKBUFFER);
4502 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4503 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4505 for (x = 0; x < MAX_BUF_XSIZE; x++)
4506 for (y = 0; y < MAX_BUF_YSIZE; y++)
4509 redraw_mask = REDRAW_ALL;
4512 static void InitLevelInfo()
4514 LoadLevelInfo(); /* global level info */
4515 LoadLevelSetup_LastSeries(); /* last played series info */
4516 LoadLevelSetup_SeriesInfo(); /* last played level info */
4519 void InitLevelArtworkInfo()
4521 LoadLevelArtworkInfo();
4524 static void InitImages()
4526 setLevelArtworkDir(artwork.gfx_first);
4529 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4530 leveldir_current->identifier,
4531 artwork.gfx_current_identifier,
4532 artwork.gfx_current->identifier,
4533 leveldir_current->graphics_set,
4534 leveldir_current->graphics_path);
4537 ReloadCustomImages();
4539 LoadCustomElementDescriptions();
4540 LoadSpecialMenuDesignSettings();
4542 ReinitializeGraphics();
4545 static void InitSound(char *identifier)
4547 if (identifier == NULL)
4548 identifier = artwork.snd_current->identifier;
4550 /* set artwork path to send it to the sound server process */
4551 setLevelArtworkDir(artwork.snd_first);
4553 InitReloadCustomSounds(identifier);
4554 ReinitializeSounds();
4557 static void InitMusic(char *identifier)
4559 if (identifier == NULL)
4560 identifier = artwork.mus_current->identifier;
4562 /* set artwork path to send it to the sound server process */
4563 setLevelArtworkDir(artwork.mus_first);
4565 InitReloadCustomMusic(identifier);
4566 ReinitializeMusic();
4569 void InitNetworkServer()
4571 #if defined(NETWORK_AVALIABLE)
4575 if (!options.network)
4578 #if defined(NETWORK_AVALIABLE)
4579 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4581 if (!ConnectToServer(options.server_host, options.server_port))
4582 Error(ERR_EXIT, "cannot connect to network game server");
4584 SendToServer_PlayerName(setup.player_name);
4585 SendToServer_ProtocolVersion();
4588 SendToServer_NrWanted(nr_wanted);
4592 static char *getNewArtworkIdentifier(int type)
4594 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4595 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4596 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4597 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4598 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4599 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4600 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4601 char *leveldir_identifier = leveldir_current->identifier;
4603 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4604 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4606 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4608 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4609 char *artwork_current_identifier;
4610 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4612 /* leveldir_current may be invalid (level group, parent link) */
4613 if (!validLevelSeries(leveldir_current))
4616 /* 1st step: determine artwork set to be activated in descending order:
4617 --------------------------------------------------------------------
4618 1. setup artwork (when configured to override everything else)
4619 2. artwork set configured in "levelinfo.conf" of current level set
4620 (artwork in level directory will have priority when loading later)
4621 3. artwork in level directory (stored in artwork sub-directory)
4622 4. setup artwork (currently configured in setup menu) */
4624 if (setup_override_artwork)
4625 artwork_current_identifier = setup_artwork_set;
4626 else if (leveldir_artwork_set != NULL)
4627 artwork_current_identifier = leveldir_artwork_set;
4628 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4629 artwork_current_identifier = leveldir_identifier;
4631 artwork_current_identifier = setup_artwork_set;
4634 /* 2nd step: check if it is really needed to reload artwork set
4635 ------------------------------------------------------------ */
4638 if (type == ARTWORK_TYPE_GRAPHICS)
4639 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4640 artwork_new_identifier,
4641 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4642 artwork_current_identifier,
4643 leveldir_current->graphics_set,
4644 leveldir_current->identifier);
4647 /* ---------- reload if level set and also artwork set has changed ------- */
4648 if (leveldir_current_identifier[type] != leveldir_identifier &&
4649 (last_has_level_artwork_set[type] || has_level_artwork_set))
4650 artwork_new_identifier = artwork_current_identifier;
4652 leveldir_current_identifier[type] = leveldir_identifier;
4653 last_has_level_artwork_set[type] = has_level_artwork_set;
4656 if (type == ARTWORK_TYPE_GRAPHICS)
4657 printf("::: 1: '%s'\n", artwork_new_identifier);
4660 /* ---------- reload if "override artwork" setting has changed ----------- */
4661 if (last_override_level_artwork[type] != setup_override_artwork)
4662 artwork_new_identifier = artwork_current_identifier;
4664 last_override_level_artwork[type] = setup_override_artwork;
4667 if (type == ARTWORK_TYPE_GRAPHICS)
4668 printf("::: 2: '%s'\n", artwork_new_identifier);
4671 /* ---------- reload if current artwork identifier has changed ----------- */
4672 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4673 artwork_current_identifier))
4674 artwork_new_identifier = artwork_current_identifier;
4676 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4679 if (type == ARTWORK_TYPE_GRAPHICS)
4680 printf("::: 3: '%s'\n", artwork_new_identifier);
4683 /* ---------- do not reload directly after starting ---------------------- */
4684 if (!initialized[type])
4685 artwork_new_identifier = NULL;
4687 initialized[type] = TRUE;
4690 if (type == ARTWORK_TYPE_GRAPHICS)
4691 printf("::: 4: '%s'\n", artwork_new_identifier);
4695 if (type == ARTWORK_TYPE_GRAPHICS)
4696 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4697 artwork.gfx_current_identifier, artwork_current_identifier,
4698 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4699 artwork_new_identifier);
4702 return artwork_new_identifier;
4705 void ReloadCustomArtwork(int force_reload)
4707 char *gfx_new_identifier;
4708 char *snd_new_identifier;
4709 char *mus_new_identifier;
4710 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4711 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4712 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4713 boolean redraw_screen = FALSE;
4715 force_reload_gfx |= AdjustGraphicsForEMC();
4717 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4718 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4719 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4721 if (gfx_new_identifier != NULL || force_reload_gfx)
4724 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4725 artwork.gfx_current_identifier,
4727 artwork.gfx_current->identifier,
4728 leveldir_current->graphics_set);
4731 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4735 redraw_screen = TRUE;
4738 if (snd_new_identifier != NULL || force_reload_snd)
4740 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4742 InitSound(snd_new_identifier);
4744 redraw_screen = TRUE;
4747 if (mus_new_identifier != NULL || force_reload_mus)
4749 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4751 InitMusic(mus_new_identifier);
4753 redraw_screen = TRUE;
4761 InitGfxBackground();
4764 /* force redraw of (open or closed) door graphics */
4765 SetDoorState(DOOR_OPEN_ALL);
4766 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4770 void KeyboardAutoRepeatOffUnlessAutoplay()
4772 if (global.autoplay_leveldir == NULL)
4773 KeyboardAutoRepeatOff();
4777 /* ========================================================================= */
4779 /* ========================================================================= */
4783 InitGlobal(); /* initialize some global variables */
4785 if (options.execute_command)
4786 Execute_Command(options.execute_command);
4788 if (options.serveronly)
4790 #if defined(PLATFORM_UNIX)
4791 NetworkServer(options.server_port, options.serveronly);
4793 Error(ERR_WARN, "networking only supported in Unix version");
4796 exit(0); /* never reached, server loops forever */
4803 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4804 InitArtworkConfig(); /* needed before forking sound child process */
4809 InitRND(NEW_RANDOMIZE);
4810 InitSimpleRND(NEW_RANDOMIZE);
4815 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4818 InitEventFilter(FilterMouseMotionEvents);
4820 InitElementPropertiesStatic();
4821 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4826 InitLevelArtworkInfo();
4828 InitImages(); /* needs to know current level directory */
4829 InitSound(NULL); /* needs to know current level directory */
4830 InitMusic(NULL); /* needs to know current level directory */
4832 InitGfxBackground();
4834 if (global.autoplay_leveldir)
4839 else if (global.convert_leveldir)
4845 game_status = GAME_MODE_MAIN;
4853 InitNetworkServer();
4856 void CloseAllAndExit(int exit_value)
4861 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4869 #if defined(TARGET_SDL)
4870 if (network_server) /* terminate network server */
4871 SDL_KillThread(server_thread);
4874 CloseVideoDisplay();
4875 ClosePlatformDependentStuff();