1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 gadgets_initialized = TRUE;
110 inline void InitElementSmallImagesScaledUp(int graphic)
112 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
115 void InitElementSmallImages()
117 static int special_graphics[] =
119 IMG_EDITOR_ELEMENT_BORDER,
120 IMG_EDITOR_ELEMENT_BORDER_INPUT,
121 IMG_EDITOR_CASCADE_LIST,
122 IMG_EDITOR_CASCADE_LIST_ACTIVE,
125 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126 int num_property_mappings = getImageListPropertyMappingSize();
129 /* initialize normal images from static configuration */
130 for (i = 0; element_to_graphic[i].element > -1; i++)
131 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
133 /* initialize special images from static configuration */
134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
135 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
137 /* initialize images from dynamic configuration (may be elements or other) */
138 for (i = 0; i < num_property_mappings; i++)
139 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
141 /* initialize special images from above list (non-element images) */
142 for (i = 0; special_graphics[i] > -1; i++)
143 InitElementSmallImagesScaledUp(special_graphics[i]);
146 void InitScaledImages()
150 /* scale normal images from static configuration, if not already scaled */
151 for (i = 0; i < NUM_IMAGE_FILES; i++)
152 ScaleImage(i, graphic_info[i].scale_up_factor);
156 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
157 void SetBitmaps_EM(Bitmap **em_bitmap)
159 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
160 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
164 static int getFontBitmapID(int font_nr)
168 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
169 special = game_status;
170 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
171 special = GFX_SPECIAL_ARG_MAIN;
172 else if (game_status == GAME_MODE_PLAYING)
173 special = GFX_SPECIAL_ARG_DOOR;
176 return font_info[font_nr].special_bitmap_id[special];
181 void InitFontGraphicInfo()
183 static struct FontBitmapInfo *font_bitmap_info = NULL;
184 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
185 int num_property_mappings = getImageListPropertyMappingSize();
186 int num_font_bitmaps = NUM_FONTS;
189 if (graphic_info == NULL) /* still at startup phase */
191 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
196 /* ---------- initialize font graphic definitions ---------- */
198 /* always start with reliable default values (normal font graphics) */
199 for (i = 0; i < NUM_FONTS; i++)
200 font_info[i].graphic = IMG_FONT_INITIAL_1;
202 /* initialize normal font/graphic mapping from static configuration */
203 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
205 int font_nr = font_to_graphic[i].font_nr;
206 int special = font_to_graphic[i].special;
207 int graphic = font_to_graphic[i].graphic;
212 font_info[font_nr].graphic = graphic;
215 /* always start with reliable default values (special font graphics) */
216 for (i = 0; i < NUM_FONTS; i++)
218 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
220 font_info[i].special_graphic[j] = font_info[i].graphic;
221 font_info[i].special_bitmap_id[j] = i;
225 /* initialize special font/graphic mapping from static configuration */
226 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
228 int font_nr = font_to_graphic[i].font_nr;
229 int special = font_to_graphic[i].special;
230 int graphic = font_to_graphic[i].graphic;
231 int base_graphic = font2baseimg(font_nr);
233 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
235 boolean base_redefined =
236 getImageListEntryFromImageID(base_graphic)->redefined;
237 boolean special_redefined =
238 getImageListEntryFromImageID(graphic)->redefined;
240 /* if the base font ("font.title_1", for example) has been redefined,
241 but not the special font ("font.title_1.LEVELS", for example), do not
242 use an existing (in this case considered obsolete) special font
243 anymore, but use the automatically determined default font */
244 if (base_redefined && !special_redefined)
247 font_info[font_nr].special_graphic[special] = graphic;
248 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
253 /* initialize special font/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 /* reset non-redefined ".active" font graphics if normal font is redefined */
272 /* (this different treatment is needed because normal and active fonts are
273 independently defined ("active" is not a property of font definitions!) */
274 for (i = 0; i < NUM_FONTS; i++)
276 int font_nr_base = i;
277 int font_nr_active = FONT_ACTIVE(font_nr_base);
279 /* check only those fonts with exist as normal and ".active" variant */
280 if (font_nr_base != font_nr_active)
282 int base_graphic = font_info[font_nr_base].graphic;
283 int active_graphic = font_info[font_nr_active].graphic;
284 boolean base_redefined =
285 getImageListEntryFromImageID(base_graphic)->redefined;
286 boolean active_redefined =
287 getImageListEntryFromImageID(active_graphic)->redefined;
289 /* if the base font ("font.menu_1", for example) has been redefined,
290 but not the active font ("font.menu_1.active", for example), do not
291 use an existing (in this case considered obsolete) active font
292 anymore, but use the automatically determined default font */
293 if (base_redefined && !active_redefined)
294 font_info[font_nr_active].graphic = base_graphic;
296 /* now also check each "special" font (which may be the same as above) */
297 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
299 int base_graphic = font_info[font_nr_base].special_graphic[j];
300 int active_graphic = font_info[font_nr_active].special_graphic[j];
301 boolean base_redefined =
302 getImageListEntryFromImageID(base_graphic)->redefined;
303 boolean active_redefined =
304 getImageListEntryFromImageID(active_graphic)->redefined;
306 /* same as above, but check special graphic definitions, for example:
307 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
308 if (base_redefined && !active_redefined)
310 font_info[font_nr_active].special_graphic[j] =
311 font_info[font_nr_base].special_graphic[j];
312 font_info[font_nr_active].special_bitmap_id[j] =
313 font_info[font_nr_base].special_bitmap_id[j];
319 /* ---------- initialize font bitmap array ---------- */
321 if (font_bitmap_info != NULL)
322 FreeFontInfo(font_bitmap_info);
325 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
327 /* ---------- initialize font bitmap definitions ---------- */
329 for (i = 0; i < NUM_FONTS; i++)
331 if (i < NUM_INITIAL_FONTS)
333 font_bitmap_info[i] = font_initial[i];
337 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
339 int font_bitmap_id = font_info[i].special_bitmap_id[j];
340 int graphic = font_info[i].special_graphic[j];
342 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
343 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
345 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
346 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
349 /* copy font relevant information from graphics information */
350 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
351 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
352 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
353 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
354 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
356 font_bitmap_info[font_bitmap_id].draw_xoffset =
357 graphic_info[graphic].draw_xoffset;
358 font_bitmap_info[font_bitmap_id].draw_yoffset =
359 graphic_info[graphic].draw_yoffset;
361 font_bitmap_info[font_bitmap_id].num_chars =
362 graphic_info[graphic].anim_frames;
363 font_bitmap_info[font_bitmap_id].num_chars_per_line =
364 graphic_info[graphic].anim_frames_per_line;
368 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
371 void InitElementGraphicInfo()
373 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
374 int num_property_mappings = getImageListPropertyMappingSize();
377 if (graphic_info == NULL) /* still at startup phase */
380 /* set values to -1 to identify later as "uninitialized" values */
381 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
383 for (act = 0; act < NUM_ACTIONS; act++)
385 element_info[i].graphic[act] = -1;
386 element_info[i].crumbled[act] = -1;
388 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
390 element_info[i].direction_graphic[act][dir] = -1;
391 element_info[i].direction_crumbled[act][dir] = -1;
396 /* initialize normal element/graphic mapping from static configuration */
397 for (i = 0; element_to_graphic[i].element > -1; i++)
399 int element = element_to_graphic[i].element;
400 int action = element_to_graphic[i].action;
401 int direction = element_to_graphic[i].direction;
402 boolean crumbled = element_to_graphic[i].crumbled;
403 int graphic = element_to_graphic[i].graphic;
404 int base_graphic = el2baseimg(element);
406 if (graphic_info[graphic].bitmap == NULL)
409 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
412 boolean base_redefined =
413 getImageListEntryFromImageID(base_graphic)->redefined;
414 boolean act_dir_redefined =
415 getImageListEntryFromImageID(graphic)->redefined;
417 /* if the base graphic ("emerald", for example) has been redefined,
418 but not the action graphic ("emerald.falling", for example), do not
419 use an existing (in this case considered obsolete) action graphic
420 anymore, but use the automatically determined default graphic */
421 if (base_redefined && !act_dir_redefined)
426 action = ACTION_DEFAULT;
431 element_info[element].direction_crumbled[action][direction] = graphic;
433 element_info[element].crumbled[action] = graphic;
438 element_info[element].direction_graphic[action][direction] = graphic;
440 element_info[element].graphic[action] = graphic;
444 /* initialize normal element/graphic mapping from dynamic configuration */
445 for (i = 0; i < num_property_mappings; i++)
447 int element = property_mapping[i].base_index;
448 int action = property_mapping[i].ext1_index;
449 int direction = property_mapping[i].ext2_index;
450 int special = property_mapping[i].ext3_index;
451 int graphic = property_mapping[i].artwork_index;
452 boolean crumbled = FALSE;
454 if (special == GFX_SPECIAL_ARG_CRUMBLED)
460 if (graphic_info[graphic].bitmap == NULL)
463 if (element >= MAX_NUM_ELEMENTS || special != -1)
467 action = ACTION_DEFAULT;
472 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
473 element_info[element].direction_crumbled[action][dir] = -1;
476 element_info[element].direction_crumbled[action][direction] = graphic;
478 element_info[element].crumbled[action] = graphic;
483 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
484 element_info[element].direction_graphic[action][dir] = -1;
487 element_info[element].direction_graphic[action][direction] = graphic;
489 element_info[element].graphic[action] = graphic;
493 /* now copy all graphics that are defined to be cloned from other graphics */
494 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
496 int graphic = element_info[i].graphic[ACTION_DEFAULT];
497 int crumbled_like, diggable_like;
502 crumbled_like = graphic_info[graphic].crumbled_like;
503 diggable_like = graphic_info[graphic].diggable_like;
505 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
507 for (act = 0; act < NUM_ACTIONS; act++)
508 element_info[i].crumbled[act] =
509 element_info[crumbled_like].crumbled[act];
510 for (act = 0; act < NUM_ACTIONS; act++)
511 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
512 element_info[i].direction_crumbled[act][dir] =
513 element_info[crumbled_like].direction_crumbled[act][dir];
516 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
518 element_info[i].graphic[ACTION_DIGGING] =
519 element_info[diggable_like].graphic[ACTION_DIGGING];
520 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
521 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
522 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
527 /* set hardcoded definitions for some runtime elements without graphic */
528 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
532 /* set hardcoded definitions for some internal elements without graphic */
533 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
535 if (IS_EDITOR_CASCADE_INACTIVE(i))
536 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
537 else if (IS_EDITOR_CASCADE_ACTIVE(i))
538 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
542 /* now set all undefined/invalid graphics to -1 to set to default after it */
543 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
545 for (act = 0; act < NUM_ACTIONS; act++)
549 graphic = element_info[i].graphic[act];
550 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
551 element_info[i].graphic[act] = -1;
553 graphic = element_info[i].crumbled[act];
554 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
555 element_info[i].crumbled[act] = -1;
557 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
559 graphic = element_info[i].direction_graphic[act][dir];
560 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
561 element_info[i].direction_graphic[act][dir] = -1;
563 graphic = element_info[i].direction_crumbled[act][dir];
564 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
565 element_info[i].direction_crumbled[act][dir] = -1;
570 /* adjust graphics with 2nd tile for movement according to direction
571 (do this before correcting '-1' values to minimize calculations) */
572 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
574 for (act = 0; act < NUM_ACTIONS; act++)
576 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
578 int graphic = element_info[i].direction_graphic[act][dir];
579 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
581 if (act == ACTION_FALLING) /* special case */
582 graphic = element_info[i].graphic[act];
585 graphic_info[graphic].double_movement &&
586 graphic_info[graphic].swap_double_tiles != 0)
588 struct GraphicInfo *g = &graphic_info[graphic];
589 int src_x_front = g->src_x;
590 int src_y_front = g->src_y;
591 int src_x_back = g->src_x + g->offset2_x;
592 int src_y_back = g->src_y + g->offset2_y;
593 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
595 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
596 src_y_front < src_y_back);
597 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
598 boolean swap_movement_tiles_autodetected =
599 (!frames_are_ordered_diagonally &&
600 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
601 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
602 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
603 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
606 /* swap frontside and backside graphic tile coordinates, if needed */
607 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
609 /* get current (wrong) backside tile coordinates */
610 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
613 /* set frontside tile coordinates to backside tile coordinates */
614 g->src_x = src_x_back;
615 g->src_y = src_y_back;
617 /* invert tile offset to point to new backside tile coordinates */
621 /* do not swap front and backside tiles again after correction */
622 g->swap_double_tiles = 0;
629 /* now set all '-1' values to element specific default values */
630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
632 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
633 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
634 int default_direction_graphic[NUM_DIRECTIONS_FULL];
635 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
637 if (default_graphic == -1)
638 default_graphic = IMG_UNKNOWN;
640 if (default_crumbled == -1)
641 default_crumbled = default_graphic;
643 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
644 if (default_crumbled == -1)
645 default_crumbled = IMG_EMPTY;
648 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
650 default_direction_graphic[dir] =
651 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
652 default_direction_crumbled[dir] =
653 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
655 if (default_direction_graphic[dir] == -1)
656 default_direction_graphic[dir] = default_graphic;
658 if (default_direction_crumbled[dir] == -1)
659 default_direction_crumbled[dir] = default_direction_graphic[dir];
661 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
662 if (default_direction_crumbled[dir] == -1)
663 default_direction_crumbled[dir] = default_crumbled;
667 for (act = 0; act < NUM_ACTIONS; act++)
669 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
670 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
671 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
672 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
673 act == ACTION_TURNING_FROM_RIGHT ||
674 act == ACTION_TURNING_FROM_UP ||
675 act == ACTION_TURNING_FROM_DOWN);
677 /* generic default action graphic (defined by "[default]" directive) */
678 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
680 int default_remove_graphic = IMG_EMPTY;
682 if (act_remove && default_action_graphic != -1)
683 default_remove_graphic = default_action_graphic;
685 /* look for special default action graphic (classic game specific) */
686 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
687 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
688 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
689 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
690 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
691 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
693 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
694 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
695 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
696 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
697 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
698 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
701 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
702 /* !!! make this better !!! */
703 if (i == EL_EMPTY_SPACE)
705 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
706 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
710 if (default_action_graphic == -1)
711 default_action_graphic = default_graphic;
713 if (default_action_crumbled == -1)
714 default_action_crumbled = default_action_graphic;
716 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
717 if (default_action_crumbled == -1)
718 default_action_crumbled = default_crumbled;
721 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
723 /* use action graphic as the default direction graphic, if undefined */
724 int default_action_direction_graphic = element_info[i].graphic[act];
725 int default_action_direction_crumbled = element_info[i].crumbled[act];
727 /* no graphic for current action -- use default direction graphic */
728 if (default_action_direction_graphic == -1)
729 default_action_direction_graphic =
730 (act_remove ? default_remove_graphic :
732 element_info[i].direction_graphic[ACTION_TURNING][dir] :
733 default_action_graphic != default_graphic ?
734 default_action_graphic :
735 default_direction_graphic[dir]);
737 if (element_info[i].direction_graphic[act][dir] == -1)
738 element_info[i].direction_graphic[act][dir] =
739 default_action_direction_graphic;
742 if (default_action_direction_crumbled == -1)
743 default_action_direction_crumbled =
744 element_info[i].direction_graphic[act][dir];
746 if (default_action_direction_crumbled == -1)
747 default_action_direction_crumbled =
748 (act_remove ? default_remove_graphic :
750 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
751 default_action_crumbled != default_crumbled ?
752 default_action_crumbled :
753 default_direction_crumbled[dir]);
756 if (element_info[i].direction_crumbled[act][dir] == -1)
757 element_info[i].direction_crumbled[act][dir] =
758 default_action_direction_crumbled;
761 /* no graphic for this specific action -- use default action graphic */
762 if (element_info[i].graphic[act] == -1)
763 element_info[i].graphic[act] =
764 (act_remove ? default_remove_graphic :
765 act_turning ? element_info[i].graphic[ACTION_TURNING] :
766 default_action_graphic);
768 if (element_info[i].crumbled[act] == -1)
769 element_info[i].crumbled[act] = element_info[i].graphic[act];
771 if (element_info[i].crumbled[act] == -1)
772 element_info[i].crumbled[act] =
773 (act_remove ? default_remove_graphic :
774 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
775 default_action_crumbled);
781 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
782 /* set animation mode to "none" for each graphic with only 1 frame */
783 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
785 for (act = 0; act < NUM_ACTIONS; act++)
787 int graphic = element_info[i].graphic[act];
788 int crumbled = element_info[i].crumbled[act];
790 if (graphic_info[graphic].anim_frames == 1)
791 graphic_info[graphic].anim_mode = ANIM_NONE;
792 if (graphic_info[crumbled].anim_frames == 1)
793 graphic_info[crumbled].anim_mode = ANIM_NONE;
795 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
797 graphic = element_info[i].direction_graphic[act][dir];
798 crumbled = element_info[i].direction_crumbled[act][dir];
800 if (graphic_info[graphic].anim_frames == 1)
801 graphic_info[graphic].anim_mode = ANIM_NONE;
802 if (graphic_info[crumbled].anim_frames == 1)
803 graphic_info[crumbled].anim_mode = ANIM_NONE;
813 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
814 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
816 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
817 element_info[i].token_name, i);
823 void InitElementSpecialGraphicInfo()
825 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
826 int num_property_mappings = getImageListPropertyMappingSize();
829 /* always start with reliable default values */
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
832 element_info[i].special_graphic[j] =
833 element_info[i].graphic[ACTION_DEFAULT];
835 /* initialize special element/graphic mapping from static configuration */
836 for (i = 0; element_to_special_graphic[i].element > -1; i++)
838 int element = element_to_special_graphic[i].element;
839 int special = element_to_special_graphic[i].special;
840 int graphic = element_to_special_graphic[i].graphic;
841 int base_graphic = el2baseimg(element);
842 boolean base_redefined =
843 getImageListEntryFromImageID(base_graphic)->redefined;
844 boolean special_redefined =
845 getImageListEntryFromImageID(graphic)->redefined;
847 /* if the base graphic ("emerald", for example) has been redefined,
848 but not the special graphic ("emerald.EDITOR", for example), do not
849 use an existing (in this case considered obsolete) special graphic
850 anymore, but use the automatically created (down-scaled) graphic */
851 if (base_redefined && !special_redefined)
854 element_info[element].special_graphic[special] = graphic;
857 /* initialize special element/graphic mapping from dynamic configuration */
858 for (i = 0; i < num_property_mappings; i++)
860 int element = property_mapping[i].base_index;
861 int special = property_mapping[i].ext3_index;
862 int graphic = property_mapping[i].artwork_index;
864 if (element >= MAX_NUM_ELEMENTS)
867 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
868 element_info[element].special_graphic[special] = graphic;
871 /* now set all undefined/invalid graphics to default */
872 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
873 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
874 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
875 element_info[i].special_graphic[j] =
876 element_info[i].graphic[ACTION_DEFAULT];
879 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
884 if (type != TYPE_TOKEN)
885 return get_parameter_value(value_raw, suffix, type);
887 if (strEqual(value_raw, ARG_UNDEFINED))
888 return ARG_UNDEFINED_VALUE;
890 /* !!! OPTIMIZE THIS BY USING HASH !!! */
891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
892 if (strEqual(element_info[i].token_name, value_raw))
895 /* !!! OPTIMIZE THIS BY USING HASH !!! */
896 for (i = 0; image_config[i].token != NULL; i++)
898 int len_config_value = strlen(image_config[i].value);
900 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
901 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
902 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
905 if (strEqual(image_config[i].token, value_raw))
914 static int get_scaled_graphic_width(int graphic)
916 int original_width = getOriginalImageWidthFromImageID(graphic);
917 int scale_up_factor = graphic_info[graphic].scale_up_factor;
919 return original_width * scale_up_factor;
922 static int get_scaled_graphic_height(int graphic)
924 int original_height = getOriginalImageHeightFromImageID(graphic);
925 int scale_up_factor = graphic_info[graphic].scale_up_factor;
927 return original_height * scale_up_factor;
930 static void set_graphic_parameters(int graphic)
932 struct FileInfo *image = getImageListEntryFromImageID(graphic);
933 char **parameter_raw = image->parameter;
934 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
935 int parameter[NUM_GFX_ARGS];
936 int anim_frames_per_row = 1, anim_frames_per_col = 1;
937 int anim_frames_per_line = 1;
940 /* if fallback to default artwork is done, also use the default parameters */
941 if (image->fallback_to_default)
942 parameter_raw = image->default_parameter;
944 /* get integer values from string parameters */
945 for (i = 0; i < NUM_GFX_ARGS; i++)
946 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
947 image_config_suffix[i].token,
948 image_config_suffix[i].type);
950 graphic_info[graphic].bitmap = src_bitmap;
952 /* start with reliable default values */
953 graphic_info[graphic].src_image_width = 0;
954 graphic_info[graphic].src_image_height = 0;
955 graphic_info[graphic].src_x = 0;
956 graphic_info[graphic].src_y = 0;
957 graphic_info[graphic].width = TILEX;
958 graphic_info[graphic].height = TILEY;
959 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
960 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
961 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
962 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
963 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
964 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
965 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
966 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
967 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
968 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
969 graphic_info[graphic].anim_delay_fixed = 0;
970 graphic_info[graphic].anim_delay_random = 0;
971 graphic_info[graphic].post_delay_fixed = 0;
972 graphic_info[graphic].post_delay_random = 0;
974 /* optional x and y tile position of animation frame sequence */
975 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
976 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
977 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
978 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
980 /* optional x and y pixel position of animation frame sequence */
981 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
982 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
983 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
984 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
986 /* optional width and height of each animation frame */
987 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
988 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
989 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
990 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
992 /* optional zoom factor for scaling up the image to a larger size */
993 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
994 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
995 if (graphic_info[graphic].scale_up_factor < 1)
996 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1000 /* get final bitmap size (with scaling, but without small images) */
1001 int src_image_width = get_scaled_graphic_width(graphic);
1002 int src_image_height = get_scaled_graphic_height(graphic);
1004 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1005 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1007 graphic_info[graphic].src_image_width = src_image_width;
1008 graphic_info[graphic].src_image_height = src_image_height;
1011 /* correct x or y offset dependent of vertical or horizontal frame order */
1012 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1014 graphic_info[graphic].offset_y =
1015 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1016 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1017 anim_frames_per_line = anim_frames_per_col;
1019 else /* frames are ordered horizontally */
1021 graphic_info[graphic].offset_x =
1022 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1023 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1024 anim_frames_per_line = anim_frames_per_row;
1027 /* optionally, the x and y offset of frames can be specified directly */
1028 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1030 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1031 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1033 /* optionally, moving animations may have separate start and end graphics */
1034 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1036 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1037 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1039 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1040 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1041 graphic_info[graphic].offset2_y =
1042 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1043 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1044 else /* frames are ordered horizontally */
1045 graphic_info[graphic].offset2_x =
1046 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1047 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1049 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1050 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1051 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1052 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1055 /* optionally, the second movement tile can be specified as start tile */
1056 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1057 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1059 /* automatically determine correct number of frames, if not defined */
1060 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1061 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1062 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1063 graphic_info[graphic].anim_frames = anim_frames_per_row;
1064 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1065 graphic_info[graphic].anim_frames = anim_frames_per_col;
1067 graphic_info[graphic].anim_frames = 1;
1069 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1070 graphic_info[graphic].anim_frames = 1;
1072 graphic_info[graphic].anim_frames_per_line =
1073 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1074 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1076 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1077 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1078 graphic_info[graphic].anim_delay = 1;
1080 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1082 if (graphic_info[graphic].anim_frames == 1)
1083 graphic_info[graphic].anim_mode = ANIM_NONE;
1086 /* automatically determine correct start frame, if not defined */
1087 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1088 graphic_info[graphic].anim_start_frame = 0;
1089 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1090 graphic_info[graphic].anim_start_frame =
1091 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1093 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1095 /* animation synchronized with global frame counter, not move position */
1096 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1098 /* optional element for cloning crumble graphics */
1099 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1100 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1102 /* optional element for cloning digging graphics */
1103 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1104 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1106 /* optional border size for "crumbling" diggable graphics */
1107 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1108 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1110 /* this is only used for player "boring" and "sleeping" actions */
1111 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1112 graphic_info[graphic].anim_delay_fixed =
1113 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1114 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1115 graphic_info[graphic].anim_delay_random =
1116 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1117 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1118 graphic_info[graphic].post_delay_fixed =
1119 parameter[GFX_ARG_POST_DELAY_FIXED];
1120 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1121 graphic_info[graphic].post_delay_random =
1122 parameter[GFX_ARG_POST_DELAY_RANDOM];
1124 /* this is only used for toon animations */
1125 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1126 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1128 /* this is only used for drawing font characters */
1129 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1130 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1132 /* this is only used for drawing envelope graphics */
1133 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1135 /* optional graphic for cloning all graphics settings */
1136 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1137 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1140 static void set_cloned_graphic_parameters(int graphic)
1142 int fallback_graphic = IMG_CHAR_EXCLAM;
1143 int max_num_images = getImageListSize();
1144 int clone_graphic = graphic_info[graphic].clone_from;
1145 int num_references_followed = 1;
1147 while (graphic_info[clone_graphic].clone_from != -1 &&
1148 num_references_followed < max_num_images)
1150 clone_graphic = graphic_info[clone_graphic].clone_from;
1152 num_references_followed++;
1155 if (num_references_followed >= max_num_images)
1157 Error(ERR_RETURN_LINE, "-");
1158 Error(ERR_RETURN, "warning: error found in config file:");
1159 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1160 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1161 Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1162 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1164 if (graphic == fallback_graphic)
1165 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1167 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1168 Error(ERR_RETURN_LINE, "-");
1170 graphic_info[graphic] = graphic_info[fallback_graphic];
1174 graphic_info[graphic] = graphic_info[clone_graphic];
1175 graphic_info[graphic].clone_from = clone_graphic;
1179 static void InitGraphicInfo()
1181 int fallback_graphic = IMG_CHAR_EXCLAM;
1182 int num_images = getImageListSize();
1185 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1186 static boolean clipmasks_initialized = FALSE;
1188 XGCValues clip_gc_values;
1189 unsigned long clip_gc_valuemask;
1190 GC copy_clipmask_gc = None;
1193 checked_free(graphic_info);
1195 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1197 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1198 if (clipmasks_initialized)
1200 for (i = 0; i < num_images; i++)
1202 if (graphic_info[i].clip_mask)
1203 XFreePixmap(display, graphic_info[i].clip_mask);
1204 if (graphic_info[i].clip_gc)
1205 XFreeGC(display, graphic_info[i].clip_gc);
1207 graphic_info[i].clip_mask = None;
1208 graphic_info[i].clip_gc = None;
1213 /* first set all graphic paramaters ... */
1214 for (i = 0; i < num_images; i++)
1215 set_graphic_parameters(i);
1217 /* ... then copy these parameters for cloned graphics */
1218 for (i = 0; i < num_images; i++)
1219 if (graphic_info[i].clone_from != -1)
1220 set_cloned_graphic_parameters(i);
1222 for (i = 0; i < num_images; i++)
1226 int first_frame, last_frame;
1227 int src_bitmap_width, src_bitmap_height;
1229 /* now check if no animation frames are outside of the loaded image */
1231 if (graphic_info[i].bitmap == NULL)
1232 continue; /* skip check for optional images that are undefined */
1234 /* get final bitmap size (with scaling, but without small images) */
1235 src_bitmap_width = graphic_info[i].src_image_width;
1236 src_bitmap_height = graphic_info[i].src_image_height;
1238 /* check if first animation frame is inside specified bitmap */
1241 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1243 if (src_x < 0 || src_y < 0 ||
1244 src_x + TILEX > src_bitmap_width ||
1245 src_y + TILEY > src_bitmap_height)
1247 Error(ERR_RETURN_LINE, "-");
1248 Error(ERR_RETURN, "warning: error found in config file:");
1249 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1250 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1251 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1253 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1254 src_x, src_y, src_bitmap_width, src_bitmap_height);
1255 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1257 if (i == fallback_graphic)
1258 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1260 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1261 Error(ERR_RETURN_LINE, "-");
1263 graphic_info[i] = graphic_info[fallback_graphic];
1266 /* check if last animation frame is inside specified bitmap */
1268 last_frame = graphic_info[i].anim_frames - 1;
1269 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1271 if (src_x < 0 || src_y < 0 ||
1272 src_x + TILEX > src_bitmap_width ||
1273 src_y + TILEY > src_bitmap_height)
1275 Error(ERR_RETURN_LINE, "-");
1276 Error(ERR_RETURN, "warning: error found in config file:");
1277 Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1278 Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1279 Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1281 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1282 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1283 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1285 if (i == fallback_graphic)
1286 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1288 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1289 Error(ERR_RETURN_LINE, "-");
1291 graphic_info[i] = graphic_info[fallback_graphic];
1294 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1295 /* currently we only need a tile clip mask from the first frame */
1296 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1298 if (copy_clipmask_gc == None)
1300 clip_gc_values.graphics_exposures = False;
1301 clip_gc_valuemask = GCGraphicsExposures;
1302 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1303 clip_gc_valuemask, &clip_gc_values);
1306 graphic_info[i].clip_mask =
1307 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1309 src_pixmap = src_bitmap->clip_mask;
1310 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1311 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1313 clip_gc_values.graphics_exposures = False;
1314 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1315 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1317 graphic_info[i].clip_gc =
1318 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1322 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1323 if (copy_clipmask_gc)
1324 XFreeGC(display, copy_clipmask_gc);
1326 clipmasks_initialized = TRUE;
1330 static void InitElementSoundInfo()
1332 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1333 int num_property_mappings = getSoundListPropertyMappingSize();
1336 /* set values to -1 to identify later as "uninitialized" values */
1337 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1338 for (act = 0; act < NUM_ACTIONS; act++)
1339 element_info[i].sound[act] = -1;
1341 /* initialize element/sound mapping from static configuration */
1342 for (i = 0; element_to_sound[i].element > -1; i++)
1344 int element = element_to_sound[i].element;
1345 int action = element_to_sound[i].action;
1346 int sound = element_to_sound[i].sound;
1347 boolean is_class = element_to_sound[i].is_class;
1350 action = ACTION_DEFAULT;
1353 element_info[element].sound[action] = sound;
1355 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1356 if (strEqual(element_info[j].class_name,
1357 element_info[element].class_name))
1358 element_info[j].sound[action] = sound;
1361 /* initialize element class/sound mapping from dynamic configuration */
1362 for (i = 0; i < num_property_mappings; i++)
1364 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1365 int action = property_mapping[i].ext1_index;
1366 int sound = property_mapping[i].artwork_index;
1368 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1372 action = ACTION_DEFAULT;
1374 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1375 if (strEqual(element_info[j].class_name,
1376 element_info[element_class].class_name))
1377 element_info[j].sound[action] = sound;
1380 /* initialize element/sound mapping from dynamic configuration */
1381 for (i = 0; i < num_property_mappings; i++)
1383 int element = property_mapping[i].base_index;
1384 int action = property_mapping[i].ext1_index;
1385 int sound = property_mapping[i].artwork_index;
1387 if (element >= MAX_NUM_ELEMENTS)
1391 action = ACTION_DEFAULT;
1393 element_info[element].sound[action] = sound;
1396 /* now set all '-1' values to element specific default values */
1397 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1399 for (act = 0; act < NUM_ACTIONS; act++)
1401 /* generic default action sound (defined by "[default]" directive) */
1402 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1404 /* look for special default action sound (classic game specific) */
1405 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1406 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1407 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1408 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1409 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1410 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1412 /* !!! there's no such thing as a "default action sound" !!! */
1414 /* look for element specific default sound (independent from action) */
1415 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1416 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1420 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1421 /* !!! make this better !!! */
1422 if (i == EL_EMPTY_SPACE)
1423 default_action_sound = element_info[EL_DEFAULT].sound[act];
1426 /* no sound for this specific action -- use default action sound */
1427 if (element_info[i].sound[act] == -1)
1428 element_info[i].sound[act] = default_action_sound;
1432 /* copy sound settings to some elements that are only stored in level file
1433 in native R'n'D levels, but are used by game engine in native EM levels */
1434 for (i = 0; copy_properties[i][0] != -1; i++)
1435 for (j = 1; j <= 4; j++)
1436 for (act = 0; act < NUM_ACTIONS; act++)
1437 element_info[copy_properties[i][j]].sound[act] =
1438 element_info[copy_properties[i][0]].sound[act];
1441 static void InitGameModeSoundInfo()
1445 /* set values to -1 to identify later as "uninitialized" values */
1446 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1449 /* initialize gamemode/sound mapping from static configuration */
1450 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1452 int gamemode = gamemode_to_sound[i].gamemode;
1453 int sound = gamemode_to_sound[i].sound;
1456 gamemode = GAME_MODE_DEFAULT;
1458 menu.sound[gamemode] = sound;
1461 /* now set all '-1' values to levelset specific default values */
1462 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1463 if (menu.sound[i] == -1)
1464 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1467 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1468 if (menu.sound[i] != -1)
1469 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1473 static void set_sound_parameters(int sound, char **parameter_raw)
1475 int parameter[NUM_SND_ARGS];
1478 /* get integer values from string parameters */
1479 for (i = 0; i < NUM_SND_ARGS; i++)
1481 get_parameter_value(parameter_raw[i],
1482 sound_config_suffix[i].token,
1483 sound_config_suffix[i].type);
1485 /* explicit loop mode setting in configuration overrides default value */
1486 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1487 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1489 /* sound volume to change the original volume when loading the sound file */
1490 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1492 /* sound priority to give certain sounds a higher or lower priority */
1493 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1496 static void InitSoundInfo()
1498 int *sound_effect_properties;
1499 int num_sounds = getSoundListSize();
1502 checked_free(sound_info);
1504 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1505 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1507 /* initialize sound effect for all elements to "no sound" */
1508 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1509 for (j = 0; j < NUM_ACTIONS; j++)
1510 element_info[i].sound[j] = SND_UNDEFINED;
1512 for (i = 0; i < num_sounds; i++)
1514 struct FileInfo *sound = getSoundListEntry(i);
1515 int len_effect_text = strlen(sound->token);
1517 sound_effect_properties[i] = ACTION_OTHER;
1518 sound_info[i].loop = FALSE; /* default: play sound only once */
1521 printf("::: sound %d: '%s'\n", i, sound->token);
1524 /* determine all loop sounds and identify certain sound classes */
1526 for (j = 0; element_action_info[j].suffix; j++)
1528 int len_action_text = strlen(element_action_info[j].suffix);
1530 if (len_action_text < len_effect_text &&
1531 strEqual(&sound->token[len_effect_text - len_action_text],
1532 element_action_info[j].suffix))
1534 sound_effect_properties[i] = element_action_info[j].value;
1535 sound_info[i].loop = element_action_info[j].is_loop_sound;
1541 /* associate elements and some selected sound actions */
1543 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1545 if (element_info[j].class_name)
1547 int len_class_text = strlen(element_info[j].class_name);
1549 if (len_class_text + 1 < len_effect_text &&
1550 strncmp(sound->token,
1551 element_info[j].class_name, len_class_text) == 0 &&
1552 sound->token[len_class_text] == '.')
1554 int sound_action_value = sound_effect_properties[i];
1556 element_info[j].sound[sound_action_value] = i;
1561 set_sound_parameters(i, sound->parameter);
1564 free(sound_effect_properties);
1567 static void InitGameModeMusicInfo()
1569 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1570 int num_property_mappings = getMusicListPropertyMappingSize();
1571 int default_levelset_music = -1;
1574 /* set values to -1 to identify later as "uninitialized" values */
1575 for (i = 0; i < MAX_LEVELS; i++)
1576 levelset.music[i] = -1;
1577 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1580 /* initialize gamemode/music mapping from static configuration */
1581 for (i = 0; gamemode_to_music[i].music > -1; i++)
1583 int gamemode = gamemode_to_music[i].gamemode;
1584 int music = gamemode_to_music[i].music;
1587 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1591 gamemode = GAME_MODE_DEFAULT;
1593 menu.music[gamemode] = music;
1596 /* initialize gamemode/music mapping from dynamic configuration */
1597 for (i = 0; i < num_property_mappings; i++)
1599 int prefix = property_mapping[i].base_index;
1600 int gamemode = property_mapping[i].ext1_index;
1601 int level = property_mapping[i].ext2_index;
1602 int music = property_mapping[i].artwork_index;
1605 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1606 prefix, gamemode, level, music);
1609 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1613 gamemode = GAME_MODE_DEFAULT;
1615 /* level specific music only allowed for in-game music */
1616 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1617 gamemode = GAME_MODE_PLAYING;
1622 default_levelset_music = music;
1625 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1626 levelset.music[level] = music;
1627 if (gamemode != GAME_MODE_PLAYING)
1628 menu.music[gamemode] = music;
1631 /* now set all '-1' values to menu specific default values */
1632 /* (undefined values of "levelset.music[]" might stay at "-1" to
1633 allow dynamic selection of music files from music directory!) */
1634 for (i = 0; i < MAX_LEVELS; i++)
1635 if (levelset.music[i] == -1)
1636 levelset.music[i] = default_levelset_music;
1637 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1638 if (menu.music[i] == -1)
1639 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1642 for (i = 0; i < MAX_LEVELS; i++)
1643 if (levelset.music[i] != -1)
1644 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1645 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1646 if (menu.music[i] != -1)
1647 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1651 static void set_music_parameters(int music, char **parameter_raw)
1653 int parameter[NUM_MUS_ARGS];
1656 /* get integer values from string parameters */
1657 for (i = 0; i < NUM_MUS_ARGS; i++)
1659 get_parameter_value(parameter_raw[i],
1660 music_config_suffix[i].token,
1661 music_config_suffix[i].type);
1663 /* explicit loop mode setting in configuration overrides default value */
1664 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1665 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1668 static void InitMusicInfo()
1670 int num_music = getMusicListSize();
1673 checked_free(music_info);
1675 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1677 for (i = 0; i < num_music; i++)
1679 struct FileInfo *music = getMusicListEntry(i);
1680 int len_music_text = strlen(music->token);
1682 music_info[i].loop = TRUE; /* default: play music in loop mode */
1684 /* determine all loop music */
1686 for (j = 0; music_prefix_info[j].prefix; j++)
1688 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1690 if (len_prefix_text < len_music_text &&
1691 strncmp(music->token,
1692 music_prefix_info[j].prefix, len_prefix_text) == 0)
1694 music_info[i].loop = music_prefix_info[j].is_loop_music;
1700 set_music_parameters(i, music->parameter);
1704 static void ReinitializeGraphics()
1706 InitGraphicInfo(); /* graphic properties mapping */
1707 InitElementGraphicInfo(); /* element game graphic mapping */
1708 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1710 InitElementSmallImages(); /* scale elements to all needed sizes */
1711 InitScaledImages(); /* scale all other images, if needed */
1712 InitFontGraphicInfo(); /* initialize text drawing functions */
1714 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1716 SetMainBackgroundImage(IMG_BACKGROUND);
1717 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1723 static void ReinitializeSounds()
1725 InitSoundInfo(); /* sound properties mapping */
1726 InitElementSoundInfo(); /* element game sound mapping */
1727 InitGameModeSoundInfo(); /* game mode sound mapping */
1729 InitPlayLevelSound(); /* internal game sound settings */
1732 static void ReinitializeMusic()
1734 InitMusicInfo(); /* music properties mapping */
1735 InitGameModeMusicInfo(); /* game mode music mapping */
1738 static int get_special_property_bit(int element, int property_bit_nr)
1740 struct PropertyBitInfo
1746 static struct PropertyBitInfo pb_can_move_into_acid[] =
1748 /* the player may be able fall into acid when gravity is activated */
1753 { EL_SP_MURPHY, 0 },
1754 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1756 /* all elements that can move may be able to also move into acid */
1759 { EL_BUG_RIGHT, 1 },
1762 { EL_SPACESHIP, 2 },
1763 { EL_SPACESHIP_LEFT, 2 },
1764 { EL_SPACESHIP_RIGHT, 2 },
1765 { EL_SPACESHIP_UP, 2 },
1766 { EL_SPACESHIP_DOWN, 2 },
1767 { EL_BD_BUTTERFLY, 3 },
1768 { EL_BD_BUTTERFLY_LEFT, 3 },
1769 { EL_BD_BUTTERFLY_RIGHT, 3 },
1770 { EL_BD_BUTTERFLY_UP, 3 },
1771 { EL_BD_BUTTERFLY_DOWN, 3 },
1772 { EL_BD_FIREFLY, 4 },
1773 { EL_BD_FIREFLY_LEFT, 4 },
1774 { EL_BD_FIREFLY_RIGHT, 4 },
1775 { EL_BD_FIREFLY_UP, 4 },
1776 { EL_BD_FIREFLY_DOWN, 4 },
1778 { EL_YAMYAM_LEFT, 5 },
1779 { EL_YAMYAM_RIGHT, 5 },
1780 { EL_YAMYAM_UP, 5 },
1781 { EL_YAMYAM_DOWN, 5 },
1782 { EL_DARK_YAMYAM, 6 },
1785 { EL_PACMAN_LEFT, 8 },
1786 { EL_PACMAN_RIGHT, 8 },
1787 { EL_PACMAN_UP, 8 },
1788 { EL_PACMAN_DOWN, 8 },
1790 { EL_MOLE_LEFT, 9 },
1791 { EL_MOLE_RIGHT, 9 },
1793 { EL_MOLE_DOWN, 9 },
1797 { EL_SATELLITE, 13 },
1798 { EL_SP_SNIKSNAK, 14 },
1799 { EL_SP_ELECTRON, 15 },
1802 { EL_EMC_ANDROID, 18 },
1807 static struct PropertyBitInfo pb_dont_collide_with[] =
1809 { EL_SP_SNIKSNAK, 0 },
1810 { EL_SP_ELECTRON, 1 },
1818 struct PropertyBitInfo *pb_info;
1821 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1822 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1827 struct PropertyBitInfo *pb_info = NULL;
1830 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1831 if (pb_definition[i].bit_nr == property_bit_nr)
1832 pb_info = pb_definition[i].pb_info;
1834 if (pb_info == NULL)
1837 for (i = 0; pb_info[i].element != -1; i++)
1838 if (pb_info[i].element == element)
1839 return pb_info[i].bit_nr;
1844 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1845 boolean property_value)
1847 int bit_nr = get_special_property_bit(element, property_bit_nr);
1852 *bitfield |= (1 << bit_nr);
1854 *bitfield &= ~(1 << bit_nr);
1858 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1860 int bit_nr = get_special_property_bit(element, property_bit_nr);
1863 return ((*bitfield & (1 << bit_nr)) != 0);
1868 static void resolve_group_element(int group_element, int recursion_depth)
1870 static int group_nr;
1871 static struct ElementGroupInfo *group;
1872 struct ElementGroupInfo *actual_group = element_info[group_element].group;
1875 if (actual_group == NULL) /* not yet initialized */
1878 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
1880 Error(ERR_WARN, "recursion too deep when resolving group element %d",
1881 group_element - EL_GROUP_START + 1);
1883 /* replace element which caused too deep recursion by question mark */
1884 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1889 if (recursion_depth == 0) /* initialization */
1891 group = actual_group;
1892 group_nr = group_element - EL_GROUP_START;
1894 group->num_elements_resolved = 0;
1895 group->choice_pos = 0;
1898 for (i = 0; i < actual_group->num_elements; i++)
1900 int element = actual_group->element[i];
1902 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1905 if (IS_GROUP_ELEMENT(element))
1906 resolve_group_element(element, recursion_depth + 1);
1909 group->element_resolved[group->num_elements_resolved++] = element;
1910 element_info[element].in_group[group_nr] = TRUE;
1915 void InitElementPropertiesStatic()
1917 static int ep_diggable[] =
1922 EL_SP_BUGGY_BASE_ACTIVATING,
1925 EL_INVISIBLE_SAND_ACTIVE,
1928 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1929 /* (if amoeba can grow into anything diggable, maybe keep these out) */
1933 EL_SP_BUGGY_BASE_ACTIVE,
1940 static int ep_collectible_only[] =
1962 EL_DYNABOMB_INCREASE_NUMBER,
1963 EL_DYNABOMB_INCREASE_SIZE,
1964 EL_DYNABOMB_INCREASE_POWER,
1984 static int ep_dont_run_into[] =
1986 /* same elements as in 'ep_dont_touch' */
1992 /* same elements as in 'ep_dont_collide_with' */
2004 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2008 EL_SP_BUGGY_BASE_ACTIVE,
2015 static int ep_dont_collide_with[] =
2017 /* same elements as in 'ep_dont_touch' */
2034 static int ep_dont_touch[] =
2044 static int ep_indestructible[] =
2048 EL_ACID_POOL_TOPLEFT,
2049 EL_ACID_POOL_TOPRIGHT,
2050 EL_ACID_POOL_BOTTOMLEFT,
2051 EL_ACID_POOL_BOTTOM,
2052 EL_ACID_POOL_BOTTOMRIGHT,
2053 EL_SP_HARDWARE_GRAY,
2054 EL_SP_HARDWARE_GREEN,
2055 EL_SP_HARDWARE_BLUE,
2057 EL_SP_HARDWARE_YELLOW,
2058 EL_SP_HARDWARE_BASE_1,
2059 EL_SP_HARDWARE_BASE_2,
2060 EL_SP_HARDWARE_BASE_3,
2061 EL_SP_HARDWARE_BASE_4,
2062 EL_SP_HARDWARE_BASE_5,
2063 EL_SP_HARDWARE_BASE_6,
2064 EL_INVISIBLE_STEELWALL,
2065 EL_INVISIBLE_STEELWALL_ACTIVE,
2066 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2067 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2068 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2069 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2070 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2071 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2072 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2073 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2074 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2075 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2076 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2077 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2079 EL_LIGHT_SWITCH_ACTIVE,
2080 EL_SIGN_EXCLAMATION,
2081 EL_SIGN_RADIOACTIVITY,
2092 EL_STEELWALL_SLIPPERY,
2106 EL_GATE_1_GRAY_ACTIVE,
2107 EL_GATE_2_GRAY_ACTIVE,
2108 EL_GATE_3_GRAY_ACTIVE,
2109 EL_GATE_4_GRAY_ACTIVE,
2118 EL_EM_GATE_1_GRAY_ACTIVE,
2119 EL_EM_GATE_2_GRAY_ACTIVE,
2120 EL_EM_GATE_3_GRAY_ACTIVE,
2121 EL_EM_GATE_4_GRAY_ACTIVE,
2130 EL_EMC_GATE_5_GRAY_ACTIVE,
2131 EL_EMC_GATE_6_GRAY_ACTIVE,
2132 EL_EMC_GATE_7_GRAY_ACTIVE,
2133 EL_EMC_GATE_8_GRAY_ACTIVE,
2135 EL_SWITCHGATE_OPENING,
2136 EL_SWITCHGATE_CLOSED,
2137 EL_SWITCHGATE_CLOSING,
2139 EL_SWITCHGATE_SWITCH_UP,
2140 EL_SWITCHGATE_SWITCH_DOWN,
2143 EL_TIMEGATE_OPENING,
2145 EL_TIMEGATE_CLOSING,
2148 EL_TIMEGATE_SWITCH_ACTIVE,
2153 EL_TUBE_VERTICAL_LEFT,
2154 EL_TUBE_VERTICAL_RIGHT,
2155 EL_TUBE_HORIZONTAL_UP,
2156 EL_TUBE_HORIZONTAL_DOWN,
2165 static int ep_slippery[] =
2179 EL_ROBOT_WHEEL_ACTIVE,
2185 EL_ACID_POOL_TOPLEFT,
2186 EL_ACID_POOL_TOPRIGHT,
2196 EL_STEELWALL_SLIPPERY,
2199 EL_EMC_WALL_SLIPPERY_1,
2200 EL_EMC_WALL_SLIPPERY_2,
2201 EL_EMC_WALL_SLIPPERY_3,
2202 EL_EMC_WALL_SLIPPERY_4,
2204 EL_EMC_MAGIC_BALL_ACTIVE,
2209 static int ep_can_change[] =
2214 static int ep_can_move[] =
2216 /* same elements as in 'pb_can_move_into_acid' */
2239 static int ep_can_fall[] =
2254 EL_BD_MAGIC_WALL_FULL,
2268 static int ep_can_smash_player[] =
2294 static int ep_can_smash_enemies[] =
2303 static int ep_can_smash_everything[] =
2312 static int ep_explodes_by_fire[] =
2314 /* same elements as in 'ep_explodes_impact' */
2319 /* same elements as in 'ep_explodes_smashed' */
2329 EL_EM_DYNAMITE_ACTIVE,
2330 EL_DYNABOMB_PLAYER_1_ACTIVE,
2331 EL_DYNABOMB_PLAYER_2_ACTIVE,
2332 EL_DYNABOMB_PLAYER_3_ACTIVE,
2333 EL_DYNABOMB_PLAYER_4_ACTIVE,
2334 EL_DYNABOMB_INCREASE_NUMBER,
2335 EL_DYNABOMB_INCREASE_SIZE,
2336 EL_DYNABOMB_INCREASE_POWER,
2337 EL_SP_DISK_RED_ACTIVE,
2351 static int ep_explodes_smashed[] =
2353 /* same elements as in 'ep_explodes_impact' */
2367 static int ep_explodes_impact[] =
2376 static int ep_walkable_over[] =
2380 EL_SOKOBAN_FIELD_EMPTY,
2392 EL_GATE_1_GRAY_ACTIVE,
2393 EL_GATE_2_GRAY_ACTIVE,
2394 EL_GATE_3_GRAY_ACTIVE,
2395 EL_GATE_4_GRAY_ACTIVE,
2403 static int ep_walkable_inside[] =
2408 EL_TUBE_VERTICAL_LEFT,
2409 EL_TUBE_VERTICAL_RIGHT,
2410 EL_TUBE_HORIZONTAL_UP,
2411 EL_TUBE_HORIZONTAL_DOWN,
2420 static int ep_walkable_under[] =
2425 static int ep_passable_over[] =
2435 EL_EM_GATE_1_GRAY_ACTIVE,
2436 EL_EM_GATE_2_GRAY_ACTIVE,
2437 EL_EM_GATE_3_GRAY_ACTIVE,
2438 EL_EM_GATE_4_GRAY_ACTIVE,
2447 EL_EMC_GATE_5_GRAY_ACTIVE,
2448 EL_EMC_GATE_6_GRAY_ACTIVE,
2449 EL_EMC_GATE_7_GRAY_ACTIVE,
2450 EL_EMC_GATE_8_GRAY_ACTIVE,
2457 static int ep_passable_inside[] =
2463 EL_SP_PORT_HORIZONTAL,
2464 EL_SP_PORT_VERTICAL,
2466 EL_SP_GRAVITY_PORT_LEFT,
2467 EL_SP_GRAVITY_PORT_RIGHT,
2468 EL_SP_GRAVITY_PORT_UP,
2469 EL_SP_GRAVITY_PORT_DOWN,
2470 EL_SP_GRAVITY_ON_PORT_LEFT,
2471 EL_SP_GRAVITY_ON_PORT_RIGHT,
2472 EL_SP_GRAVITY_ON_PORT_UP,
2473 EL_SP_GRAVITY_ON_PORT_DOWN,
2474 EL_SP_GRAVITY_OFF_PORT_LEFT,
2475 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2476 EL_SP_GRAVITY_OFF_PORT_UP,
2477 EL_SP_GRAVITY_OFF_PORT_DOWN,
2482 static int ep_passable_under[] =
2487 static int ep_droppable[] =
2492 static int ep_explodes_1x1_old[] =
2497 static int ep_pushable[] =
2509 EL_SOKOBAN_FIELD_FULL,
2518 static int ep_explodes_cross_old[] =
2523 static int ep_protected[] =
2525 /* same elements as in 'ep_walkable_inside' */
2529 EL_TUBE_VERTICAL_LEFT,
2530 EL_TUBE_VERTICAL_RIGHT,
2531 EL_TUBE_HORIZONTAL_UP,
2532 EL_TUBE_HORIZONTAL_DOWN,
2538 /* same elements as in 'ep_passable_over' */
2547 EL_EM_GATE_1_GRAY_ACTIVE,
2548 EL_EM_GATE_2_GRAY_ACTIVE,
2549 EL_EM_GATE_3_GRAY_ACTIVE,
2550 EL_EM_GATE_4_GRAY_ACTIVE,
2559 EL_EMC_GATE_5_GRAY_ACTIVE,
2560 EL_EMC_GATE_6_GRAY_ACTIVE,
2561 EL_EMC_GATE_7_GRAY_ACTIVE,
2562 EL_EMC_GATE_8_GRAY_ACTIVE,
2566 /* same elements as in 'ep_passable_inside' */
2571 EL_SP_PORT_HORIZONTAL,
2572 EL_SP_PORT_VERTICAL,
2574 EL_SP_GRAVITY_PORT_LEFT,
2575 EL_SP_GRAVITY_PORT_RIGHT,
2576 EL_SP_GRAVITY_PORT_UP,
2577 EL_SP_GRAVITY_PORT_DOWN,
2578 EL_SP_GRAVITY_ON_PORT_LEFT,
2579 EL_SP_GRAVITY_ON_PORT_RIGHT,
2580 EL_SP_GRAVITY_ON_PORT_UP,
2581 EL_SP_GRAVITY_ON_PORT_DOWN,
2582 EL_SP_GRAVITY_OFF_PORT_LEFT,
2583 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2584 EL_SP_GRAVITY_OFF_PORT_UP,
2585 EL_SP_GRAVITY_OFF_PORT_DOWN,
2590 static int ep_throwable[] =
2595 static int ep_can_explode[] =
2597 /* same elements as in 'ep_explodes_impact' */
2602 /* same elements as in 'ep_explodes_smashed' */
2608 /* elements that can explode by explosion or by dragonfire */
2612 EL_EM_DYNAMITE_ACTIVE,
2613 EL_DYNABOMB_PLAYER_1_ACTIVE,
2614 EL_DYNABOMB_PLAYER_2_ACTIVE,
2615 EL_DYNABOMB_PLAYER_3_ACTIVE,
2616 EL_DYNABOMB_PLAYER_4_ACTIVE,
2617 EL_DYNABOMB_INCREASE_NUMBER,
2618 EL_DYNABOMB_INCREASE_SIZE,
2619 EL_DYNABOMB_INCREASE_POWER,
2620 EL_SP_DISK_RED_ACTIVE,
2628 /* elements that can explode only by explosion */
2634 static int ep_gravity_reachable[] =
2640 EL_INVISIBLE_SAND_ACTIVE,
2645 EL_SP_PORT_HORIZONTAL,
2646 EL_SP_PORT_VERTICAL,
2648 EL_SP_GRAVITY_PORT_LEFT,
2649 EL_SP_GRAVITY_PORT_RIGHT,
2650 EL_SP_GRAVITY_PORT_UP,
2651 EL_SP_GRAVITY_PORT_DOWN,
2652 EL_SP_GRAVITY_ON_PORT_LEFT,
2653 EL_SP_GRAVITY_ON_PORT_RIGHT,
2654 EL_SP_GRAVITY_ON_PORT_UP,
2655 EL_SP_GRAVITY_ON_PORT_DOWN,
2656 EL_SP_GRAVITY_OFF_PORT_LEFT,
2657 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2658 EL_SP_GRAVITY_OFF_PORT_UP,
2659 EL_SP_GRAVITY_OFF_PORT_DOWN,
2665 static int ep_player[] =
2672 EL_SOKOBAN_FIELD_PLAYER,
2678 static int ep_can_pass_magic_wall[] =
2692 static int ep_switchable[] =
2696 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2697 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2698 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2699 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2700 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2701 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2702 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2703 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2704 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2705 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2706 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2707 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2708 EL_SWITCHGATE_SWITCH_UP,
2709 EL_SWITCHGATE_SWITCH_DOWN,
2711 EL_LIGHT_SWITCH_ACTIVE,
2713 EL_BALLOON_SWITCH_LEFT,
2714 EL_BALLOON_SWITCH_RIGHT,
2715 EL_BALLOON_SWITCH_UP,
2716 EL_BALLOON_SWITCH_DOWN,
2717 EL_BALLOON_SWITCH_ANY,
2718 EL_BALLOON_SWITCH_NONE,
2721 EL_EMC_MAGIC_BALL_SWITCH,
2722 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2727 static int ep_bd_element[] =
2761 static int ep_sp_element[] =
2763 /* should always be valid */
2766 /* standard classic Supaplex elements */
2773 EL_SP_HARDWARE_GRAY,
2781 EL_SP_GRAVITY_PORT_RIGHT,
2782 EL_SP_GRAVITY_PORT_DOWN,
2783 EL_SP_GRAVITY_PORT_LEFT,
2784 EL_SP_GRAVITY_PORT_UP,
2789 EL_SP_PORT_VERTICAL,
2790 EL_SP_PORT_HORIZONTAL,
2796 EL_SP_HARDWARE_BASE_1,
2797 EL_SP_HARDWARE_GREEN,
2798 EL_SP_HARDWARE_BLUE,
2800 EL_SP_HARDWARE_YELLOW,
2801 EL_SP_HARDWARE_BASE_2,
2802 EL_SP_HARDWARE_BASE_3,
2803 EL_SP_HARDWARE_BASE_4,
2804 EL_SP_HARDWARE_BASE_5,
2805 EL_SP_HARDWARE_BASE_6,
2809 /* additional elements that appeared in newer Supaplex levels */
2812 /* additional gravity port elements (not switching, but setting gravity) */
2813 EL_SP_GRAVITY_ON_PORT_LEFT,
2814 EL_SP_GRAVITY_ON_PORT_RIGHT,
2815 EL_SP_GRAVITY_ON_PORT_UP,
2816 EL_SP_GRAVITY_ON_PORT_DOWN,
2817 EL_SP_GRAVITY_OFF_PORT_LEFT,
2818 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2819 EL_SP_GRAVITY_OFF_PORT_UP,
2820 EL_SP_GRAVITY_OFF_PORT_DOWN,
2822 /* more than one Murphy in a level results in an inactive clone */
2825 /* runtime Supaplex elements */
2826 EL_SP_DISK_RED_ACTIVE,
2827 EL_SP_TERMINAL_ACTIVE,
2828 EL_SP_BUGGY_BASE_ACTIVATING,
2829 EL_SP_BUGGY_BASE_ACTIVE,
2836 static int ep_sb_element[] =
2841 EL_SOKOBAN_FIELD_EMPTY,
2842 EL_SOKOBAN_FIELD_FULL,
2843 EL_SOKOBAN_FIELD_PLAYER,
2848 EL_INVISIBLE_STEELWALL,
2853 static int ep_gem[] =
2865 static int ep_food_dark_yamyam[] =
2893 static int ep_food_penguin[] =
2907 static int ep_food_pig[] =
2919 static int ep_historic_wall[] =
2930 EL_GATE_1_GRAY_ACTIVE,
2931 EL_GATE_2_GRAY_ACTIVE,
2932 EL_GATE_3_GRAY_ACTIVE,
2933 EL_GATE_4_GRAY_ACTIVE,
2942 EL_EM_GATE_1_GRAY_ACTIVE,
2943 EL_EM_GATE_2_GRAY_ACTIVE,
2944 EL_EM_GATE_3_GRAY_ACTIVE,
2945 EL_EM_GATE_4_GRAY_ACTIVE,
2952 EL_EXPANDABLE_WALL_HORIZONTAL,
2953 EL_EXPANDABLE_WALL_VERTICAL,
2954 EL_EXPANDABLE_WALL_ANY,
2955 EL_EXPANDABLE_WALL_GROWING,
2956 EL_BD_EXPANDABLE_WALL,
2963 EL_SP_HARDWARE_GRAY,
2964 EL_SP_HARDWARE_GREEN,
2965 EL_SP_HARDWARE_BLUE,
2967 EL_SP_HARDWARE_YELLOW,
2968 EL_SP_HARDWARE_BASE_1,
2969 EL_SP_HARDWARE_BASE_2,
2970 EL_SP_HARDWARE_BASE_3,
2971 EL_SP_HARDWARE_BASE_4,
2972 EL_SP_HARDWARE_BASE_5,
2973 EL_SP_HARDWARE_BASE_6,
2975 EL_SP_TERMINAL_ACTIVE,
2978 EL_INVISIBLE_STEELWALL,
2979 EL_INVISIBLE_STEELWALL_ACTIVE,
2981 EL_INVISIBLE_WALL_ACTIVE,
2982 EL_STEELWALL_SLIPPERY,
2999 static int ep_historic_solid[] =
3003 EL_EXPANDABLE_WALL_HORIZONTAL,
3004 EL_EXPANDABLE_WALL_VERTICAL,
3005 EL_EXPANDABLE_WALL_ANY,
3006 EL_BD_EXPANDABLE_WALL,
3019 EL_QUICKSAND_FILLING,
3020 EL_QUICKSAND_EMPTYING,
3022 EL_MAGIC_WALL_ACTIVE,
3023 EL_MAGIC_WALL_EMPTYING,
3024 EL_MAGIC_WALL_FILLING,
3028 EL_BD_MAGIC_WALL_ACTIVE,
3029 EL_BD_MAGIC_WALL_EMPTYING,
3030 EL_BD_MAGIC_WALL_FULL,
3031 EL_BD_MAGIC_WALL_FILLING,
3032 EL_BD_MAGIC_WALL_DEAD,
3041 EL_SP_TERMINAL_ACTIVE,
3045 EL_INVISIBLE_WALL_ACTIVE,
3046 EL_SWITCHGATE_SWITCH_UP,
3047 EL_SWITCHGATE_SWITCH_DOWN,
3049 EL_TIMEGATE_SWITCH_ACTIVE,
3061 /* the following elements are a direct copy of "indestructible" elements,
3062 except "EL_ACID", which is "indestructible", but not "solid"! */
3067 EL_ACID_POOL_TOPLEFT,
3068 EL_ACID_POOL_TOPRIGHT,
3069 EL_ACID_POOL_BOTTOMLEFT,
3070 EL_ACID_POOL_BOTTOM,
3071 EL_ACID_POOL_BOTTOMRIGHT,
3072 EL_SP_HARDWARE_GRAY,
3073 EL_SP_HARDWARE_GREEN,
3074 EL_SP_HARDWARE_BLUE,
3076 EL_SP_HARDWARE_YELLOW,
3077 EL_SP_HARDWARE_BASE_1,
3078 EL_SP_HARDWARE_BASE_2,
3079 EL_SP_HARDWARE_BASE_3,
3080 EL_SP_HARDWARE_BASE_4,
3081 EL_SP_HARDWARE_BASE_5,
3082 EL_SP_HARDWARE_BASE_6,
3083 EL_INVISIBLE_STEELWALL,
3084 EL_INVISIBLE_STEELWALL_ACTIVE,
3085 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3086 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3087 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3088 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3089 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3090 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3091 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3092 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3093 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3094 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3095 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3096 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3098 EL_LIGHT_SWITCH_ACTIVE,
3099 EL_SIGN_EXCLAMATION,
3100 EL_SIGN_RADIOACTIVITY,
3111 EL_STEELWALL_SLIPPERY,
3125 EL_GATE_1_GRAY_ACTIVE,
3126 EL_GATE_2_GRAY_ACTIVE,
3127 EL_GATE_3_GRAY_ACTIVE,
3128 EL_GATE_4_GRAY_ACTIVE,
3137 EL_EM_GATE_1_GRAY_ACTIVE,
3138 EL_EM_GATE_2_GRAY_ACTIVE,
3139 EL_EM_GATE_3_GRAY_ACTIVE,
3140 EL_EM_GATE_4_GRAY_ACTIVE,
3142 EL_SWITCHGATE_OPENING,
3143 EL_SWITCHGATE_CLOSED,
3144 EL_SWITCHGATE_CLOSING,
3146 EL_TIMEGATE_OPENING,
3148 EL_TIMEGATE_CLOSING,
3152 EL_TUBE_VERTICAL_LEFT,
3153 EL_TUBE_VERTICAL_RIGHT,
3154 EL_TUBE_HORIZONTAL_UP,
3155 EL_TUBE_HORIZONTAL_DOWN,
3164 static int ep_classic_enemy[] =
3181 static int ep_belt[] =
3183 EL_CONVEYOR_BELT_1_LEFT,
3184 EL_CONVEYOR_BELT_1_MIDDLE,
3185 EL_CONVEYOR_BELT_1_RIGHT,
3186 EL_CONVEYOR_BELT_2_LEFT,
3187 EL_CONVEYOR_BELT_2_MIDDLE,
3188 EL_CONVEYOR_BELT_2_RIGHT,
3189 EL_CONVEYOR_BELT_3_LEFT,
3190 EL_CONVEYOR_BELT_3_MIDDLE,
3191 EL_CONVEYOR_BELT_3_RIGHT,
3192 EL_CONVEYOR_BELT_4_LEFT,
3193 EL_CONVEYOR_BELT_4_MIDDLE,
3194 EL_CONVEYOR_BELT_4_RIGHT,
3199 static int ep_belt_active[] =
3201 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3202 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3203 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3204 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3205 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3206 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3207 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3208 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3209 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3210 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3211 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3212 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3217 static int ep_belt_switch[] =
3219 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3220 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3221 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3222 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3223 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3224 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3225 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3226 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3227 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3228 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3229 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3230 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3235 static int ep_tube[] =
3242 EL_TUBE_HORIZONTAL_UP,
3243 EL_TUBE_HORIZONTAL_DOWN,
3245 EL_TUBE_VERTICAL_LEFT,
3246 EL_TUBE_VERTICAL_RIGHT,
3252 static int ep_keygate[] =
3262 EL_GATE_1_GRAY_ACTIVE,
3263 EL_GATE_2_GRAY_ACTIVE,
3264 EL_GATE_3_GRAY_ACTIVE,
3265 EL_GATE_4_GRAY_ACTIVE,
3274 EL_EM_GATE_1_GRAY_ACTIVE,
3275 EL_EM_GATE_2_GRAY_ACTIVE,
3276 EL_EM_GATE_3_GRAY_ACTIVE,
3277 EL_EM_GATE_4_GRAY_ACTIVE,
3286 EL_EMC_GATE_5_GRAY_ACTIVE,
3287 EL_EMC_GATE_6_GRAY_ACTIVE,
3288 EL_EMC_GATE_7_GRAY_ACTIVE,
3289 EL_EMC_GATE_8_GRAY_ACTIVE,
3294 static int ep_amoeboid[] =
3306 static int ep_amoebalive[] =
3317 static int ep_has_editor_content[] =
3339 static int ep_can_turn_each_move[] =
3341 /* !!! do something with this one !!! */
3345 static int ep_can_grow[] =
3359 static int ep_active_bomb[] =
3362 EL_EM_DYNAMITE_ACTIVE,
3363 EL_DYNABOMB_PLAYER_1_ACTIVE,
3364 EL_DYNABOMB_PLAYER_2_ACTIVE,
3365 EL_DYNABOMB_PLAYER_3_ACTIVE,
3366 EL_DYNABOMB_PLAYER_4_ACTIVE,
3367 EL_SP_DISK_RED_ACTIVE,
3372 static int ep_inactive[] =
3404 EL_GATE_1_GRAY_ACTIVE,
3405 EL_GATE_2_GRAY_ACTIVE,
3406 EL_GATE_3_GRAY_ACTIVE,
3407 EL_GATE_4_GRAY_ACTIVE,
3416 EL_EM_GATE_1_GRAY_ACTIVE,
3417 EL_EM_GATE_2_GRAY_ACTIVE,
3418 EL_EM_GATE_3_GRAY_ACTIVE,
3419 EL_EM_GATE_4_GRAY_ACTIVE,
3428 EL_EMC_GATE_5_GRAY_ACTIVE,
3429 EL_EMC_GATE_6_GRAY_ACTIVE,
3430 EL_EMC_GATE_7_GRAY_ACTIVE,
3431 EL_EMC_GATE_8_GRAY_ACTIVE,
3434 EL_INVISIBLE_STEELWALL,
3442 EL_WALL_EMERALD_YELLOW,
3443 EL_DYNABOMB_INCREASE_NUMBER,
3444 EL_DYNABOMB_INCREASE_SIZE,
3445 EL_DYNABOMB_INCREASE_POWER,
3449 EL_SOKOBAN_FIELD_EMPTY,
3450 EL_SOKOBAN_FIELD_FULL,
3451 EL_WALL_EMERALD_RED,
3452 EL_WALL_EMERALD_PURPLE,
3453 EL_ACID_POOL_TOPLEFT,
3454 EL_ACID_POOL_TOPRIGHT,
3455 EL_ACID_POOL_BOTTOMLEFT,
3456 EL_ACID_POOL_BOTTOM,
3457 EL_ACID_POOL_BOTTOMRIGHT,
3461 EL_BD_MAGIC_WALL_DEAD,
3462 EL_AMOEBA_TO_DIAMOND,
3470 EL_SP_GRAVITY_PORT_RIGHT,
3471 EL_SP_GRAVITY_PORT_DOWN,
3472 EL_SP_GRAVITY_PORT_LEFT,
3473 EL_SP_GRAVITY_PORT_UP,
3474 EL_SP_PORT_HORIZONTAL,
3475 EL_SP_PORT_VERTICAL,
3486 EL_SP_HARDWARE_GRAY,
3487 EL_SP_HARDWARE_GREEN,
3488 EL_SP_HARDWARE_BLUE,
3490 EL_SP_HARDWARE_YELLOW,
3491 EL_SP_HARDWARE_BASE_1,
3492 EL_SP_HARDWARE_BASE_2,
3493 EL_SP_HARDWARE_BASE_3,
3494 EL_SP_HARDWARE_BASE_4,
3495 EL_SP_HARDWARE_BASE_5,
3496 EL_SP_HARDWARE_BASE_6,
3497 EL_SP_GRAVITY_ON_PORT_LEFT,
3498 EL_SP_GRAVITY_ON_PORT_RIGHT,
3499 EL_SP_GRAVITY_ON_PORT_UP,
3500 EL_SP_GRAVITY_ON_PORT_DOWN,
3501 EL_SP_GRAVITY_OFF_PORT_LEFT,
3502 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3503 EL_SP_GRAVITY_OFF_PORT_UP,
3504 EL_SP_GRAVITY_OFF_PORT_DOWN,
3505 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3506 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3507 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3508 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3509 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3510 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3511 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3512 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3513 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3514 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3515 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3516 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3517 EL_SIGN_EXCLAMATION,
3518 EL_SIGN_RADIOACTIVITY,
3529 EL_STEELWALL_SLIPPERY,
3534 EL_EMC_WALL_SLIPPERY_1,
3535 EL_EMC_WALL_SLIPPERY_2,
3536 EL_EMC_WALL_SLIPPERY_3,
3537 EL_EMC_WALL_SLIPPERY_4,
3558 static int ep_em_slippery_wall[] =
3563 static int ep_gfx_crumbled[] =
3573 static int ep_editor_cascade_active[] =
3575 EL_INTERNAL_CASCADE_BD_ACTIVE,
3576 EL_INTERNAL_CASCADE_EM_ACTIVE,
3577 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3578 EL_INTERNAL_CASCADE_RND_ACTIVE,
3579 EL_INTERNAL_CASCADE_SB_ACTIVE,
3580 EL_INTERNAL_CASCADE_SP_ACTIVE,
3581 EL_INTERNAL_CASCADE_DC_ACTIVE,
3582 EL_INTERNAL_CASCADE_DX_ACTIVE,
3583 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3584 EL_INTERNAL_CASCADE_CE_ACTIVE,
3585 EL_INTERNAL_CASCADE_GE_ACTIVE,
3586 EL_INTERNAL_CASCADE_REF_ACTIVE,
3587 EL_INTERNAL_CASCADE_USER_ACTIVE,
3588 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3593 static int ep_editor_cascade_inactive[] =
3595 EL_INTERNAL_CASCADE_BD,
3596 EL_INTERNAL_CASCADE_EM,
3597 EL_INTERNAL_CASCADE_EMC,
3598 EL_INTERNAL_CASCADE_RND,
3599 EL_INTERNAL_CASCADE_SB,
3600 EL_INTERNAL_CASCADE_SP,
3601 EL_INTERNAL_CASCADE_DC,
3602 EL_INTERNAL_CASCADE_DX,
3603 EL_INTERNAL_CASCADE_CHARS,
3604 EL_INTERNAL_CASCADE_CE,
3605 EL_INTERNAL_CASCADE_GE,
3606 EL_INTERNAL_CASCADE_REF,
3607 EL_INTERNAL_CASCADE_USER,
3608 EL_INTERNAL_CASCADE_DYNAMIC,
3613 static int ep_obsolete[] =
3617 EL_EM_KEY_1_FILE_OBSOLETE,
3618 EL_EM_KEY_2_FILE_OBSOLETE,
3619 EL_EM_KEY_3_FILE_OBSOLETE,
3620 EL_EM_KEY_4_FILE_OBSOLETE,
3621 EL_ENVELOPE_OBSOLETE,
3630 } element_properties[] =
3632 { ep_diggable, EP_DIGGABLE },
3633 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3634 { ep_dont_run_into, EP_DONT_RUN_INTO },
3635 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3636 { ep_dont_touch, EP_DONT_TOUCH },
3637 { ep_indestructible, EP_INDESTRUCTIBLE },
3638 { ep_slippery, EP_SLIPPERY },
3639 { ep_can_change, EP_CAN_CHANGE },
3640 { ep_can_move, EP_CAN_MOVE },
3641 { ep_can_fall, EP_CAN_FALL },
3642 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3643 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3644 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3645 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3646 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3647 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3648 { ep_walkable_over, EP_WALKABLE_OVER },
3649 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3650 { ep_walkable_under, EP_WALKABLE_UNDER },
3651 { ep_passable_over, EP_PASSABLE_OVER },
3652 { ep_passable_inside, EP_PASSABLE_INSIDE },
3653 { ep_passable_under, EP_PASSABLE_UNDER },
3654 { ep_droppable, EP_DROPPABLE },
3655 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3656 { ep_pushable, EP_PUSHABLE },
3657 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3658 { ep_protected, EP_PROTECTED },
3659 { ep_throwable, EP_THROWABLE },
3660 { ep_can_explode, EP_CAN_EXPLODE },
3661 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3663 { ep_player, EP_PLAYER },
3664 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3665 { ep_switchable, EP_SWITCHABLE },
3666 { ep_bd_element, EP_BD_ELEMENT },
3667 { ep_sp_element, EP_SP_ELEMENT },
3668 { ep_sb_element, EP_SB_ELEMENT },
3670 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3671 { ep_food_penguin, EP_FOOD_PENGUIN },
3672 { ep_food_pig, EP_FOOD_PIG },
3673 { ep_historic_wall, EP_HISTORIC_WALL },
3674 { ep_historic_solid, EP_HISTORIC_SOLID },
3675 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3676 { ep_belt, EP_BELT },
3677 { ep_belt_active, EP_BELT_ACTIVE },
3678 { ep_belt_switch, EP_BELT_SWITCH },
3679 { ep_tube, EP_TUBE },
3680 { ep_keygate, EP_KEYGATE },
3681 { ep_amoeboid, EP_AMOEBOID },
3682 { ep_amoebalive, EP_AMOEBALIVE },
3683 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3684 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3685 { ep_can_grow, EP_CAN_GROW },
3686 { ep_active_bomb, EP_ACTIVE_BOMB },
3687 { ep_inactive, EP_INACTIVE },
3689 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3691 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3693 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
3694 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
3696 { ep_obsolete, EP_OBSOLETE },
3703 /* always start with reliable default values (element has no properties) */
3704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3705 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3706 SET_PROPERTY(i, j, FALSE);
3708 /* set all base element properties from above array definitions */
3709 for (i = 0; element_properties[i].elements != NULL; i++)
3710 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3711 SET_PROPERTY((element_properties[i].elements)[j],
3712 element_properties[i].property, TRUE);
3714 /* copy properties to some elements that are only stored in level file */
3715 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3716 for (j = 0; copy_properties[j][0] != -1; j++)
3717 if (HAS_PROPERTY(copy_properties[j][0], i))
3718 for (k = 1; k <= 4; k++)
3719 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3722 void InitElementPropertiesEngine(int engine_version)
3724 static int no_wall_properties[] =
3727 EP_COLLECTIBLE_ONLY,
3729 EP_DONT_COLLIDE_WITH,
3732 EP_CAN_SMASH_PLAYER,
3733 EP_CAN_SMASH_ENEMIES,
3734 EP_CAN_SMASH_EVERYTHING,
3739 EP_FOOD_DARK_YAMYAM,
3755 /* important: after initialization in InitElementPropertiesStatic(), the
3756 elements are not again initialized to a default value; therefore all
3757 changes have to make sure that they leave the element with a defined
3758 property (which means that conditional property changes must be set to
3759 a reliable default value before) */
3761 /* ---------- recursively resolve group elements ------------------------- */
3763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3764 for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3765 element_info[i].in_group[j] = FALSE;
3767 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3768 resolve_group_element(EL_GROUP_START + i, 0);
3770 /* set all special, combined or engine dependent element properties */
3771 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3773 /* ---------- INACTIVE ------------------------------------------------- */
3774 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3776 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3777 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3778 IS_WALKABLE_INSIDE(i) ||
3779 IS_WALKABLE_UNDER(i)));
3781 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3782 IS_PASSABLE_INSIDE(i) ||
3783 IS_PASSABLE_UNDER(i)));
3785 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3786 IS_PASSABLE_OVER(i)));
3788 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3789 IS_PASSABLE_INSIDE(i)));
3791 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3792 IS_PASSABLE_UNDER(i)));
3794 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3797 /* ---------- COLLECTIBLE ---------------------------------------------- */
3798 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3802 /* ---------- SNAPPABLE ------------------------------------------------ */
3803 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3804 IS_COLLECTIBLE(i) ||
3808 /* ---------- WALL ----------------------------------------------------- */
3809 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3811 for (j = 0; no_wall_properties[j] != -1; j++)
3812 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3813 i >= EL_FIRST_RUNTIME_UNREAL)
3814 SET_PROPERTY(i, EP_WALL, FALSE);
3816 if (IS_HISTORIC_WALL(i))
3817 SET_PROPERTY(i, EP_WALL, TRUE);
3819 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3820 if (engine_version < VERSION_IDENT(2,2,0,0))
3821 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3823 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3825 !IS_COLLECTIBLE(i)));
3827 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3829 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3830 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3832 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3833 IS_INDESTRUCTIBLE(i)));
3835 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3837 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3838 else if (engine_version < VERSION_IDENT(2,2,0,0))
3839 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3841 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3845 if (IS_CUSTOM_ELEMENT(i))
3847 /* these are additional properties which are initially false when set */
3849 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3851 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3852 if (DONT_COLLIDE_WITH(i))
3853 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3855 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3856 if (CAN_SMASH_EVERYTHING(i))
3857 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3858 if (CAN_SMASH_ENEMIES(i))
3859 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3862 /* ---------- CAN_SMASH ------------------------------------------------ */
3863 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3864 CAN_SMASH_ENEMIES(i) ||
3865 CAN_SMASH_EVERYTHING(i)));
3867 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3868 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3869 EXPLODES_BY_FIRE(i)));
3871 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3872 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3873 EXPLODES_SMASHED(i)));
3875 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3876 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3877 EXPLODES_IMPACT(i)));
3879 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3880 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3882 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3883 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3884 i == EL_BLACK_ORB));
3886 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3887 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3889 IS_CUSTOM_ELEMENT(i)));
3891 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3892 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3893 i == EL_SP_ELECTRON));
3895 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3896 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3897 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3898 getMoveIntoAcidProperty(&level, i));
3900 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3901 if (MAYBE_DONT_COLLIDE_WITH(i))
3902 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3903 getDontCollideWithProperty(&level, i));
3905 /* ---------- SP_PORT -------------------------------------------------- */
3906 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3907 IS_PASSABLE_INSIDE(i)));
3909 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3910 for (j = 0; j < level.num_android_clone_elements; j++)
3911 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3913 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3915 /* ---------- CAN_CHANGE ----------------------------------------------- */
3916 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3917 for (j = 0; j < element_info[i].num_change_pages; j++)
3918 if (element_info[i].change_page[j].can_change)
3919 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3921 /* ---------- HAS_ACTION ----------------------------------------------- */
3922 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
3923 for (j = 0; j < element_info[i].num_change_pages; j++)
3924 if (element_info[i].change_page[j].has_action)
3925 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3927 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3928 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3931 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3933 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3934 element_info[i].crumbled[ACTION_DEFAULT] !=
3935 element_info[i].graphic[ACTION_DEFAULT]);
3937 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3938 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3939 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3942 /* ---------- EDITOR_CASCADE ------------------------------------------- */
3943 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3944 IS_EDITOR_CASCADE_INACTIVE(i)));
3947 /* dynamically adjust element properties according to game engine version */
3949 static int ep_em_slippery_wall[] =
3954 EL_EXPANDABLE_WALL_HORIZONTAL,
3955 EL_EXPANDABLE_WALL_VERTICAL,
3956 EL_EXPANDABLE_WALL_ANY,
3960 /* special EM style gems behaviour */
3961 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3962 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3963 level.em_slippery_gems);
3965 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3966 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3967 (level.em_slippery_gems &&
3968 engine_version > VERSION_IDENT(2,0,1,0)));
3971 /* this is needed because some graphics depend on element properties */
3972 if (game_status == GAME_MODE_PLAYING)
3973 InitElementGraphicInfo();
3976 void InitElementPropertiesAfterLoading(int engine_version)
3980 /* set some other uninitialized values of custom elements in older levels */
3981 if (engine_version < VERSION_IDENT(3,1,0,0))
3983 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3985 int element = EL_CUSTOM_START + i;
3987 element_info[element].access_direction = MV_ALL_DIRECTIONS;
3989 element_info[element].explosion_delay = 17;
3990 element_info[element].ignition_delay = 8;
3995 static void InitGlobal()
3999 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4001 /* check if element_name_info entry defined for each element in "main.h" */
4002 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4003 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4005 element_info[i].token_name = element_name_info[i].token_name;
4006 element_info[i].class_name = element_name_info[i].class_name;
4007 element_info[i].editor_description=element_name_info[i].editor_description;
4010 global.autoplay_leveldir = NULL;
4011 global.convert_leveldir = NULL;
4013 global.frames_per_second = 0;
4014 global.fps_slowdown = FALSE;
4015 global.fps_slowdown_factor = 1;
4018 void Execute_Command(char *command)
4022 if (strEqual(command, "print graphicsinfo.conf"))
4024 printf("# You can configure additional/alternative image files here.\n");
4025 printf("# (The entries below are default and therefore commented out.)\n");
4027 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4029 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4032 for (i = 0; image_config[i].token != NULL; i++)
4033 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4034 image_config[i].value));
4038 else if (strEqual(command, "print soundsinfo.conf"))
4040 printf("# You can configure additional/alternative sound files here.\n");
4041 printf("# (The entries below are default and therefore commented out.)\n");
4043 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4045 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4048 for (i = 0; sound_config[i].token != NULL; i++)
4049 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4050 sound_config[i].value));
4054 else if (strEqual(command, "print musicinfo.conf"))
4056 printf("# You can configure additional/alternative music files here.\n");
4057 printf("# (The entries below are default and therefore commented out.)\n");
4059 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4061 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4064 for (i = 0; music_config[i].token != NULL; i++)
4065 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4066 music_config[i].value));
4070 else if (strEqual(command, "print editorsetup.conf"))
4072 printf("# You can configure your personal editor element list here.\n");
4073 printf("# (The entries below are default and therefore commented out.)\n");
4076 /* this is needed to be able to check element list for cascade elements */
4077 InitElementPropertiesStatic();
4078 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4080 PrintEditorElementList();
4084 else if (strEqual(command, "print helpanim.conf"))
4086 printf("# You can configure different element help animations here.\n");
4087 printf("# (The entries below are default and therefore commented out.)\n");
4090 for (i = 0; helpanim_config[i].token != NULL; i++)
4092 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4093 helpanim_config[i].value));
4095 if (strEqual(helpanim_config[i].token, "end"))
4101 else if (strEqual(command, "print helptext.conf"))
4103 printf("# You can configure different element help text here.\n");
4104 printf("# (The entries below are default and therefore commented out.)\n");
4107 for (i = 0; helptext_config[i].token != NULL; i++)
4108 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4109 helptext_config[i].value));
4113 else if (strncmp(command, "dump level ", 11) == 0)
4115 char *filename = &command[11];
4117 if (!fileExists(filename))
4118 Error(ERR_EXIT, "cannot open file '%s'", filename);
4120 LoadLevelFromFilename(&level, filename);
4125 else if (strncmp(command, "dump tape ", 10) == 0)
4127 char *filename = &command[10];
4129 if (!fileExists(filename))
4130 Error(ERR_EXIT, "cannot open file '%s'", filename);
4132 LoadTapeFromFilename(filename);
4137 else if (strncmp(command, "autoplay ", 9) == 0)
4139 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4141 while (*str_ptr != '\0') /* continue parsing string */
4143 /* cut leading whitespace from string, replace it by string terminator */
4144 while (*str_ptr == ' ' || *str_ptr == '\t')
4147 if (*str_ptr == '\0') /* end of string reached */
4150 if (global.autoplay_leveldir == NULL) /* read level set string */
4152 global.autoplay_leveldir = str_ptr;
4153 global.autoplay_all = TRUE; /* default: play all tapes */
4155 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4156 global.autoplay_level[i] = FALSE;
4158 else /* read level number string */
4160 int level_nr = atoi(str_ptr); /* get level_nr value */
4162 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4163 global.autoplay_level[level_nr] = TRUE;
4165 global.autoplay_all = FALSE;
4168 /* advance string pointer to the next whitespace (or end of string) */
4169 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4173 else if (strncmp(command, "convert ", 8) == 0)
4175 char *str_copy = getStringCopy(&command[8]);
4176 char *str_ptr = strchr(str_copy, ' ');
4178 global.convert_leveldir = str_copy;
4179 global.convert_level_nr = -1;
4181 if (str_ptr != NULL) /* level number follows */
4183 *str_ptr++ = '\0'; /* terminate leveldir string */
4184 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4189 #if defined(TARGET_SDL)
4190 else if (strEqual(command, "SDL_ListModes"))
4195 SDL_Init(SDL_INIT_VIDEO);
4197 /* get available fullscreen/hardware modes */
4198 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4200 /* check if there are any modes available */
4203 printf("No modes available!\n");
4208 /* check if our resolution is restricted */
4209 if (modes == (SDL_Rect **)-1)
4211 printf("All resolutions available.\n");
4215 printf("Available Modes:\n");
4217 for(i = 0; modes[i]; i++)
4218 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4228 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4232 static void InitSetup()
4234 LoadSetup(); /* global setup info */
4236 /* set some options from setup file */
4238 if (setup.options.verbose)
4239 options.verbose = TRUE;
4242 static void InitGameInfo()
4244 game.restart_level = FALSE;
4247 static void InitPlayerInfo()
4251 /* choose default local player */
4252 local_player = &stored_player[0];
4254 for (i = 0; i < MAX_PLAYERS; i++)
4255 stored_player[i].connected = FALSE;
4257 local_player->connected = TRUE;
4260 static void InitArtworkInfo()
4265 static char *get_string_in_brackets(char *string)
4267 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4269 sprintf(string_in_brackets, "[%s]", string);
4271 return string_in_brackets;
4274 static char *get_level_id_suffix(int id_nr)
4276 char *id_suffix = checked_malloc(1 + 3 + 1);
4278 if (id_nr < 0 || id_nr > 999)
4281 sprintf(id_suffix, ".%03d", id_nr);
4287 static char *get_element_class_token(int element)
4289 char *element_class_name = element_info[element].class_name;
4290 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4292 sprintf(element_class_token, "[%s]", element_class_name);
4294 return element_class_token;
4297 static char *get_action_class_token(int action)
4299 char *action_class_name = &element_action_info[action].suffix[1];
4300 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4302 sprintf(action_class_token, "[%s]", action_class_name);
4304 return action_class_token;
4308 static void InitArtworkConfig()
4310 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4311 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4312 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4313 static char *action_id_suffix[NUM_ACTIONS + 1];
4314 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4315 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4316 static char *level_id_suffix[MAX_LEVELS + 1];
4317 static char *dummy[1] = { NULL };
4318 static char *ignore_generic_tokens[] =
4324 static char **ignore_image_tokens;
4325 static char **ignore_sound_tokens;
4326 static char **ignore_music_tokens;
4327 int num_ignore_generic_tokens;
4328 int num_ignore_image_tokens;
4329 int num_ignore_sound_tokens;
4330 int num_ignore_music_tokens;
4333 /* dynamically determine list of generic tokens to be ignored */
4334 num_ignore_generic_tokens = 0;
4335 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4336 num_ignore_generic_tokens++;
4338 /* dynamically determine list of image tokens to be ignored */
4339 num_ignore_image_tokens = num_ignore_generic_tokens;
4340 for (i = 0; image_config_vars[i].token != NULL; i++)
4341 num_ignore_image_tokens++;
4342 ignore_image_tokens =
4343 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4344 for (i = 0; i < num_ignore_generic_tokens; i++)
4345 ignore_image_tokens[i] = ignore_generic_tokens[i];
4346 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4347 ignore_image_tokens[num_ignore_generic_tokens + i] =
4348 image_config_vars[i].token;
4349 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4351 /* dynamically determine list of sound tokens to be ignored */
4352 num_ignore_sound_tokens = num_ignore_generic_tokens;
4353 ignore_sound_tokens =
4354 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4355 for (i = 0; i < num_ignore_generic_tokens; i++)
4356 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4357 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4359 /* dynamically determine list of music tokens to be ignored */
4360 num_ignore_music_tokens = num_ignore_generic_tokens;
4361 ignore_music_tokens =
4362 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4363 for (i = 0; i < num_ignore_generic_tokens; i++)
4364 ignore_music_tokens[i] = ignore_generic_tokens[i];
4365 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4367 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4368 image_id_prefix[i] = element_info[i].token_name;
4369 for (i = 0; i < NUM_FONTS; i++)
4370 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4371 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4373 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4374 sound_id_prefix[i] = element_info[i].token_name;
4375 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4376 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4377 get_string_in_brackets(element_info[i].class_name);
4378 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4380 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4381 music_id_prefix[i] = music_prefix_info[i].prefix;
4382 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4384 for (i = 0; i < NUM_ACTIONS; i++)
4385 action_id_suffix[i] = element_action_info[i].suffix;
4386 action_id_suffix[NUM_ACTIONS] = NULL;
4388 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4389 direction_id_suffix[i] = element_direction_info[i].suffix;
4390 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4392 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4393 special_id_suffix[i] = special_suffix_info[i].suffix;
4394 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4396 for (i = 0; i < MAX_LEVELS; i++)
4397 level_id_suffix[i] = get_level_id_suffix(i);
4398 level_id_suffix[MAX_LEVELS] = NULL;
4400 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4401 image_id_prefix, action_id_suffix, direction_id_suffix,
4402 special_id_suffix, ignore_image_tokens);
4403 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4404 sound_id_prefix, action_id_suffix, dummy,
4405 special_id_suffix, ignore_sound_tokens);
4406 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4407 music_id_prefix, special_id_suffix, level_id_suffix,
4408 dummy, ignore_music_tokens);
4411 static void InitMixer()
4419 char *filename_font_initial = NULL;
4420 Bitmap *bitmap_font_initial = NULL;
4424 /* determine settings for initial font (for displaying startup messages) */
4425 for (i = 0; image_config[i].token != NULL; i++)
4427 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4429 char font_token[128];
4432 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4433 len_font_token = strlen(font_token);
4435 if (strEqual(image_config[i].token, font_token))
4436 filename_font_initial = image_config[i].value;
4437 else if (strlen(image_config[i].token) > len_font_token &&
4438 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4440 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4441 font_initial[j].src_x = atoi(image_config[i].value);
4442 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4443 font_initial[j].src_y = atoi(image_config[i].value);
4444 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4445 font_initial[j].width = atoi(image_config[i].value);
4446 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4447 font_initial[j].height = atoi(image_config[i].value);
4452 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4454 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4455 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4458 if (filename_font_initial == NULL) /* should not happen */
4459 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4461 /* create additional image buffers for double-buffering and cross-fading */
4462 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4463 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4464 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4465 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4467 /* initialize screen properties */
4468 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4469 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4471 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4472 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4473 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4475 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4477 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4478 font_initial[j].bitmap = bitmap_font_initial;
4480 InitFontGraphicInfo();
4482 font_height = getFontHeight(FC_RED);
4484 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4485 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4486 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4488 DrawInitText("Loading graphics:", 120, FC_GREEN);
4491 void RedrawBackground()
4493 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4494 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4496 redraw_mask = REDRAW_ALL;
4499 void InitGfxBackground()
4503 drawto = backbuffer;
4504 fieldbuffer = bitmap_db_field;
4505 SetDrawtoField(DRAW_BACKBUFFER);
4509 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4510 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4512 for (x = 0; x < MAX_BUF_XSIZE; x++)
4513 for (y = 0; y < MAX_BUF_YSIZE; y++)
4516 redraw_mask = REDRAW_ALL;
4519 static void InitLevelInfo()
4521 LoadLevelInfo(); /* global level info */
4522 LoadLevelSetup_LastSeries(); /* last played series info */
4523 LoadLevelSetup_SeriesInfo(); /* last played level info */
4526 void InitLevelArtworkInfo()
4528 LoadLevelArtworkInfo();
4531 static void InitImages()
4533 setLevelArtworkDir(artwork.gfx_first);
4536 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4537 leveldir_current->identifier,
4538 artwork.gfx_current_identifier,
4539 artwork.gfx_current->identifier,
4540 leveldir_current->graphics_set,
4541 leveldir_current->graphics_path);
4544 ReloadCustomImages();
4546 LoadCustomElementDescriptions();
4547 LoadSpecialMenuDesignSettings();
4549 ReinitializeGraphics();
4552 static void InitSound(char *identifier)
4554 if (identifier == NULL)
4555 identifier = artwork.snd_current->identifier;
4557 /* set artwork path to send it to the sound server process */
4558 setLevelArtworkDir(artwork.snd_first);
4560 InitReloadCustomSounds(identifier);
4561 ReinitializeSounds();
4564 static void InitMusic(char *identifier)
4566 if (identifier == NULL)
4567 identifier = artwork.mus_current->identifier;
4569 /* set artwork path to send it to the sound server process */
4570 setLevelArtworkDir(artwork.mus_first);
4572 InitReloadCustomMusic(identifier);
4573 ReinitializeMusic();
4576 void InitNetworkServer()
4578 #if defined(NETWORK_AVALIABLE)
4582 if (!options.network)
4585 #if defined(NETWORK_AVALIABLE)
4586 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4588 if (!ConnectToServer(options.server_host, options.server_port))
4589 Error(ERR_EXIT, "cannot connect to network game server");
4591 SendToServer_PlayerName(setup.player_name);
4592 SendToServer_ProtocolVersion();
4595 SendToServer_NrWanted(nr_wanted);
4599 static char *getNewArtworkIdentifier(int type)
4601 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4602 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4603 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4604 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4605 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4606 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4607 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4608 char *leveldir_identifier = leveldir_current->identifier;
4610 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4611 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4613 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4615 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4616 char *artwork_current_identifier;
4617 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4619 /* leveldir_current may be invalid (level group, parent link) */
4620 if (!validLevelSeries(leveldir_current))
4623 /* 1st step: determine artwork set to be activated in descending order:
4624 --------------------------------------------------------------------
4625 1. setup artwork (when configured to override everything else)
4626 2. artwork set configured in "levelinfo.conf" of current level set
4627 (artwork in level directory will have priority when loading later)
4628 3. artwork in level directory (stored in artwork sub-directory)
4629 4. setup artwork (currently configured in setup menu) */
4631 if (setup_override_artwork)
4632 artwork_current_identifier = setup_artwork_set;
4633 else if (leveldir_artwork_set != NULL)
4634 artwork_current_identifier = leveldir_artwork_set;
4635 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4636 artwork_current_identifier = leveldir_identifier;
4638 artwork_current_identifier = setup_artwork_set;
4641 /* 2nd step: check if it is really needed to reload artwork set
4642 ------------------------------------------------------------ */
4645 if (type == ARTWORK_TYPE_GRAPHICS)
4646 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4647 artwork_new_identifier,
4648 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4649 artwork_current_identifier,
4650 leveldir_current->graphics_set,
4651 leveldir_current->identifier);
4654 /* ---------- reload if level set and also artwork set has changed ------- */
4655 if (leveldir_current_identifier[type] != leveldir_identifier &&
4656 (last_has_level_artwork_set[type] || has_level_artwork_set))
4657 artwork_new_identifier = artwork_current_identifier;
4659 leveldir_current_identifier[type] = leveldir_identifier;
4660 last_has_level_artwork_set[type] = has_level_artwork_set;
4663 if (type == ARTWORK_TYPE_GRAPHICS)
4664 printf("::: 1: '%s'\n", artwork_new_identifier);
4667 /* ---------- reload if "override artwork" setting has changed ----------- */
4668 if (last_override_level_artwork[type] != setup_override_artwork)
4669 artwork_new_identifier = artwork_current_identifier;
4671 last_override_level_artwork[type] = setup_override_artwork;
4674 if (type == ARTWORK_TYPE_GRAPHICS)
4675 printf("::: 2: '%s'\n", artwork_new_identifier);
4678 /* ---------- reload if current artwork identifier has changed ----------- */
4679 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4680 artwork_current_identifier))
4681 artwork_new_identifier = artwork_current_identifier;
4683 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4686 if (type == ARTWORK_TYPE_GRAPHICS)
4687 printf("::: 3: '%s'\n", artwork_new_identifier);
4690 /* ---------- do not reload directly after starting ---------------------- */
4691 if (!initialized[type])
4692 artwork_new_identifier = NULL;
4694 initialized[type] = TRUE;
4697 if (type == ARTWORK_TYPE_GRAPHICS)
4698 printf("::: 4: '%s'\n", artwork_new_identifier);
4702 if (type == ARTWORK_TYPE_GRAPHICS)
4703 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4704 artwork.gfx_current_identifier, artwork_current_identifier,
4705 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4706 artwork_new_identifier);
4709 return artwork_new_identifier;
4712 void ReloadCustomArtwork(int force_reload)
4714 char *gfx_new_identifier;
4715 char *snd_new_identifier;
4716 char *mus_new_identifier;
4717 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4718 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4719 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4720 boolean redraw_screen = FALSE;
4722 force_reload_gfx |= AdjustGraphicsForEMC();
4724 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4725 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4726 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4728 if (gfx_new_identifier != NULL || force_reload_gfx)
4731 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4732 artwork.gfx_current_identifier,
4734 artwork.gfx_current->identifier,
4735 leveldir_current->graphics_set);
4738 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4742 redraw_screen = TRUE;
4745 if (snd_new_identifier != NULL || force_reload_snd)
4747 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4749 InitSound(snd_new_identifier);
4751 redraw_screen = TRUE;
4754 if (mus_new_identifier != NULL || force_reload_mus)
4756 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4758 InitMusic(mus_new_identifier);
4760 redraw_screen = TRUE;
4767 /* force redraw of (open or closed) door graphics */
4768 SetDoorState(DOOR_OPEN_ALL);
4769 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4773 void KeyboardAutoRepeatOffUnlessAutoplay()
4775 if (global.autoplay_leveldir == NULL)
4776 KeyboardAutoRepeatOff();
4780 /* ========================================================================= */
4782 /* ========================================================================= */
4786 InitGlobal(); /* initialize some global variables */
4788 if (options.execute_command)
4789 Execute_Command(options.execute_command);
4791 if (options.serveronly)
4793 #if defined(PLATFORM_UNIX)
4794 NetworkServer(options.server_port, options.serveronly);
4796 Error(ERR_WARN, "networking only supported in Unix version");
4799 exit(0); /* never reached, server loops forever */
4806 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4807 InitArtworkConfig(); /* needed before forking sound child process */
4812 InitRND(NEW_RANDOMIZE);
4813 InitSimpleRandom(NEW_RANDOMIZE);
4818 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4821 InitEventFilter(FilterMouseMotionEvents);
4823 InitElementPropertiesStatic();
4824 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4829 InitLevelArtworkInfo();
4831 InitImages(); /* needs to know current level directory */
4832 InitSound(NULL); /* needs to know current level directory */
4833 InitMusic(NULL); /* needs to know current level directory */
4835 InitGfxBackground();
4841 if (global.autoplay_leveldir)
4846 else if (global.convert_leveldir)
4852 game_status = GAME_MODE_MAIN;
4856 InitNetworkServer();
4859 void CloseAllAndExit(int exit_value)
4864 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4872 #if defined(TARGET_SDL)
4873 if (network_server) /* terminate network server */
4874 SDL_KillThread(server_thread);
4877 CloseVideoDisplay();
4878 ClosePlatformDependentStuff();
4880 if (exit_value != 0)
4881 NotifyUserAboutErrorFile();