1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY_INITIAL "global.busy_initial"
38 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
39 #define CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD "global.busy_playfield"
40 #define CONFIG_TOKEN_BACKGROUND "background"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
42 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
44 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
45 #define INITIAL_IMG_GLOBAL_BUSY 1
46 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD 2
48 #define NUM_INITIAL_IMAGES_BUSY 3
50 #define INITIAL_IMG_BACKGROUND 3
51 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 4
52 #define INITIAL_IMG_BACKGROUND_LOADING 5
54 #define NUM_INITIAL_IMAGES 6
57 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
58 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
60 static int copy_properties[][5] =
64 EL_BUG_LEFT, EL_BUG_RIGHT,
65 EL_BUG_UP, EL_BUG_DOWN
69 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
70 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
74 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
75 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
79 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
80 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
84 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
85 EL_PACMAN_UP, EL_PACMAN_DOWN
89 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
90 EL_YAMYAM_UP, EL_YAMYAM_DOWN
94 EL_MOLE_LEFT, EL_MOLE_RIGHT,
95 EL_MOLE_UP, EL_MOLE_DOWN
99 EL_SPRING_LEFT, EL_SPRING_RIGHT,
100 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
109 // forward declaration for internal use
110 static int get_graphic_parameter_value(char *, char *, int);
113 static int getLoadingBackgroundImage(int graphic)
115 return getImageFromGraphicOrDefault(graphic, INITIAL_IMG_BACKGROUND);
118 static void SetLoadingWindowBackgroundImage(int graphic)
120 SetBackgroundImage(getLoadingBackgroundImage(graphic), REDRAW_ALL);
123 static void SetLoadingBackgroundImage(void)
125 struct GraphicInfo *graphic_info_last = graphic_info;
126 int background_image = (game_status_last_screen == -1 ?
127 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
128 INITIAL_IMG_BACKGROUND_LOADING);
130 graphic_info = image_initial;
132 SetDrawDeactivationMask(REDRAW_NONE);
133 SetDrawBackgroundMask(REDRAW_ALL);
135 SetLoadingWindowBackgroundImage(background_image);
137 graphic_info = graphic_info_last;
140 static void DrawInitAnim(boolean only_when_loading)
142 struct GraphicInfo *graphic_info_last = graphic_info;
143 int graphic = (game_status_last_screen == -1 ?
144 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
145 game_status == GAME_MODE_LOADING ?
146 INITIAL_IMG_GLOBAL_BUSY :
147 INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
148 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
149 &init_last.busy_initial :
150 game_status == GAME_MODE_LOADING ?
152 &init_last.busy_playfield);
153 static DelayCounter action_delay = { 0 };
154 int sync_frame = FrameCounter;
157 action_delay.value = GameFrameDelay;
159 // prevent OS (Windows) from complaining about program not responding
162 if (game_status != GAME_MODE_LOADING && only_when_loading)
165 if (image_initial[graphic].bitmap == NULL || window == NULL)
168 if (!DelayReached(&action_delay))
172 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
174 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
176 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
177 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
179 graphic_info = image_initial;
181 if (sync_frame % image_initial[graphic].anim_delay == 0)
185 int width = graphic_info[graphic].width;
186 int height = graphic_info[graphic].height;
187 int frame = getGraphicAnimationFrame(graphic, sync_frame);
189 ClearRectangleOnBackground(drawto, x, y, width, height);
191 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
192 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 graphic_info = graphic_info_last;
202 static void DrawProgramInfo(void)
204 int font1_nr = FC_YELLOW;
205 int font2_nr = FC_RED;
206 int font2_height = getFontHeight(font2_nr);
209 int ypos3 = WIN_YSIZE - 20 - font2_height;
211 DrawInitText(getProgramInitString(), ypos1, font1_nr);
212 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
213 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
216 static void FreeGadgets(void)
218 FreeLevelEditorGadgets();
225 void InitGadgets(void)
227 static boolean gadgets_initialized = FALSE;
229 if (gadgets_initialized)
232 CreateLevelEditorGadgets();
236 CreateScreenGadgets();
238 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
240 gadgets_initialized = TRUE;
243 static void InitElementSmallImagesScaledUp(int graphic)
245 struct GraphicInfo *g = &graphic_info[graphic];
247 // if graphic was cloned, scale cloned graphic
248 if (graphic_info[graphic].clone_from != -1)
249 graphic = graphic_info[graphic].clone_from;
251 // create small and game tile sized bitmaps (and scale up, if needed)
252 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
255 static void InitElementSmallImages(void)
257 print_timestamp_init("InitElementSmallImages");
259 static int special_graphics[] =
273 IMG_EDITOR_ELEMENT_BORDER,
274 IMG_EDITOR_ELEMENT_BORDER_INPUT,
275 IMG_EDITOR_CASCADE_LIST,
276 IMG_EDITOR_CASCADE_LIST_ACTIVE,
279 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
280 int num_property_mappings = getImageListPropertyMappingSize();
283 print_timestamp_time("getImageListPropertyMapping/Size");
285 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
286 // initialize normal element images from static configuration
287 for (i = 0; element_to_graphic[i].element > -1; i++)
288 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
289 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
291 // initialize special element images from static configuration
292 for (i = 0; element_to_special_graphic[i].element > -1; i++)
293 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
294 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
296 // initialize element images from dynamic configuration
297 for (i = 0; i < num_property_mappings; i++)
298 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
299 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
300 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
302 // initialize special non-element images from above list
303 for (i = 0; special_graphics[i] > -1; i++)
304 InitElementSmallImagesScaledUp(special_graphics[i]);
305 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
307 print_timestamp_done("InitElementSmallImages");
310 static void InitScaledImagesScaledUp(int graphic)
312 struct GraphicInfo *g = &graphic_info[graphic];
314 // if graphic was cloned, scale cloned graphic
315 if (graphic_info[graphic].clone_from != -1)
316 graphic = graphic_info[graphic].clone_from;
318 ScaleImage(graphic, g->scale_up_factor);
321 static void InitScaledImages(void)
323 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
324 int num_property_mappings = getImageListPropertyMappingSize();
327 // scale normal images from static configuration, if not already scaled
328 for (i = 0; i < NUM_IMAGE_FILES; i++)
329 InitScaledImagesScaledUp(i);
331 // scale images from dynamic configuration, if not already scaled
332 for (i = 0; i < num_property_mappings; i++)
333 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
336 static void InitBitmapPointers(void)
338 int num_images = getImageListSize();
341 // standard size bitmap may have changed -- update default bitmap pointer
342 for (i = 0; i < num_images; i++)
343 if (graphic_info[i].bitmaps)
344 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
347 void InitImageTextures(void)
349 static int texture_graphics[] =
351 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
352 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
353 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
354 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
355 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
356 IMG_MENU_BUTTON_TOUCH_BACK,
357 IMG_MENU_BUTTON_TOUCH_NEXT,
358 IMG_MENU_BUTTON_TOUCH_BACK2,
359 IMG_MENU_BUTTON_TOUCH_NEXT2,
364 FreeAllImageTextures();
366 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
367 CreateImageTextures(i);
369 for (i = 0; i < MAX_NUM_TOONS; i++)
370 CreateImageTextures(IMG_TOON_1 + i);
372 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
374 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
376 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
378 int graphic = global_anim_info[i].graphic[j][k];
380 if (graphic == IMG_UNDEFINED)
383 CreateImageTextures(graphic);
388 for (i = 0; texture_graphics[i] > -1; i++)
389 CreateImageTextures(texture_graphics[i]);
392 static int getFontSpecialSuffix(void)
396 // (special case: do not use special font for GAME_MODE_LOADING)
397 if (game_status >= GAME_MODE_TITLE_INITIAL &&
398 game_status <= GAME_MODE_PSEUDO_PREVIEW)
399 special = game_status;
400 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
401 special = GFX_SPECIAL_ARG_MAIN;
402 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
403 special = GFX_SPECIAL_ARG_NAMES;
408 static int getFontBitmapID(int font_nr)
410 int special = getFontSpecialSuffix();
413 return font_info[font_nr].special_bitmap_id[special];
418 static int getFontFromToken(char *token)
420 char *value = getHashEntry(font_token_hash, token);
425 // if font not found, use reliable default value
426 return FONT_INITIAL_1;
429 static char *getTokenFromFont(int font_nr)
431 static char *token = NULL;
432 int special = getFontSpecialSuffix();
437 token = getStringCat2(font_info[font_nr].token_name,
438 special_suffix_info[special].suffix);
440 token = getStringCopy(font_info[font_nr].token_name);
445 static void InitFontGraphicInfo(void)
447 static struct FontBitmapInfo *font_bitmap_info = NULL;
448 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
449 int num_property_mappings = getImageListPropertyMappingSize();
450 int num_font_bitmaps = NUM_FONTS;
453 if (graphic_info == NULL) // still at startup phase
455 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
456 getFontBitmapID, getFontFromToken, getTokenFromFont);
461 // ---------- initialize font graphic definitions ----------
463 // always start with reliable default values (normal font graphics)
464 for (i = 0; i < NUM_FONTS; i++)
465 font_info[i].graphic = IMG_FONT_INITIAL_1;
467 // initialize normal font/graphic mapping from static configuration
468 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
470 int font_nr = font_to_graphic[i].font_nr;
471 int special = font_to_graphic[i].special;
472 int graphic = font_to_graphic[i].graphic;
477 font_info[font_nr].graphic = graphic;
480 // always start with reliable default values (special font graphics)
481 for (i = 0; i < NUM_FONTS; i++)
483 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
485 font_info[i].special_graphic[j] = font_info[i].graphic;
486 font_info[i].special_bitmap_id[j] = i;
490 // initialize special font/graphic mapping from static configuration
491 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
493 int font_nr = font_to_graphic[i].font_nr;
494 int special = font_to_graphic[i].special;
495 int graphic = font_to_graphic[i].graphic;
496 int base_graphic = font2baseimg(font_nr);
498 if (IS_SPECIAL_GFX_ARG(special))
500 boolean base_redefined =
501 getImageListEntryFromImageID(base_graphic)->redefined;
502 boolean special_redefined =
503 getImageListEntryFromImageID(graphic)->redefined;
504 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
506 /* if the base font ("font.title_1", for example) has been redefined,
507 but not the special font ("font.title_1.LEVELS", for example), do not
508 use an existing (in this case considered obsolete) special font
509 anymore, but use the automatically determined default font */
510 /* special case: cloned special fonts must be explicitly redefined,
511 but are not automatically redefined by redefining base font */
512 if (base_redefined && !special_redefined && !special_cloned)
515 font_info[font_nr].special_graphic[special] = graphic;
516 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
521 // initialize special font/graphic mapping from dynamic configuration
522 for (i = 0; i < num_property_mappings; i++)
524 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
525 int special = property_mapping[i].ext3_index;
526 int graphic = property_mapping[i].artwork_index;
528 if (font_nr < 0 || font_nr >= NUM_FONTS)
531 if (IS_SPECIAL_GFX_ARG(special))
533 font_info[font_nr].special_graphic[special] = graphic;
534 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
539 /* correct special font/graphic mapping for cloned fonts for downwards
540 compatibility of PREVIEW fonts -- this is only needed for implicit
541 redefinition of special font by redefined base font, and only if other
542 fonts are cloned from this special font (like in the "Zelda" level set) */
543 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
545 int font_nr = font_to_graphic[i].font_nr;
546 int special = font_to_graphic[i].special;
547 int graphic = font_to_graphic[i].graphic;
549 if (IS_SPECIAL_GFX_ARG(special))
551 boolean special_redefined =
552 getImageListEntryFromImageID(graphic)->redefined;
553 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
555 if (special_cloned && !special_redefined)
559 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
561 int font_nr2 = font_to_graphic[j].font_nr;
562 int special2 = font_to_graphic[j].special;
563 int graphic2 = font_to_graphic[j].graphic;
565 if (IS_SPECIAL_GFX_ARG(special2) &&
566 graphic2 == graphic_info[graphic].clone_from)
568 font_info[font_nr].special_graphic[special] =
569 font_info[font_nr2].special_graphic[special2];
570 font_info[font_nr].special_bitmap_id[special] =
571 font_info[font_nr2].special_bitmap_id[special2];
578 // reset non-redefined ".active" font graphics if normal font is redefined
579 // (this different treatment is needed because normal and active fonts are
580 // independently defined ("active" is not a property of font definitions!)
581 for (i = 0; i < NUM_FONTS; i++)
583 int font_nr_base = i;
584 int font_nr_active = FONT_ACTIVE(font_nr_base);
586 // check only those fonts with exist as normal and ".active" variant
587 if (font_nr_base != font_nr_active)
589 int base_graphic = font_info[font_nr_base].graphic;
590 int active_graphic = font_info[font_nr_active].graphic;
591 boolean base_redefined =
592 getImageListEntryFromImageID(base_graphic)->redefined;
593 boolean active_redefined =
594 getImageListEntryFromImageID(active_graphic)->redefined;
596 /* if the base font ("font.menu_1", for example) has been redefined,
597 but not the active font ("font.menu_1.active", for example), do not
598 use an existing (in this case considered obsolete) active font
599 anymore, but use the automatically determined default font */
600 if (base_redefined && !active_redefined)
601 font_info[font_nr_active].graphic = base_graphic;
603 // now also check each "special" font (which may be the same as above)
604 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
606 int base_graphic = font_info[font_nr_base].special_graphic[j];
607 int active_graphic = font_info[font_nr_active].special_graphic[j];
608 boolean base_redefined =
609 getImageListEntryFromImageID(base_graphic)->redefined;
610 boolean active_redefined =
611 getImageListEntryFromImageID(active_graphic)->redefined;
613 // same as above, but check special graphic definitions, for example:
614 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
615 if (base_redefined && !active_redefined)
617 font_info[font_nr_active].special_graphic[j] =
618 font_info[font_nr_base].special_graphic[j];
619 font_info[font_nr_active].special_bitmap_id[j] =
620 font_info[font_nr_base].special_bitmap_id[j];
626 // ---------- initialize font bitmap array ----------
628 if (font_bitmap_info != NULL)
629 FreeFontInfo(font_bitmap_info);
632 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
634 // ---------- initialize font bitmap definitions ----------
636 for (i = 0; i < NUM_FONTS; i++)
638 if (i < NUM_INITIAL_FONTS)
640 font_bitmap_info[i] = font_initial[i];
644 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
646 int font_bitmap_id = font_info[i].special_bitmap_id[j];
647 int graphic = font_info[i].special_graphic[j];
649 // set 'graphic_info' for font entries, if uninitialized (guessed)
650 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
652 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
653 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
656 // copy font relevant information from graphics information
657 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
658 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
659 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
660 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
661 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
663 font_bitmap_info[font_bitmap_id].offset_x =
664 graphic_info[graphic].offset_x;
665 font_bitmap_info[font_bitmap_id].offset_y =
666 graphic_info[graphic].offset_y;
668 font_bitmap_info[font_bitmap_id].draw_xoffset =
669 graphic_info[graphic].draw_xoffset;
670 font_bitmap_info[font_bitmap_id].draw_yoffset =
671 graphic_info[graphic].draw_yoffset;
673 font_bitmap_info[font_bitmap_id].num_chars =
674 graphic_info[graphic].anim_frames;
675 font_bitmap_info[font_bitmap_id].num_chars_per_line =
676 graphic_info[graphic].anim_frames_per_line;
680 InitFontInfo(font_bitmap_info, num_font_bitmaps,
681 getFontBitmapID, getFontFromToken, getTokenFromFont);
684 static void InitGlobalAnimGraphicInfo(void)
686 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
687 int num_property_mappings = getImageListPropertyMappingSize();
690 if (graphic_info == NULL) // still at startup phase
693 // always start with reliable default values (no global animations)
694 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
695 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
696 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
697 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
699 // initialize global animation definitions from static configuration
700 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
702 int j = GLOBAL_ANIM_ID_PART_BASE;
703 int k = GFX_SPECIAL_ARG_DEFAULT;
705 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
708 // initialize global animation definitions from dynamic configuration
709 for (i = 0; i < num_property_mappings; i++)
711 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
712 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
713 int special = property_mapping[i].ext3_index;
714 int graphic = property_mapping[i].artwork_index;
716 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
719 // set animation part to base part, if not specified
720 if (!IS_GLOBAL_ANIM_PART(part_nr))
721 part_nr = GLOBAL_ANIM_ID_PART_BASE;
723 // set animation screen to default, if not specified
724 if (!IS_SPECIAL_GFX_ARG(special))
725 special = GFX_SPECIAL_ARG_DEFAULT;
727 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
729 // fix default value for ".draw_masked" (for backward compatibility)
730 struct GraphicInfo *g = &graphic_info[graphic];
731 struct FileInfo *image = getImageListEntryFromImageID(graphic);
732 char **parameter_raw = image->parameter;
733 int p = GFX_ARG_DRAW_MASKED;
734 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
735 image_config_suffix[p].token,
736 image_config_suffix[p].type);
738 // if ".draw_masked" parameter is undefined, use default value "TRUE"
739 if (draw_masked == ARG_UNDEFINED_VALUE)
740 g->draw_masked = TRUE;
744 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
745 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
746 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
747 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
748 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
749 Debug("init:InitGlobalAnimGraphicInfo",
750 "anim %d, part %d, mode %d => %d",
751 i, j, k, global_anim_info[i].graphic[j][k]);
755 static void InitGlobalAnimSoundInfo(void)
757 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
758 int num_property_mappings = getSoundListPropertyMappingSize();
761 // always start with reliable default values (no global animation sounds)
762 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
763 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
764 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
765 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
767 // initialize global animation sound definitions from dynamic configuration
768 for (i = 0; i < num_property_mappings; i++)
770 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
771 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
772 int special = property_mapping[i].ext3_index;
773 int sound = property_mapping[i].artwork_index;
775 // sound uses control definition; map it to position of graphic (artwork)
776 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
778 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
781 // set animation part to base part, if not specified
782 if (!IS_GLOBAL_ANIM_PART(part_nr))
783 part_nr = GLOBAL_ANIM_ID_PART_BASE;
785 // set animation screen to default, if not specified
786 if (!IS_SPECIAL_GFX_ARG(special))
787 special = GFX_SPECIAL_ARG_DEFAULT;
789 global_anim_info[anim_nr].sound[part_nr][special] = sound;
793 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
794 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
795 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
796 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
797 Debug("init:InitGlobalAnimSoundInfo",
798 "anim %d, part %d, mode %d => %d",
799 i, j, k, global_anim_info[i].sound[j][k]);
803 static void InitGlobalAnimMusicInfo(void)
805 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
806 int num_property_mappings = getMusicListPropertyMappingSize();
809 // always start with reliable default values (no global animation music)
810 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
811 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
812 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
813 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
815 // initialize global animation music definitions from dynamic configuration
816 for (i = 0; i < num_property_mappings; i++)
818 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
819 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
820 int special = property_mapping[i].ext2_index;
821 int music = property_mapping[i].artwork_index;
823 // music uses control definition; map it to position of graphic (artwork)
824 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
826 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
829 // set animation part to base part, if not specified
830 if (!IS_GLOBAL_ANIM_PART(part_nr))
831 part_nr = GLOBAL_ANIM_ID_PART_BASE;
833 // set animation screen to default, if not specified
834 if (!IS_SPECIAL_GFX_ARG(special))
835 special = GFX_SPECIAL_ARG_DEFAULT;
837 global_anim_info[anim_nr].music[part_nr][special] = music;
841 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
842 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
843 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
844 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
845 Debug("init:InitGlobalAnimMusicInfo",
846 "anim %d, part %d, mode %d => %d",
847 i, j, k, global_anim_info[i].music[j][k]);
851 static void InitElementGraphicInfo(void)
853 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
854 int num_property_mappings = getImageListPropertyMappingSize();
857 if (graphic_info == NULL) // still at startup phase
860 // set values to -1 to identify later as "uninitialized" values
861 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
863 for (act = 0; act < NUM_ACTIONS; act++)
865 element_info[i].graphic[act] = -1;
866 element_info[i].crumbled[act] = -1;
868 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
870 element_info[i].direction_graphic[act][dir] = -1;
871 element_info[i].direction_crumbled[act][dir] = -1;
878 // initialize normal element/graphic mapping from static configuration
879 for (i = 0; element_to_graphic[i].element > -1; i++)
881 int element = element_to_graphic[i].element;
882 int action = element_to_graphic[i].action;
883 int direction = element_to_graphic[i].direction;
884 boolean crumbled = element_to_graphic[i].crumbled;
885 int graphic = element_to_graphic[i].graphic;
886 int base_graphic = el2baseimg(element);
888 if (graphic_info[graphic].bitmap == NULL)
891 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
894 boolean base_redefined =
895 getImageListEntryFromImageID(base_graphic)->redefined;
896 boolean act_dir_redefined =
897 getImageListEntryFromImageID(graphic)->redefined;
899 /* if the base graphic ("emerald", for example) has been redefined,
900 but not the action graphic ("emerald.falling", for example), do not
901 use an existing (in this case considered obsolete) action graphic
902 anymore, but use the automatically determined default graphic */
903 if (base_redefined && !act_dir_redefined)
908 action = ACTION_DEFAULT;
913 element_info[element].direction_crumbled[action][direction] = graphic;
915 element_info[element].crumbled[action] = graphic;
920 element_info[element].direction_graphic[action][direction] = graphic;
922 element_info[element].graphic[action] = graphic;
926 // initialize normal element/graphic mapping from dynamic configuration
927 for (i = 0; i < num_property_mappings; i++)
929 int element = property_mapping[i].base_index;
930 int action = property_mapping[i].ext1_index;
931 int direction = property_mapping[i].ext2_index;
932 int special = property_mapping[i].ext3_index;
933 int graphic = property_mapping[i].artwork_index;
934 boolean crumbled = FALSE;
936 if (special == GFX_SPECIAL_ARG_CRUMBLED)
942 if (graphic_info[graphic].bitmap == NULL)
945 if (element >= MAX_NUM_ELEMENTS || special != -1)
949 action = ACTION_DEFAULT;
954 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
955 element_info[element].direction_crumbled[action][dir] = -1;
958 element_info[element].direction_crumbled[action][direction] = graphic;
960 element_info[element].crumbled[action] = graphic;
965 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
966 element_info[element].direction_graphic[action][dir] = -1;
969 element_info[element].direction_graphic[action][direction] = graphic;
971 element_info[element].graphic[action] = graphic;
975 // now copy all graphics that are defined to be cloned from other graphics
976 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
978 int graphic = element_info[i].graphic[ACTION_DEFAULT];
979 int crumbled_like, diggable_like;
984 crumbled_like = graphic_info[graphic].crumbled_like;
985 diggable_like = graphic_info[graphic].diggable_like;
987 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
989 for (act = 0; act < NUM_ACTIONS; act++)
990 element_info[i].crumbled[act] =
991 element_info[crumbled_like].crumbled[act];
992 for (act = 0; act < NUM_ACTIONS; act++)
993 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
994 element_info[i].direction_crumbled[act][dir] =
995 element_info[crumbled_like].direction_crumbled[act][dir];
998 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
1000 element_info[i].graphic[ACTION_DIGGING] =
1001 element_info[diggable_like].graphic[ACTION_DIGGING];
1002 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1003 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
1004 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
1008 // set hardcoded definitions for some runtime elements without graphic
1009 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
1011 // set hardcoded definitions for some internal elements without graphic
1012 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1014 if (IS_EDITOR_CASCADE_INACTIVE(i))
1015 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
1016 else if (IS_EDITOR_CASCADE_ACTIVE(i))
1017 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
1020 // now set all undefined/invalid graphics to -1 to set to default after it
1021 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1023 for (act = 0; act < NUM_ACTIONS; act++)
1027 graphic = element_info[i].graphic[act];
1028 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1029 element_info[i].graphic[act] = -1;
1031 graphic = element_info[i].crumbled[act];
1032 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1033 element_info[i].crumbled[act] = -1;
1035 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1037 graphic = element_info[i].direction_graphic[act][dir];
1038 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1039 element_info[i].direction_graphic[act][dir] = -1;
1041 graphic = element_info[i].direction_crumbled[act][dir];
1042 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1043 element_info[i].direction_crumbled[act][dir] = -1;
1048 UPDATE_BUSY_STATE();
1050 // adjust graphics with 2nd tile for movement according to direction
1051 // (do this before correcting '-1' values to minimize calculations)
1052 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1054 for (act = 0; act < NUM_ACTIONS; act++)
1056 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1058 int graphic = element_info[i].direction_graphic[act][dir];
1059 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1061 if (act == ACTION_FALLING) // special case
1062 graphic = element_info[i].graphic[act];
1064 if (graphic != -1 &&
1065 graphic_info[graphic].double_movement &&
1066 graphic_info[graphic].swap_double_tiles != 0)
1068 struct GraphicInfo *g = &graphic_info[graphic];
1069 int src_x_front = g->src_x;
1070 int src_y_front = g->src_y;
1071 int src_x_back = g->src_x + g->offset2_x;
1072 int src_y_back = g->src_y + g->offset2_y;
1073 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1075 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1076 src_y_front < src_y_back);
1077 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1078 boolean swap_movement_tiles_autodetected =
1079 (!frames_are_ordered_diagonally &&
1080 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1081 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1082 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1083 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1085 // swap frontside and backside graphic tile coordinates, if needed
1086 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1088 // get current (wrong) backside tile coordinates
1089 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1091 // set frontside tile coordinates to backside tile coordinates
1092 g->src_x = src_x_back;
1093 g->src_y = src_y_back;
1095 // invert tile offset to point to new backside tile coordinates
1099 // do not swap front and backside tiles again after correction
1100 g->swap_double_tiles = 0;
1107 UPDATE_BUSY_STATE();
1109 // now set all '-1' values to element specific default values
1110 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1112 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1113 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1114 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1115 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1117 if (default_graphic == -1)
1118 default_graphic = IMG_UNKNOWN;
1120 if (default_crumbled == -1)
1121 default_crumbled = default_graphic;
1123 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1125 default_direction_graphic[dir] =
1126 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1127 default_direction_crumbled[dir] =
1128 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1130 if (default_direction_graphic[dir] == -1)
1131 default_direction_graphic[dir] = default_graphic;
1133 if (default_direction_crumbled[dir] == -1)
1134 default_direction_crumbled[dir] = default_direction_graphic[dir];
1137 for (act = 0; act < NUM_ACTIONS; act++)
1139 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1140 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1141 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1142 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1143 act == ACTION_TURNING_FROM_RIGHT ||
1144 act == ACTION_TURNING_FROM_UP ||
1145 act == ACTION_TURNING_FROM_DOWN);
1147 // generic default action graphic (defined by "[default]" directive)
1148 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1149 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1150 int default_remove_graphic = IMG_EMPTY;
1152 if (act_remove && default_action_graphic != -1)
1153 default_remove_graphic = default_action_graphic;
1155 // look for special default action graphic (classic game specific)
1156 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1157 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1158 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1159 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1160 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1161 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1162 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1163 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1165 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1166 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1167 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1168 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1169 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1170 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1171 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1172 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1174 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1175 // !!! make this better !!!
1176 if (i == EL_EMPTY_SPACE)
1178 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1179 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1182 if (default_action_graphic == -1)
1183 default_action_graphic = default_graphic;
1185 if (default_action_crumbled == -1)
1186 default_action_crumbled = default_action_graphic;
1188 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1190 // use action graphic as the default direction graphic, if undefined
1191 int default_action_direction_graphic = element_info[i].graphic[act];
1192 int default_action_direction_crumbled = element_info[i].crumbled[act];
1194 // no graphic for current action -- use default direction graphic
1195 if (default_action_direction_graphic == -1)
1196 default_action_direction_graphic =
1197 (act_remove ? default_remove_graphic :
1199 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1200 default_action_graphic != default_graphic ?
1201 default_action_graphic :
1202 default_direction_graphic[dir]);
1204 if (element_info[i].direction_graphic[act][dir] == -1)
1205 element_info[i].direction_graphic[act][dir] =
1206 default_action_direction_graphic;
1208 if (default_action_direction_crumbled == -1)
1209 default_action_direction_crumbled =
1210 element_info[i].direction_graphic[act][dir];
1212 if (element_info[i].direction_crumbled[act][dir] == -1)
1213 element_info[i].direction_crumbled[act][dir] =
1214 default_action_direction_crumbled;
1217 // no graphic for this specific action -- use default action graphic
1218 if (element_info[i].graphic[act] == -1)
1219 element_info[i].graphic[act] =
1220 (act_remove ? default_remove_graphic :
1221 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1222 default_action_graphic);
1224 if (element_info[i].crumbled[act] == -1)
1225 element_info[i].crumbled[act] = element_info[i].graphic[act];
1229 UPDATE_BUSY_STATE();
1232 static void InitElementSpecialGraphicInfo(void)
1234 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1235 int num_property_mappings = getImageListPropertyMappingSize();
1238 // always start with reliable default values
1239 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1240 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1241 element_info[i].special_graphic[j] =
1242 element_info[i].graphic[ACTION_DEFAULT];
1244 // initialize special element/graphic mapping from static configuration
1245 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1247 int element = element_to_special_graphic[i].element;
1248 int special = element_to_special_graphic[i].special;
1249 int graphic = element_to_special_graphic[i].graphic;
1250 int base_graphic = el2baseimg(element);
1251 boolean base_redefined =
1252 getImageListEntryFromImageID(base_graphic)->redefined;
1253 boolean special_redefined =
1254 getImageListEntryFromImageID(graphic)->redefined;
1256 /* if the base graphic ("emerald", for example) has been redefined,
1257 but not the special graphic ("emerald.EDITOR", for example), do not
1258 use an existing (in this case considered obsolete) special graphic
1259 anymore, but use the automatically created (down-scaled) graphic */
1260 if (base_redefined && !special_redefined)
1263 element_info[element].special_graphic[special] = graphic;
1266 // initialize special element/graphic mapping from dynamic configuration
1267 for (i = 0; i < num_property_mappings; i++)
1269 int element = property_mapping[i].base_index;
1270 int action = property_mapping[i].ext1_index;
1271 int direction = property_mapping[i].ext2_index;
1272 int special = property_mapping[i].ext3_index;
1273 int graphic = property_mapping[i].artwork_index;
1275 // for action ".active", replace element with active element, if exists
1276 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1278 element = ELEMENT_ACTIVE(element);
1282 // for BD effect editor graphics, replace element with effect element, if exists
1283 if (action != -1 && special == GFX_SPECIAL_ARG_EDITOR)
1285 int element_bd = map_element_RND_to_BD_effect(element, action);
1286 int element_ef = map_element_BD_to_RND_cave(element_bd);
1288 if (element_ef != EL_UNKNOWN)
1290 element = element_ef;
1295 if (element >= MAX_NUM_ELEMENTS)
1298 // do not change special graphic if action or direction was specified
1299 if (action != -1 || direction != -1)
1302 if (IS_SPECIAL_GFX_ARG(special))
1303 element_info[element].special_graphic[special] = graphic;
1306 // now set all undefined/invalid graphics to default
1307 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1308 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1309 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1310 element_info[i].special_graphic[j] =
1311 element_info[i].graphic[ACTION_DEFAULT];
1314 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1316 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1317 return get_parameter_value(value_raw, suffix, type);
1319 if (strEqual(value_raw, ARG_UNDEFINED))
1320 return ARG_UNDEFINED_VALUE;
1322 if (type == TYPE_ELEMENT)
1324 char *value = getHashEntry(element_token_hash, value_raw);
1329 Warn("error found in config file:");
1330 Warn("- config file: '%s'", getImageConfigFilename());
1331 Warn("error: invalid element token '%s'", value_raw);
1332 Warn("custom graphic rejected for this element/action");
1333 Warn("fallback done to undefined element for this graphic");
1337 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1339 else if (type == TYPE_GRAPHIC)
1341 char *value = getHashEntry(graphic_token_hash, value_raw);
1342 int fallback_graphic = IMG_CHAR_EXCLAM;
1347 Warn("error found in config file:");
1348 Warn("- config file: '%s'", getImageConfigFilename());
1349 Warn("error: invalid graphic token '%s'", value_raw);
1350 Warn("custom graphic rejected for this element/action");
1351 Warn("fallback done to 'char_exclam' for this graphic");
1355 return (value != NULL ? atoi(value) : fallback_graphic);
1361 static int get_scaled_graphic_width(Bitmap *src_bitmap, int graphic)
1363 int original_width = getOriginalImageWidthFromImageID(graphic);
1364 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1366 // only happens when loaded outside artwork system (like "global.busy")
1367 if (graphic_info == image_initial && src_bitmap)
1368 original_width = src_bitmap->width;
1370 return original_width * scale_up_factor;
1373 static int get_scaled_graphic_height(Bitmap *src_bitmap, int graphic)
1375 int original_height = getOriginalImageHeightFromImageID(graphic);
1376 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1378 // only happens when loaded outside artwork system (like "global.busy")
1379 if (graphic_info == image_initial && src_bitmap)
1380 original_height = src_bitmap->height;
1382 return original_height * scale_up_factor;
1385 static void set_graphic_parameters_ext(int graphic, int *parameter,
1386 Bitmap **src_bitmaps)
1388 struct GraphicInfo *g = &graphic_info[graphic];
1389 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1390 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1391 int anim_frames_per_line = 1;
1393 // always start with reliable default values
1394 g->src_image_width = 0;
1395 g->src_image_height = 0;
1398 g->width = TILEX; // default for element graphics
1399 g->height = TILEY; // default for element graphics
1400 g->offset_x = 0; // one or both of these values ...
1401 g->offset_y = 0; // ... will be corrected later
1402 g->offset2_x = 0; // one or both of these values ...
1403 g->offset2_y = 0; // ... will be corrected later
1404 g->swap_double_tiles = -1; // auto-detect tile swapping
1405 g->crumbled_like = -1; // do not use clone element
1406 g->diggable_like = -1; // do not use clone element
1407 g->border_size = TILEX / 8; // "CRUMBLED" border size
1408 g->scale_up_factor = 1; // default: no scaling up
1409 g->tile_size = TILESIZE; // default: standard tile size
1410 g->clone_from = -1; // do not use clone graphic
1411 g->init_delay_fixed = 0;
1412 g->init_delay_random = 0;
1413 g->init_delay_action = -1;
1414 g->anim_delay_fixed = 0;
1415 g->anim_delay_random = 0;
1416 g->anim_delay_action = -1;
1417 g->post_delay_fixed = 0;
1418 g->post_delay_random = 0;
1419 g->post_delay_action = -1;
1420 g->init_event = ANIM_EVENT_UNDEFINED;
1421 g->anim_event = ANIM_EVENT_UNDEFINED;
1422 g->init_event_action = -1;
1423 g->anim_event_action = -1;
1424 g->draw_masked = FALSE;
1426 g->fade_mode = FADE_MODE_DEFAULT;
1430 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1431 g->align = ALIGN_CENTER; // default for title screens
1432 g->valign = VALIGN_MIDDLE; // default for title screens
1433 g->sort_priority = 0; // default for title screens
1435 g->style = STYLE_DEFAULT;
1438 g->bitmaps = src_bitmaps;
1439 g->bitmap = src_bitmap;
1441 // optional zoom factor for scaling up the image to a larger size
1442 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1443 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1444 if (g->scale_up_factor < 1)
1445 g->scale_up_factor = 1; // no scaling
1447 // optional tile size for using non-standard image size
1448 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1450 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1453 // CHECK: should tile sizes less than standard tile size be allowed?
1454 if (g->tile_size < TILESIZE)
1455 g->tile_size = TILESIZE; // standard tile size
1458 // when setting tile size, also set width and height accordingly
1459 g->width = g->tile_size;
1460 g->height = g->tile_size;
1463 if (g->use_image_size)
1465 // set new default bitmap size (with scaling, but without small images)
1466 g->width = get_scaled_graphic_width(src_bitmap, graphic);
1467 g->height = get_scaled_graphic_height(src_bitmap, graphic);
1470 // optional width and height of each animation frame
1471 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1472 g->width = parameter[GFX_ARG_WIDTH];
1473 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1474 g->height = parameter[GFX_ARG_HEIGHT];
1476 // optional x and y tile position of animation frame sequence
1477 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1478 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1479 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1480 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1482 // optional x and y pixel position of animation frame sequence
1483 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1484 g->src_x = parameter[GFX_ARG_X];
1485 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1486 g->src_y = parameter[GFX_ARG_Y];
1493 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1494 g->width, getTokenFromImageID(graphic), TILEX);
1497 g->width = TILEX; // will be checked to be inside bitmap later
1503 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1504 g->height, getTokenFromImageID(graphic), TILEY);
1507 g->height = TILEY; // will be checked to be inside bitmap later
1513 // get final bitmap size (with scaling, but without small images)
1514 int src_image_width = get_scaled_graphic_width(src_bitmap, graphic);
1515 int src_image_height = get_scaled_graphic_height(src_bitmap, graphic);
1517 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1519 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1520 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1524 anim_frames_per_row = MAX(1, src_image_width / g->width);
1525 anim_frames_per_col = MAX(1, src_image_height / g->height);
1528 g->src_image_width = src_image_width;
1529 g->src_image_height = src_image_height;
1532 // correct x or y offset dependent of vertical or horizontal frame order
1533 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1535 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1536 parameter[GFX_ARG_OFFSET] : g->height);
1537 anim_frames_per_line = anim_frames_per_col;
1539 else // frames are ordered horizontally
1541 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1542 parameter[GFX_ARG_OFFSET] : g->width);
1543 anim_frames_per_line = anim_frames_per_row;
1546 // optionally, the x and y offset of frames can be specified directly
1547 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1548 g->offset_x = parameter[GFX_ARG_XOFFSET];
1549 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1550 g->offset_y = parameter[GFX_ARG_YOFFSET];
1552 // optionally, moving animations may have separate start and end graphics
1553 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1555 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1556 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1558 // correct x or y offset2 dependent of vertical or horizontal frame order
1559 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1560 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1561 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1562 else // frames are ordered horizontally
1563 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1564 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1566 // optionally, the x and y offset of 2nd graphic can be specified directly
1567 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1568 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1569 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1570 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1572 // optionally, the second movement tile can be specified as start tile
1573 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1574 g->swap_double_tiles = parameter[GFX_ARG_2ND_SWAP_TILES];
1576 // automatically determine correct number of frames, if not defined
1577 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1578 g->anim_frames = parameter[GFX_ARG_FRAMES];
1579 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1580 g->anim_frames = anim_frames_per_row;
1581 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1582 g->anim_frames = anim_frames_per_col;
1586 if (g->anim_frames < 1) // frames must be at least 1
1589 g->anim_frames_per_line =
1590 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1591 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1593 g->anim_delay = parameter[GFX_ARG_DELAY];
1594 if (g->anim_delay < 1) // delay must be at least 1
1597 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1599 // automatically determine correct start frame, if not defined
1600 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1601 g->anim_start_frame = 0;
1602 else if (g->anim_mode & ANIM_REVERSE)
1603 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1605 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1607 // animation synchronized with global frame counter, not move position
1608 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1610 // animation synchronized with global anim frame counter, not move position
1611 g->anim_global_anim_sync = parameter[GFX_ARG_GLOBAL_ANIM_SYNC];
1613 // optional element for cloning crumble graphics
1614 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1615 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1617 // optional element for cloning digging graphics
1618 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1619 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1621 // optional border size for "crumbling" diggable graphics
1622 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1623 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1625 // used for global animations and player "boring" and "sleeping" actions
1626 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1627 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1628 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1629 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1630 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1631 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1632 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1633 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1634 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1635 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1636 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1637 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1639 // used for global animations
1640 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1641 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1642 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1643 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1644 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1645 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1646 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1647 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1648 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1649 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1650 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1651 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1652 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1653 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1655 // used for toon animations and global animations
1656 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1657 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1658 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1659 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1660 g->direction = parameter[GFX_ARG_DIRECTION];
1661 g->position = parameter[GFX_ARG_POSITION];
1662 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1663 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1665 if (g->step_delay < 1) // delay must be at least 1
1668 // this is only used for drawing font characters
1669 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1670 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1672 // use a different default value for global animations and toons
1673 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_32) ||
1674 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1675 g->draw_masked = TRUE;
1677 // this is used for drawing envelopes, global animations and toons
1678 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1679 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1681 // used for toon animations and global animations
1682 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1683 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1685 // optional graphic for cloning all graphics settings
1686 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1687 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1689 // optional settings for drawing title screens and title messages
1690 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1691 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1692 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1693 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1694 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1695 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1696 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1697 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1698 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1699 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1700 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1701 g->align = parameter[GFX_ARG_ALIGN];
1702 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1703 g->valign = parameter[GFX_ARG_VALIGN];
1704 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1705 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1707 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1708 g->class = parameter[GFX_ARG_CLASS];
1709 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1710 g->style = parameter[GFX_ARG_STYLE];
1711 if (parameter[GFX_ARG_ALPHA] != ARG_UNDEFINED_VALUE)
1712 g->alpha = parameter[GFX_ARG_ALPHA];
1714 // this is only used for drawing menu buttons and text
1715 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1716 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1717 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1718 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1720 // this is only used for drawing stacked global animations
1721 g->stacked_xfactor = parameter[GFX_ARG_STACKED_XFACTOR];
1722 g->stacked_yfactor = parameter[GFX_ARG_STACKED_YFACTOR];
1723 g->stacked_xoffset = parameter[GFX_ARG_STACKED_XOFFSET];
1724 g->stacked_yoffset = parameter[GFX_ARG_STACKED_YOFFSET];
1727 static void set_graphic_parameters(int graphic)
1729 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1730 char **parameter_raw = image->parameter;
1731 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1732 int parameter[NUM_GFX_ARGS];
1735 // if fallback to default artwork is done, also use the default parameters
1736 if (image->fallback_to_default)
1737 parameter_raw = image->default_parameter;
1739 // get integer values from string parameters
1740 for (i = 0; i < NUM_GFX_ARGS; i++)
1741 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1742 image_config_suffix[i].token,
1743 image_config_suffix[i].type);
1745 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1747 UPDATE_BUSY_STATE();
1750 static void set_cloned_graphic_parameters(int graphic)
1752 int fallback_graphic = IMG_CHAR_EXCLAM;
1753 int max_num_images = getImageListSize();
1754 int clone_graphic = graphic_info[graphic].clone_from;
1755 int num_references_followed = 1;
1757 while (graphic_info[clone_graphic].clone_from != -1 &&
1758 num_references_followed < max_num_images)
1760 clone_graphic = graphic_info[clone_graphic].clone_from;
1762 num_references_followed++;
1765 if (num_references_followed >= max_num_images)
1768 Warn("error found in config file:");
1769 Warn("- config file: '%s'", getImageConfigFilename());
1770 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1771 Warn("error: loop discovered when resolving cloned graphics");
1772 Warn("custom graphic rejected for this element/action");
1774 if (graphic == fallback_graphic)
1775 Fail("no fallback graphic available");
1777 Warn("fallback done to 'char_exclam' for this graphic");
1780 graphic_info[graphic] = graphic_info[fallback_graphic];
1784 graphic_info[graphic] = graphic_info[clone_graphic];
1785 graphic_info[graphic].clone_from = clone_graphic;
1789 static void InitGraphicInfo(void)
1791 int fallback_graphic = IMG_CHAR_EXCLAM;
1792 int num_images = getImageListSize();
1795 // use image size as default values for width and height for these images
1796 static int full_size_graphics[] =
1799 IMG_GLOBAL_BORDER_MAIN,
1800 IMG_GLOBAL_BORDER_SCORES,
1801 IMG_GLOBAL_BORDER_EDITOR,
1802 IMG_GLOBAL_BORDER_PLAYING,
1805 IMG_BACKGROUND_ENVELOPE_1,
1806 IMG_BACKGROUND_ENVELOPE_2,
1807 IMG_BACKGROUND_ENVELOPE_3,
1808 IMG_BACKGROUND_ENVELOPE_4,
1809 IMG_BACKGROUND_REQUEST,
1812 IMG_BACKGROUND_LOADING_INITIAL,
1813 IMG_BACKGROUND_LOADING,
1814 IMG_BACKGROUND_TITLE_INITIAL,
1815 IMG_BACKGROUND_TITLE,
1816 IMG_BACKGROUND_MAIN,
1817 IMG_BACKGROUND_NAMES,
1818 IMG_BACKGROUND_LEVELS,
1819 IMG_BACKGROUND_LEVELNR,
1820 IMG_BACKGROUND_SCORES,
1821 IMG_BACKGROUND_SCOREINFO,
1822 IMG_BACKGROUND_EDITOR,
1823 IMG_BACKGROUND_INFO,
1824 IMG_BACKGROUND_INFO_ELEMENTS,
1825 IMG_BACKGROUND_INFO_MUSIC,
1826 IMG_BACKGROUND_INFO_CREDITS,
1827 IMG_BACKGROUND_INFO_PROGRAM,
1828 IMG_BACKGROUND_INFO_VERSION,
1829 IMG_BACKGROUND_INFO_LEVELSET,
1830 IMG_BACKGROUND_SETUP,
1831 IMG_BACKGROUND_PLAYING,
1832 IMG_BACKGROUND_DOOR,
1833 IMG_BACKGROUND_TAPE,
1834 IMG_BACKGROUND_PANEL,
1835 IMG_BACKGROUND_PALETTE,
1836 IMG_BACKGROUND_TOOLBOX,
1838 IMG_TITLESCREEN_INITIAL_1,
1839 IMG_TITLESCREEN_INITIAL_2,
1840 IMG_TITLESCREEN_INITIAL_3,
1841 IMG_TITLESCREEN_INITIAL_4,
1842 IMG_TITLESCREEN_INITIAL_5,
1849 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1850 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1851 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1852 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1853 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1854 IMG_BACKGROUND_TITLEMESSAGE_1,
1855 IMG_BACKGROUND_TITLEMESSAGE_2,
1856 IMG_BACKGROUND_TITLEMESSAGE_3,
1857 IMG_BACKGROUND_TITLEMESSAGE_4,
1858 IMG_BACKGROUND_TITLEMESSAGE_5,
1863 FreeGlobalAnimEventInfo();
1865 checked_free(graphic_info);
1867 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1869 // initialize "use_image_size" flag with default value
1870 for (i = 0; i < num_images; i++)
1871 graphic_info[i].use_image_size = FALSE;
1873 // initialize "use_image_size" flag from static configuration above
1874 for (i = 0; full_size_graphics[i] != -1; i++)
1875 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1877 // first set all graphic paramaters ...
1878 for (i = 0; i < num_images; i++)
1879 set_graphic_parameters(i);
1881 // ... then copy these parameters for cloned graphics
1882 for (i = 0; i < num_images; i++)
1883 if (graphic_info[i].clone_from != -1)
1884 set_cloned_graphic_parameters(i);
1886 for (i = 0; i < num_images; i++)
1888 Bitmap *src_bitmap = graphic_info[i].bitmap;
1892 int src_bitmap_width, src_bitmap_height;
1894 // now check if no animation frames are outside of the loaded image
1896 if (graphic_info[i].bitmap == NULL)
1897 continue; // skip check for optional images that are undefined
1899 // get image size (this can differ from the standard element tile size!)
1900 width = graphic_info[i].width;
1901 height = graphic_info[i].height;
1903 // get final bitmap size (with scaling, but without small images)
1904 src_bitmap_width = graphic_info[i].src_image_width;
1905 src_bitmap_height = graphic_info[i].src_image_height;
1907 // check if first animation frame is inside specified bitmap
1909 // do not use getGraphicSourceXY() here to get position of first frame;
1910 // this avoids calculating wrong start position for out-of-bounds frame
1911 src_x = graphic_info[i].src_x;
1912 src_y = graphic_info[i].src_y;
1914 if (program.headless)
1917 if (src_x < 0 || src_y < 0 ||
1918 src_x + width > src_bitmap_width ||
1919 src_y + height > src_bitmap_height)
1922 Warn("error found in config file:");
1923 Warn("- config file: '%s'", getImageConfigFilename());
1924 Warn("- config token: '%s'", getTokenFromImageID(i));
1925 Warn("- image file: '%s'", src_bitmap->source_filename);
1926 Warn("- frame size: %d, %d", width, height);
1927 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1928 src_x, src_y, src_bitmap_width, src_bitmap_height);
1929 Warn("custom graphic rejected for this element/action");
1931 if (i == fallback_graphic)
1932 Fail("no fallback graphic available");
1934 Warn("fallback done to 'char_exclam' for this graphic");
1937 graphic_info[i] = graphic_info[fallback_graphic];
1939 // if first frame out of bounds, do not check last frame anymore
1943 // check if last animation frame is inside specified bitmap
1945 last_frame = graphic_info[i].anim_frames - 1;
1946 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1948 if (src_x < 0 || src_y < 0 ||
1949 src_x + width > src_bitmap_width ||
1950 src_y + height > src_bitmap_height)
1953 Warn("error found in config file:");
1954 Warn("- config file: '%s'", getImageConfigFilename());
1955 Warn("- config token: '%s'", getTokenFromImageID(i));
1956 Warn("- image file: '%s'", src_bitmap->source_filename);
1957 Warn("- frame size: %d, %d", width, height);
1958 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1959 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1960 Warn("custom graphic rejected for this element/action");
1962 if (i == fallback_graphic)
1963 Fail("no fallback graphic available");
1965 Warn("fallback done to 'char_exclam' for this graphic");
1968 graphic_info[i] = graphic_info[fallback_graphic];
1973 static void InitGraphicCompatibilityInfo(void)
1975 struct FileInfo *fi_global_door =
1976 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1977 int num_images = getImageListSize();
1980 /* the following compatibility handling is needed for the following case:
1981 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1982 graphics mainly used for door and panel graphics, like editor, tape and
1983 in-game buttons with hard-coded bitmap positions and button sizes; as
1984 these graphics now have individual definitions, redefining "global.door"
1985 to change all these graphics at once like before does not work anymore
1986 (because all those individual definitions still have their default values);
1987 to solve this, remap all those individual definitions that are not
1988 redefined to the new bitmap of "global.door" if it was redefined */
1990 // special compatibility handling if image "global.door" was redefined
1991 if (fi_global_door->redefined)
1993 for (i = 0; i < num_images; i++)
1995 struct FileInfo *fi = getImageListEntryFromImageID(i);
1997 // process only those images that still use the default settings
2000 // process all images which default to same image as "global.door"
2001 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2003 // skip all images that are cloned from images that default to same
2004 // image as "global.door", but that are redefined to something else
2005 if (graphic_info[i].clone_from != -1)
2007 int cloned_graphic = graphic_info[i].clone_from;
2009 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
2014 Debug("init:InitGraphicCompatibilityInfo",
2015 "special treatment needed for token '%s'", fi->token);
2018 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
2019 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2025 // special compatibility handling for "Snake Bite" graphics set
2026 if (strPrefix(leveldir_current->identifier, "snake_bite"))
2028 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
2030 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
2031 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
2033 ClearRectangle(bitmap, 2, 66, 32, 480);
2034 ClearRectangle(bitmap, 514, 66, 32, 480);
2037 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
2038 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
2039 if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
2057 int mode_old = GAME_MODE_SCORES;
2058 int mode_new = GAME_MODE_SCOREINFO;
2061 // adjust title screens on score info page
2062 for (i = 0; font_title[i] != -1; i++)
2064 struct FontInfo *fi = &font_info[font_title[i]];
2066 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
2067 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2070 // adjust vertical text and button positions on scores page
2071 for (i = 0; font_text[i] != -1; i++)
2073 for (j = 0; j < 2; j++)
2075 boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2076 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2077 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2078 int font_yoffset = (jue0 ? 10 : 5);
2080 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2084 // adjust page offsets on score info page
2085 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2086 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2089 InitGraphicCompatibilityInfo_Doors();
2092 static void InitElementSoundInfo(void)
2094 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2095 int num_property_mappings = getSoundListPropertyMappingSize();
2098 // set values to -1 to identify later as "uninitialized" values
2099 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2100 for (act = 0; act < NUM_ACTIONS; act++)
2101 element_info[i].sound[act] = -1;
2103 // initialize element/sound mapping from static configuration
2104 for (i = 0; element_to_sound[i].element > -1; i++)
2106 int element = element_to_sound[i].element;
2107 int action = element_to_sound[i].action;
2108 int sound = element_to_sound[i].sound;
2109 boolean is_class = element_to_sound[i].is_class;
2112 action = ACTION_DEFAULT;
2115 element_info[element].sound[action] = sound;
2117 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2118 if (strEqual(element_info[j].class_name,
2119 element_info[element].class_name))
2120 element_info[j].sound[action] = sound;
2123 // initialize element class/sound mapping from dynamic configuration
2124 for (i = 0; i < num_property_mappings; i++)
2126 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2127 int action = property_mapping[i].ext1_index;
2128 int sound = property_mapping[i].artwork_index;
2130 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2134 action = ACTION_DEFAULT;
2136 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2137 if (strEqual(element_info[j].class_name,
2138 element_info[element_class].class_name))
2139 element_info[j].sound[action] = sound;
2142 // initialize element/sound mapping from dynamic configuration
2143 for (i = 0; i < num_property_mappings; i++)
2145 int element = property_mapping[i].base_index;
2146 int action = property_mapping[i].ext1_index;
2147 int sound = property_mapping[i].artwork_index;
2149 if (element >= MAX_NUM_ELEMENTS)
2153 action = ACTION_DEFAULT;
2155 element_info[element].sound[action] = sound;
2158 // now set all '-1' values to element specific default values
2159 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2161 for (act = 0; act < NUM_ACTIONS; act++)
2163 // generic default action sound (defined by "[default]" directive)
2164 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2166 // look for special default action sound (classic game specific)
2167 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2168 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2169 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2170 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2171 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2172 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2173 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2174 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2176 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2177 // !!! make this better !!!
2178 if (i == EL_EMPTY_SPACE)
2179 default_action_sound = element_info[EL_DEFAULT].sound[act];
2181 // no sound for this specific action -- use default action sound
2182 if (element_info[i].sound[act] == -1)
2183 element_info[i].sound[act] = default_action_sound;
2187 // copy sound settings to some elements that are only stored in level file
2188 // in native R'n'D levels, but are used by game engine in native EM levels
2189 for (i = 0; copy_properties[i][0] != -1; i++)
2190 for (j = 1; j <= 4; j++)
2191 for (act = 0; act < NUM_ACTIONS; act++)
2192 element_info[copy_properties[i][j]].sound[act] =
2193 element_info[copy_properties[i][0]].sound[act];
2196 static void InitGameModeSoundInfo(void)
2200 // set values to -1 to identify later as "uninitialized" values
2201 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2204 // initialize gamemode/sound mapping from static configuration
2205 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2207 int gamemode = gamemode_to_sound[i].gamemode;
2208 int sound = gamemode_to_sound[i].sound;
2211 gamemode = GAME_MODE_DEFAULT;
2213 menu.sound[gamemode] = sound;
2216 // now set all '-1' values to levelset specific default values
2217 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2218 if (menu.sound[i] == -1)
2219 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2222 static void set_sound_parameters(int sound, char **parameter_raw)
2224 int parameter[NUM_SND_ARGS];
2227 // get integer values from string parameters
2228 for (i = 0; i < NUM_SND_ARGS; i++)
2230 get_parameter_value(parameter_raw[i],
2231 sound_config_suffix[i].token,
2232 sound_config_suffix[i].type);
2234 // explicit loop mode setting in configuration overrides default value
2235 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2236 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2238 // sound volume to change the original volume when loading the sound file
2239 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2241 // sound priority to give certain sounds a higher or lower priority
2242 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2245 static void InitSoundInfo(void)
2247 int *sound_effect_properties;
2248 int num_sounds = getSoundListSize();
2251 checked_free(sound_info);
2253 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2254 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2256 // initialize sound effect for all elements to "no sound"
2257 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2258 for (j = 0; j < NUM_ACTIONS; j++)
2259 element_info[i].sound[j] = SND_UNDEFINED;
2261 for (i = 0; i < num_sounds; i++)
2263 struct FileInfo *sound = getSoundListEntry(i);
2264 int len_effect_text = strlen(sound->token);
2266 sound_effect_properties[i] = ACTION_OTHER;
2267 sound_info[i].loop = FALSE; // default: play sound only once
2269 // determine all loop sounds and identify certain sound classes
2271 for (j = 0; element_action_info[j].suffix; j++)
2273 int len_action_text = strlen(element_action_info[j].suffix);
2275 if (len_action_text < len_effect_text &&
2276 strEqual(&sound->token[len_effect_text - len_action_text],
2277 element_action_info[j].suffix))
2279 sound_effect_properties[i] = element_action_info[j].value;
2280 sound_info[i].loop = element_action_info[j].is_loop_sound;
2286 // associate elements and some selected sound actions
2288 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2290 if (element_info[j].class_name)
2292 int len_class_text = strlen(element_info[j].class_name);
2294 if (len_class_text + 1 < len_effect_text &&
2295 strncmp(sound->token,
2296 element_info[j].class_name, len_class_text) == 0 &&
2297 sound->token[len_class_text] == '.')
2299 int sound_action_value = sound_effect_properties[i];
2301 element_info[j].sound[sound_action_value] = i;
2306 set_sound_parameters(i, sound->parameter);
2309 Debug("init:InitSoundInfo", "loop mode: %d ['%s']",
2310 sound_info[i].loop, sound->token);
2314 free(sound_effect_properties);
2317 static void InitGameModeMusicInfo(void)
2319 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2320 int num_property_mappings = getMusicListPropertyMappingSize();
2321 int default_levelset_music = -1;
2324 // set values to -1 to identify later as "uninitialized" values
2325 for (i = 0; i < MAX_LEVELS; i++)
2326 levelset.music[i] = -1;
2327 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2330 // initialize gamemode/music mapping from static configuration
2331 for (i = 0; gamemode_to_music[i].music > -1; i++)
2333 int gamemode = gamemode_to_music[i].gamemode;
2334 int music = gamemode_to_music[i].music;
2337 gamemode = GAME_MODE_DEFAULT;
2339 menu.music[gamemode] = music;
2342 // initialize gamemode/music mapping from dynamic configuration
2343 for (i = 0; i < num_property_mappings; i++)
2345 int prefix = property_mapping[i].base_index;
2346 int gamemode = property_mapping[i].ext2_index;
2347 int level = property_mapping[i].ext3_index;
2348 int music = property_mapping[i].artwork_index;
2350 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2354 gamemode = GAME_MODE_DEFAULT;
2356 // level specific music only allowed for in-game music
2357 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2358 gamemode = GAME_MODE_PLAYING;
2363 default_levelset_music = music;
2366 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2367 levelset.music[level] = music;
2368 if (gamemode != GAME_MODE_PLAYING)
2369 menu.music[gamemode] = music;
2372 // now set all '-1' values to menu specific default values
2373 // (undefined values of "levelset.music[]" might stay at "-1" to
2374 // allow dynamic selection of music files from music directory!)
2375 for (i = 0; i < MAX_LEVELS; i++)
2376 if (levelset.music[i] == -1)
2377 levelset.music[i] = default_levelset_music;
2378 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2379 if (menu.music[i] == -1)
2380 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2383 static void set_music_parameters(int music, char **parameter_raw)
2385 int parameter[NUM_MUS_ARGS];
2388 // get integer values from string parameters
2389 for (i = 0; i < NUM_MUS_ARGS; i++)
2391 get_parameter_value(parameter_raw[i],
2392 music_config_suffix[i].token,
2393 music_config_suffix[i].type);
2395 // explicit loop mode setting in configuration overrides default value
2396 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2397 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2400 static void InitMusicInfo(void)
2402 int num_music = getMusicListSize();
2405 checked_free(music_info);
2407 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2409 for (i = 0; i < num_music; i++)
2411 struct FileInfo *music = getMusicListEntry(i);
2412 int len_music_text = strlen(music->token);
2414 music_info[i].loop = TRUE; // default: play music in loop mode
2416 // determine all loop music
2418 for (j = 0; music_prefix_info[j].prefix; j++)
2420 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2422 if (len_prefix_text < len_music_text &&
2423 strncmp(music->token,
2424 music_prefix_info[j].prefix, len_prefix_text) == 0)
2426 music_info[i].loop = music_prefix_info[j].is_loop_music;
2432 set_music_parameters(i, music->parameter);
2437 static void InitGameInfoFromArtworkInfo(void)
2439 // special case: store initial value of custom artwork setting
2440 game.use_masked_elements_initial = game.use_masked_elements;
2443 static void ReinitializeGraphics(void)
2445 print_timestamp_init("ReinitializeGraphics");
2447 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2449 InitGraphicInfo(); // graphic properties mapping
2450 print_timestamp_time("InitGraphicInfo");
2451 InitElementGraphicInfo(); // element game graphic mapping
2452 print_timestamp_time("InitElementGraphicInfo");
2453 InitElementSpecialGraphicInfo(); // element special graphic mapping
2454 print_timestamp_time("InitElementSpecialGraphicInfo");
2456 InitElementSmallImages(); // scale elements to all needed sizes
2457 print_timestamp_time("InitElementSmallImages");
2458 InitScaledImages(); // scale all other images, if needed
2459 print_timestamp_time("InitScaledImages");
2460 InitBitmapPointers(); // set standard size bitmap pointers
2461 print_timestamp_time("InitBitmapPointers");
2462 InitFontGraphicInfo(); // initialize text drawing functions
2463 print_timestamp_time("InitFontGraphicInfo");
2464 InitGlobalAnimGraphicInfo(); // initialize global animation config
2465 print_timestamp_time("InitGlobalAnimGraphicInfo");
2467 InitImageTextures(); // create textures for certain images
2468 print_timestamp_time("InitImageTextures");
2470 InitGraphicInfo_BD(); // graphic mapping for BD engine
2471 print_timestamp_time("InitGraphicInfo_BD");
2472 InitGraphicInfo_EM(); // graphic mapping for EM engine
2473 print_timestamp_time("InitGraphicInfo_EM");
2475 InitGraphicCompatibilityInfo();
2476 print_timestamp_time("InitGraphicCompatibilityInfo");
2479 print_timestamp_time("InitGadgets");
2481 print_timestamp_time("InitDoors");
2483 InitGameInfoFromArtworkInfo();
2485 print_timestamp_done("ReinitializeGraphics");
2488 static void ReinitializeSounds(void)
2490 InitSoundInfo(); // sound properties mapping
2491 InitElementSoundInfo(); // element game sound mapping
2492 InitGameModeSoundInfo(); // game mode sound mapping
2493 InitGlobalAnimSoundInfo(); // global animation sound settings
2495 InitPlayLevelSound(); // internal game sound settings
2498 static void ReinitializeMusic(void)
2500 InitMusicInfo(); // music properties mapping
2501 InitGameModeMusicInfo(); // game mode music mapping
2502 InitGlobalAnimMusicInfo(); // global animation music settings
2505 static int get_special_property_bit(int element, int property_bit_nr)
2507 struct PropertyBitInfo
2513 static struct PropertyBitInfo pb_can_move_into_acid[] =
2515 // the player may be able fall into acid when gravity is activated
2520 { EL_SP_MURPHY, 0 },
2521 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2523 // all elements that can move may be able to also move into acid
2526 { EL_BUG_RIGHT, 1 },
2529 { EL_SPACESHIP, 2 },
2530 { EL_SPACESHIP_LEFT, 2 },
2531 { EL_SPACESHIP_RIGHT, 2 },
2532 { EL_SPACESHIP_UP, 2 },
2533 { EL_SPACESHIP_DOWN, 2 },
2534 { EL_BD_BUTTERFLY, 3 },
2535 { EL_BD_BUTTERFLY_LEFT, 3 },
2536 { EL_BD_BUTTERFLY_RIGHT, 3 },
2537 { EL_BD_BUTTERFLY_UP, 3 },
2538 { EL_BD_BUTTERFLY_DOWN, 3 },
2539 { EL_BD_FIREFLY, 4 },
2540 { EL_BD_FIREFLY_LEFT, 4 },
2541 { EL_BD_FIREFLY_RIGHT, 4 },
2542 { EL_BD_FIREFLY_UP, 4 },
2543 { EL_BD_FIREFLY_DOWN, 4 },
2545 { EL_YAMYAM_LEFT, 5 },
2546 { EL_YAMYAM_RIGHT, 5 },
2547 { EL_YAMYAM_UP, 5 },
2548 { EL_YAMYAM_DOWN, 5 },
2549 { EL_DARK_YAMYAM, 6 },
2552 { EL_PACMAN_LEFT, 8 },
2553 { EL_PACMAN_RIGHT, 8 },
2554 { EL_PACMAN_UP, 8 },
2555 { EL_PACMAN_DOWN, 8 },
2557 { EL_MOLE_LEFT, 9 },
2558 { EL_MOLE_RIGHT, 9 },
2560 { EL_MOLE_DOWN, 9 },
2564 { EL_SATELLITE, 13 },
2565 { EL_SP_SNIKSNAK, 14 },
2566 { EL_SP_ELECTRON, 15 },
2569 { EL_SPRING_LEFT, 17 },
2570 { EL_SPRING_RIGHT, 17 },
2571 { EL_EMC_ANDROID, 18 },
2576 static struct PropertyBitInfo pb_dont_collide_with[] =
2578 { EL_SP_SNIKSNAK, 0 },
2579 { EL_SP_ELECTRON, 1 },
2587 struct PropertyBitInfo *pb_info;
2590 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2591 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2596 struct PropertyBitInfo *pb_info = NULL;
2599 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2600 if (pb_definition[i].bit_nr == property_bit_nr)
2601 pb_info = pb_definition[i].pb_info;
2603 if (pb_info == NULL)
2606 for (i = 0; pb_info[i].element != -1; i++)
2607 if (pb_info[i].element == element)
2608 return pb_info[i].bit_nr;
2613 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2614 boolean property_value)
2616 int bit_nr = get_special_property_bit(element, property_bit_nr);
2621 *bitfield |= (1 << bit_nr);
2623 *bitfield &= ~(1 << bit_nr);
2627 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2629 int bit_nr = get_special_property_bit(element, property_bit_nr);
2632 return ((*bitfield & (1 << bit_nr)) != 0);
2637 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2639 static int group_nr;
2640 static struct ElementGroupInfo *group;
2641 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2644 if (actual_group == NULL) // not yet initialized
2647 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2649 Warn("recursion too deep when resolving group element %d",
2650 group_element - EL_GROUP_START + 1);
2652 // replace element which caused too deep recursion by question mark
2653 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2658 if (recursion_depth == 0) // initialization
2660 group = actual_group;
2661 group_nr = GROUP_NR(group_element);
2663 group->num_elements_resolved = 0;
2664 group->choice_pos = 0;
2666 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2667 element_info[i].in_group[group_nr] = FALSE;
2670 for (i = 0; i < actual_group->num_elements; i++)
2672 int element = actual_group->element[i];
2674 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2677 if (IS_GROUP_ELEMENT(element))
2678 ResolveGroupElementExt(element, recursion_depth + 1);
2681 group->element_resolved[group->num_elements_resolved++] = element;
2682 element_info[element].in_group[group_nr] = TRUE;
2687 void ResolveGroupElement(int group_element)
2689 ResolveGroupElementExt(group_element, 0);
2692 void InitElementPropertiesStatic(void)
2694 static boolean clipboard_elements_initialized = FALSE;
2696 static int ep_diggable[] =
2701 EL_SP_BUGGY_BASE_ACTIVATING,
2704 EL_INVISIBLE_SAND_ACTIVE,
2707 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2708 // (if amoeba can grow into anything diggable, maybe keep these out)
2713 EL_SP_BUGGY_BASE_ACTIVE,
2720 static int ep_collectible_only[] =
2742 EL_DYNABOMB_INCREASE_NUMBER,
2743 EL_DYNABOMB_INCREASE_SIZE,
2744 EL_DYNABOMB_INCREASE_POWER,
2762 // !!! handle separately !!!
2763 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2769 static int ep_dont_run_into[] =
2771 // same elements as in 'ep_dont_touch'
2777 // same elements as in 'ep_dont_collide_with'
2789 // !!! maybe this should better be handled by 'ep_diggable' !!!
2794 EL_SP_BUGGY_BASE_ACTIVE,
2801 static int ep_dont_collide_with[] =
2803 // same elements as in 'ep_dont_touch'
2820 static int ep_dont_touch[] =
2830 static int ep_indestructible[] =
2834 EL_ACID_POOL_TOPLEFT,
2835 EL_ACID_POOL_TOPRIGHT,
2836 EL_ACID_POOL_BOTTOMLEFT,
2837 EL_ACID_POOL_BOTTOM,
2838 EL_ACID_POOL_BOTTOMRIGHT,
2839 EL_SP_HARDWARE_GRAY,
2840 EL_SP_HARDWARE_GREEN,
2841 EL_SP_HARDWARE_BLUE,
2843 EL_SP_HARDWARE_YELLOW,
2844 EL_SP_HARDWARE_BASE_1,
2845 EL_SP_HARDWARE_BASE_2,
2846 EL_SP_HARDWARE_BASE_3,
2847 EL_SP_HARDWARE_BASE_4,
2848 EL_SP_HARDWARE_BASE_5,
2849 EL_SP_HARDWARE_BASE_6,
2850 EL_INVISIBLE_STEELWALL,
2851 EL_INVISIBLE_STEELWALL_ACTIVE,
2852 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2853 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2854 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2855 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2856 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2857 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2858 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2859 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2860 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2861 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2862 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2863 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2865 EL_LIGHT_SWITCH_ACTIVE,
2866 EL_SIGN_EXCLAMATION,
2867 EL_SIGN_RADIOACTIVITY,
2874 EL_SIGN_ENTRY_FORBIDDEN,
2875 EL_SIGN_EMERGENCY_EXIT,
2883 EL_STEEL_EXIT_CLOSED,
2885 EL_STEEL_EXIT_OPENING,
2886 EL_STEEL_EXIT_CLOSING,
2887 EL_EM_STEEL_EXIT_CLOSED,
2888 EL_EM_STEEL_EXIT_OPEN,
2889 EL_EM_STEEL_EXIT_OPENING,
2890 EL_EM_STEEL_EXIT_CLOSING,
2891 EL_DC_STEELWALL_1_LEFT,
2892 EL_DC_STEELWALL_1_RIGHT,
2893 EL_DC_STEELWALL_1_TOP,
2894 EL_DC_STEELWALL_1_BOTTOM,
2895 EL_DC_STEELWALL_1_HORIZONTAL,
2896 EL_DC_STEELWALL_1_VERTICAL,
2897 EL_DC_STEELWALL_1_TOPLEFT,
2898 EL_DC_STEELWALL_1_TOPRIGHT,
2899 EL_DC_STEELWALL_1_BOTTOMLEFT,
2900 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2901 EL_DC_STEELWALL_1_TOPLEFT_2,
2902 EL_DC_STEELWALL_1_TOPRIGHT_2,
2903 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2904 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2905 EL_DC_STEELWALL_2_LEFT,
2906 EL_DC_STEELWALL_2_RIGHT,
2907 EL_DC_STEELWALL_2_TOP,
2908 EL_DC_STEELWALL_2_BOTTOM,
2909 EL_DC_STEELWALL_2_HORIZONTAL,
2910 EL_DC_STEELWALL_2_VERTICAL,
2911 EL_DC_STEELWALL_2_MIDDLE,
2912 EL_DC_STEELWALL_2_SINGLE,
2913 EL_STEELWALL_SLIPPERY,
2927 EL_GATE_1_GRAY_ACTIVE,
2928 EL_GATE_2_GRAY_ACTIVE,
2929 EL_GATE_3_GRAY_ACTIVE,
2930 EL_GATE_4_GRAY_ACTIVE,
2939 EL_EM_GATE_1_GRAY_ACTIVE,
2940 EL_EM_GATE_2_GRAY_ACTIVE,
2941 EL_EM_GATE_3_GRAY_ACTIVE,
2942 EL_EM_GATE_4_GRAY_ACTIVE,
2951 EL_EMC_GATE_5_GRAY_ACTIVE,
2952 EL_EMC_GATE_6_GRAY_ACTIVE,
2953 EL_EMC_GATE_7_GRAY_ACTIVE,
2954 EL_EMC_GATE_8_GRAY_ACTIVE,
2956 EL_DC_GATE_WHITE_GRAY,
2957 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2958 EL_DC_GATE_FAKE_GRAY,
2960 EL_SWITCHGATE_OPENING,
2961 EL_SWITCHGATE_CLOSED,
2962 EL_SWITCHGATE_CLOSING,
2963 EL_DC_SWITCHGATE_SWITCH_UP,
2964 EL_DC_SWITCHGATE_SWITCH_DOWN,
2966 EL_TIMEGATE_OPENING,
2968 EL_TIMEGATE_CLOSING,
2969 EL_DC_TIMEGATE_SWITCH,
2970 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2974 EL_TUBE_VERTICAL_LEFT,
2975 EL_TUBE_VERTICAL_RIGHT,
2976 EL_TUBE_HORIZONTAL_UP,
2977 EL_TUBE_HORIZONTAL_DOWN,
2982 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2983 EL_EXPANDABLE_STEELWALL_VERTICAL,
2984 EL_EXPANDABLE_STEELWALL_ANY,
2989 static int ep_slippery[] =
3003 EL_ROBOT_WHEEL_ACTIVE,
3009 EL_ACID_POOL_TOPLEFT,
3010 EL_ACID_POOL_TOPRIGHT,
3020 EL_STEELWALL_SLIPPERY,
3023 EL_EMC_WALL_SLIPPERY_1,
3024 EL_EMC_WALL_SLIPPERY_2,
3025 EL_EMC_WALL_SLIPPERY_3,
3026 EL_EMC_WALL_SLIPPERY_4,
3028 EL_EMC_MAGIC_BALL_ACTIVE,
3033 static int ep_can_change[] =
3038 static int ep_can_move[] =
3040 // same elements as in 'pb_can_move_into_acid'
3063 static int ep_can_fall[] =
3078 EL_QUICKSAND_FAST_FULL,
3080 EL_BD_MAGIC_WALL_FULL,
3081 EL_DC_MAGIC_WALL_FULL,
3095 static int ep_can_smash_player[] =
3121 static int ep_can_smash_enemies[] =
3130 static int ep_can_smash_everything[] =
3139 static int ep_explodes_by_fire[] =
3141 // same elements as in 'ep_explodes_impact'
3146 // same elements as in 'ep_explodes_smashed'
3156 EL_EM_DYNAMITE_ACTIVE,
3157 EL_DYNABOMB_PLAYER_1_ACTIVE,
3158 EL_DYNABOMB_PLAYER_2_ACTIVE,
3159 EL_DYNABOMB_PLAYER_3_ACTIVE,
3160 EL_DYNABOMB_PLAYER_4_ACTIVE,
3161 EL_DYNABOMB_INCREASE_NUMBER,
3162 EL_DYNABOMB_INCREASE_SIZE,
3163 EL_DYNABOMB_INCREASE_POWER,
3164 EL_SP_DISK_RED_ACTIVE,
3178 static int ep_explodes_smashed[] =
3180 // same elements as in 'ep_explodes_impact'
3194 static int ep_explodes_impact[] =
3203 static int ep_walkable_over[] =
3223 EL_SOKOBAN_FIELD_EMPTY,
3230 EL_EM_STEEL_EXIT_OPEN,
3231 EL_EM_STEEL_EXIT_OPENING,
3240 EL_GATE_1_GRAY_ACTIVE,
3241 EL_GATE_2_GRAY_ACTIVE,
3242 EL_GATE_3_GRAY_ACTIVE,
3243 EL_GATE_4_GRAY_ACTIVE,
3251 static int ep_walkable_inside[] =
3256 EL_TUBE_VERTICAL_LEFT,
3257 EL_TUBE_VERTICAL_RIGHT,
3258 EL_TUBE_HORIZONTAL_UP,
3259 EL_TUBE_HORIZONTAL_DOWN,
3268 static int ep_walkable_under[] =
3273 static int ep_passable_over[] =
3283 EL_EM_GATE_1_GRAY_ACTIVE,
3284 EL_EM_GATE_2_GRAY_ACTIVE,
3285 EL_EM_GATE_3_GRAY_ACTIVE,
3286 EL_EM_GATE_4_GRAY_ACTIVE,
3295 EL_EMC_GATE_5_GRAY_ACTIVE,
3296 EL_EMC_GATE_6_GRAY_ACTIVE,
3297 EL_EMC_GATE_7_GRAY_ACTIVE,
3298 EL_EMC_GATE_8_GRAY_ACTIVE,
3300 EL_DC_GATE_WHITE_GRAY,
3301 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3308 static int ep_passable_inside[] =
3314 EL_SP_PORT_HORIZONTAL,
3315 EL_SP_PORT_VERTICAL,
3317 EL_SP_GRAVITY_PORT_LEFT,
3318 EL_SP_GRAVITY_PORT_RIGHT,
3319 EL_SP_GRAVITY_PORT_UP,
3320 EL_SP_GRAVITY_PORT_DOWN,
3321 EL_SP_GRAVITY_ON_PORT_LEFT,
3322 EL_SP_GRAVITY_ON_PORT_RIGHT,
3323 EL_SP_GRAVITY_ON_PORT_UP,
3324 EL_SP_GRAVITY_ON_PORT_DOWN,
3325 EL_SP_GRAVITY_OFF_PORT_LEFT,
3326 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3327 EL_SP_GRAVITY_OFF_PORT_UP,
3328 EL_SP_GRAVITY_OFF_PORT_DOWN,
3333 static int ep_passable_under[] =
3338 static int ep_droppable[] =
3343 static int ep_explodes_1x1_old[] =
3348 static int ep_pushable[] =
3360 EL_SOKOBAN_FIELD_FULL,
3369 static int ep_explodes_cross_old[] =
3374 static int ep_protected[] =
3376 // same elements as in 'ep_walkable_inside'
3380 EL_TUBE_VERTICAL_LEFT,
3381 EL_TUBE_VERTICAL_RIGHT,
3382 EL_TUBE_HORIZONTAL_UP,
3383 EL_TUBE_HORIZONTAL_DOWN,
3389 // same elements as in 'ep_passable_over'
3398 EL_EM_GATE_1_GRAY_ACTIVE,
3399 EL_EM_GATE_2_GRAY_ACTIVE,
3400 EL_EM_GATE_3_GRAY_ACTIVE,
3401 EL_EM_GATE_4_GRAY_ACTIVE,
3410 EL_EMC_GATE_5_GRAY_ACTIVE,
3411 EL_EMC_GATE_6_GRAY_ACTIVE,
3412 EL_EMC_GATE_7_GRAY_ACTIVE,
3413 EL_EMC_GATE_8_GRAY_ACTIVE,
3415 EL_DC_GATE_WHITE_GRAY,
3416 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3420 // same elements as in 'ep_passable_inside'
3425 EL_SP_PORT_HORIZONTAL,
3426 EL_SP_PORT_VERTICAL,
3428 EL_SP_GRAVITY_PORT_LEFT,
3429 EL_SP_GRAVITY_PORT_RIGHT,
3430 EL_SP_GRAVITY_PORT_UP,
3431 EL_SP_GRAVITY_PORT_DOWN,
3432 EL_SP_GRAVITY_ON_PORT_LEFT,
3433 EL_SP_GRAVITY_ON_PORT_RIGHT,
3434 EL_SP_GRAVITY_ON_PORT_UP,
3435 EL_SP_GRAVITY_ON_PORT_DOWN,
3436 EL_SP_GRAVITY_OFF_PORT_LEFT,
3437 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3438 EL_SP_GRAVITY_OFF_PORT_UP,
3439 EL_SP_GRAVITY_OFF_PORT_DOWN,
3444 static int ep_throwable[] =
3449 static int ep_can_explode[] =
3451 // same elements as in 'ep_explodes_impact'
3456 // same elements as in 'ep_explodes_smashed'
3462 // elements that can explode by explosion or by dragonfire
3466 EL_EM_DYNAMITE_ACTIVE,
3467 EL_DYNABOMB_PLAYER_1_ACTIVE,
3468 EL_DYNABOMB_PLAYER_2_ACTIVE,
3469 EL_DYNABOMB_PLAYER_3_ACTIVE,
3470 EL_DYNABOMB_PLAYER_4_ACTIVE,
3471 EL_DYNABOMB_INCREASE_NUMBER,
3472 EL_DYNABOMB_INCREASE_SIZE,
3473 EL_DYNABOMB_INCREASE_POWER,
3474 EL_SP_DISK_RED_ACTIVE,
3482 // elements that can explode only by explosion
3488 static int ep_gravity_reachable[] =
3494 EL_INVISIBLE_SAND_ACTIVE,
3499 EL_SP_PORT_HORIZONTAL,
3500 EL_SP_PORT_VERTICAL,
3502 EL_SP_GRAVITY_PORT_LEFT,
3503 EL_SP_GRAVITY_PORT_RIGHT,
3504 EL_SP_GRAVITY_PORT_UP,
3505 EL_SP_GRAVITY_PORT_DOWN,
3506 EL_SP_GRAVITY_ON_PORT_LEFT,
3507 EL_SP_GRAVITY_ON_PORT_RIGHT,
3508 EL_SP_GRAVITY_ON_PORT_UP,
3509 EL_SP_GRAVITY_ON_PORT_DOWN,
3510 EL_SP_GRAVITY_OFF_PORT_LEFT,
3511 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3512 EL_SP_GRAVITY_OFF_PORT_UP,
3513 EL_SP_GRAVITY_OFF_PORT_DOWN,
3519 static int ep_empty_space[] =
3542 static int ep_player[] =
3549 EL_SOKOBAN_FIELD_PLAYER,
3555 static int ep_can_pass_magic_wall[] =
3569 static int ep_can_pass_dc_magic_wall[] =
3585 static int ep_switchable[] =
3589 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3590 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3591 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3592 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3593 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3594 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3595 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3596 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3597 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3598 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3599 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3600 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3601 EL_SWITCHGATE_SWITCH_UP,
3602 EL_SWITCHGATE_SWITCH_DOWN,
3603 EL_DC_SWITCHGATE_SWITCH_UP,
3604 EL_DC_SWITCHGATE_SWITCH_DOWN,
3606 EL_LIGHT_SWITCH_ACTIVE,
3608 EL_DC_TIMEGATE_SWITCH,
3609 EL_BALLOON_SWITCH_LEFT,
3610 EL_BALLOON_SWITCH_RIGHT,
3611 EL_BALLOON_SWITCH_UP,
3612 EL_BALLOON_SWITCH_DOWN,
3613 EL_BALLOON_SWITCH_ANY,
3614 EL_BALLOON_SWITCH_NONE,
3617 EL_EMC_MAGIC_BALL_SWITCH,
3618 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3623 static int ep_bd_element[] =
3643 EL_BD_FIREFLY_RIGHT,
3646 EL_BD_BUTTERFLY_DOWN,
3647 EL_BD_BUTTERFLY_LEFT,
3649 EL_BD_BUTTERFLY_RIGHT,
3657 static int ep_sp_element[] =
3659 // should always be valid
3662 // standard classic Supaplex elements
3669 EL_SP_HARDWARE_GRAY,
3677 EL_SP_GRAVITY_PORT_RIGHT,
3678 EL_SP_GRAVITY_PORT_DOWN,
3679 EL_SP_GRAVITY_PORT_LEFT,
3680 EL_SP_GRAVITY_PORT_UP,
3685 EL_SP_PORT_VERTICAL,
3686 EL_SP_PORT_HORIZONTAL,
3692 EL_SP_HARDWARE_BASE_1,
3693 EL_SP_HARDWARE_GREEN,
3694 EL_SP_HARDWARE_BLUE,
3696 EL_SP_HARDWARE_YELLOW,
3697 EL_SP_HARDWARE_BASE_2,
3698 EL_SP_HARDWARE_BASE_3,
3699 EL_SP_HARDWARE_BASE_4,
3700 EL_SP_HARDWARE_BASE_5,
3701 EL_SP_HARDWARE_BASE_6,
3705 // additional elements that appeared in newer Supaplex levels
3708 // additional gravity port elements (not switching, but setting gravity)
3709 EL_SP_GRAVITY_ON_PORT_LEFT,
3710 EL_SP_GRAVITY_ON_PORT_RIGHT,
3711 EL_SP_GRAVITY_ON_PORT_UP,
3712 EL_SP_GRAVITY_ON_PORT_DOWN,
3713 EL_SP_GRAVITY_OFF_PORT_LEFT,
3714 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3715 EL_SP_GRAVITY_OFF_PORT_UP,
3716 EL_SP_GRAVITY_OFF_PORT_DOWN,
3718 // more than one Murphy in a level results in an inactive clone
3721 // runtime Supaplex elements
3722 EL_SP_DISK_RED_ACTIVE,
3723 EL_SP_TERMINAL_ACTIVE,
3724 EL_SP_BUGGY_BASE_ACTIVATING,
3725 EL_SP_BUGGY_BASE_ACTIVE,
3732 static int ep_sb_element[] =
3737 EL_SOKOBAN_FIELD_EMPTY,
3738 EL_SOKOBAN_FIELD_FULL,
3739 EL_SOKOBAN_FIELD_PLAYER,
3744 EL_INVISIBLE_STEELWALL,
3749 static int ep_gem[] =
3761 static int ep_food_dark_yamyam[] =
3789 static int ep_food_penguin[] =
3803 static int ep_food_pig[] =
3815 static int ep_historic_wall[] =
3826 EL_GATE_1_GRAY_ACTIVE,
3827 EL_GATE_2_GRAY_ACTIVE,
3828 EL_GATE_3_GRAY_ACTIVE,
3829 EL_GATE_4_GRAY_ACTIVE,
3838 EL_EM_GATE_1_GRAY_ACTIVE,
3839 EL_EM_GATE_2_GRAY_ACTIVE,
3840 EL_EM_GATE_3_GRAY_ACTIVE,
3841 EL_EM_GATE_4_GRAY_ACTIVE,
3848 EL_EXPANDABLE_WALL_HORIZONTAL,
3849 EL_EXPANDABLE_WALL_VERTICAL,
3850 EL_EXPANDABLE_WALL_ANY,
3851 EL_EXPANDABLE_WALL_GROWING,
3852 EL_BD_EXPANDABLE_WALL,
3859 EL_SP_HARDWARE_GRAY,
3860 EL_SP_HARDWARE_GREEN,
3861 EL_SP_HARDWARE_BLUE,
3863 EL_SP_HARDWARE_YELLOW,
3864 EL_SP_HARDWARE_BASE_1,
3865 EL_SP_HARDWARE_BASE_2,
3866 EL_SP_HARDWARE_BASE_3,
3867 EL_SP_HARDWARE_BASE_4,
3868 EL_SP_HARDWARE_BASE_5,
3869 EL_SP_HARDWARE_BASE_6,
3871 EL_SP_TERMINAL_ACTIVE,
3874 EL_INVISIBLE_STEELWALL,
3875 EL_INVISIBLE_STEELWALL_ACTIVE,
3877 EL_INVISIBLE_WALL_ACTIVE,
3878 EL_STEELWALL_SLIPPERY,
3895 static int ep_historic_solid[] =
3899 EL_EXPANDABLE_WALL_HORIZONTAL,
3900 EL_EXPANDABLE_WALL_VERTICAL,
3901 EL_EXPANDABLE_WALL_ANY,
3902 EL_BD_EXPANDABLE_WALL,
3915 EL_QUICKSAND_FILLING,
3916 EL_QUICKSAND_EMPTYING,
3918 EL_MAGIC_WALL_ACTIVE,
3919 EL_MAGIC_WALL_EMPTYING,
3920 EL_MAGIC_WALL_FILLING,
3924 EL_BD_MAGIC_WALL_ACTIVE,
3925 EL_BD_MAGIC_WALL_EMPTYING,
3926 EL_BD_MAGIC_WALL_FULL,
3927 EL_BD_MAGIC_WALL_FILLING,
3928 EL_BD_MAGIC_WALL_DEAD,
3937 EL_SP_TERMINAL_ACTIVE,
3941 EL_INVISIBLE_WALL_ACTIVE,
3942 EL_SWITCHGATE_SWITCH_UP,
3943 EL_SWITCHGATE_SWITCH_DOWN,
3945 EL_TIMEGATE_SWITCH_ACTIVE,
3957 // the following elements are a direct copy of "indestructible" elements,
3958 // except "EL_ACID", which is "indestructible", but not "solid"!
3963 EL_ACID_POOL_TOPLEFT,
3964 EL_ACID_POOL_TOPRIGHT,
3965 EL_ACID_POOL_BOTTOMLEFT,
3966 EL_ACID_POOL_BOTTOM,
3967 EL_ACID_POOL_BOTTOMRIGHT,
3968 EL_SP_HARDWARE_GRAY,
3969 EL_SP_HARDWARE_GREEN,
3970 EL_SP_HARDWARE_BLUE,
3972 EL_SP_HARDWARE_YELLOW,
3973 EL_SP_HARDWARE_BASE_1,
3974 EL_SP_HARDWARE_BASE_2,
3975 EL_SP_HARDWARE_BASE_3,
3976 EL_SP_HARDWARE_BASE_4,
3977 EL_SP_HARDWARE_BASE_5,
3978 EL_SP_HARDWARE_BASE_6,
3979 EL_INVISIBLE_STEELWALL,
3980 EL_INVISIBLE_STEELWALL_ACTIVE,
3981 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3982 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3983 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3984 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3985 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3986 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3987 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3988 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3989 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3990 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3991 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3992 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3994 EL_LIGHT_SWITCH_ACTIVE,
3995 EL_SIGN_EXCLAMATION,
3996 EL_SIGN_RADIOACTIVITY,
4003 EL_SIGN_ENTRY_FORBIDDEN,
4004 EL_SIGN_EMERGENCY_EXIT,
4012 EL_STEEL_EXIT_CLOSED,
4014 EL_STEEL_EXIT_OPENING,
4015 EL_STEEL_EXIT_CLOSING,
4016 EL_EM_STEEL_EXIT_CLOSED,
4017 EL_EM_STEEL_EXIT_OPEN,
4018 EL_EM_STEEL_EXIT_OPENING,
4019 EL_EM_STEEL_EXIT_CLOSING,
4020 EL_DC_STEELWALL_1_LEFT,
4021 EL_DC_STEELWALL_1_RIGHT,
4022 EL_DC_STEELWALL_1_TOP,
4023 EL_DC_STEELWALL_1_BOTTOM,
4024 EL_DC_STEELWALL_1_HORIZONTAL,
4025 EL_DC_STEELWALL_1_VERTICAL,
4026 EL_DC_STEELWALL_1_TOPLEFT,
4027 EL_DC_STEELWALL_1_TOPRIGHT,
4028 EL_DC_STEELWALL_1_BOTTOMLEFT,
4029 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4030 EL_DC_STEELWALL_1_TOPLEFT_2,
4031 EL_DC_STEELWALL_1_TOPRIGHT_2,
4032 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4033 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4034 EL_DC_STEELWALL_2_LEFT,
4035 EL_DC_STEELWALL_2_RIGHT,
4036 EL_DC_STEELWALL_2_TOP,
4037 EL_DC_STEELWALL_2_BOTTOM,
4038 EL_DC_STEELWALL_2_HORIZONTAL,
4039 EL_DC_STEELWALL_2_VERTICAL,
4040 EL_DC_STEELWALL_2_MIDDLE,
4041 EL_DC_STEELWALL_2_SINGLE,
4042 EL_STEELWALL_SLIPPERY,
4056 EL_GATE_1_GRAY_ACTIVE,
4057 EL_GATE_2_GRAY_ACTIVE,
4058 EL_GATE_3_GRAY_ACTIVE,
4059 EL_GATE_4_GRAY_ACTIVE,
4068 EL_EM_GATE_1_GRAY_ACTIVE,
4069 EL_EM_GATE_2_GRAY_ACTIVE,
4070 EL_EM_GATE_3_GRAY_ACTIVE,
4071 EL_EM_GATE_4_GRAY_ACTIVE,
4080 EL_EMC_GATE_5_GRAY_ACTIVE,
4081 EL_EMC_GATE_6_GRAY_ACTIVE,
4082 EL_EMC_GATE_7_GRAY_ACTIVE,
4083 EL_EMC_GATE_8_GRAY_ACTIVE,
4085 EL_DC_GATE_WHITE_GRAY,
4086 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4087 EL_DC_GATE_FAKE_GRAY,
4089 EL_SWITCHGATE_OPENING,
4090 EL_SWITCHGATE_CLOSED,
4091 EL_SWITCHGATE_CLOSING,
4092 EL_DC_SWITCHGATE_SWITCH_UP,
4093 EL_DC_SWITCHGATE_SWITCH_DOWN,
4095 EL_TIMEGATE_OPENING,
4097 EL_TIMEGATE_CLOSING,
4098 EL_DC_TIMEGATE_SWITCH,
4099 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4103 EL_TUBE_VERTICAL_LEFT,
4104 EL_TUBE_VERTICAL_RIGHT,
4105 EL_TUBE_HORIZONTAL_UP,
4106 EL_TUBE_HORIZONTAL_DOWN,
4111 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4112 EL_EXPANDABLE_STEELWALL_VERTICAL,
4113 EL_EXPANDABLE_STEELWALL_ANY,
4118 static int ep_classic_enemy[] =
4135 static int ep_belt[] =
4137 EL_CONVEYOR_BELT_1_LEFT,
4138 EL_CONVEYOR_BELT_1_MIDDLE,
4139 EL_CONVEYOR_BELT_1_RIGHT,
4140 EL_CONVEYOR_BELT_2_LEFT,
4141 EL_CONVEYOR_BELT_2_MIDDLE,
4142 EL_CONVEYOR_BELT_2_RIGHT,
4143 EL_CONVEYOR_BELT_3_LEFT,
4144 EL_CONVEYOR_BELT_3_MIDDLE,
4145 EL_CONVEYOR_BELT_3_RIGHT,
4146 EL_CONVEYOR_BELT_4_LEFT,
4147 EL_CONVEYOR_BELT_4_MIDDLE,
4148 EL_CONVEYOR_BELT_4_RIGHT,
4153 static int ep_belt_active[] =
4155 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4156 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4157 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4158 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4159 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4160 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4161 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4162 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4163 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4164 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4165 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4166 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4171 static int ep_belt_switch[] =
4173 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4174 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4175 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4176 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4177 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4178 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4179 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4180 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4181 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4182 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4183 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4184 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4189 static int ep_tube[] =
4196 EL_TUBE_HORIZONTAL_UP,
4197 EL_TUBE_HORIZONTAL_DOWN,
4199 EL_TUBE_VERTICAL_LEFT,
4200 EL_TUBE_VERTICAL_RIGHT,
4206 static int ep_acid_pool[] =
4208 EL_ACID_POOL_TOPLEFT,
4209 EL_ACID_POOL_TOPRIGHT,
4210 EL_ACID_POOL_BOTTOMLEFT,
4211 EL_ACID_POOL_BOTTOM,
4212 EL_ACID_POOL_BOTTOMRIGHT,
4217 static int ep_keygate[] =
4227 EL_GATE_1_GRAY_ACTIVE,
4228 EL_GATE_2_GRAY_ACTIVE,
4229 EL_GATE_3_GRAY_ACTIVE,
4230 EL_GATE_4_GRAY_ACTIVE,
4239 EL_EM_GATE_1_GRAY_ACTIVE,
4240 EL_EM_GATE_2_GRAY_ACTIVE,
4241 EL_EM_GATE_3_GRAY_ACTIVE,
4242 EL_EM_GATE_4_GRAY_ACTIVE,
4251 EL_EMC_GATE_5_GRAY_ACTIVE,
4252 EL_EMC_GATE_6_GRAY_ACTIVE,
4253 EL_EMC_GATE_7_GRAY_ACTIVE,
4254 EL_EMC_GATE_8_GRAY_ACTIVE,
4256 EL_DC_GATE_WHITE_GRAY,
4257 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4262 static int ep_amoeboid[] =
4274 static int ep_amoebalive[] =
4285 static int ep_has_editor_content[] =
4291 EL_SOKOBAN_FIELD_PLAYER,
4319 static int ep_can_turn_each_move[] =
4321 // !!! do something with this one !!!
4325 static int ep_can_grow[] =
4339 static int ep_active_bomb[] =
4342 EL_EM_DYNAMITE_ACTIVE,
4343 EL_DYNABOMB_PLAYER_1_ACTIVE,
4344 EL_DYNABOMB_PLAYER_2_ACTIVE,
4345 EL_DYNABOMB_PLAYER_3_ACTIVE,
4346 EL_DYNABOMB_PLAYER_4_ACTIVE,
4347 EL_SP_DISK_RED_ACTIVE,
4352 static int ep_inactive[] =
4378 EL_QUICKSAND_FAST_EMPTY,
4401 EL_GATE_1_GRAY_ACTIVE,
4402 EL_GATE_2_GRAY_ACTIVE,
4403 EL_GATE_3_GRAY_ACTIVE,
4404 EL_GATE_4_GRAY_ACTIVE,
4413 EL_EM_GATE_1_GRAY_ACTIVE,
4414 EL_EM_GATE_2_GRAY_ACTIVE,
4415 EL_EM_GATE_3_GRAY_ACTIVE,
4416 EL_EM_GATE_4_GRAY_ACTIVE,
4425 EL_EMC_GATE_5_GRAY_ACTIVE,
4426 EL_EMC_GATE_6_GRAY_ACTIVE,
4427 EL_EMC_GATE_7_GRAY_ACTIVE,
4428 EL_EMC_GATE_8_GRAY_ACTIVE,
4430 EL_DC_GATE_WHITE_GRAY,
4431 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4432 EL_DC_GATE_FAKE_GRAY,
4435 EL_INVISIBLE_STEELWALL,
4443 EL_WALL_EMERALD_YELLOW,
4444 EL_DYNABOMB_INCREASE_NUMBER,
4445 EL_DYNABOMB_INCREASE_SIZE,
4446 EL_DYNABOMB_INCREASE_POWER,
4450 EL_SOKOBAN_FIELD_EMPTY,
4451 EL_SOKOBAN_FIELD_FULL,
4452 EL_WALL_EMERALD_RED,
4453 EL_WALL_EMERALD_PURPLE,
4454 EL_ACID_POOL_TOPLEFT,
4455 EL_ACID_POOL_TOPRIGHT,
4456 EL_ACID_POOL_BOTTOMLEFT,
4457 EL_ACID_POOL_BOTTOM,
4458 EL_ACID_POOL_BOTTOMRIGHT,
4462 EL_BD_MAGIC_WALL_DEAD,
4464 EL_DC_MAGIC_WALL_DEAD,
4465 EL_AMOEBA_TO_DIAMOND,
4473 EL_SP_GRAVITY_PORT_RIGHT,
4474 EL_SP_GRAVITY_PORT_DOWN,
4475 EL_SP_GRAVITY_PORT_LEFT,
4476 EL_SP_GRAVITY_PORT_UP,
4477 EL_SP_PORT_HORIZONTAL,
4478 EL_SP_PORT_VERTICAL,
4489 EL_SP_HARDWARE_GRAY,
4490 EL_SP_HARDWARE_GREEN,
4491 EL_SP_HARDWARE_BLUE,
4493 EL_SP_HARDWARE_YELLOW,
4494 EL_SP_HARDWARE_BASE_1,
4495 EL_SP_HARDWARE_BASE_2,
4496 EL_SP_HARDWARE_BASE_3,
4497 EL_SP_HARDWARE_BASE_4,
4498 EL_SP_HARDWARE_BASE_5,
4499 EL_SP_HARDWARE_BASE_6,
4500 EL_SP_GRAVITY_ON_PORT_LEFT,
4501 EL_SP_GRAVITY_ON_PORT_RIGHT,
4502 EL_SP_GRAVITY_ON_PORT_UP,
4503 EL_SP_GRAVITY_ON_PORT_DOWN,
4504 EL_SP_GRAVITY_OFF_PORT_LEFT,
4505 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4506 EL_SP_GRAVITY_OFF_PORT_UP,
4507 EL_SP_GRAVITY_OFF_PORT_DOWN,
4508 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4509 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4510 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4511 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4512 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4513 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4514 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4515 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4516 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4517 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4518 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4519 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4520 EL_SIGN_EXCLAMATION,
4521 EL_SIGN_RADIOACTIVITY,
4528 EL_SIGN_ENTRY_FORBIDDEN,
4529 EL_SIGN_EMERGENCY_EXIT,
4537 EL_DC_STEELWALL_1_LEFT,
4538 EL_DC_STEELWALL_1_RIGHT,
4539 EL_DC_STEELWALL_1_TOP,
4540 EL_DC_STEELWALL_1_BOTTOM,
4541 EL_DC_STEELWALL_1_HORIZONTAL,
4542 EL_DC_STEELWALL_1_VERTICAL,
4543 EL_DC_STEELWALL_1_TOPLEFT,
4544 EL_DC_STEELWALL_1_TOPRIGHT,
4545 EL_DC_STEELWALL_1_BOTTOMLEFT,
4546 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4547 EL_DC_STEELWALL_1_TOPLEFT_2,
4548 EL_DC_STEELWALL_1_TOPRIGHT_2,
4549 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4550 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4551 EL_DC_STEELWALL_2_LEFT,
4552 EL_DC_STEELWALL_2_RIGHT,
4553 EL_DC_STEELWALL_2_TOP,
4554 EL_DC_STEELWALL_2_BOTTOM,
4555 EL_DC_STEELWALL_2_HORIZONTAL,
4556 EL_DC_STEELWALL_2_VERTICAL,
4557 EL_DC_STEELWALL_2_MIDDLE,
4558 EL_DC_STEELWALL_2_SINGLE,
4559 EL_STEELWALL_SLIPPERY,
4564 EL_EMC_WALL_SLIPPERY_1,
4565 EL_EMC_WALL_SLIPPERY_2,
4566 EL_EMC_WALL_SLIPPERY_3,
4567 EL_EMC_WALL_SLIPPERY_4,
4588 static int ep_em_slippery_wall[] =
4593 static int ep_gfx_crumbled[] =
4604 static int ep_editor_cascade_active[] =
4606 EL_INTERNAL_CASCADE_BD_ACTIVE,
4607 EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
4608 EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
4609 EL_INTERNAL_CASCADE_EM_ACTIVE,
4610 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4611 EL_INTERNAL_CASCADE_RND_ACTIVE,
4612 EL_INTERNAL_CASCADE_SB_ACTIVE,
4613 EL_INTERNAL_CASCADE_SP_ACTIVE,
4614 EL_INTERNAL_CASCADE_DC_ACTIVE,
4615 EL_INTERNAL_CASCADE_DX_ACTIVE,
4616 EL_INTERNAL_CASCADE_MM_ACTIVE,
4617 EL_INTERNAL_CASCADE_DF_ACTIVE,
4618 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4619 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4620 EL_INTERNAL_CASCADE_CE_ACTIVE,
4621 EL_INTERNAL_CASCADE_GE_ACTIVE,
4622 EL_INTERNAL_CASCADE_ES_ACTIVE,
4623 EL_INTERNAL_CASCADE_REF_ACTIVE,
4624 EL_INTERNAL_CASCADE_USER_ACTIVE,
4625 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4630 static int ep_editor_cascade_inactive[] =
4632 EL_INTERNAL_CASCADE_BD,
4633 EL_INTERNAL_CASCADE_BD_NATIVE,
4634 EL_INTERNAL_CASCADE_BD_EFFECTS,
4635 EL_INTERNAL_CASCADE_EM,
4636 EL_INTERNAL_CASCADE_EMC,
4637 EL_INTERNAL_CASCADE_RND,
4638 EL_INTERNAL_CASCADE_SB,
4639 EL_INTERNAL_CASCADE_SP,
4640 EL_INTERNAL_CASCADE_DC,
4641 EL_INTERNAL_CASCADE_DX,
4642 EL_INTERNAL_CASCADE_MM,
4643 EL_INTERNAL_CASCADE_DF,
4644 EL_INTERNAL_CASCADE_CHARS,
4645 EL_INTERNAL_CASCADE_STEEL_CHARS,
4646 EL_INTERNAL_CASCADE_CE,
4647 EL_INTERNAL_CASCADE_GE,
4648 EL_INTERNAL_CASCADE_ES,
4649 EL_INTERNAL_CASCADE_REF,
4650 EL_INTERNAL_CASCADE_USER,
4651 EL_INTERNAL_CASCADE_DYNAMIC,
4656 static int ep_obsolete[] =
4660 EL_EM_KEY_1_FILE_OBSOLETE,
4661 EL_EM_KEY_2_FILE_OBSOLETE,
4662 EL_EM_KEY_3_FILE_OBSOLETE,
4663 EL_EM_KEY_4_FILE_OBSOLETE,
4664 EL_ENVELOPE_OBSOLETE,
4673 } element_properties[] =
4675 { ep_diggable, EP_DIGGABLE },
4676 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4677 { ep_dont_run_into, EP_DONT_RUN_INTO },
4678 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4679 { ep_dont_touch, EP_DONT_TOUCH },
4680 { ep_indestructible, EP_INDESTRUCTIBLE },
4681 { ep_slippery, EP_SLIPPERY },
4682 { ep_can_change, EP_CAN_CHANGE },
4683 { ep_can_move, EP_CAN_MOVE },
4684 { ep_can_fall, EP_CAN_FALL },
4685 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4686 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4687 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4688 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4689 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4690 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4691 { ep_walkable_over, EP_WALKABLE_OVER },
4692 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4693 { ep_walkable_under, EP_WALKABLE_UNDER },
4694 { ep_passable_over, EP_PASSABLE_OVER },
4695 { ep_passable_inside, EP_PASSABLE_INSIDE },
4696 { ep_passable_under, EP_PASSABLE_UNDER },
4697 { ep_droppable, EP_DROPPABLE },
4698 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4699 { ep_pushable, EP_PUSHABLE },
4700 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4701 { ep_protected, EP_PROTECTED },
4702 { ep_throwable, EP_THROWABLE },
4703 { ep_can_explode, EP_CAN_EXPLODE },
4704 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4706 { ep_empty_space, EP_EMPTY_SPACE },
4707 { ep_player, EP_PLAYER },
4708 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4709 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4710 { ep_switchable, EP_SWITCHABLE },
4711 { ep_bd_element, EP_BD_ELEMENT },
4712 { ep_sp_element, EP_SP_ELEMENT },
4713 { ep_sb_element, EP_SB_ELEMENT },
4715 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4716 { ep_food_penguin, EP_FOOD_PENGUIN },
4717 { ep_food_pig, EP_FOOD_PIG },
4718 { ep_historic_wall, EP_HISTORIC_WALL },
4719 { ep_historic_solid, EP_HISTORIC_SOLID },
4720 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4721 { ep_belt, EP_BELT },
4722 { ep_belt_active, EP_BELT_ACTIVE },
4723 { ep_belt_switch, EP_BELT_SWITCH },
4724 { ep_tube, EP_TUBE },
4725 { ep_acid_pool, EP_ACID_POOL },
4726 { ep_keygate, EP_KEYGATE },
4727 { ep_amoeboid, EP_AMOEBOID },
4728 { ep_amoebalive, EP_AMOEBALIVE },
4729 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4730 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4731 { ep_can_grow, EP_CAN_GROW },
4732 { ep_active_bomb, EP_ACTIVE_BOMB },
4733 { ep_inactive, EP_INACTIVE },
4735 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4737 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4739 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4740 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4742 { ep_obsolete, EP_OBSOLETE },
4749 // always start with reliable default values (element has no properties)
4750 // (but never initialize clipboard elements after the very first time)
4751 // (to be able to use clipboard elements between several levels)
4752 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4753 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4754 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4755 SET_PROPERTY(i, j, FALSE);
4757 // set all base element properties from above array definitions
4758 for (i = 0; element_properties[i].elements != NULL; i++)
4759 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4760 SET_PROPERTY((element_properties[i].elements)[j],
4761 element_properties[i].property, TRUE);
4763 // copy properties to some elements that are only stored in level file
4764 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4765 for (j = 0; copy_properties[j][0] != -1; j++)
4766 if (HAS_PROPERTY(copy_properties[j][0], i))
4767 for (k = 1; k <= 4; k++)
4768 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4770 // set static element properties that are not listed in array definitions
4771 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4772 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4774 clipboard_elements_initialized = TRUE;
4777 void InitElementPropertiesEngine(int engine_version)
4779 static int no_wall_properties[] =
4782 EP_COLLECTIBLE_ONLY,
4784 EP_DONT_COLLIDE_WITH,
4787 EP_CAN_SMASH_PLAYER,
4788 EP_CAN_SMASH_ENEMIES,
4789 EP_CAN_SMASH_EVERYTHING,
4794 EP_FOOD_DARK_YAMYAM,
4810 /* important: after initialization in InitElementPropertiesStatic(), the
4811 elements are not again initialized to a default value; therefore all
4812 changes have to make sure that they leave the element with a defined
4813 property (which means that conditional property changes must be set to
4814 a reliable default value before) */
4816 // resolve group elements
4817 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4818 ResolveGroupElement(EL_GROUP_START + i);
4820 // set all special, combined or engine dependent element properties
4821 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4823 // do not change (already initialized) clipboard elements here
4824 if (IS_CLIPBOARD_ELEMENT(i))
4827 // ---------- INACTIVE ----------------------------------------------------
4828 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4829 i <= EL_CHAR_END) ||
4830 (i >= EL_STEEL_CHAR_START &&
4831 i <= EL_STEEL_CHAR_END)));
4833 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4834 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4835 IS_WALKABLE_INSIDE(i) ||
4836 IS_WALKABLE_UNDER(i)));
4838 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4839 IS_PASSABLE_INSIDE(i) ||
4840 IS_PASSABLE_UNDER(i)));
4842 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4843 IS_PASSABLE_OVER(i)));
4845 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4846 IS_PASSABLE_INSIDE(i)));
4848 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4849 IS_PASSABLE_UNDER(i)));
4851 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4854 // ---------- COLLECTIBLE -------------------------------------------------
4855 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4859 // ---------- SNAPPABLE ---------------------------------------------------
4860 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4861 IS_COLLECTIBLE(i) ||
4865 // ---------- WALL --------------------------------------------------------
4866 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4868 for (j = 0; no_wall_properties[j] != -1; j++)
4869 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4870 i >= EL_FIRST_RUNTIME_UNREAL)
4871 SET_PROPERTY(i, EP_WALL, FALSE);
4873 if (IS_HISTORIC_WALL(i))
4874 SET_PROPERTY(i, EP_WALL, TRUE);
4876 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4877 if (engine_version < VERSION_IDENT(2,2,0,0))
4878 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4880 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4882 !IS_COLLECTIBLE(i)));
4884 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4885 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4886 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4888 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4891 // ---------- EXPLOSION_PROOF ---------------------------------------------
4893 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4894 else if (engine_version < VERSION_IDENT(2,2,0,0))
4895 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4897 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4901 if (IS_CUSTOM_ELEMENT(i))
4903 // these are additional properties which are initially false when set
4905 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4907 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4908 if (DONT_COLLIDE_WITH(i))
4909 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4911 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4912 if (CAN_SMASH_EVERYTHING(i))
4913 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4914 if (CAN_SMASH_ENEMIES(i))
4915 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4918 // ---------- CAN_SMASH ---------------------------------------------------
4919 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4920 CAN_SMASH_ENEMIES(i) ||
4921 CAN_SMASH_EVERYTHING(i)));
4923 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4924 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4925 EXPLODES_BY_FIRE(i)));
4927 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4928 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4929 EXPLODES_SMASHED(i)));
4931 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4932 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4933 EXPLODES_IMPACT(i)));
4935 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4936 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4938 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4939 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4940 i == EL_BLACK_ORB));
4942 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4943 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4945 IS_CUSTOM_ELEMENT(i)));
4947 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4948 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4949 i == EL_SP_ELECTRON));
4951 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4952 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4953 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4954 getMoveIntoAcidProperty(&level, i));
4956 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4957 if (MAYBE_DONT_COLLIDE_WITH(i))
4958 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4959 getDontCollideWithProperty(&level, i));
4961 // ---------- SP_PORT -----------------------------------------------------
4962 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4963 IS_PASSABLE_INSIDE(i)));
4965 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4966 for (j = 0; j < level.num_android_clone_elements; j++)
4967 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4969 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4971 // ---------- CAN_CHANGE --------------------------------------------------
4972 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4973 for (j = 0; j < element_info[i].num_change_pages; j++)
4974 if (element_info[i].change_page[j].can_change)
4975 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4977 // ---------- HAS_ACTION --------------------------------------------------
4978 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4979 for (j = 0; j < element_info[i].num_change_pages; j++)
4980 if (element_info[i].change_page[j].has_action)
4981 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4983 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4984 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4987 // ---------- GFX_CRUMBLED ------------------------------------------------
4988 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4989 element_info[i].crumbled[ACTION_DEFAULT] !=
4990 element_info[i].graphic[ACTION_DEFAULT]);
4992 // ---------- EDITOR_CASCADE ----------------------------------------------
4993 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4994 IS_EDITOR_CASCADE_INACTIVE(i)));
4997 // dynamically adjust element properties according to game engine version
4999 static int ep_em_slippery_wall[] =
5004 EL_EXPANDABLE_WALL_HORIZONTAL,
5005 EL_EXPANDABLE_WALL_VERTICAL,
5006 EL_EXPANDABLE_WALL_ANY,
5007 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5008 EL_EXPANDABLE_STEELWALL_VERTICAL,
5009 EL_EXPANDABLE_STEELWALL_ANY,
5010 EL_EXPANDABLE_STEELWALL_GROWING,
5014 static int ep_em_explodes_by_fire[] =
5017 EL_EM_DYNAMITE_ACTIVE,
5022 // special EM style gems behaviour
5023 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
5024 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
5025 level.em_slippery_gems);
5027 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
5028 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
5029 (level.em_slippery_gems &&
5030 engine_version > VERSION_IDENT(2,0,1,0)));
5032 // special EM style explosion behaviour regarding chain reactions
5033 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
5034 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
5035 level.em_explodes_by_fire);
5038 // this is needed because some graphics depend on element properties
5039 if (game_status == GAME_MODE_PLAYING)
5040 InitElementGraphicInfo();
5043 void InitElementPropertiesGfxElement(void)
5047 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5049 struct ElementInfo *ei = &element_info[i];
5051 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5055 static void InitGlobal(void)
5060 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5062 // check if element_name_info entry defined for each element in "main.h"
5063 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5064 Fail("undefined 'element_name_info' entry for element %d", i);
5066 element_info[i].token_name = element_name_info[i].token_name;
5067 element_info[i].class_name = element_name_info[i].class_name;
5068 element_info[i].editor_description = element_name_info[i].editor_description;
5071 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
5073 // check if global_anim_name_info defined for each entry in "main.h"
5074 if (i < NUM_GLOBAL_ANIM_TOKENS &&
5075 global_anim_name_info[i].token_name == NULL)
5076 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
5078 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
5081 // create hash to store URLs for global animations
5082 anim_url_hash = newSetupFileHash();
5084 // create hash from image config list
5085 image_config_hash = newSetupFileHash();
5086 for (i = 0; image_config[i].token != NULL; i++)
5087 setHashEntry(image_config_hash,
5088 image_config[i].token,
5089 image_config[i].value);
5091 // create hash from sound config list
5092 sound_config_hash = newSetupFileHash();
5093 for (i = 0; sound_config[i].token != NULL; i++)
5094 setHashEntry(sound_config_hash,
5095 sound_config[i].token,
5096 sound_config[i].value);
5098 // create hash from element token list
5099 element_token_hash = newSetupFileHash();
5100 for (i = 0; element_name_info[i].token_name != NULL; i++)
5101 setHashEntry(element_token_hash,
5102 element_name_info[i].token_name,
5105 // create hash from graphic token list
5106 graphic_token_hash = newSetupFileHash();
5107 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5108 if (strSuffix(image_config[i].value, ".png") ||
5109 strSuffix(image_config[i].value, ".pcx") ||
5110 strSuffix(image_config[i].value, ".wav") ||
5111 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5112 setHashEntry(graphic_token_hash,
5113 image_config[i].token,
5114 int2str(graphic++, 0));
5116 // create hash from font token list
5117 font_token_hash = newSetupFileHash();
5118 for (i = 0; font_info[i].token_name != NULL; i++)
5119 setHashEntry(font_token_hash,
5120 font_info[i].token_name,
5123 // set default filenames for all cloned graphics in static configuration
5124 for (i = 0; image_config[i].token != NULL; i++)
5126 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5128 char *token = image_config[i].token;
5129 char *token_clone_from = getStringCat2(token, ".clone_from");
5130 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5132 if (token_cloned != NULL)
5134 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5136 if (value_cloned != NULL)
5138 // set default filename in static configuration
5139 image_config[i].value = value_cloned;
5141 // set default filename in image config hash
5142 setHashEntry(image_config_hash, token, value_cloned);
5146 free(token_clone_from);
5150 // always start with reliable default values (all elements)
5151 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5152 ActiveElement[i] = i;
5154 // now add all entries that have an active state (active elements)
5155 for (i = 0; element_with_active_state[i].element != -1; i++)
5157 int element = element_with_active_state[i].element;
5158 int element_active = element_with_active_state[i].element_active;
5160 ActiveElement[element] = element_active;
5163 // always start with reliable default values (all buttons)
5164 for (i = 0; i < NUM_IMAGE_FILES; i++)
5165 ActiveButton[i] = i;
5167 // now add all entries that have an active state (active buttons)
5168 for (i = 0; button_with_active_state[i].button != -1; i++)
5170 int button = button_with_active_state[i].button;
5171 int button_active = button_with_active_state[i].button_active;
5173 ActiveButton[button] = button_active;
5176 // always start with reliable default values (all fonts)
5177 for (i = 0; i < NUM_FONTS; i++)
5180 // now add all entries that have an active state (active fonts)
5181 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5183 int font = font_with_active_state[i].font_nr;
5184 int font_active = font_with_active_state[i].font_nr_active;
5186 ActiveFont[font] = font_active;
5189 global.autoplay_leveldir = NULL;
5190 global.patchtapes_leveldir = NULL;
5191 global.convert_leveldir = NULL;
5192 global.dumplevel_leveldir = NULL;
5193 global.dumptape_leveldir = NULL;
5194 global.create_sketch_images_dir = NULL;
5195 global.create_collect_images_dir = NULL;
5197 global.frames_per_second = 0;
5198 global.show_frames_per_second = FALSE;
5200 global.border_status = GAME_MODE_LOADING;
5201 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5203 global.use_envelope_request = FALSE;
5205 global.user_names = NULL;
5208 static void Execute_Command(char *command)
5212 if (strEqual(command, "print graphicsinfo.conf"))
5214 Print("# You can configure additional/alternative image files here.\n");
5215 Print("# (The entries below are default and therefore commented out.)\n");
5217 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5219 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5222 for (i = 0; image_config[i].token != NULL; i++)
5223 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5224 image_config[i].value));
5228 else if (strEqual(command, "print soundsinfo.conf"))
5230 Print("# You can configure additional/alternative sound files here.\n");
5231 Print("# (The entries below are default and therefore commented out.)\n");
5233 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5235 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5238 for (i = 0; sound_config[i].token != NULL; i++)
5239 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5240 sound_config[i].value));
5244 else if (strEqual(command, "print musicinfo.conf"))
5246 Print("# You can configure additional/alternative music files here.\n");
5247 Print("# (The entries below are default and therefore commented out.)\n");
5249 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5251 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5254 for (i = 0; music_config[i].token != NULL; i++)
5255 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5256 music_config[i].value));
5260 else if (strEqual(command, "print editorsetup.conf"))
5262 Print("# You can configure your personal editor element list here.\n");
5263 Print("# (The entries below are default and therefore commented out.)\n");
5266 // this is needed to be able to check element list for cascade elements
5267 InitElementPropertiesStatic();
5268 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5270 PrintEditorElementList();
5274 else if (strEqual(command, "print helpanim.conf"))
5276 Print("# You can configure different element help animations here.\n");
5277 Print("# (The entries below are default and therefore commented out.)\n");
5280 for (i = 0; helpanim_config[i].token != NULL; i++)
5282 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5283 helpanim_config[i].value));
5285 if (strEqual(helpanim_config[i].token, "end"))
5291 else if (strEqual(command, "print helptext.conf"))
5293 Print("# You can configure different element help text here.\n");
5294 Print("# (The entries below are default and therefore commented out.)\n");
5297 for (i = 0; helptext_config[i].token != NULL; i++)
5298 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5299 helptext_config[i].value));
5303 else if (strPrefix(command, "dump level "))
5305 char *filename = &command[11];
5307 if (fileExists(filename))
5309 LoadLevelFromFilename(&level, filename);
5315 char *leveldir = getStringCopy(filename); // read command parameters
5316 char *level_nr = strchr(leveldir, ' ');
5318 if (level_nr == NULL)
5319 Fail("cannot open file '%s'", filename);
5323 global.dumplevel_leveldir = leveldir;
5324 global.dumplevel_level_nr = atoi(level_nr);
5326 program.headless = TRUE;
5328 else if (strPrefix(command, "dump tape "))
5330 char *filename = &command[10];
5332 if (fileExists(filename))
5334 LoadTapeFromFilename(filename);
5340 char *leveldir = getStringCopy(filename); // read command parameters
5341 char *level_nr = strchr(leveldir, ' ');
5343 if (level_nr == NULL)
5344 Fail("cannot open file '%s'", filename);
5348 global.dumptape_leveldir = leveldir;
5349 global.dumptape_level_nr = atoi(level_nr);
5351 program.headless = TRUE;
5353 else if (strPrefix(command, "autoplay ") ||
5354 strPrefix(command, "autoffwd ") ||
5355 strPrefix(command, "autowarp ") ||
5356 strPrefix(command, "autotest ") ||
5357 strPrefix(command, "autosave ") ||
5358 strPrefix(command, "autoupload ") ||
5359 strPrefix(command, "autofix "))
5361 char *arg_ptr = strchr(command, ' ');
5362 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5364 global.autoplay_mode =
5365 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5366 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5367 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5368 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5369 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5370 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5371 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5372 AUTOPLAY_MODE_NONE);
5374 while (*str_ptr != '\0') // continue parsing string
5376 // cut leading whitespace from string, replace it by string terminator
5377 while (*str_ptr == ' ' || *str_ptr == '\t')
5380 if (*str_ptr == '\0') // end of string reached
5383 if (global.autoplay_leveldir == NULL) // read level set string
5385 global.autoplay_leveldir = str_ptr;
5386 global.autoplay_all = TRUE; // default: play all tapes
5388 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5389 global.autoplay_level[i] = FALSE;
5391 else // read level number string
5393 int level_nr = atoi(str_ptr); // get level_nr value
5395 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5396 global.autoplay_level[level_nr] = TRUE;
5398 global.autoplay_all = FALSE;
5401 // advance string pointer to the next whitespace (or end of string)
5402 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5406 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5407 program.headless = TRUE;
5409 else if (strPrefix(command, "patch tapes "))
5411 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5413 // skip leading whitespace
5414 while (*str_ptr == ' ' || *str_ptr == '\t')
5417 if (*str_ptr == '\0')
5418 Fail("cannot find MODE in command '%s'", command);
5420 global.patchtapes_mode = str_ptr; // store patch mode
5422 // advance to next whitespace (or end of string)
5423 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5426 while (*str_ptr != '\0') // continue parsing string
5428 // cut leading whitespace from string, replace it by string terminator
5429 while (*str_ptr == ' ' || *str_ptr == '\t')
5432 if (*str_ptr == '\0') // end of string reached
5435 if (global.patchtapes_leveldir == NULL) // read level set string
5437 global.patchtapes_leveldir = str_ptr;
5438 global.patchtapes_all = TRUE; // default: patch all tapes
5440 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5441 global.patchtapes_level[i] = FALSE;
5443 else // read level number string
5445 int level_nr = atoi(str_ptr); // get level_nr value
5447 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5448 global.patchtapes_level[level_nr] = TRUE;
5450 global.patchtapes_all = FALSE;
5453 // advance string pointer to the next whitespace (or end of string)
5454 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5458 if (global.patchtapes_leveldir == NULL)
5460 if (strEqual(global.patchtapes_mode, "help"))
5461 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5463 Fail("cannot find LEVELDIR in command '%s'", command);
5466 program.headless = TRUE;
5468 else if (strPrefix(command, "convert "))
5470 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5471 char *str_ptr = strchr(str_copy, ' ');
5473 global.convert_leveldir = str_copy;
5474 global.convert_level_nr = -1;
5476 if (str_ptr != NULL) // level number follows
5478 *str_ptr++ = '\0'; // terminate leveldir string
5479 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5482 program.headless = TRUE;
5484 else if (strPrefix(command, "create sketch images "))
5486 global.create_sketch_images_dir = getStringCopy(&command[21]);
5488 if (access(global.create_sketch_images_dir, W_OK) != 0)
5489 Fail("image target directory '%s' not found or not writable",
5490 global.create_sketch_images_dir);
5492 else if (strPrefix(command, "create collect image "))
5494 global.create_collect_images_dir = getStringCopy(&command[21]);
5496 if (access(global.create_collect_images_dir, W_OK) != 0)
5497 Fail("image target directory '%s' not found or not writable",
5498 global.create_collect_images_dir);
5500 else if (strPrefix(command, "create CE image "))
5502 CreateCustomElementImages(&command[16]);
5508 FailWithHelp("unrecognized command '%s'", command);
5511 // disable networking if any valid command was recognized
5512 options.network = setup.network_mode = FALSE;
5515 static void InitSetup(void)
5517 LoadUserNames(); // global user names
5518 LoadUserSetup(); // global user number
5520 LoadSetup(); // global setup info
5522 // set some options from setup file
5524 if (setup.options.verbose)
5525 options.verbose = TRUE;
5527 if (setup.options.debug)
5528 options.debug = TRUE;
5530 if (!strEqual(setup.options.debug_mode, ARG_UNDEFINED_STRING))
5531 options.debug_mode = getStringCopy(setup.options.debug_mode);
5533 if (setup.debug.show_frames_per_second)
5534 global.show_frames_per_second = TRUE;
5537 static void InitGameInfo(void)
5539 game.restart_level = FALSE;
5540 game.request_active = FALSE;
5542 game.use_masked_elements_initial = FALSE;
5545 static void InitPlayerInfo(void)
5549 // choose default local player
5550 local_player = &stored_player[0];
5552 for (i = 0; i < MAX_PLAYERS; i++)
5554 stored_player[i].connected_locally = FALSE;
5555 stored_player[i].connected_network = FALSE;
5558 local_player->connected_locally = TRUE;
5561 static void InitArtworkInfo(void)
5566 static char *get_string_in_brackets(char *string)
5568 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5570 sprintf(string_in_brackets, "[%s]", string);
5572 return string_in_brackets;
5575 static char *get_level_id_suffix(int id_nr)
5577 char *id_suffix = checked_malloc(1 + 3 + 1);
5579 if (id_nr < 0 || id_nr > 999)
5582 sprintf(id_suffix, ".%03d", id_nr);
5587 static void InitArtworkConfig(void)
5589 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5591 NUM_GLOBAL_ANIM_TOKENS + 1];
5592 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5593 NUM_GLOBAL_ANIM_TOKENS + 1];
5594 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5595 NUM_GLOBAL_ANIM_TOKENS + 1];
5596 static char *action_id_suffix[NUM_ACTIONS + 1];
5597 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5598 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5599 static char *level_id_suffix[MAX_LEVELS + 1];
5600 static char *dummy[1] = { NULL };
5601 static char *ignore_generic_tokens[] =
5606 "program_copyright",
5611 static char **ignore_image_tokens;
5612 static char **ignore_sound_tokens;
5613 static char **ignore_music_tokens;
5614 int num_ignore_generic_tokens;
5615 int num_ignore_image_tokens;
5616 int num_ignore_sound_tokens;
5617 int num_ignore_music_tokens;
5620 // dynamically determine list of generic tokens to be ignored
5621 num_ignore_generic_tokens = 0;
5622 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5623 num_ignore_generic_tokens++;
5625 // dynamically determine list of image tokens to be ignored
5626 num_ignore_image_tokens = num_ignore_generic_tokens;
5627 for (i = 0; image_config_vars[i].token != NULL; i++)
5628 num_ignore_image_tokens++;
5629 ignore_image_tokens =
5630 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5631 for (i = 0; i < num_ignore_generic_tokens; i++)
5632 ignore_image_tokens[i] = ignore_generic_tokens[i];
5633 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5634 ignore_image_tokens[num_ignore_generic_tokens + i] =
5635 image_config_vars[i].token;
5636 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5638 // dynamically determine list of sound tokens to be ignored
5639 num_ignore_sound_tokens = num_ignore_generic_tokens;
5640 for (i = 0; sound_config_vars[i].token != NULL; i++)
5641 num_ignore_sound_tokens++;
5642 ignore_sound_tokens =
5643 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5644 for (i = 0; i < num_ignore_generic_tokens; i++)
5645 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5646 for (i = 0; i < num_ignore_sound_tokens - num_ignore_generic_tokens; i++)
5647 ignore_sound_tokens[num_ignore_generic_tokens + i] =
5648 sound_config_vars[i].token;
5649 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5651 // dynamically determine list of music tokens to be ignored
5652 num_ignore_music_tokens = num_ignore_generic_tokens;
5653 ignore_music_tokens =
5654 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5655 for (i = 0; i < num_ignore_generic_tokens; i++)
5656 ignore_music_tokens[i] = ignore_generic_tokens[i];
5657 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5659 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5660 image_id_prefix[i] = element_info[i].token_name;
5661 for (i = 0; i < NUM_FONTS; i++)
5662 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5663 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5664 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5665 global_anim_info[i].token_name;
5666 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5668 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5669 sound_id_prefix[i] = element_info[i].token_name;
5670 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5671 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5672 get_string_in_brackets(element_info[i].class_name);
5673 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5674 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5675 global_anim_info[i].token_name;
5676 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5678 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5679 music_id_prefix[i] = music_prefix_info[i].prefix;
5680 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5681 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5682 global_anim_info[i].token_name;
5683 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5685 for (i = 0; i < NUM_ACTIONS; i++)
5686 action_id_suffix[i] = element_action_info[i].suffix;
5687 action_id_suffix[NUM_ACTIONS] = NULL;
5689 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5690 direction_id_suffix[i] = element_direction_info[i].suffix;
5691 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5693 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5694 special_id_suffix[i] = special_suffix_info[i].suffix;
5695 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5697 for (i = 0; i < MAX_LEVELS; i++)
5698 level_id_suffix[i] = get_level_id_suffix(i);
5699 level_id_suffix[MAX_LEVELS] = NULL;
5701 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5702 image_id_prefix, action_id_suffix, direction_id_suffix,
5703 special_id_suffix, ignore_image_tokens);
5704 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5705 sound_id_prefix, action_id_suffix, dummy,
5706 special_id_suffix, ignore_sound_tokens);
5707 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5708 music_id_prefix, action_id_suffix, special_id_suffix,
5709 level_id_suffix, ignore_music_tokens);
5712 static void InitMixer(void)
5719 static void InitVideoOverlay(void)
5721 // if virtual buttons are not loaded from setup file, repeat initializing
5722 // virtual buttons grid with default values now that video is initialized
5723 if (!setup.touch.grid_initialized)
5726 InitTileCursorInfo();
5730 void InitGfxBuffers(void)
5732 static int win_xsize_last = -1;
5733 static int win_ysize_last = -1;
5735 // create additional image buffers for double-buffering and cross-fading
5737 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5739 // used to temporarily store the backbuffer -- only re-create if changed
5740 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5741 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5743 win_xsize_last = WIN_XSIZE;
5744 win_ysize_last = WIN_YSIZE;
5747 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5748 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5749 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5751 // initialize screen properties
5752 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5753 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5755 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5756 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5757 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5758 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5759 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5760 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5762 // required if door size definitions have changed
5763 InitGraphicCompatibilityInfo_Doors();
5765 InitGfxBuffers_BD();
5766 InitGfxBuffers_EM();
5767 InitGfxBuffers_SP();
5768 InitGfxBuffers_MM();
5771 static void InitGfx(void)
5773 struct GraphicInfo *graphic_info_last = graphic_info;
5774 char *filename_font_initial = NULL;
5775 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5776 char *image_token[NUM_INITIAL_IMAGES] =
5778 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5779 CONFIG_TOKEN_GLOBAL_BUSY,
5780 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5781 CONFIG_TOKEN_BACKGROUND,
5782 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5783 CONFIG_TOKEN_BACKGROUND_LOADING
5785 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5789 &init.busy_playfield
5791 Bitmap *bitmap_font_initial = NULL;
5792 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5795 // determine settings for initial font (for displaying startup messages)
5796 for (i = 0; image_config[i].token != NULL; i++)
5798 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5800 char font_token[128];
5803 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5804 len_font_token = strlen(font_token);
5806 if (strEqual(image_config[i].token, font_token))
5808 filename_font_initial = image_config[i].value;
5810 else if (strlen(image_config[i].token) > len_font_token &&
5811 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5813 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5814 font_initial[j].src_x = atoi(image_config[i].value);
5815 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5816 font_initial[j].src_y = atoi(image_config[i].value);
5817 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5818 font_initial[j].width = atoi(image_config[i].value);
5819 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5820 font_initial[j].height = atoi(image_config[i].value);
5825 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5827 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5828 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5831 if (filename_font_initial == NULL) // should not happen
5832 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5835 InitGfxCustomArtworkInfo();
5836 InitGfxOtherSettings();
5838 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5840 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5842 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5843 font_initial[j].bitmap = bitmap_font_initial;
5845 InitFontGraphicInfo();
5847 InitMenuDesignSettings_Static();
5849 // initialize settings for initial images with default values
5850 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5851 for (j = 0; j < NUM_GFX_ARGS; j++)
5853 get_graphic_parameter_value(image_config_suffix[j].value,
5854 image_config_suffix[j].token,
5855 image_config_suffix[j].type);
5857 // read settings for initial images from default custom artwork config
5858 char *gfx_config_filename = getPath3(options.graphics_directory,
5860 GRAPHICSINFO_FILENAME);
5862 if (fileExists(gfx_config_filename))
5864 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5866 if (setup_file_hash)
5868 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5870 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5874 filename_image_initial[i] = getStringCopy(filename);
5876 for (j = 0; image_config_suffix[j].token != NULL; j++)
5878 int type = image_config_suffix[j].type;
5879 char *suffix = image_config_suffix[j].token;
5880 char *token = getStringCat2(image_token[i], suffix);
5881 char *value = getHashEntry(setup_file_hash, token);
5883 checked_free(token);
5887 get_graphic_parameter_value(value, suffix, type);
5892 // read values from custom graphics config file
5893 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5895 freeSetupFileHash(setup_file_hash);
5899 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5901 if (filename_image_initial[i] == NULL)
5903 int len_token = strlen(image_token[i]);
5905 // read settings for initial images from static default artwork config
5906 for (j = 0; image_config[j].token != NULL; j++)
5908 if (strEqual(image_config[j].token, image_token[i]))
5910 filename_image_initial[i] = getStringCopy(image_config[j].value);
5912 else if (strlen(image_config[j].token) > len_token &&
5913 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5915 for (k = 0; image_config_suffix[k].token != NULL; k++)
5917 if (strEqual(&image_config[j].token[len_token],
5918 image_config_suffix[k].token))
5920 get_graphic_parameter_value(image_config[j].value,
5921 image_config_suffix[k].token,
5922 image_config_suffix[k].type);
5929 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5931 if (filename_image_initial[i] == NULL) // should not happen
5932 Fail("cannot get filename for '%s'", image_token[i]);
5934 image_initial[i].bitmaps =
5935 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5937 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5938 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5939 LoadCustomImage(filename_image_initial[i]);
5941 checked_free(filename_image_initial[i]);
5944 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5945 image_initial[i].use_image_size = TRUE;
5947 graphic_info = image_initial; // graphic == 0 => image_initial
5949 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5950 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5952 graphic_info = graphic_info_last;
5954 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5956 // set image size for busy animations
5957 init_busy[i]->width = image_initial[i].width;
5958 init_busy[i]->height = image_initial[i].height;
5961 SetLoadingBackgroundImage();
5963 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5967 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5968 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5969 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5970 InitGfxDrawTileCursorFunction(DrawTileCursor);
5971 InitGfxDrawEnvelopeRequestFunction(DrawEnvelopeRequestToScreen);
5973 gfx.fade_border_source_status = global.border_status;
5974 gfx.fade_border_target_status = global.border_status;
5975 gfx.masked_border_bitmap_ptr = backbuffer;
5977 // use copy of busy animation to prevent change while reloading artwork
5981 static void InitGfxBackground(void)
5983 fieldbuffer = bitmap_db_field;
5984 SetDrawtoField(DRAW_TO_BACKBUFFER);
5986 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5988 redraw_mask = REDRAW_ALL;
5991 static void InitSnd(void)
5993 InitSoundSettings_Static();
5995 // read settings for initial sounds from default custom artwork config
5996 char *snd_config_filename = getPath3(options.sounds_directory,
5998 SOUNDSINFO_FILENAME);
6000 if (fileExists(snd_config_filename))
6002 SetupFileHash *setup_file_hash = loadSetupFileHash(snd_config_filename);
6004 if (setup_file_hash)
6006 // read values from custom sounds config file
6007 InitSoundSettings_FromHash(setup_file_hash, FALSE);
6009 freeSetupFileHash(setup_file_hash);
6014 static void InitLevelInfo(void)
6016 LoadLevelInfo(); // global level info
6017 LoadLevelSetup_LastSeries(); // last played series info
6018 LoadLevelSetup_SeriesInfo(); // last played level info
6020 if (global.autoplay_leveldir &&
6021 global.autoplay_mode != AUTOPLAY_MODE_TEST)
6023 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
6024 global.autoplay_leveldir);
6025 if (leveldir_current == NULL)
6026 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
6029 SetLevelSetInfo(leveldir_current->identifier, level_nr);
6032 static void InitLevelArtworkInfo(void)
6034 LoadLevelArtworkInfo();
6037 static void InitImages(void)
6039 print_timestamp_init("InitImages");
6042 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6043 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6044 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6045 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6046 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6047 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6048 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6049 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6052 setLevelArtworkDir(artwork.gfx_first);
6055 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6056 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6057 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6058 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6059 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6060 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6061 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6062 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6066 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
6067 leveldir_current->identifier,
6068 artwork.gfx_current_identifier,
6069 artwork.gfx_current->identifier,
6070 leveldir_current->graphics_set,
6071 leveldir_current->graphics_path);
6074 UPDATE_BUSY_STATE();
6076 ReloadCustomImages();
6077 print_timestamp_time("ReloadCustomImages");
6079 UPDATE_BUSY_STATE();
6081 LoadCustomElementDescriptions();
6082 print_timestamp_time("LoadCustomElementDescriptions");
6084 UPDATE_BUSY_STATE();
6086 LoadMenuDesignSettings();
6087 print_timestamp_time("LoadMenuDesignSettings");
6089 UPDATE_BUSY_STATE();
6091 ReinitializeGraphics();
6092 print_timestamp_time("ReinitializeGraphics");
6094 LoadMenuDesignSettings_AfterGraphics();
6095 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
6097 UPDATE_BUSY_STATE();
6099 print_timestamp_done("InitImages");
6102 static void InitSound(void)
6104 print_timestamp_init("InitSound");
6106 // set artwork path to send it to the sound server process
6107 setLevelArtworkDir(artwork.snd_first);
6109 InitReloadCustomSounds();
6110 print_timestamp_time("InitReloadCustomSounds");
6112 LoadSoundSettings();
6113 print_timestamp_time("LoadSoundSettings");
6115 ReinitializeSounds();
6116 print_timestamp_time("ReinitializeSounds");
6118 print_timestamp_done("InitSound");
6121 static void InitMusic(void)
6123 print_timestamp_init("InitMusic");
6125 // set artwork path to send it to the sound server process
6126 setLevelArtworkDir(artwork.mus_first);
6128 InitReloadCustomMusic();
6129 print_timestamp_time("InitReloadCustomMusic");
6131 ReinitializeMusic();
6132 print_timestamp_time("ReinitializeMusic");
6134 print_timestamp_done("InitMusic");
6137 static void InitArtworkDone(void)
6139 if (program.headless)
6142 InitGlobalAnimations();
6145 static void InitNetworkSettings(void)
6147 boolean network_enabled = (options.network || setup.network_mode);
6148 char *network_server = (options.server_host != NULL ? options.server_host :
6149 setup.network_server_hostname);
6151 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6152 network_server = NULL;
6154 InitNetworkInfo(network_enabled,
6158 options.server_port);
6161 void InitNetworkServer(void)
6163 if (!network.enabled || network.connected)
6166 LimitScreenUpdates(FALSE);
6168 if (game_status == GAME_MODE_LOADING)
6171 if (!ConnectToServer(network.server_host, network.server_port))
6173 network.enabled = FALSE;
6175 setup.network_mode = FALSE;
6179 SendToServer_ProtocolVersion();
6180 SendToServer_PlayerName(setup.player_name);
6181 SendToServer_NrWanted(setup.network_player_nr + 1);
6183 network.connected = TRUE;
6186 // short time to recognize result of network initialization
6187 if (game_status == GAME_MODE_LOADING)
6188 Delay_WithScreenUpdates(1000);
6191 static boolean CheckArtworkConfigForCustomElements(char *filename)
6193 SetupFileHash *setup_file_hash;
6194 boolean redefined_ce_found = FALSE;
6196 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6198 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6200 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6202 char *token = HASH_ITERATION_TOKEN(itr);
6204 if (strPrefix(token, "custom_"))
6206 redefined_ce_found = TRUE;
6211 END_HASH_ITERATION(setup_file_hash, itr)
6213 freeSetupFileHash(setup_file_hash);
6216 return redefined_ce_found;
6219 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6221 char *filename_base, *filename_local;
6222 boolean redefined_ce_found = FALSE;
6224 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6227 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6228 "leveldir_current->identifier == '%s'",
6229 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6230 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6231 "leveldir_current->graphics_path == '%s'",
6232 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6233 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6234 "leveldir_current->graphics_set == '%s'",
6235 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6236 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6237 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6238 leveldir_current == NULL ? "[NULL]" :
6239 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6242 // first look for special artwork configured in level series config
6243 filename_base = getCustomArtworkLevelConfigFilename(type);
6246 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6247 "filename_base == '%s'", filename_base);
6250 if (fileExists(filename_base))
6251 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6253 filename_local = getCustomArtworkConfigFilename(type);
6256 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6257 "filename_local == '%s'", filename_local);
6260 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6261 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6264 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6265 "redefined_ce_found == %d", redefined_ce_found);
6268 return redefined_ce_found;
6271 static void InitOverrideArtwork(void)
6273 boolean redefined_ce_found = FALSE;
6275 // to check if this level set redefines any CEs, do not use overriding
6276 gfx.override_level_graphics = FALSE;
6277 gfx.override_level_sounds = FALSE;
6278 gfx.override_level_music = FALSE;
6280 // now check if this level set has definitions for custom elements
6281 if (setup.override_level_graphics == STATE_AUTO ||
6282 setup.override_level_sounds == STATE_AUTO ||
6283 setup.override_level_music == STATE_AUTO)
6284 redefined_ce_found =
6285 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6286 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6287 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6290 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6291 redefined_ce_found);
6294 if (redefined_ce_found)
6296 // this level set has CE definitions: change "MODE_AUTO" to "FALSE"
6297 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6298 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6299 gfx.override_level_music = (setup.override_level_music == TRUE);
6303 // this level set has no CE definitions: change "MODE_AUTO" to "TRUE"
6304 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6305 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6306 gfx.override_level_music = (setup.override_level_music != FALSE);
6310 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6311 gfx.override_level_graphics,
6312 gfx.override_level_sounds,
6313 gfx.override_level_music);
6317 static char *setNewArtworkIdentifier(int type)
6319 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6320 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6321 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6322 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6323 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6324 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6325 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6326 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6327 char *leveldir_identifier = leveldir_current->identifier;
6328 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6329 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6330 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6331 TreeInfo *custom_artwork_set =
6332 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6333 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6334 char *artwork_current_identifier;
6335 char *artwork_new_identifier = NULL; // default: nothing has changed
6337 // leveldir_current may be invalid (level group, parent link)
6338 if (!validLevelSeries(leveldir_current))
6341 /* 1st step: determine artwork set to be activated in descending order:
6342 --------------------------------------------------------------------
6343 1. setup artwork (when configured to override everything else)
6344 2. artwork set configured in "levelinfo.conf" of current level set
6345 (artwork in level directory will have priority when loading later)
6346 3. artwork in level directory (stored in artwork sub-directory)
6347 4. setup artwork (currently configured in setup menu) */
6349 if (setup_override_artwork)
6350 artwork_current_identifier = setup_artwork_set;
6351 else if (has_level_artwork_set)
6352 artwork_current_identifier = leveldir_artwork_set;
6353 else if (has_custom_artwork_set)
6354 artwork_current_identifier = leveldir_identifier;
6356 artwork_current_identifier = setup_artwork_set;
6358 /* 2nd step: check if it is really needed to reload artwork set
6359 ------------------------------------------------------------ */
6361 // ---------- reload if level set and also artwork set has changed ----------
6362 if (last_leveldir_identifier[type] != leveldir_identifier &&
6363 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6364 artwork_new_identifier = artwork_current_identifier;
6366 last_leveldir_identifier[type] = leveldir_identifier;
6367 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6369 // ---------- reload if "override artwork" setting has changed --------------
6370 if (last_override_level_artwork[type] != setup_override_artwork)
6371 artwork_new_identifier = artwork_current_identifier;
6373 last_override_level_artwork[type] = setup_override_artwork;
6375 // ---------- reload if current artwork identifier has changed --------------
6376 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6377 artwork_new_identifier = artwork_current_identifier;
6379 // (we cannot compare string pointers here, so copy string content itself)
6380 setString(&last_artwork_identifier[type], artwork_current_identifier);
6382 // ---------- set new artwork identifier ----------
6383 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6385 // ---------- do not reload directly after starting -------------------------
6386 if (!initialized[type])
6387 artwork_new_identifier = NULL;
6389 initialized[type] = TRUE;
6391 return artwork_new_identifier;
6394 static void InitArtworkIdentifier(void)
6396 setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6397 setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6398 setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6401 void ReloadCustomArtwork(int force_reload)
6403 int last_game_status = game_status; // save current game status
6404 char *gfx_new_identifier;
6405 char *snd_new_identifier;
6406 char *mus_new_identifier;
6407 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6408 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6409 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6410 boolean reload_needed;
6412 InitOverrideArtwork();
6414 AdjustGraphicsForEMC();
6415 AdjustSoundsForEMC();
6417 gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6418 snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6419 mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6421 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6422 snd_new_identifier != NULL || force_reload_snd ||
6423 mus_new_identifier != NULL || force_reload_mus);
6428 print_timestamp_init("ReloadCustomArtwork");
6430 SetGameStatus(GAME_MODE_LOADING);
6432 FadeOut(REDRAW_ALL);
6434 SetLoadingBackgroundImage();
6436 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6437 print_timestamp_time("ClearRectangleOnBackground");
6441 UPDATE_BUSY_STATE();
6443 InitMissingFileHash();
6445 if (gfx_new_identifier != NULL || force_reload_gfx)
6448 Debug("init:ReloadCustomArtwork",
6449 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6450 artwork.gfx_current_identifier,
6452 artwork.gfx_current->identifier,
6453 leveldir_current->graphics_set);
6457 print_timestamp_time("InitImages");
6460 if (snd_new_identifier != NULL || force_reload_snd)
6463 print_timestamp_time("InitSound");
6466 if (mus_new_identifier != NULL || force_reload_mus)
6469 print_timestamp_time("InitMusic");
6474 SetGameStatus(last_game_status); // restore current game status
6476 FadeOut(REDRAW_ALL);
6478 RedrawGlobalBorder();
6480 // force redraw of (open or closed) door graphics
6481 SetDoorState(DOOR_OPEN_ALL);
6482 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6484 FadeSetEnterScreen();
6485 FadeSkipNextFadeOut();
6487 print_timestamp_done("ReloadCustomArtwork");
6489 LimitScreenUpdates(FALSE);
6492 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6494 if (global.autoplay_leveldir == NULL)
6495 KeyboardAutoRepeatOff();
6498 void DisplayExitMessage(char *format, va_list ap)
6500 // also check for initialized video (headless flag may be temporarily unset)
6501 if (program.headless || !video.initialized)
6504 // check if draw buffer and fonts for exit message are already available
6505 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6508 int font_1 = FC_RED;
6509 int font_2 = FC_YELLOW;
6510 int font_3 = FC_BLUE;
6511 int font_width = getFontWidth(font_2);
6512 int font_height = getFontHeight(font_2);
6515 int sxsize = WIN_XSIZE - 2 * sx;
6516 int sysize = WIN_YSIZE - 2 * sy;
6517 int line_length = sxsize / font_width;
6518 int max_lines = sysize / font_height;
6519 int num_lines_printed;
6523 gfx.sxsize = sxsize;
6524 gfx.sysize = sysize;
6528 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6530 DrawTextSCentered(sy, font_1, "Fatal error:");
6531 sy += 3 * font_height;;
6534 DrawTextBufferVA(sx, sy, format, ap, font_2,
6535 line_length, line_length, max_lines,
6536 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6537 sy += (num_lines_printed + 3) * font_height;
6539 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6540 sy += 3 * font_height;
6543 DrawTextBuffer(sx, sy, program.log_filename, font_2,
6544 line_length, line_length, max_lines,
6545 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6547 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6549 redraw_mask = REDRAW_ALL;
6551 // force drawing exit message even if screen updates are currently limited
6552 LimitScreenUpdates(FALSE);
6556 // deactivate toons and global animations on error message screen
6557 setup.global_animations = FALSE;
6559 WaitForEventToContinue();
6563 // ============================================================================
6565 // ============================================================================
6569 print_timestamp_init("OpenAll");
6571 SetGameStatus(GAME_MODE_LOADING);
6575 InitGlobal(); // initialize some global variables
6577 InitRND(NEW_RANDOMIZE);
6578 InitSimpleRandom(NEW_RANDOMIZE);
6579 InitBetterRandom(NEW_RANDOMIZE);
6581 InitMissingFileHash();
6583 print_timestamp_time("[init global stuff]");
6587 print_timestamp_time("[init setup/config stuff (1)]");
6589 if (options.execute_command)
6590 Execute_Command(options.execute_command);
6592 InitNetworkSettings();
6596 if (network.serveronly)
6598 #if defined(PLATFORM_UNIX)
6599 NetworkServer(network.server_port, TRUE);
6601 Warn("networking only supported in Unix version");
6604 exit(0); // never reached, server loops forever
6608 print_timestamp_time("[init setup/config stuff (2)]");
6610 print_timestamp_time("[init setup/config stuff (3)]");
6611 InitArtworkInfo(); // needed before loading gfx, sound & music
6612 print_timestamp_time("[init setup/config stuff (4)]");
6613 InitArtworkConfig(); // needed before forking sound child process
6614 print_timestamp_time("[init setup/config stuff (5)]");
6616 print_timestamp_time("[init setup/config stuff (6)]");
6620 print_timestamp_time("[init setup/config stuff]");
6622 InitVideoDefaults();
6624 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6627 InitEventFilter(FilterMouseMotionEvents);
6629 print_timestamp_time("[init video stuff]");
6631 InitElementPropertiesStatic();
6632 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6633 InitElementPropertiesGfxElement();
6635 print_timestamp_time("[init element properties stuff]");
6640 print_timestamp_time("InitGfx");
6643 print_timestamp_time("InitLevelInfo");
6645 InitLevelArtworkInfo();
6646 print_timestamp_time("InitLevelArtworkInfo");
6648 InitOverrideArtwork(); // needs to know current level directory
6649 print_timestamp_time("InitOverrideArtwork");
6651 InitArtworkIdentifier(); // needs to know current level directory
6652 print_timestamp_time("InitArtworkIdentifier");
6654 InitImages(); // needs to know current level directory
6655 print_timestamp_time("InitImages");
6657 InitSound(); // needs to know current level directory
6658 print_timestamp_time("InitSound");
6660 InitMusic(); // needs to know current level directory
6661 print_timestamp_time("InitMusic");
6665 InitGfxBackground();
6672 if (global.autoplay_leveldir)
6677 else if (global.patchtapes_leveldir)
6682 else if (global.convert_leveldir)
6687 else if (global.dumplevel_leveldir)
6692 else if (global.dumptape_leveldir)
6697 else if (global.create_sketch_images_dir)
6699 CreateLevelSketchImages();
6702 else if (global.create_collect_images_dir)
6704 CreateCollectElementImages();
6708 InitNetworkServer();
6710 SetGameStatus(GAME_MODE_MAIN);
6712 FadeSetEnterScreen();
6713 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6714 FadeSkipNextFadeOut();
6716 print_timestamp_time("[post-artwork]");
6718 print_timestamp_done("OpenAll");
6720 if (setup.ask_for_remaining_tapes)
6721 setup.ask_for_uploading_tapes = TRUE;
6726 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6728 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6729 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6730 #if defined(PLATFORM_ANDROID)
6731 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6732 SDL_AndroidGetInternalStoragePath());
6733 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6734 SDL_AndroidGetExternalStoragePath());
6735 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6736 (SDL_AndroidGetExternalStorageState() &
6737 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6738 SDL_AndroidGetExternalStorageState() &
6739 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6744 static boolean WaitForApiThreads(void)
6746 DelayCounter thread_delay = { 10000 };
6748 if (program.api_thread_count == 0)
6751 // deactivate global animations (not accessible in game state "loading")
6752 setup.global_animations = FALSE;
6754 // set game state to "loading" to be able to show busy animation
6755 SetGameStatus(GAME_MODE_LOADING);
6757 ResetDelayCounter(&thread_delay);
6759 // wait for threads to finish (and fail on timeout)
6760 while (program.api_thread_count > 0)
6762 if (DelayReached(&thread_delay))
6764 Error("failed waiting for threads - TIMEOUT");
6769 UPDATE_BUSY_STATE();
6777 void CloseAllAndExit(int exit_value)
6779 WaitForApiThreads();
6784 CloseAudio(); // called after freeing sounds (needed for SDL)
6793 // set a flag to tell the network server thread to quit and wait for it
6794 // using SDL_WaitThread()
6796 // Code used with SDL 1.2:
6797 // if (network.server_thread) // terminate network server
6798 // SDL_KillThread(network.server_thread);
6800 CloseVideoDisplay();
6801 ClosePlatformDependentStuff();
6803 if (exit_value != 0 && !options.execute_command)
6805 // fall back to default level set (current set may have caused an error)
6806 SaveLevelSetup_LastSeries_Deactivate();
6808 // tell user where to find error log file which may contain more details
6809 // (error notification now directly displayed on screen inside R'n'D
6810 // NotifyUserAboutErrorFile(); // currently only works for Windows