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 // create small and game tile sized bitmaps (and scale up, if needed)
248 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
251 static void InitElementSmallImages(void)
253 print_timestamp_init("InitElementSmallImages");
255 static int special_graphics[] =
269 IMG_EDITOR_ELEMENT_BORDER,
270 IMG_EDITOR_ELEMENT_BORDER_INPUT,
271 IMG_EDITOR_CASCADE_LIST,
272 IMG_EDITOR_CASCADE_LIST_ACTIVE,
275 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
276 int num_property_mappings = getImageListPropertyMappingSize();
279 print_timestamp_time("getImageListPropertyMapping/Size");
281 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
282 // initialize normal element images from static configuration
283 for (i = 0; element_to_graphic[i].element > -1; i++)
284 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
285 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
287 // initialize special element images from static configuration
288 for (i = 0; element_to_special_graphic[i].element > -1; i++)
289 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
290 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
292 // initialize element images from dynamic configuration
293 for (i = 0; i < num_property_mappings; i++)
294 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
295 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
296 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
298 // initialize special non-element images from above list
299 for (i = 0; special_graphics[i] > -1; i++)
300 InitElementSmallImagesScaledUp(special_graphics[i]);
301 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
303 print_timestamp_done("InitElementSmallImages");
306 static void InitScaledImagesScaledUp(int graphic)
308 struct GraphicInfo *g = &graphic_info[graphic];
310 ScaleImage(graphic, g->scale_up_factor);
313 static void InitScaledImages(void)
315 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
316 int num_property_mappings = getImageListPropertyMappingSize();
319 // scale normal images from static configuration, if not already scaled
320 for (i = 0; i < NUM_IMAGE_FILES; i++)
321 InitScaledImagesScaledUp(i);
323 // scale images from dynamic configuration, if not already scaled
324 for (i = 0; i < num_property_mappings; i++)
325 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
328 static void InitBitmapPointers(void)
330 int num_images = getImageListSize();
333 // standard size bitmap may have changed -- update default bitmap pointer
334 for (i = 0; i < num_images; i++)
335 if (graphic_info[i].bitmaps)
336 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
339 void InitImageTextures(void)
341 static int texture_graphics[] =
343 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
344 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
345 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
346 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
347 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
348 IMG_MENU_BUTTON_TOUCH_BACK,
349 IMG_MENU_BUTTON_TOUCH_NEXT,
350 IMG_MENU_BUTTON_TOUCH_BACK2,
351 IMG_MENU_BUTTON_TOUCH_NEXT2,
356 FreeAllImageTextures();
358 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
359 CreateImageTextures(i);
361 for (i = 0; i < MAX_NUM_TOONS; i++)
362 CreateImageTextures(IMG_TOON_1 + i);
364 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
366 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
368 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
370 int graphic = global_anim_info[i].graphic[j][k];
372 if (graphic == IMG_UNDEFINED)
375 CreateImageTextures(graphic);
380 for (i = 0; texture_graphics[i] > -1; i++)
381 CreateImageTextures(texture_graphics[i]);
384 static int getFontSpecialSuffix(void)
388 // (special case: do not use special font for GAME_MODE_LOADING)
389 if (game_status >= GAME_MODE_TITLE_INITIAL &&
390 game_status <= GAME_MODE_PSEUDO_PREVIEW)
391 special = game_status;
392 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
393 special = GFX_SPECIAL_ARG_MAIN;
394 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
395 special = GFX_SPECIAL_ARG_NAMES;
400 static int getFontBitmapID(int font_nr)
402 int special = getFontSpecialSuffix();
405 return font_info[font_nr].special_bitmap_id[special];
410 static int getFontFromToken(char *token)
412 char *value = getHashEntry(font_token_hash, token);
417 // if font not found, use reliable default value
418 return FONT_INITIAL_1;
421 static char *getTokenFromFont(int font_nr)
423 static char *token = NULL;
424 int special = getFontSpecialSuffix();
429 token = getStringCat2(font_info[font_nr].token_name,
430 special_suffix_info[special].suffix);
432 token = getStringCopy(font_info[font_nr].token_name);
437 static void InitFontGraphicInfo(void)
439 static struct FontBitmapInfo *font_bitmap_info = NULL;
440 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
441 int num_property_mappings = getImageListPropertyMappingSize();
442 int num_font_bitmaps = NUM_FONTS;
445 if (graphic_info == NULL) // still at startup phase
447 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
448 getFontBitmapID, getFontFromToken, getTokenFromFont);
453 // ---------- initialize font graphic definitions ----------
455 // always start with reliable default values (normal font graphics)
456 for (i = 0; i < NUM_FONTS; i++)
457 font_info[i].graphic = IMG_FONT_INITIAL_1;
459 // initialize normal font/graphic mapping from static configuration
460 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
462 int font_nr = font_to_graphic[i].font_nr;
463 int special = font_to_graphic[i].special;
464 int graphic = font_to_graphic[i].graphic;
469 font_info[font_nr].graphic = graphic;
472 // always start with reliable default values (special font graphics)
473 for (i = 0; i < NUM_FONTS; i++)
475 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
477 font_info[i].special_graphic[j] = font_info[i].graphic;
478 font_info[i].special_bitmap_id[j] = i;
482 // initialize special font/graphic mapping from static configuration
483 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
485 int font_nr = font_to_graphic[i].font_nr;
486 int special = font_to_graphic[i].special;
487 int graphic = font_to_graphic[i].graphic;
488 int base_graphic = font2baseimg(font_nr);
490 if (IS_SPECIAL_GFX_ARG(special))
492 boolean base_redefined =
493 getImageListEntryFromImageID(base_graphic)->redefined;
494 boolean special_redefined =
495 getImageListEntryFromImageID(graphic)->redefined;
496 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
498 /* if the base font ("font.title_1", for example) has been redefined,
499 but not the special font ("font.title_1.LEVELS", for example), do not
500 use an existing (in this case considered obsolete) special font
501 anymore, but use the automatically determined default font */
502 /* special case: cloned special fonts must be explicitly redefined,
503 but are not automatically redefined by redefining base font */
504 if (base_redefined && !special_redefined && !special_cloned)
507 font_info[font_nr].special_graphic[special] = graphic;
508 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
513 // initialize special font/graphic mapping from dynamic configuration
514 for (i = 0; i < num_property_mappings; i++)
516 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
517 int special = property_mapping[i].ext3_index;
518 int graphic = property_mapping[i].artwork_index;
520 if (font_nr < 0 || font_nr >= NUM_FONTS)
523 if (IS_SPECIAL_GFX_ARG(special))
525 font_info[font_nr].special_graphic[special] = graphic;
526 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
531 /* correct special font/graphic mapping for cloned fonts for downwards
532 compatibility of PREVIEW fonts -- this is only needed for implicit
533 redefinition of special font by redefined base font, and only if other
534 fonts are cloned from this special font (like in the "Zelda" level set) */
535 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
537 int font_nr = font_to_graphic[i].font_nr;
538 int special = font_to_graphic[i].special;
539 int graphic = font_to_graphic[i].graphic;
541 if (IS_SPECIAL_GFX_ARG(special))
543 boolean special_redefined =
544 getImageListEntryFromImageID(graphic)->redefined;
545 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
547 if (special_cloned && !special_redefined)
551 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
553 int font_nr2 = font_to_graphic[j].font_nr;
554 int special2 = font_to_graphic[j].special;
555 int graphic2 = font_to_graphic[j].graphic;
557 if (IS_SPECIAL_GFX_ARG(special2) &&
558 graphic2 == graphic_info[graphic].clone_from)
560 font_info[font_nr].special_graphic[special] =
561 font_info[font_nr2].special_graphic[special2];
562 font_info[font_nr].special_bitmap_id[special] =
563 font_info[font_nr2].special_bitmap_id[special2];
570 // reset non-redefined ".active" font graphics if normal font is redefined
571 // (this different treatment is needed because normal and active fonts are
572 // independently defined ("active" is not a property of font definitions!)
573 for (i = 0; i < NUM_FONTS; i++)
575 int font_nr_base = i;
576 int font_nr_active = FONT_ACTIVE(font_nr_base);
578 // check only those fonts with exist as normal and ".active" variant
579 if (font_nr_base != font_nr_active)
581 int base_graphic = font_info[font_nr_base].graphic;
582 int active_graphic = font_info[font_nr_active].graphic;
583 boolean base_redefined =
584 getImageListEntryFromImageID(base_graphic)->redefined;
585 boolean active_redefined =
586 getImageListEntryFromImageID(active_graphic)->redefined;
588 /* if the base font ("font.menu_1", for example) has been redefined,
589 but not the active font ("font.menu_1.active", for example), do not
590 use an existing (in this case considered obsolete) active font
591 anymore, but use the automatically determined default font */
592 if (base_redefined && !active_redefined)
593 font_info[font_nr_active].graphic = base_graphic;
595 // now also check each "special" font (which may be the same as above)
596 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
598 int base_graphic = font_info[font_nr_base].special_graphic[j];
599 int active_graphic = font_info[font_nr_active].special_graphic[j];
600 boolean base_redefined =
601 getImageListEntryFromImageID(base_graphic)->redefined;
602 boolean active_redefined =
603 getImageListEntryFromImageID(active_graphic)->redefined;
605 // same as above, but check special graphic definitions, for example:
606 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
607 if (base_redefined && !active_redefined)
609 font_info[font_nr_active].special_graphic[j] =
610 font_info[font_nr_base].special_graphic[j];
611 font_info[font_nr_active].special_bitmap_id[j] =
612 font_info[font_nr_base].special_bitmap_id[j];
618 // ---------- initialize font bitmap array ----------
620 if (font_bitmap_info != NULL)
621 FreeFontInfo(font_bitmap_info);
624 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
626 // ---------- initialize font bitmap definitions ----------
628 for (i = 0; i < NUM_FONTS; i++)
630 if (i < NUM_INITIAL_FONTS)
632 font_bitmap_info[i] = font_initial[i];
636 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
638 int font_bitmap_id = font_info[i].special_bitmap_id[j];
639 int graphic = font_info[i].special_graphic[j];
641 // set 'graphic_info' for font entries, if uninitialized (guessed)
642 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
644 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
645 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
648 // copy font relevant information from graphics information
649 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
650 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
651 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
652 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
653 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
655 font_bitmap_info[font_bitmap_id].offset_x =
656 graphic_info[graphic].offset_x;
657 font_bitmap_info[font_bitmap_id].offset_y =
658 graphic_info[graphic].offset_y;
660 font_bitmap_info[font_bitmap_id].draw_xoffset =
661 graphic_info[graphic].draw_xoffset;
662 font_bitmap_info[font_bitmap_id].draw_yoffset =
663 graphic_info[graphic].draw_yoffset;
665 font_bitmap_info[font_bitmap_id].num_chars =
666 graphic_info[graphic].anim_frames;
667 font_bitmap_info[font_bitmap_id].num_chars_per_line =
668 graphic_info[graphic].anim_frames_per_line;
672 InitFontInfo(font_bitmap_info, num_font_bitmaps,
673 getFontBitmapID, getFontFromToken, getTokenFromFont);
676 static void InitGlobalAnimGraphicInfo(void)
678 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
679 int num_property_mappings = getImageListPropertyMappingSize();
682 if (graphic_info == NULL) // still at startup phase
685 // always start with reliable default values (no global animations)
686 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
687 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
688 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
689 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
691 // initialize global animation definitions from static configuration
692 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
694 int j = GLOBAL_ANIM_ID_PART_BASE;
695 int k = GFX_SPECIAL_ARG_DEFAULT;
697 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
700 // initialize global animation definitions from dynamic configuration
701 for (i = 0; i < num_property_mappings; i++)
703 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
704 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
705 int special = property_mapping[i].ext3_index;
706 int graphic = property_mapping[i].artwork_index;
708 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
711 // set animation part to base part, if not specified
712 if (!IS_GLOBAL_ANIM_PART(part_nr))
713 part_nr = GLOBAL_ANIM_ID_PART_BASE;
715 // set animation screen to default, if not specified
716 if (!IS_SPECIAL_GFX_ARG(special))
717 special = GFX_SPECIAL_ARG_DEFAULT;
719 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
721 // fix default value for ".draw_masked" (for backward compatibility)
722 struct GraphicInfo *g = &graphic_info[graphic];
723 struct FileInfo *image = getImageListEntryFromImageID(graphic);
724 char **parameter_raw = image->parameter;
725 int p = GFX_ARG_DRAW_MASKED;
726 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
727 image_config_suffix[p].token,
728 image_config_suffix[p].type);
730 // if ".draw_masked" parameter is undefined, use default value "TRUE"
731 if (draw_masked == ARG_UNDEFINED_VALUE)
732 g->draw_masked = TRUE;
736 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
737 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
738 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
739 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
740 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
741 Debug("init:InitGlobalAnimGraphicInfo",
742 "anim %d, part %d, mode %d => %d",
743 i, j, k, global_anim_info[i].graphic[j][k]);
747 static void InitGlobalAnimSoundInfo(void)
749 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
750 int num_property_mappings = getSoundListPropertyMappingSize();
753 // always start with reliable default values (no global animation sounds)
754 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
755 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
756 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
757 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
759 // initialize global animation sound definitions from dynamic configuration
760 for (i = 0; i < num_property_mappings; i++)
762 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
763 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
764 int special = property_mapping[i].ext3_index;
765 int sound = property_mapping[i].artwork_index;
767 // sound uses control definition; map it to position of graphic (artwork)
768 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
770 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
773 // set animation part to base part, if not specified
774 if (!IS_GLOBAL_ANIM_PART(part_nr))
775 part_nr = GLOBAL_ANIM_ID_PART_BASE;
777 // set animation screen to default, if not specified
778 if (!IS_SPECIAL_GFX_ARG(special))
779 special = GFX_SPECIAL_ARG_DEFAULT;
781 global_anim_info[anim_nr].sound[part_nr][special] = sound;
785 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
786 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
787 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
788 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
789 Debug("init:InitGlobalAnimSoundInfo",
790 "anim %d, part %d, mode %d => %d",
791 i, j, k, global_anim_info[i].sound[j][k]);
795 static void InitGlobalAnimMusicInfo(void)
797 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
798 int num_property_mappings = getMusicListPropertyMappingSize();
801 // always start with reliable default values (no global animation music)
802 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
803 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
804 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
805 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
807 // initialize global animation music definitions from dynamic configuration
808 for (i = 0; i < num_property_mappings; i++)
810 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
811 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
812 int special = property_mapping[i].ext2_index;
813 int music = property_mapping[i].artwork_index;
815 // music uses control definition; map it to position of graphic (artwork)
816 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
818 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
821 // set animation part to base part, if not specified
822 if (!IS_GLOBAL_ANIM_PART(part_nr))
823 part_nr = GLOBAL_ANIM_ID_PART_BASE;
825 // set animation screen to default, if not specified
826 if (!IS_SPECIAL_GFX_ARG(special))
827 special = GFX_SPECIAL_ARG_DEFAULT;
829 global_anim_info[anim_nr].music[part_nr][special] = music;
833 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
834 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
835 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
836 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
837 Debug("init:InitGlobalAnimMusicInfo",
838 "anim %d, part %d, mode %d => %d",
839 i, j, k, global_anim_info[i].music[j][k]);
843 static void InitElementGraphicInfo(void)
845 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
846 int num_property_mappings = getImageListPropertyMappingSize();
849 if (graphic_info == NULL) // still at startup phase
852 // set values to -1 to identify later as "uninitialized" values
853 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
855 for (act = 0; act < NUM_ACTIONS; act++)
857 element_info[i].graphic[act] = -1;
858 element_info[i].crumbled[act] = -1;
860 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
862 element_info[i].direction_graphic[act][dir] = -1;
863 element_info[i].direction_crumbled[act][dir] = -1;
870 // initialize normal element/graphic mapping from static configuration
871 for (i = 0; element_to_graphic[i].element > -1; i++)
873 int element = element_to_graphic[i].element;
874 int action = element_to_graphic[i].action;
875 int direction = element_to_graphic[i].direction;
876 boolean crumbled = element_to_graphic[i].crumbled;
877 int graphic = element_to_graphic[i].graphic;
878 int base_graphic = el2baseimg(element);
880 if (graphic_info[graphic].bitmap == NULL)
883 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
886 boolean base_redefined =
887 getImageListEntryFromImageID(base_graphic)->redefined;
888 boolean act_dir_redefined =
889 getImageListEntryFromImageID(graphic)->redefined;
891 /* if the base graphic ("emerald", for example) has been redefined,
892 but not the action graphic ("emerald.falling", for example), do not
893 use an existing (in this case considered obsolete) action graphic
894 anymore, but use the automatically determined default graphic */
895 if (base_redefined && !act_dir_redefined)
900 action = ACTION_DEFAULT;
905 element_info[element].direction_crumbled[action][direction] = graphic;
907 element_info[element].crumbled[action] = graphic;
912 element_info[element].direction_graphic[action][direction] = graphic;
914 element_info[element].graphic[action] = graphic;
918 // initialize normal element/graphic mapping from dynamic configuration
919 for (i = 0; i < num_property_mappings; i++)
921 int element = property_mapping[i].base_index;
922 int action = property_mapping[i].ext1_index;
923 int direction = property_mapping[i].ext2_index;
924 int special = property_mapping[i].ext3_index;
925 int graphic = property_mapping[i].artwork_index;
926 boolean crumbled = FALSE;
928 if (special == GFX_SPECIAL_ARG_CRUMBLED)
934 if (graphic_info[graphic].bitmap == NULL)
937 if (element >= MAX_NUM_ELEMENTS || special != -1)
941 action = ACTION_DEFAULT;
946 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
947 element_info[element].direction_crumbled[action][dir] = -1;
950 element_info[element].direction_crumbled[action][direction] = graphic;
952 element_info[element].crumbled[action] = graphic;
957 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
958 element_info[element].direction_graphic[action][dir] = -1;
961 element_info[element].direction_graphic[action][direction] = graphic;
963 element_info[element].graphic[action] = graphic;
967 // now copy all graphics that are defined to be cloned from other graphics
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 int graphic = element_info[i].graphic[ACTION_DEFAULT];
971 int crumbled_like, diggable_like;
976 crumbled_like = graphic_info[graphic].crumbled_like;
977 diggable_like = graphic_info[graphic].diggable_like;
979 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
981 for (act = 0; act < NUM_ACTIONS; act++)
982 element_info[i].crumbled[act] =
983 element_info[crumbled_like].crumbled[act];
984 for (act = 0; act < NUM_ACTIONS; act++)
985 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
986 element_info[i].direction_crumbled[act][dir] =
987 element_info[crumbled_like].direction_crumbled[act][dir];
990 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
992 element_info[i].graphic[ACTION_DIGGING] =
993 element_info[diggable_like].graphic[ACTION_DIGGING];
994 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
995 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
996 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
1000 // set hardcoded definitions for some runtime elements without graphic
1001 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
1003 // set hardcoded definitions for some internal elements without graphic
1004 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1006 if (IS_EDITOR_CASCADE_INACTIVE(i))
1007 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
1008 else if (IS_EDITOR_CASCADE_ACTIVE(i))
1009 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
1012 // now set all undefined/invalid graphics to -1 to set to default after it
1013 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1015 for (act = 0; act < NUM_ACTIONS; act++)
1019 graphic = element_info[i].graphic[act];
1020 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1021 element_info[i].graphic[act] = -1;
1023 graphic = element_info[i].crumbled[act];
1024 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1025 element_info[i].crumbled[act] = -1;
1027 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1029 graphic = element_info[i].direction_graphic[act][dir];
1030 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1031 element_info[i].direction_graphic[act][dir] = -1;
1033 graphic = element_info[i].direction_crumbled[act][dir];
1034 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1035 element_info[i].direction_crumbled[act][dir] = -1;
1040 UPDATE_BUSY_STATE();
1042 // adjust graphics with 2nd tile for movement according to direction
1043 // (do this before correcting '-1' values to minimize calculations)
1044 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1046 for (act = 0; act < NUM_ACTIONS; act++)
1048 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1050 int graphic = element_info[i].direction_graphic[act][dir];
1051 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1053 if (act == ACTION_FALLING) // special case
1054 graphic = element_info[i].graphic[act];
1056 if (graphic != -1 &&
1057 graphic_info[graphic].double_movement &&
1058 graphic_info[graphic].swap_double_tiles != 0)
1060 struct GraphicInfo *g = &graphic_info[graphic];
1061 int src_x_front = g->src_x;
1062 int src_y_front = g->src_y;
1063 int src_x_back = g->src_x + g->offset2_x;
1064 int src_y_back = g->src_y + g->offset2_y;
1065 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1067 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1068 src_y_front < src_y_back);
1069 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1070 boolean swap_movement_tiles_autodetected =
1071 (!frames_are_ordered_diagonally &&
1072 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1073 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1074 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1075 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1077 // swap frontside and backside graphic tile coordinates, if needed
1078 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1080 // get current (wrong) backside tile coordinates
1081 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1083 // set frontside tile coordinates to backside tile coordinates
1084 g->src_x = src_x_back;
1085 g->src_y = src_y_back;
1087 // invert tile offset to point to new backside tile coordinates
1091 // do not swap front and backside tiles again after correction
1092 g->swap_double_tiles = 0;
1099 UPDATE_BUSY_STATE();
1101 // now set all '-1' values to element specific default values
1102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1104 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1105 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1106 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1107 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1109 if (default_graphic == -1)
1110 default_graphic = IMG_UNKNOWN;
1112 if (default_crumbled == -1)
1113 default_crumbled = default_graphic;
1115 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1117 default_direction_graphic[dir] =
1118 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1119 default_direction_crumbled[dir] =
1120 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1122 if (default_direction_graphic[dir] == -1)
1123 default_direction_graphic[dir] = default_graphic;
1125 if (default_direction_crumbled[dir] == -1)
1126 default_direction_crumbled[dir] = default_direction_graphic[dir];
1129 for (act = 0; act < NUM_ACTIONS; act++)
1131 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1132 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1133 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1134 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1135 act == ACTION_TURNING_FROM_RIGHT ||
1136 act == ACTION_TURNING_FROM_UP ||
1137 act == ACTION_TURNING_FROM_DOWN);
1139 // generic default action graphic (defined by "[default]" directive)
1140 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1141 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1142 int default_remove_graphic = IMG_EMPTY;
1144 if (act_remove && default_action_graphic != -1)
1145 default_remove_graphic = default_action_graphic;
1147 // look for special default action graphic (classic game specific)
1148 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1149 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1150 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1151 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1152 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1153 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1154 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1155 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1157 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1158 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1159 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1160 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1161 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1162 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1163 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1164 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1166 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1167 // !!! make this better !!!
1168 if (i == EL_EMPTY_SPACE)
1170 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1171 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1174 if (default_action_graphic == -1)
1175 default_action_graphic = default_graphic;
1177 if (default_action_crumbled == -1)
1178 default_action_crumbled = default_action_graphic;
1180 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1182 // use action graphic as the default direction graphic, if undefined
1183 int default_action_direction_graphic = element_info[i].graphic[act];
1184 int default_action_direction_crumbled = element_info[i].crumbled[act];
1186 // no graphic for current action -- use default direction graphic
1187 if (default_action_direction_graphic == -1)
1188 default_action_direction_graphic =
1189 (act_remove ? default_remove_graphic :
1191 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1192 default_action_graphic != default_graphic ?
1193 default_action_graphic :
1194 default_direction_graphic[dir]);
1196 if (element_info[i].direction_graphic[act][dir] == -1)
1197 element_info[i].direction_graphic[act][dir] =
1198 default_action_direction_graphic;
1200 if (default_action_direction_crumbled == -1)
1201 default_action_direction_crumbled =
1202 element_info[i].direction_graphic[act][dir];
1204 if (element_info[i].direction_crumbled[act][dir] == -1)
1205 element_info[i].direction_crumbled[act][dir] =
1206 default_action_direction_crumbled;
1209 // no graphic for this specific action -- use default action graphic
1210 if (element_info[i].graphic[act] == -1)
1211 element_info[i].graphic[act] =
1212 (act_remove ? default_remove_graphic :
1213 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1214 default_action_graphic);
1216 if (element_info[i].crumbled[act] == -1)
1217 element_info[i].crumbled[act] = element_info[i].graphic[act];
1221 UPDATE_BUSY_STATE();
1224 static void InitElementSpecialGraphicInfo(void)
1226 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1227 int num_property_mappings = getImageListPropertyMappingSize();
1230 // always start with reliable default values
1231 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1232 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1233 element_info[i].special_graphic[j] =
1234 element_info[i].graphic[ACTION_DEFAULT];
1236 // initialize special element/graphic mapping from static configuration
1237 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1239 int element = element_to_special_graphic[i].element;
1240 int special = element_to_special_graphic[i].special;
1241 int graphic = element_to_special_graphic[i].graphic;
1242 int base_graphic = el2baseimg(element);
1243 boolean base_redefined =
1244 getImageListEntryFromImageID(base_graphic)->redefined;
1245 boolean special_redefined =
1246 getImageListEntryFromImageID(graphic)->redefined;
1248 /* if the base graphic ("emerald", for example) has been redefined,
1249 but not the special graphic ("emerald.EDITOR", for example), do not
1250 use an existing (in this case considered obsolete) special graphic
1251 anymore, but use the automatically created (down-scaled) graphic */
1252 if (base_redefined && !special_redefined)
1255 element_info[element].special_graphic[special] = graphic;
1258 // initialize special element/graphic mapping from dynamic configuration
1259 for (i = 0; i < num_property_mappings; i++)
1261 int element = property_mapping[i].base_index;
1262 int action = property_mapping[i].ext1_index;
1263 int direction = property_mapping[i].ext2_index;
1264 int special = property_mapping[i].ext3_index;
1265 int graphic = property_mapping[i].artwork_index;
1267 // for action ".active", replace element with active element, if exists
1268 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1270 element = ELEMENT_ACTIVE(element);
1274 // for BD effect editor graphics, replace element with effect element, if exists
1275 if (action != -1 && special == GFX_SPECIAL_ARG_EDITOR)
1277 int element_bd = map_element_RND_to_BD_effect(element, action);
1278 int element_ef = map_element_BD_to_RND_cave(element_bd);
1280 if (element_ef != EL_UNKNOWN)
1282 element = element_ef;
1287 if (element >= MAX_NUM_ELEMENTS)
1290 // do not change special graphic if action or direction was specified
1291 if (action != -1 || direction != -1)
1294 if (IS_SPECIAL_GFX_ARG(special))
1295 element_info[element].special_graphic[special] = graphic;
1298 // now set all undefined/invalid graphics to default
1299 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1300 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1301 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1302 element_info[i].special_graphic[j] =
1303 element_info[i].graphic[ACTION_DEFAULT];
1306 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1308 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1309 return get_parameter_value(value_raw, suffix, type);
1311 if (strEqual(value_raw, ARG_UNDEFINED))
1312 return ARG_UNDEFINED_VALUE;
1314 if (type == TYPE_ELEMENT)
1316 char *value = getHashEntry(element_token_hash, value_raw);
1321 Warn("error found in config file:");
1322 Warn("- config file: '%s'", getImageConfigFilename());
1323 Warn("error: invalid element token '%s'", value_raw);
1324 Warn("custom graphic rejected for this element/action");
1325 Warn("fallback done to undefined element for this graphic");
1329 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1331 else if (type == TYPE_GRAPHIC)
1333 char *value = getHashEntry(graphic_token_hash, value_raw);
1334 int fallback_graphic = IMG_CHAR_EXCLAM;
1339 Warn("error found in config file:");
1340 Warn("- config file: '%s'", getImageConfigFilename());
1341 Warn("error: invalid graphic token '%s'", value_raw);
1342 Warn("custom graphic rejected for this element/action");
1343 Warn("fallback done to 'char_exclam' for this graphic");
1347 return (value != NULL ? atoi(value) : fallback_graphic);
1353 static int get_scaled_graphic_width(Bitmap *src_bitmap, int graphic)
1355 int original_width = getOriginalImageWidthFromImageID(graphic);
1356 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1358 // only happens when loaded outside artwork system (like "global.busy")
1359 if (graphic_info == image_initial && src_bitmap)
1360 original_width = src_bitmap->width;
1362 return original_width * scale_up_factor;
1365 static int get_scaled_graphic_height(Bitmap *src_bitmap, int graphic)
1367 int original_height = getOriginalImageHeightFromImageID(graphic);
1368 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1370 // only happens when loaded outside artwork system (like "global.busy")
1371 if (graphic_info == image_initial && src_bitmap)
1372 original_height = src_bitmap->height;
1374 return original_height * scale_up_factor;
1377 static void set_graphic_parameters_ext(int graphic, int *parameter,
1378 Bitmap **src_bitmaps)
1380 struct GraphicInfo *g = &graphic_info[graphic];
1381 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1382 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1383 int anim_frames_per_line = 1;
1385 // always start with reliable default values
1386 g->src_image_width = 0;
1387 g->src_image_height = 0;
1390 g->width = TILEX; // default for element graphics
1391 g->height = TILEY; // default for element graphics
1392 g->offset_x = 0; // one or both of these values ...
1393 g->offset_y = 0; // ... will be corrected later
1394 g->offset2_x = 0; // one or both of these values ...
1395 g->offset2_y = 0; // ... will be corrected later
1396 g->swap_double_tiles = -1; // auto-detect tile swapping
1397 g->crumbled_like = -1; // do not use clone element
1398 g->diggable_like = -1; // do not use clone element
1399 g->border_size = TILEX / 8; // "CRUMBLED" border size
1400 g->scale_up_factor = 1; // default: no scaling up
1401 g->tile_size = TILESIZE; // default: standard tile size
1402 g->clone_from = -1; // do not use clone graphic
1403 g->init_delay_fixed = 0;
1404 g->init_delay_random = 0;
1405 g->init_delay_action = -1;
1406 g->anim_delay_fixed = 0;
1407 g->anim_delay_random = 0;
1408 g->anim_delay_action = -1;
1409 g->post_delay_fixed = 0;
1410 g->post_delay_random = 0;
1411 g->post_delay_action = -1;
1412 g->init_event = ANIM_EVENT_UNDEFINED;
1413 g->anim_event = ANIM_EVENT_UNDEFINED;
1414 g->init_event_action = -1;
1415 g->anim_event_action = -1;
1416 g->draw_masked = FALSE;
1418 g->fade_mode = FADE_MODE_DEFAULT;
1422 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1423 g->align = ALIGN_CENTER; // default for title screens
1424 g->valign = VALIGN_MIDDLE; // default for title screens
1425 g->sort_priority = 0; // default for title screens
1427 g->style = STYLE_DEFAULT;
1430 g->bitmaps = src_bitmaps;
1431 g->bitmap = src_bitmap;
1433 // optional zoom factor for scaling up the image to a larger size
1434 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1435 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1436 if (g->scale_up_factor < 1)
1437 g->scale_up_factor = 1; // no scaling
1439 // optional tile size for using non-standard image size
1440 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1442 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1445 // CHECK: should tile sizes less than standard tile size be allowed?
1446 if (g->tile_size < TILESIZE)
1447 g->tile_size = TILESIZE; // standard tile size
1450 // when setting tile size, also set width and height accordingly
1451 g->width = g->tile_size;
1452 g->height = g->tile_size;
1455 if (g->use_image_size)
1457 // set new default bitmap size (with scaling, but without small images)
1458 g->width = get_scaled_graphic_width(src_bitmap, graphic);
1459 g->height = get_scaled_graphic_height(src_bitmap, graphic);
1462 // optional width and height of each animation frame
1463 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1464 g->width = parameter[GFX_ARG_WIDTH];
1465 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1466 g->height = parameter[GFX_ARG_HEIGHT];
1468 // optional x and y tile position of animation frame sequence
1469 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1470 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1471 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1472 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1474 // optional x and y pixel position of animation frame sequence
1475 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1476 g->src_x = parameter[GFX_ARG_X];
1477 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1478 g->src_y = parameter[GFX_ARG_Y];
1485 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1486 g->width, getTokenFromImageID(graphic), TILEX);
1489 g->width = TILEX; // will be checked to be inside bitmap later
1495 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1496 g->height, getTokenFromImageID(graphic), TILEY);
1499 g->height = TILEY; // will be checked to be inside bitmap later
1505 // get final bitmap size (with scaling, but without small images)
1506 int src_image_width = get_scaled_graphic_width(src_bitmap, graphic);
1507 int src_image_height = get_scaled_graphic_height(src_bitmap, graphic);
1509 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1511 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1512 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1516 anim_frames_per_row = MAX(1, src_image_width / g->width);
1517 anim_frames_per_col = MAX(1, src_image_height / g->height);
1520 g->src_image_width = src_image_width;
1521 g->src_image_height = src_image_height;
1524 // correct x or y offset dependent of vertical or horizontal frame order
1525 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1527 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1528 parameter[GFX_ARG_OFFSET] : g->height);
1529 anim_frames_per_line = anim_frames_per_col;
1531 else // frames are ordered horizontally
1533 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1534 parameter[GFX_ARG_OFFSET] : g->width);
1535 anim_frames_per_line = anim_frames_per_row;
1538 // optionally, the x and y offset of frames can be specified directly
1539 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1540 g->offset_x = parameter[GFX_ARG_XOFFSET];
1541 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1542 g->offset_y = parameter[GFX_ARG_YOFFSET];
1544 // optionally, moving animations may have separate start and end graphics
1545 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1547 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1548 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1550 // correct x or y offset2 dependent of vertical or horizontal frame order
1551 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1552 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1553 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1554 else // frames are ordered horizontally
1555 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1556 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1558 // optionally, the x and y offset of 2nd graphic can be specified directly
1559 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1560 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1561 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1562 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1564 // optionally, the second movement tile can be specified as start tile
1565 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1566 g->swap_double_tiles = parameter[GFX_ARG_2ND_SWAP_TILES];
1568 // automatically determine correct number of frames, if not defined
1569 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1570 g->anim_frames = parameter[GFX_ARG_FRAMES];
1571 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1572 g->anim_frames = anim_frames_per_row;
1573 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1574 g->anim_frames = anim_frames_per_col;
1578 if (g->anim_frames < 1) // frames must be at least 1
1581 g->anim_frames_per_line =
1582 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1583 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1585 g->anim_delay = parameter[GFX_ARG_DELAY];
1586 if (g->anim_delay < 1) // delay must be at least 1
1589 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1591 // automatically determine correct start frame, if not defined
1592 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1593 g->anim_start_frame = 0;
1594 else if (g->anim_mode & ANIM_REVERSE)
1595 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1597 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1599 // animation synchronized with global frame counter, not move position
1600 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1602 // animation synchronized with global anim frame counter, not move position
1603 g->anim_global_anim_sync = parameter[GFX_ARG_GLOBAL_ANIM_SYNC];
1605 // optional element for cloning crumble graphics
1606 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1607 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1609 // optional element for cloning digging graphics
1610 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1611 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1613 // optional border size for "crumbling" diggable graphics
1614 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1615 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1617 // used for global animations and player "boring" and "sleeping" actions
1618 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1619 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1620 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1621 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1622 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1623 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1624 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1625 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1626 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1627 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1628 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1629 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1631 // used for global animations
1632 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1633 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1634 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1635 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1636 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1637 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1638 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1639 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1640 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1641 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1642 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1643 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1644 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1645 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1647 // used for toon animations and global animations
1648 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1649 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1650 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1651 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1652 g->direction = parameter[GFX_ARG_DIRECTION];
1653 g->position = parameter[GFX_ARG_POSITION];
1654 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1655 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1657 if (g->step_delay < 1) // delay must be at least 1
1660 // this is only used for drawing font characters
1661 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1662 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1664 // use a different default value for global animations and toons
1665 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_32) ||
1666 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1667 g->draw_masked = TRUE;
1669 // this is used for drawing envelopes, global animations and toons
1670 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1671 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1673 // used for toon animations and global animations
1674 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1675 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1677 // optional graphic for cloning all graphics settings
1678 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1679 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1681 // optional settings for drawing title screens and title messages
1682 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1683 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1684 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1685 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1686 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1687 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1688 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1689 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1690 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1691 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1692 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1693 g->align = parameter[GFX_ARG_ALIGN];
1694 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1695 g->valign = parameter[GFX_ARG_VALIGN];
1696 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1697 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1699 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1700 g->class = parameter[GFX_ARG_CLASS];
1701 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1702 g->style = parameter[GFX_ARG_STYLE];
1703 if (parameter[GFX_ARG_ALPHA] != ARG_UNDEFINED_VALUE)
1704 g->alpha = parameter[GFX_ARG_ALPHA];
1706 // this is only used for drawing menu buttons and text
1707 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1708 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1709 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1710 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1712 // this is only used for drawing stacked global animations
1713 g->stacked_xfactor = parameter[GFX_ARG_STACKED_XFACTOR];
1714 g->stacked_yfactor = parameter[GFX_ARG_STACKED_YFACTOR];
1715 g->stacked_xoffset = parameter[GFX_ARG_STACKED_XOFFSET];
1716 g->stacked_yoffset = parameter[GFX_ARG_STACKED_YOFFSET];
1719 static void set_graphic_parameters(int graphic)
1721 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1722 char **parameter_raw = image->parameter;
1723 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1724 int parameter[NUM_GFX_ARGS];
1727 // if fallback to default artwork is done, also use the default parameters
1728 if (image->fallback_to_default)
1729 parameter_raw = image->default_parameter;
1731 // get integer values from string parameters
1732 for (i = 0; i < NUM_GFX_ARGS; i++)
1733 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1734 image_config_suffix[i].token,
1735 image_config_suffix[i].type);
1737 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1739 UPDATE_BUSY_STATE();
1742 static void set_cloned_graphic_parameters(int graphic)
1744 int fallback_graphic = IMG_CHAR_EXCLAM;
1745 int max_num_images = getImageListSize();
1746 int clone_graphic = graphic_info[graphic].clone_from;
1747 int num_references_followed = 1;
1749 while (graphic_info[clone_graphic].clone_from != -1 &&
1750 num_references_followed < max_num_images)
1752 clone_graphic = graphic_info[clone_graphic].clone_from;
1754 num_references_followed++;
1757 if (num_references_followed >= max_num_images)
1760 Warn("error found in config file:");
1761 Warn("- config file: '%s'", getImageConfigFilename());
1762 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1763 Warn("error: loop discovered when resolving cloned graphics");
1764 Warn("custom graphic rejected for this element/action");
1766 if (graphic == fallback_graphic)
1767 Fail("no fallback graphic available");
1769 Warn("fallback done to 'char_exclam' for this graphic");
1772 graphic_info[graphic] = graphic_info[fallback_graphic];
1776 graphic_info[graphic] = graphic_info[clone_graphic];
1777 graphic_info[graphic].clone_from = clone_graphic;
1781 static void InitGraphicInfo(void)
1783 int fallback_graphic = IMG_CHAR_EXCLAM;
1784 int num_images = getImageListSize();
1787 // use image size as default values for width and height for these images
1788 static int full_size_graphics[] =
1791 IMG_GLOBAL_BORDER_MAIN,
1792 IMG_GLOBAL_BORDER_SCORES,
1793 IMG_GLOBAL_BORDER_EDITOR,
1794 IMG_GLOBAL_BORDER_PLAYING,
1797 IMG_BACKGROUND_ENVELOPE_1,
1798 IMG_BACKGROUND_ENVELOPE_2,
1799 IMG_BACKGROUND_ENVELOPE_3,
1800 IMG_BACKGROUND_ENVELOPE_4,
1801 IMG_BACKGROUND_REQUEST,
1804 IMG_BACKGROUND_LOADING_INITIAL,
1805 IMG_BACKGROUND_LOADING,
1806 IMG_BACKGROUND_TITLE_INITIAL,
1807 IMG_BACKGROUND_TITLE,
1808 IMG_BACKGROUND_MAIN,
1809 IMG_BACKGROUND_NAMES,
1810 IMG_BACKGROUND_LEVELS,
1811 IMG_BACKGROUND_LEVELNR,
1812 IMG_BACKGROUND_SCORES,
1813 IMG_BACKGROUND_SCOREINFO,
1814 IMG_BACKGROUND_EDITOR,
1815 IMG_BACKGROUND_INFO,
1816 IMG_BACKGROUND_INFO_ELEMENTS,
1817 IMG_BACKGROUND_INFO_MUSIC,
1818 IMG_BACKGROUND_INFO_CREDITS,
1819 IMG_BACKGROUND_INFO_PROGRAM,
1820 IMG_BACKGROUND_INFO_VERSION,
1821 IMG_BACKGROUND_INFO_LEVELSET,
1822 IMG_BACKGROUND_SETUP,
1823 IMG_BACKGROUND_PLAYING,
1824 IMG_BACKGROUND_DOOR,
1825 IMG_BACKGROUND_TAPE,
1826 IMG_BACKGROUND_PANEL,
1827 IMG_BACKGROUND_PALETTE,
1828 IMG_BACKGROUND_TOOLBOX,
1830 IMG_TITLESCREEN_INITIAL_1,
1831 IMG_TITLESCREEN_INITIAL_2,
1832 IMG_TITLESCREEN_INITIAL_3,
1833 IMG_TITLESCREEN_INITIAL_4,
1834 IMG_TITLESCREEN_INITIAL_5,
1841 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1842 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1843 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1844 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1845 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1846 IMG_BACKGROUND_TITLEMESSAGE_1,
1847 IMG_BACKGROUND_TITLEMESSAGE_2,
1848 IMG_BACKGROUND_TITLEMESSAGE_3,
1849 IMG_BACKGROUND_TITLEMESSAGE_4,
1850 IMG_BACKGROUND_TITLEMESSAGE_5,
1855 FreeGlobalAnimEventInfo();
1857 checked_free(graphic_info);
1859 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1861 // initialize "use_image_size" flag with default value
1862 for (i = 0; i < num_images; i++)
1863 graphic_info[i].use_image_size = FALSE;
1865 // initialize "use_image_size" flag from static configuration above
1866 for (i = 0; full_size_graphics[i] != -1; i++)
1867 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1869 // first set all graphic paramaters ...
1870 for (i = 0; i < num_images; i++)
1871 set_graphic_parameters(i);
1873 // ... then copy these parameters for cloned graphics
1874 for (i = 0; i < num_images; i++)
1875 if (graphic_info[i].clone_from != -1)
1876 set_cloned_graphic_parameters(i);
1878 for (i = 0; i < num_images; i++)
1880 Bitmap *src_bitmap = graphic_info[i].bitmap;
1884 int src_bitmap_width, src_bitmap_height;
1886 // now check if no animation frames are outside of the loaded image
1888 if (graphic_info[i].bitmap == NULL)
1889 continue; // skip check for optional images that are undefined
1891 // get image size (this can differ from the standard element tile size!)
1892 width = graphic_info[i].width;
1893 height = graphic_info[i].height;
1895 // get final bitmap size (with scaling, but without small images)
1896 src_bitmap_width = graphic_info[i].src_image_width;
1897 src_bitmap_height = graphic_info[i].src_image_height;
1899 // check if first animation frame is inside specified bitmap
1901 // do not use getGraphicSourceXY() here to get position of first frame;
1902 // this avoids calculating wrong start position for out-of-bounds frame
1903 src_x = graphic_info[i].src_x;
1904 src_y = graphic_info[i].src_y;
1906 if (program.headless)
1909 if (src_x < 0 || src_y < 0 ||
1910 src_x + width > src_bitmap_width ||
1911 src_y + height > src_bitmap_height)
1914 Warn("error found in config file:");
1915 Warn("- config file: '%s'", getImageConfigFilename());
1916 Warn("- config token: '%s'", getTokenFromImageID(i));
1917 Warn("- image file: '%s'", src_bitmap->source_filename);
1918 Warn("- frame size: %d, %d", width, height);
1919 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1920 src_x, src_y, src_bitmap_width, src_bitmap_height);
1921 Warn("custom graphic rejected for this element/action");
1923 if (i == fallback_graphic)
1924 Fail("no fallback graphic available");
1926 Warn("fallback done to 'char_exclam' for this graphic");
1929 graphic_info[i] = graphic_info[fallback_graphic];
1931 // if first frame out of bounds, do not check last frame anymore
1935 // check if last animation frame is inside specified bitmap
1937 last_frame = graphic_info[i].anim_frames - 1;
1938 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1940 if (src_x < 0 || src_y < 0 ||
1941 src_x + width > src_bitmap_width ||
1942 src_y + height > src_bitmap_height)
1945 Warn("error found in config file:");
1946 Warn("- config file: '%s'", getImageConfigFilename());
1947 Warn("- config token: '%s'", getTokenFromImageID(i));
1948 Warn("- image file: '%s'", src_bitmap->source_filename);
1949 Warn("- frame size: %d, %d", width, height);
1950 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1951 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1952 Warn("custom graphic rejected for this element/action");
1954 if (i == fallback_graphic)
1955 Fail("no fallback graphic available");
1957 Warn("fallback done to 'char_exclam' for this graphic");
1960 graphic_info[i] = graphic_info[fallback_graphic];
1965 static void InitGraphicCompatibilityInfo(void)
1967 struct FileInfo *fi_global_door =
1968 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1969 int num_images = getImageListSize();
1972 /* the following compatibility handling is needed for the following case:
1973 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1974 graphics mainly used for door and panel graphics, like editor, tape and
1975 in-game buttons with hard-coded bitmap positions and button sizes; as
1976 these graphics now have individual definitions, redefining "global.door"
1977 to change all these graphics at once like before does not work anymore
1978 (because all those individual definitions still have their default values);
1979 to solve this, remap all those individual definitions that are not
1980 redefined to the new bitmap of "global.door" if it was redefined */
1982 // special compatibility handling if image "global.door" was redefined
1983 if (fi_global_door->redefined)
1985 for (i = 0; i < num_images; i++)
1987 struct FileInfo *fi = getImageListEntryFromImageID(i);
1989 // process only those images that still use the default settings
1992 // process all images which default to same image as "global.door"
1993 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1995 // skip all images that are cloned from images that default to same
1996 // image as "global.door", but that are redefined to something else
1997 if (graphic_info[i].clone_from != -1)
1999 int cloned_graphic = graphic_info[i].clone_from;
2001 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
2006 Debug("init:InitGraphicCompatibilityInfo",
2007 "special treatment needed for token '%s'", fi->token);
2010 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
2011 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2017 // special compatibility handling for "Snake Bite" graphics set
2018 if (strPrefix(leveldir_current->identifier, "snake_bite"))
2020 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
2022 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
2023 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
2025 ClearRectangle(bitmap, 2, 66, 32, 480);
2026 ClearRectangle(bitmap, 514, 66, 32, 480);
2029 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
2030 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
2031 if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
2049 int mode_old = GAME_MODE_SCORES;
2050 int mode_new = GAME_MODE_SCOREINFO;
2053 // adjust title screens on score info page
2054 for (i = 0; font_title[i] != -1; i++)
2056 struct FontInfo *fi = &font_info[font_title[i]];
2058 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
2059 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2062 // adjust vertical text and button positions on scores page
2063 for (i = 0; font_text[i] != -1; i++)
2065 for (j = 0; j < 2; j++)
2067 boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2068 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2069 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2070 int font_yoffset = (jue0 ? 10 : 5);
2072 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2076 // adjust page offsets on score info page
2077 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2078 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2081 InitGraphicCompatibilityInfo_Doors();
2084 static void InitElementSoundInfo(void)
2086 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2087 int num_property_mappings = getSoundListPropertyMappingSize();
2090 // set values to -1 to identify later as "uninitialized" values
2091 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2092 for (act = 0; act < NUM_ACTIONS; act++)
2093 element_info[i].sound[act] = -1;
2095 // initialize element/sound mapping from static configuration
2096 for (i = 0; element_to_sound[i].element > -1; i++)
2098 int element = element_to_sound[i].element;
2099 int action = element_to_sound[i].action;
2100 int sound = element_to_sound[i].sound;
2101 boolean is_class = element_to_sound[i].is_class;
2104 action = ACTION_DEFAULT;
2107 element_info[element].sound[action] = sound;
2109 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2110 if (strEqual(element_info[j].class_name,
2111 element_info[element].class_name))
2112 element_info[j].sound[action] = sound;
2115 // initialize element class/sound mapping from dynamic configuration
2116 for (i = 0; i < num_property_mappings; i++)
2118 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2119 int action = property_mapping[i].ext1_index;
2120 int sound = property_mapping[i].artwork_index;
2122 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2126 action = ACTION_DEFAULT;
2128 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2129 if (strEqual(element_info[j].class_name,
2130 element_info[element_class].class_name))
2131 element_info[j].sound[action] = sound;
2134 // initialize element/sound mapping from dynamic configuration
2135 for (i = 0; i < num_property_mappings; i++)
2137 int element = property_mapping[i].base_index;
2138 int action = property_mapping[i].ext1_index;
2139 int sound = property_mapping[i].artwork_index;
2141 if (element >= MAX_NUM_ELEMENTS)
2145 action = ACTION_DEFAULT;
2147 element_info[element].sound[action] = sound;
2150 // now set all '-1' values to element specific default values
2151 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2153 for (act = 0; act < NUM_ACTIONS; act++)
2155 // generic default action sound (defined by "[default]" directive)
2156 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2158 // look for special default action sound (classic game specific)
2159 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2160 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2161 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2162 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2163 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2164 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2165 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2166 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2168 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2169 // !!! make this better !!!
2170 if (i == EL_EMPTY_SPACE)
2171 default_action_sound = element_info[EL_DEFAULT].sound[act];
2173 // no sound for this specific action -- use default action sound
2174 if (element_info[i].sound[act] == -1)
2175 element_info[i].sound[act] = default_action_sound;
2179 // copy sound settings to some elements that are only stored in level file
2180 // in native R'n'D levels, but are used by game engine in native EM levels
2181 for (i = 0; copy_properties[i][0] != -1; i++)
2182 for (j = 1; j <= 4; j++)
2183 for (act = 0; act < NUM_ACTIONS; act++)
2184 element_info[copy_properties[i][j]].sound[act] =
2185 element_info[copy_properties[i][0]].sound[act];
2188 static void InitGameModeSoundInfo(void)
2192 // set values to -1 to identify later as "uninitialized" values
2193 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2196 // initialize gamemode/sound mapping from static configuration
2197 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2199 int gamemode = gamemode_to_sound[i].gamemode;
2200 int sound = gamemode_to_sound[i].sound;
2203 gamemode = GAME_MODE_DEFAULT;
2205 menu.sound[gamemode] = sound;
2208 // now set all '-1' values to levelset specific default values
2209 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2210 if (menu.sound[i] == -1)
2211 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2214 static void set_sound_parameters(int sound, char **parameter_raw)
2216 int parameter[NUM_SND_ARGS];
2219 // get integer values from string parameters
2220 for (i = 0; i < NUM_SND_ARGS; i++)
2222 get_parameter_value(parameter_raw[i],
2223 sound_config_suffix[i].token,
2224 sound_config_suffix[i].type);
2226 // explicit loop mode setting in configuration overrides default value
2227 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2228 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2230 // sound volume to change the original volume when loading the sound file
2231 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2233 // sound priority to give certain sounds a higher or lower priority
2234 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2237 static void InitSoundInfo(void)
2239 int *sound_effect_properties;
2240 int num_sounds = getSoundListSize();
2243 checked_free(sound_info);
2245 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2246 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2248 // initialize sound effect for all elements to "no sound"
2249 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2250 for (j = 0; j < NUM_ACTIONS; j++)
2251 element_info[i].sound[j] = SND_UNDEFINED;
2253 for (i = 0; i < num_sounds; i++)
2255 struct FileInfo *sound = getSoundListEntry(i);
2256 int len_effect_text = strlen(sound->token);
2258 sound_effect_properties[i] = ACTION_OTHER;
2259 sound_info[i].loop = FALSE; // default: play sound only once
2261 // determine all loop sounds and identify certain sound classes
2263 for (j = 0; element_action_info[j].suffix; j++)
2265 int len_action_text = strlen(element_action_info[j].suffix);
2267 if (len_action_text < len_effect_text &&
2268 strEqual(&sound->token[len_effect_text - len_action_text],
2269 element_action_info[j].suffix))
2271 sound_effect_properties[i] = element_action_info[j].value;
2272 sound_info[i].loop = element_action_info[j].is_loop_sound;
2278 // associate elements and some selected sound actions
2280 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2282 if (element_info[j].class_name)
2284 int len_class_text = strlen(element_info[j].class_name);
2286 if (len_class_text + 1 < len_effect_text &&
2287 strncmp(sound->token,
2288 element_info[j].class_name, len_class_text) == 0 &&
2289 sound->token[len_class_text] == '.')
2291 int sound_action_value = sound_effect_properties[i];
2293 element_info[j].sound[sound_action_value] = i;
2298 set_sound_parameters(i, sound->parameter);
2301 Debug("init:InitSoundInfo", "loop mode: %d ['%s']",
2302 sound_info[i].loop, sound->token);
2306 free(sound_effect_properties);
2309 static void InitGameModeMusicInfo(void)
2311 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2312 int num_property_mappings = getMusicListPropertyMappingSize();
2313 int default_levelset_music = -1;
2316 // set values to -1 to identify later as "uninitialized" values
2317 for (i = 0; i < MAX_LEVELS; i++)
2318 levelset.music[i] = -1;
2319 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2322 // initialize gamemode/music mapping from static configuration
2323 for (i = 0; gamemode_to_music[i].music > -1; i++)
2325 int gamemode = gamemode_to_music[i].gamemode;
2326 int music = gamemode_to_music[i].music;
2329 gamemode = GAME_MODE_DEFAULT;
2331 menu.music[gamemode] = music;
2334 // initialize gamemode/music mapping from dynamic configuration
2335 for (i = 0; i < num_property_mappings; i++)
2337 int prefix = property_mapping[i].base_index;
2338 int gamemode = property_mapping[i].ext2_index;
2339 int level = property_mapping[i].ext3_index;
2340 int music = property_mapping[i].artwork_index;
2342 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2346 gamemode = GAME_MODE_DEFAULT;
2348 // level specific music only allowed for in-game music
2349 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2350 gamemode = GAME_MODE_PLAYING;
2355 default_levelset_music = music;
2358 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2359 levelset.music[level] = music;
2360 if (gamemode != GAME_MODE_PLAYING)
2361 menu.music[gamemode] = music;
2364 // now set all '-1' values to menu specific default values
2365 // (undefined values of "levelset.music[]" might stay at "-1" to
2366 // allow dynamic selection of music files from music directory!)
2367 for (i = 0; i < MAX_LEVELS; i++)
2368 if (levelset.music[i] == -1)
2369 levelset.music[i] = default_levelset_music;
2370 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2371 if (menu.music[i] == -1)
2372 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2375 static void set_music_parameters(int music, char **parameter_raw)
2377 int parameter[NUM_MUS_ARGS];
2380 // get integer values from string parameters
2381 for (i = 0; i < NUM_MUS_ARGS; i++)
2383 get_parameter_value(parameter_raw[i],
2384 music_config_suffix[i].token,
2385 music_config_suffix[i].type);
2387 // explicit loop mode setting in configuration overrides default value
2388 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2389 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2392 static void InitMusicInfo(void)
2394 int num_music = getMusicListSize();
2397 checked_free(music_info);
2399 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2401 for (i = 0; i < num_music; i++)
2403 struct FileInfo *music = getMusicListEntry(i);
2404 int len_music_text = strlen(music->token);
2406 music_info[i].loop = TRUE; // default: play music in loop mode
2408 // determine all loop music
2410 for (j = 0; music_prefix_info[j].prefix; j++)
2412 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2414 if (len_prefix_text < len_music_text &&
2415 strncmp(music->token,
2416 music_prefix_info[j].prefix, len_prefix_text) == 0)
2418 music_info[i].loop = music_prefix_info[j].is_loop_music;
2424 set_music_parameters(i, music->parameter);
2429 static void InitGameInfoFromArtworkInfo(void)
2431 // special case: store initial value of custom artwork setting
2432 game.use_masked_elements_initial = game.use_masked_elements;
2435 static void ReinitializeGraphics(void)
2437 print_timestamp_init("ReinitializeGraphics");
2439 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2441 InitGraphicInfo(); // graphic properties mapping
2442 print_timestamp_time("InitGraphicInfo");
2443 InitElementGraphicInfo(); // element game graphic mapping
2444 print_timestamp_time("InitElementGraphicInfo");
2445 InitElementSpecialGraphicInfo(); // element special graphic mapping
2446 print_timestamp_time("InitElementSpecialGraphicInfo");
2448 InitElementSmallImages(); // scale elements to all needed sizes
2449 print_timestamp_time("InitElementSmallImages");
2450 InitScaledImages(); // scale all other images, if needed
2451 print_timestamp_time("InitScaledImages");
2452 InitBitmapPointers(); // set standard size bitmap pointers
2453 print_timestamp_time("InitBitmapPointers");
2454 InitFontGraphicInfo(); // initialize text drawing functions
2455 print_timestamp_time("InitFontGraphicInfo");
2456 InitGlobalAnimGraphicInfo(); // initialize global animation config
2457 print_timestamp_time("InitGlobalAnimGraphicInfo");
2459 InitImageTextures(); // create textures for certain images
2460 print_timestamp_time("InitImageTextures");
2462 InitGraphicInfo_BD(); // graphic mapping for BD engine
2463 print_timestamp_time("InitGraphicInfo_BD");
2464 InitGraphicInfo_EM(); // graphic mapping for EM engine
2465 print_timestamp_time("InitGraphicInfo_EM");
2467 InitGraphicCompatibilityInfo();
2468 print_timestamp_time("InitGraphicCompatibilityInfo");
2471 print_timestamp_time("InitGadgets");
2473 print_timestamp_time("InitDoors");
2475 InitGameInfoFromArtworkInfo();
2477 print_timestamp_done("ReinitializeGraphics");
2480 static void ReinitializeSounds(void)
2482 InitSoundInfo(); // sound properties mapping
2483 InitElementSoundInfo(); // element game sound mapping
2484 InitGameModeSoundInfo(); // game mode sound mapping
2485 InitGlobalAnimSoundInfo(); // global animation sound settings
2487 InitPlayLevelSound(); // internal game sound settings
2490 static void ReinitializeMusic(void)
2492 InitMusicInfo(); // music properties mapping
2493 InitGameModeMusicInfo(); // game mode music mapping
2494 InitGlobalAnimMusicInfo(); // global animation music settings
2497 static int get_special_property_bit(int element, int property_bit_nr)
2499 struct PropertyBitInfo
2505 static struct PropertyBitInfo pb_can_move_into_acid[] =
2507 // the player may be able fall into acid when gravity is activated
2512 { EL_SP_MURPHY, 0 },
2513 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2515 // all elements that can move may be able to also move into acid
2518 { EL_BUG_RIGHT, 1 },
2521 { EL_SPACESHIP, 2 },
2522 { EL_SPACESHIP_LEFT, 2 },
2523 { EL_SPACESHIP_RIGHT, 2 },
2524 { EL_SPACESHIP_UP, 2 },
2525 { EL_SPACESHIP_DOWN, 2 },
2526 { EL_BD_BUTTERFLY, 3 },
2527 { EL_BD_BUTTERFLY_LEFT, 3 },
2528 { EL_BD_BUTTERFLY_RIGHT, 3 },
2529 { EL_BD_BUTTERFLY_UP, 3 },
2530 { EL_BD_BUTTERFLY_DOWN, 3 },
2531 { EL_BD_FIREFLY, 4 },
2532 { EL_BD_FIREFLY_LEFT, 4 },
2533 { EL_BD_FIREFLY_RIGHT, 4 },
2534 { EL_BD_FIREFLY_UP, 4 },
2535 { EL_BD_FIREFLY_DOWN, 4 },
2537 { EL_YAMYAM_LEFT, 5 },
2538 { EL_YAMYAM_RIGHT, 5 },
2539 { EL_YAMYAM_UP, 5 },
2540 { EL_YAMYAM_DOWN, 5 },
2541 { EL_DARK_YAMYAM, 6 },
2544 { EL_PACMAN_LEFT, 8 },
2545 { EL_PACMAN_RIGHT, 8 },
2546 { EL_PACMAN_UP, 8 },
2547 { EL_PACMAN_DOWN, 8 },
2549 { EL_MOLE_LEFT, 9 },
2550 { EL_MOLE_RIGHT, 9 },
2552 { EL_MOLE_DOWN, 9 },
2556 { EL_SATELLITE, 13 },
2557 { EL_SP_SNIKSNAK, 14 },
2558 { EL_SP_ELECTRON, 15 },
2561 { EL_SPRING_LEFT, 17 },
2562 { EL_SPRING_RIGHT, 17 },
2563 { EL_EMC_ANDROID, 18 },
2568 static struct PropertyBitInfo pb_dont_collide_with[] =
2570 { EL_SP_SNIKSNAK, 0 },
2571 { EL_SP_ELECTRON, 1 },
2579 struct PropertyBitInfo *pb_info;
2582 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2583 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2588 struct PropertyBitInfo *pb_info = NULL;
2591 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2592 if (pb_definition[i].bit_nr == property_bit_nr)
2593 pb_info = pb_definition[i].pb_info;
2595 if (pb_info == NULL)
2598 for (i = 0; pb_info[i].element != -1; i++)
2599 if (pb_info[i].element == element)
2600 return pb_info[i].bit_nr;
2605 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2606 boolean property_value)
2608 int bit_nr = get_special_property_bit(element, property_bit_nr);
2613 *bitfield |= (1 << bit_nr);
2615 *bitfield &= ~(1 << bit_nr);
2619 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2621 int bit_nr = get_special_property_bit(element, property_bit_nr);
2624 return ((*bitfield & (1 << bit_nr)) != 0);
2629 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2631 static int group_nr;
2632 static struct ElementGroupInfo *group;
2633 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2636 if (actual_group == NULL) // not yet initialized
2639 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2641 Warn("recursion too deep when resolving group element %d",
2642 group_element - EL_GROUP_START + 1);
2644 // replace element which caused too deep recursion by question mark
2645 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2650 if (recursion_depth == 0) // initialization
2652 group = actual_group;
2653 group_nr = GROUP_NR(group_element);
2655 group->num_elements_resolved = 0;
2656 group->choice_pos = 0;
2658 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2659 element_info[i].in_group[group_nr] = FALSE;
2662 for (i = 0; i < actual_group->num_elements; i++)
2664 int element = actual_group->element[i];
2666 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2669 if (IS_GROUP_ELEMENT(element))
2670 ResolveGroupElementExt(element, recursion_depth + 1);
2673 group->element_resolved[group->num_elements_resolved++] = element;
2674 element_info[element].in_group[group_nr] = TRUE;
2679 void ResolveGroupElement(int group_element)
2681 ResolveGroupElementExt(group_element, 0);
2684 void InitElementPropertiesStatic(void)
2686 static boolean clipboard_elements_initialized = FALSE;
2688 static int ep_diggable[] =
2693 EL_SP_BUGGY_BASE_ACTIVATING,
2696 EL_INVISIBLE_SAND_ACTIVE,
2699 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2700 // (if amoeba can grow into anything diggable, maybe keep these out)
2705 EL_SP_BUGGY_BASE_ACTIVE,
2712 static int ep_collectible_only[] =
2734 EL_DYNABOMB_INCREASE_NUMBER,
2735 EL_DYNABOMB_INCREASE_SIZE,
2736 EL_DYNABOMB_INCREASE_POWER,
2754 // !!! handle separately !!!
2755 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2761 static int ep_dont_run_into[] =
2763 // same elements as in 'ep_dont_touch'
2769 // same elements as in 'ep_dont_collide_with'
2781 // !!! maybe this should better be handled by 'ep_diggable' !!!
2786 EL_SP_BUGGY_BASE_ACTIVE,
2793 static int ep_dont_collide_with[] =
2795 // same elements as in 'ep_dont_touch'
2812 static int ep_dont_touch[] =
2822 static int ep_indestructible[] =
2826 EL_ACID_POOL_TOPLEFT,
2827 EL_ACID_POOL_TOPRIGHT,
2828 EL_ACID_POOL_BOTTOMLEFT,
2829 EL_ACID_POOL_BOTTOM,
2830 EL_ACID_POOL_BOTTOMRIGHT,
2831 EL_SP_HARDWARE_GRAY,
2832 EL_SP_HARDWARE_GREEN,
2833 EL_SP_HARDWARE_BLUE,
2835 EL_SP_HARDWARE_YELLOW,
2836 EL_SP_HARDWARE_BASE_1,
2837 EL_SP_HARDWARE_BASE_2,
2838 EL_SP_HARDWARE_BASE_3,
2839 EL_SP_HARDWARE_BASE_4,
2840 EL_SP_HARDWARE_BASE_5,
2841 EL_SP_HARDWARE_BASE_6,
2842 EL_INVISIBLE_STEELWALL,
2843 EL_INVISIBLE_STEELWALL_ACTIVE,
2844 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2845 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2846 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2847 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2848 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2849 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2850 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2851 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2852 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2853 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2854 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2855 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2857 EL_LIGHT_SWITCH_ACTIVE,
2858 EL_SIGN_EXCLAMATION,
2859 EL_SIGN_RADIOACTIVITY,
2866 EL_SIGN_ENTRY_FORBIDDEN,
2867 EL_SIGN_EMERGENCY_EXIT,
2875 EL_STEEL_EXIT_CLOSED,
2877 EL_STEEL_EXIT_OPENING,
2878 EL_STEEL_EXIT_CLOSING,
2879 EL_EM_STEEL_EXIT_CLOSED,
2880 EL_EM_STEEL_EXIT_OPEN,
2881 EL_EM_STEEL_EXIT_OPENING,
2882 EL_EM_STEEL_EXIT_CLOSING,
2883 EL_DC_STEELWALL_1_LEFT,
2884 EL_DC_STEELWALL_1_RIGHT,
2885 EL_DC_STEELWALL_1_TOP,
2886 EL_DC_STEELWALL_1_BOTTOM,
2887 EL_DC_STEELWALL_1_HORIZONTAL,
2888 EL_DC_STEELWALL_1_VERTICAL,
2889 EL_DC_STEELWALL_1_TOPLEFT,
2890 EL_DC_STEELWALL_1_TOPRIGHT,
2891 EL_DC_STEELWALL_1_BOTTOMLEFT,
2892 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2893 EL_DC_STEELWALL_1_TOPLEFT_2,
2894 EL_DC_STEELWALL_1_TOPRIGHT_2,
2895 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2896 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2897 EL_DC_STEELWALL_2_LEFT,
2898 EL_DC_STEELWALL_2_RIGHT,
2899 EL_DC_STEELWALL_2_TOP,
2900 EL_DC_STEELWALL_2_BOTTOM,
2901 EL_DC_STEELWALL_2_HORIZONTAL,
2902 EL_DC_STEELWALL_2_VERTICAL,
2903 EL_DC_STEELWALL_2_MIDDLE,
2904 EL_DC_STEELWALL_2_SINGLE,
2905 EL_STEELWALL_SLIPPERY,
2919 EL_GATE_1_GRAY_ACTIVE,
2920 EL_GATE_2_GRAY_ACTIVE,
2921 EL_GATE_3_GRAY_ACTIVE,
2922 EL_GATE_4_GRAY_ACTIVE,
2931 EL_EM_GATE_1_GRAY_ACTIVE,
2932 EL_EM_GATE_2_GRAY_ACTIVE,
2933 EL_EM_GATE_3_GRAY_ACTIVE,
2934 EL_EM_GATE_4_GRAY_ACTIVE,
2943 EL_EMC_GATE_5_GRAY_ACTIVE,
2944 EL_EMC_GATE_6_GRAY_ACTIVE,
2945 EL_EMC_GATE_7_GRAY_ACTIVE,
2946 EL_EMC_GATE_8_GRAY_ACTIVE,
2948 EL_DC_GATE_WHITE_GRAY,
2949 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2950 EL_DC_GATE_FAKE_GRAY,
2952 EL_SWITCHGATE_OPENING,
2953 EL_SWITCHGATE_CLOSED,
2954 EL_SWITCHGATE_CLOSING,
2955 EL_DC_SWITCHGATE_SWITCH_UP,
2956 EL_DC_SWITCHGATE_SWITCH_DOWN,
2958 EL_TIMEGATE_OPENING,
2960 EL_TIMEGATE_CLOSING,
2961 EL_DC_TIMEGATE_SWITCH,
2962 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2966 EL_TUBE_VERTICAL_LEFT,
2967 EL_TUBE_VERTICAL_RIGHT,
2968 EL_TUBE_HORIZONTAL_UP,
2969 EL_TUBE_HORIZONTAL_DOWN,
2974 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2975 EL_EXPANDABLE_STEELWALL_VERTICAL,
2976 EL_EXPANDABLE_STEELWALL_ANY,
2981 static int ep_slippery[] =
2995 EL_ROBOT_WHEEL_ACTIVE,
3001 EL_ACID_POOL_TOPLEFT,
3002 EL_ACID_POOL_TOPRIGHT,
3012 EL_STEELWALL_SLIPPERY,
3015 EL_EMC_WALL_SLIPPERY_1,
3016 EL_EMC_WALL_SLIPPERY_2,
3017 EL_EMC_WALL_SLIPPERY_3,
3018 EL_EMC_WALL_SLIPPERY_4,
3020 EL_EMC_MAGIC_BALL_ACTIVE,
3025 static int ep_can_change[] =
3030 static int ep_can_move[] =
3032 // same elements as in 'pb_can_move_into_acid'
3055 static int ep_can_fall[] =
3070 EL_QUICKSAND_FAST_FULL,
3072 EL_BD_MAGIC_WALL_FULL,
3073 EL_DC_MAGIC_WALL_FULL,
3087 static int ep_can_smash_player[] =
3113 static int ep_can_smash_enemies[] =
3122 static int ep_can_smash_everything[] =
3131 static int ep_explodes_by_fire[] =
3133 // same elements as in 'ep_explodes_impact'
3138 // same elements as in 'ep_explodes_smashed'
3148 EL_EM_DYNAMITE_ACTIVE,
3149 EL_DYNABOMB_PLAYER_1_ACTIVE,
3150 EL_DYNABOMB_PLAYER_2_ACTIVE,
3151 EL_DYNABOMB_PLAYER_3_ACTIVE,
3152 EL_DYNABOMB_PLAYER_4_ACTIVE,
3153 EL_DYNABOMB_INCREASE_NUMBER,
3154 EL_DYNABOMB_INCREASE_SIZE,
3155 EL_DYNABOMB_INCREASE_POWER,
3156 EL_SP_DISK_RED_ACTIVE,
3170 static int ep_explodes_smashed[] =
3172 // same elements as in 'ep_explodes_impact'
3186 static int ep_explodes_impact[] =
3195 static int ep_walkable_over[] =
3215 EL_SOKOBAN_FIELD_EMPTY,
3222 EL_EM_STEEL_EXIT_OPEN,
3223 EL_EM_STEEL_EXIT_OPENING,
3232 EL_GATE_1_GRAY_ACTIVE,
3233 EL_GATE_2_GRAY_ACTIVE,
3234 EL_GATE_3_GRAY_ACTIVE,
3235 EL_GATE_4_GRAY_ACTIVE,
3243 static int ep_walkable_inside[] =
3248 EL_TUBE_VERTICAL_LEFT,
3249 EL_TUBE_VERTICAL_RIGHT,
3250 EL_TUBE_HORIZONTAL_UP,
3251 EL_TUBE_HORIZONTAL_DOWN,
3260 static int ep_walkable_under[] =
3265 static int ep_passable_over[] =
3275 EL_EM_GATE_1_GRAY_ACTIVE,
3276 EL_EM_GATE_2_GRAY_ACTIVE,
3277 EL_EM_GATE_3_GRAY_ACTIVE,
3278 EL_EM_GATE_4_GRAY_ACTIVE,
3287 EL_EMC_GATE_5_GRAY_ACTIVE,
3288 EL_EMC_GATE_6_GRAY_ACTIVE,
3289 EL_EMC_GATE_7_GRAY_ACTIVE,
3290 EL_EMC_GATE_8_GRAY_ACTIVE,
3292 EL_DC_GATE_WHITE_GRAY,
3293 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3300 static int ep_passable_inside[] =
3306 EL_SP_PORT_HORIZONTAL,
3307 EL_SP_PORT_VERTICAL,
3309 EL_SP_GRAVITY_PORT_LEFT,
3310 EL_SP_GRAVITY_PORT_RIGHT,
3311 EL_SP_GRAVITY_PORT_UP,
3312 EL_SP_GRAVITY_PORT_DOWN,
3313 EL_SP_GRAVITY_ON_PORT_LEFT,
3314 EL_SP_GRAVITY_ON_PORT_RIGHT,
3315 EL_SP_GRAVITY_ON_PORT_UP,
3316 EL_SP_GRAVITY_ON_PORT_DOWN,
3317 EL_SP_GRAVITY_OFF_PORT_LEFT,
3318 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3319 EL_SP_GRAVITY_OFF_PORT_UP,
3320 EL_SP_GRAVITY_OFF_PORT_DOWN,
3325 static int ep_passable_under[] =
3330 static int ep_droppable[] =
3335 static int ep_explodes_1x1_old[] =
3340 static int ep_pushable[] =
3352 EL_SOKOBAN_FIELD_FULL,
3361 static int ep_explodes_cross_old[] =
3366 static int ep_protected[] =
3368 // same elements as in 'ep_walkable_inside'
3372 EL_TUBE_VERTICAL_LEFT,
3373 EL_TUBE_VERTICAL_RIGHT,
3374 EL_TUBE_HORIZONTAL_UP,
3375 EL_TUBE_HORIZONTAL_DOWN,
3381 // same elements as in 'ep_passable_over'
3390 EL_EM_GATE_1_GRAY_ACTIVE,
3391 EL_EM_GATE_2_GRAY_ACTIVE,
3392 EL_EM_GATE_3_GRAY_ACTIVE,
3393 EL_EM_GATE_4_GRAY_ACTIVE,
3402 EL_EMC_GATE_5_GRAY_ACTIVE,
3403 EL_EMC_GATE_6_GRAY_ACTIVE,
3404 EL_EMC_GATE_7_GRAY_ACTIVE,
3405 EL_EMC_GATE_8_GRAY_ACTIVE,
3407 EL_DC_GATE_WHITE_GRAY,
3408 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3412 // same elements as in 'ep_passable_inside'
3417 EL_SP_PORT_HORIZONTAL,
3418 EL_SP_PORT_VERTICAL,
3420 EL_SP_GRAVITY_PORT_LEFT,
3421 EL_SP_GRAVITY_PORT_RIGHT,
3422 EL_SP_GRAVITY_PORT_UP,
3423 EL_SP_GRAVITY_PORT_DOWN,
3424 EL_SP_GRAVITY_ON_PORT_LEFT,
3425 EL_SP_GRAVITY_ON_PORT_RIGHT,
3426 EL_SP_GRAVITY_ON_PORT_UP,
3427 EL_SP_GRAVITY_ON_PORT_DOWN,
3428 EL_SP_GRAVITY_OFF_PORT_LEFT,
3429 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3430 EL_SP_GRAVITY_OFF_PORT_UP,
3431 EL_SP_GRAVITY_OFF_PORT_DOWN,
3436 static int ep_throwable[] =
3441 static int ep_can_explode[] =
3443 // same elements as in 'ep_explodes_impact'
3448 // same elements as in 'ep_explodes_smashed'
3454 // elements that can explode by explosion or by dragonfire
3458 EL_EM_DYNAMITE_ACTIVE,
3459 EL_DYNABOMB_PLAYER_1_ACTIVE,
3460 EL_DYNABOMB_PLAYER_2_ACTIVE,
3461 EL_DYNABOMB_PLAYER_3_ACTIVE,
3462 EL_DYNABOMB_PLAYER_4_ACTIVE,
3463 EL_DYNABOMB_INCREASE_NUMBER,
3464 EL_DYNABOMB_INCREASE_SIZE,
3465 EL_DYNABOMB_INCREASE_POWER,
3466 EL_SP_DISK_RED_ACTIVE,
3474 // elements that can explode only by explosion
3480 static int ep_gravity_reachable[] =
3486 EL_INVISIBLE_SAND_ACTIVE,
3491 EL_SP_PORT_HORIZONTAL,
3492 EL_SP_PORT_VERTICAL,
3494 EL_SP_GRAVITY_PORT_LEFT,
3495 EL_SP_GRAVITY_PORT_RIGHT,
3496 EL_SP_GRAVITY_PORT_UP,
3497 EL_SP_GRAVITY_PORT_DOWN,
3498 EL_SP_GRAVITY_ON_PORT_LEFT,
3499 EL_SP_GRAVITY_ON_PORT_RIGHT,
3500 EL_SP_GRAVITY_ON_PORT_UP,
3501 EL_SP_GRAVITY_ON_PORT_DOWN,
3502 EL_SP_GRAVITY_OFF_PORT_LEFT,
3503 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3504 EL_SP_GRAVITY_OFF_PORT_UP,
3505 EL_SP_GRAVITY_OFF_PORT_DOWN,
3511 static int ep_empty_space[] =
3534 static int ep_player[] =
3541 EL_SOKOBAN_FIELD_PLAYER,
3547 static int ep_can_pass_magic_wall[] =
3561 static int ep_can_pass_dc_magic_wall[] =
3577 static int ep_switchable[] =
3581 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3582 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3583 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3584 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3585 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3586 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3587 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3588 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3589 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3590 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3591 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3592 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3593 EL_SWITCHGATE_SWITCH_UP,
3594 EL_SWITCHGATE_SWITCH_DOWN,
3595 EL_DC_SWITCHGATE_SWITCH_UP,
3596 EL_DC_SWITCHGATE_SWITCH_DOWN,
3598 EL_LIGHT_SWITCH_ACTIVE,
3600 EL_DC_TIMEGATE_SWITCH,
3601 EL_BALLOON_SWITCH_LEFT,
3602 EL_BALLOON_SWITCH_RIGHT,
3603 EL_BALLOON_SWITCH_UP,
3604 EL_BALLOON_SWITCH_DOWN,
3605 EL_BALLOON_SWITCH_ANY,
3606 EL_BALLOON_SWITCH_NONE,
3609 EL_EMC_MAGIC_BALL_SWITCH,
3610 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3615 static int ep_bd_element[] =
3635 EL_BD_FIREFLY_RIGHT,
3638 EL_BD_BUTTERFLY_DOWN,
3639 EL_BD_BUTTERFLY_LEFT,
3641 EL_BD_BUTTERFLY_RIGHT,
3649 static int ep_sp_element[] =
3651 // should always be valid
3654 // standard classic Supaplex elements
3661 EL_SP_HARDWARE_GRAY,
3669 EL_SP_GRAVITY_PORT_RIGHT,
3670 EL_SP_GRAVITY_PORT_DOWN,
3671 EL_SP_GRAVITY_PORT_LEFT,
3672 EL_SP_GRAVITY_PORT_UP,
3677 EL_SP_PORT_VERTICAL,
3678 EL_SP_PORT_HORIZONTAL,
3684 EL_SP_HARDWARE_BASE_1,
3685 EL_SP_HARDWARE_GREEN,
3686 EL_SP_HARDWARE_BLUE,
3688 EL_SP_HARDWARE_YELLOW,
3689 EL_SP_HARDWARE_BASE_2,
3690 EL_SP_HARDWARE_BASE_3,
3691 EL_SP_HARDWARE_BASE_4,
3692 EL_SP_HARDWARE_BASE_5,
3693 EL_SP_HARDWARE_BASE_6,
3697 // additional elements that appeared in newer Supaplex levels
3700 // additional gravity port elements (not switching, but setting gravity)
3701 EL_SP_GRAVITY_ON_PORT_LEFT,
3702 EL_SP_GRAVITY_ON_PORT_RIGHT,
3703 EL_SP_GRAVITY_ON_PORT_UP,
3704 EL_SP_GRAVITY_ON_PORT_DOWN,
3705 EL_SP_GRAVITY_OFF_PORT_LEFT,
3706 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3707 EL_SP_GRAVITY_OFF_PORT_UP,
3708 EL_SP_GRAVITY_OFF_PORT_DOWN,
3710 // more than one Murphy in a level results in an inactive clone
3713 // runtime Supaplex elements
3714 EL_SP_DISK_RED_ACTIVE,
3715 EL_SP_TERMINAL_ACTIVE,
3716 EL_SP_BUGGY_BASE_ACTIVATING,
3717 EL_SP_BUGGY_BASE_ACTIVE,
3724 static int ep_sb_element[] =
3729 EL_SOKOBAN_FIELD_EMPTY,
3730 EL_SOKOBAN_FIELD_FULL,
3731 EL_SOKOBAN_FIELD_PLAYER,
3736 EL_INVISIBLE_STEELWALL,
3741 static int ep_gem[] =
3753 static int ep_food_dark_yamyam[] =
3781 static int ep_food_penguin[] =
3795 static int ep_food_pig[] =
3807 static int ep_historic_wall[] =
3818 EL_GATE_1_GRAY_ACTIVE,
3819 EL_GATE_2_GRAY_ACTIVE,
3820 EL_GATE_3_GRAY_ACTIVE,
3821 EL_GATE_4_GRAY_ACTIVE,
3830 EL_EM_GATE_1_GRAY_ACTIVE,
3831 EL_EM_GATE_2_GRAY_ACTIVE,
3832 EL_EM_GATE_3_GRAY_ACTIVE,
3833 EL_EM_GATE_4_GRAY_ACTIVE,
3840 EL_EXPANDABLE_WALL_HORIZONTAL,
3841 EL_EXPANDABLE_WALL_VERTICAL,
3842 EL_EXPANDABLE_WALL_ANY,
3843 EL_EXPANDABLE_WALL_GROWING,
3844 EL_BD_EXPANDABLE_WALL,
3851 EL_SP_HARDWARE_GRAY,
3852 EL_SP_HARDWARE_GREEN,
3853 EL_SP_HARDWARE_BLUE,
3855 EL_SP_HARDWARE_YELLOW,
3856 EL_SP_HARDWARE_BASE_1,
3857 EL_SP_HARDWARE_BASE_2,
3858 EL_SP_HARDWARE_BASE_3,
3859 EL_SP_HARDWARE_BASE_4,
3860 EL_SP_HARDWARE_BASE_5,
3861 EL_SP_HARDWARE_BASE_6,
3863 EL_SP_TERMINAL_ACTIVE,
3866 EL_INVISIBLE_STEELWALL,
3867 EL_INVISIBLE_STEELWALL_ACTIVE,
3869 EL_INVISIBLE_WALL_ACTIVE,
3870 EL_STEELWALL_SLIPPERY,
3887 static int ep_historic_solid[] =
3891 EL_EXPANDABLE_WALL_HORIZONTAL,
3892 EL_EXPANDABLE_WALL_VERTICAL,
3893 EL_EXPANDABLE_WALL_ANY,
3894 EL_BD_EXPANDABLE_WALL,
3907 EL_QUICKSAND_FILLING,
3908 EL_QUICKSAND_EMPTYING,
3910 EL_MAGIC_WALL_ACTIVE,
3911 EL_MAGIC_WALL_EMPTYING,
3912 EL_MAGIC_WALL_FILLING,
3916 EL_BD_MAGIC_WALL_ACTIVE,
3917 EL_BD_MAGIC_WALL_EMPTYING,
3918 EL_BD_MAGIC_WALL_FULL,
3919 EL_BD_MAGIC_WALL_FILLING,
3920 EL_BD_MAGIC_WALL_DEAD,
3929 EL_SP_TERMINAL_ACTIVE,
3933 EL_INVISIBLE_WALL_ACTIVE,
3934 EL_SWITCHGATE_SWITCH_UP,
3935 EL_SWITCHGATE_SWITCH_DOWN,
3937 EL_TIMEGATE_SWITCH_ACTIVE,
3949 // the following elements are a direct copy of "indestructible" elements,
3950 // except "EL_ACID", which is "indestructible", but not "solid"!
3955 EL_ACID_POOL_TOPLEFT,
3956 EL_ACID_POOL_TOPRIGHT,
3957 EL_ACID_POOL_BOTTOMLEFT,
3958 EL_ACID_POOL_BOTTOM,
3959 EL_ACID_POOL_BOTTOMRIGHT,
3960 EL_SP_HARDWARE_GRAY,
3961 EL_SP_HARDWARE_GREEN,
3962 EL_SP_HARDWARE_BLUE,
3964 EL_SP_HARDWARE_YELLOW,
3965 EL_SP_HARDWARE_BASE_1,
3966 EL_SP_HARDWARE_BASE_2,
3967 EL_SP_HARDWARE_BASE_3,
3968 EL_SP_HARDWARE_BASE_4,
3969 EL_SP_HARDWARE_BASE_5,
3970 EL_SP_HARDWARE_BASE_6,
3971 EL_INVISIBLE_STEELWALL,
3972 EL_INVISIBLE_STEELWALL_ACTIVE,
3973 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3974 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3975 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3976 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3977 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3978 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3979 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3980 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3981 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3982 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3983 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3984 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3986 EL_LIGHT_SWITCH_ACTIVE,
3987 EL_SIGN_EXCLAMATION,
3988 EL_SIGN_RADIOACTIVITY,
3995 EL_SIGN_ENTRY_FORBIDDEN,
3996 EL_SIGN_EMERGENCY_EXIT,
4004 EL_STEEL_EXIT_CLOSED,
4006 EL_STEEL_EXIT_OPENING,
4007 EL_STEEL_EXIT_CLOSING,
4008 EL_EM_STEEL_EXIT_CLOSED,
4009 EL_EM_STEEL_EXIT_OPEN,
4010 EL_EM_STEEL_EXIT_OPENING,
4011 EL_EM_STEEL_EXIT_CLOSING,
4012 EL_DC_STEELWALL_1_LEFT,
4013 EL_DC_STEELWALL_1_RIGHT,
4014 EL_DC_STEELWALL_1_TOP,
4015 EL_DC_STEELWALL_1_BOTTOM,
4016 EL_DC_STEELWALL_1_HORIZONTAL,
4017 EL_DC_STEELWALL_1_VERTICAL,
4018 EL_DC_STEELWALL_1_TOPLEFT,
4019 EL_DC_STEELWALL_1_TOPRIGHT,
4020 EL_DC_STEELWALL_1_BOTTOMLEFT,
4021 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4022 EL_DC_STEELWALL_1_TOPLEFT_2,
4023 EL_DC_STEELWALL_1_TOPRIGHT_2,
4024 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4025 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4026 EL_DC_STEELWALL_2_LEFT,
4027 EL_DC_STEELWALL_2_RIGHT,
4028 EL_DC_STEELWALL_2_TOP,
4029 EL_DC_STEELWALL_2_BOTTOM,
4030 EL_DC_STEELWALL_2_HORIZONTAL,
4031 EL_DC_STEELWALL_2_VERTICAL,
4032 EL_DC_STEELWALL_2_MIDDLE,
4033 EL_DC_STEELWALL_2_SINGLE,
4034 EL_STEELWALL_SLIPPERY,
4048 EL_GATE_1_GRAY_ACTIVE,
4049 EL_GATE_2_GRAY_ACTIVE,
4050 EL_GATE_3_GRAY_ACTIVE,
4051 EL_GATE_4_GRAY_ACTIVE,
4060 EL_EM_GATE_1_GRAY_ACTIVE,
4061 EL_EM_GATE_2_GRAY_ACTIVE,
4062 EL_EM_GATE_3_GRAY_ACTIVE,
4063 EL_EM_GATE_4_GRAY_ACTIVE,
4072 EL_EMC_GATE_5_GRAY_ACTIVE,
4073 EL_EMC_GATE_6_GRAY_ACTIVE,
4074 EL_EMC_GATE_7_GRAY_ACTIVE,
4075 EL_EMC_GATE_8_GRAY_ACTIVE,
4077 EL_DC_GATE_WHITE_GRAY,
4078 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4079 EL_DC_GATE_FAKE_GRAY,
4081 EL_SWITCHGATE_OPENING,
4082 EL_SWITCHGATE_CLOSED,
4083 EL_SWITCHGATE_CLOSING,
4084 EL_DC_SWITCHGATE_SWITCH_UP,
4085 EL_DC_SWITCHGATE_SWITCH_DOWN,
4087 EL_TIMEGATE_OPENING,
4089 EL_TIMEGATE_CLOSING,
4090 EL_DC_TIMEGATE_SWITCH,
4091 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4095 EL_TUBE_VERTICAL_LEFT,
4096 EL_TUBE_VERTICAL_RIGHT,
4097 EL_TUBE_HORIZONTAL_UP,
4098 EL_TUBE_HORIZONTAL_DOWN,
4103 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4104 EL_EXPANDABLE_STEELWALL_VERTICAL,
4105 EL_EXPANDABLE_STEELWALL_ANY,
4110 static int ep_classic_enemy[] =
4127 static int ep_belt[] =
4129 EL_CONVEYOR_BELT_1_LEFT,
4130 EL_CONVEYOR_BELT_1_MIDDLE,
4131 EL_CONVEYOR_BELT_1_RIGHT,
4132 EL_CONVEYOR_BELT_2_LEFT,
4133 EL_CONVEYOR_BELT_2_MIDDLE,
4134 EL_CONVEYOR_BELT_2_RIGHT,
4135 EL_CONVEYOR_BELT_3_LEFT,
4136 EL_CONVEYOR_BELT_3_MIDDLE,
4137 EL_CONVEYOR_BELT_3_RIGHT,
4138 EL_CONVEYOR_BELT_4_LEFT,
4139 EL_CONVEYOR_BELT_4_MIDDLE,
4140 EL_CONVEYOR_BELT_4_RIGHT,
4145 static int ep_belt_active[] =
4147 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4148 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4149 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4150 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4151 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4152 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4153 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4154 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4155 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4156 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4157 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4158 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4163 static int ep_belt_switch[] =
4165 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4166 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4167 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4168 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4169 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4170 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4171 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4172 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4173 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4174 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4175 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4176 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4181 static int ep_tube[] =
4188 EL_TUBE_HORIZONTAL_UP,
4189 EL_TUBE_HORIZONTAL_DOWN,
4191 EL_TUBE_VERTICAL_LEFT,
4192 EL_TUBE_VERTICAL_RIGHT,
4198 static int ep_acid_pool[] =
4200 EL_ACID_POOL_TOPLEFT,
4201 EL_ACID_POOL_TOPRIGHT,
4202 EL_ACID_POOL_BOTTOMLEFT,
4203 EL_ACID_POOL_BOTTOM,
4204 EL_ACID_POOL_BOTTOMRIGHT,
4209 static int ep_keygate[] =
4219 EL_GATE_1_GRAY_ACTIVE,
4220 EL_GATE_2_GRAY_ACTIVE,
4221 EL_GATE_3_GRAY_ACTIVE,
4222 EL_GATE_4_GRAY_ACTIVE,
4231 EL_EM_GATE_1_GRAY_ACTIVE,
4232 EL_EM_GATE_2_GRAY_ACTIVE,
4233 EL_EM_GATE_3_GRAY_ACTIVE,
4234 EL_EM_GATE_4_GRAY_ACTIVE,
4243 EL_EMC_GATE_5_GRAY_ACTIVE,
4244 EL_EMC_GATE_6_GRAY_ACTIVE,
4245 EL_EMC_GATE_7_GRAY_ACTIVE,
4246 EL_EMC_GATE_8_GRAY_ACTIVE,
4248 EL_DC_GATE_WHITE_GRAY,
4249 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4254 static int ep_amoeboid[] =
4266 static int ep_amoebalive[] =
4277 static int ep_has_editor_content[] =
4283 EL_SOKOBAN_FIELD_PLAYER,
4310 static int ep_can_turn_each_move[] =
4312 // !!! do something with this one !!!
4316 static int ep_can_grow[] =
4330 static int ep_active_bomb[] =
4333 EL_EM_DYNAMITE_ACTIVE,
4334 EL_DYNABOMB_PLAYER_1_ACTIVE,
4335 EL_DYNABOMB_PLAYER_2_ACTIVE,
4336 EL_DYNABOMB_PLAYER_3_ACTIVE,
4337 EL_DYNABOMB_PLAYER_4_ACTIVE,
4338 EL_SP_DISK_RED_ACTIVE,
4343 static int ep_inactive[] =
4369 EL_QUICKSAND_FAST_EMPTY,
4392 EL_GATE_1_GRAY_ACTIVE,
4393 EL_GATE_2_GRAY_ACTIVE,
4394 EL_GATE_3_GRAY_ACTIVE,
4395 EL_GATE_4_GRAY_ACTIVE,
4404 EL_EM_GATE_1_GRAY_ACTIVE,
4405 EL_EM_GATE_2_GRAY_ACTIVE,
4406 EL_EM_GATE_3_GRAY_ACTIVE,
4407 EL_EM_GATE_4_GRAY_ACTIVE,
4416 EL_EMC_GATE_5_GRAY_ACTIVE,
4417 EL_EMC_GATE_6_GRAY_ACTIVE,
4418 EL_EMC_GATE_7_GRAY_ACTIVE,
4419 EL_EMC_GATE_8_GRAY_ACTIVE,
4421 EL_DC_GATE_WHITE_GRAY,
4422 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4423 EL_DC_GATE_FAKE_GRAY,
4426 EL_INVISIBLE_STEELWALL,
4434 EL_WALL_EMERALD_YELLOW,
4435 EL_DYNABOMB_INCREASE_NUMBER,
4436 EL_DYNABOMB_INCREASE_SIZE,
4437 EL_DYNABOMB_INCREASE_POWER,
4441 EL_SOKOBAN_FIELD_EMPTY,
4442 EL_SOKOBAN_FIELD_FULL,
4443 EL_WALL_EMERALD_RED,
4444 EL_WALL_EMERALD_PURPLE,
4445 EL_ACID_POOL_TOPLEFT,
4446 EL_ACID_POOL_TOPRIGHT,
4447 EL_ACID_POOL_BOTTOMLEFT,
4448 EL_ACID_POOL_BOTTOM,
4449 EL_ACID_POOL_BOTTOMRIGHT,
4453 EL_BD_MAGIC_WALL_DEAD,
4455 EL_DC_MAGIC_WALL_DEAD,
4456 EL_AMOEBA_TO_DIAMOND,
4464 EL_SP_GRAVITY_PORT_RIGHT,
4465 EL_SP_GRAVITY_PORT_DOWN,
4466 EL_SP_GRAVITY_PORT_LEFT,
4467 EL_SP_GRAVITY_PORT_UP,
4468 EL_SP_PORT_HORIZONTAL,
4469 EL_SP_PORT_VERTICAL,
4480 EL_SP_HARDWARE_GRAY,
4481 EL_SP_HARDWARE_GREEN,
4482 EL_SP_HARDWARE_BLUE,
4484 EL_SP_HARDWARE_YELLOW,
4485 EL_SP_HARDWARE_BASE_1,
4486 EL_SP_HARDWARE_BASE_2,
4487 EL_SP_HARDWARE_BASE_3,
4488 EL_SP_HARDWARE_BASE_4,
4489 EL_SP_HARDWARE_BASE_5,
4490 EL_SP_HARDWARE_BASE_6,
4491 EL_SP_GRAVITY_ON_PORT_LEFT,
4492 EL_SP_GRAVITY_ON_PORT_RIGHT,
4493 EL_SP_GRAVITY_ON_PORT_UP,
4494 EL_SP_GRAVITY_ON_PORT_DOWN,
4495 EL_SP_GRAVITY_OFF_PORT_LEFT,
4496 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4497 EL_SP_GRAVITY_OFF_PORT_UP,
4498 EL_SP_GRAVITY_OFF_PORT_DOWN,
4499 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4500 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4501 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4502 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4503 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4504 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4505 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4506 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4507 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4508 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4509 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4510 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4511 EL_SIGN_EXCLAMATION,
4512 EL_SIGN_RADIOACTIVITY,
4519 EL_SIGN_ENTRY_FORBIDDEN,
4520 EL_SIGN_EMERGENCY_EXIT,
4528 EL_DC_STEELWALL_1_LEFT,
4529 EL_DC_STEELWALL_1_RIGHT,
4530 EL_DC_STEELWALL_1_TOP,
4531 EL_DC_STEELWALL_1_BOTTOM,
4532 EL_DC_STEELWALL_1_HORIZONTAL,
4533 EL_DC_STEELWALL_1_VERTICAL,
4534 EL_DC_STEELWALL_1_TOPLEFT,
4535 EL_DC_STEELWALL_1_TOPRIGHT,
4536 EL_DC_STEELWALL_1_BOTTOMLEFT,
4537 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4538 EL_DC_STEELWALL_1_TOPLEFT_2,
4539 EL_DC_STEELWALL_1_TOPRIGHT_2,
4540 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4541 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4542 EL_DC_STEELWALL_2_LEFT,
4543 EL_DC_STEELWALL_2_RIGHT,
4544 EL_DC_STEELWALL_2_TOP,
4545 EL_DC_STEELWALL_2_BOTTOM,
4546 EL_DC_STEELWALL_2_HORIZONTAL,
4547 EL_DC_STEELWALL_2_VERTICAL,
4548 EL_DC_STEELWALL_2_MIDDLE,
4549 EL_DC_STEELWALL_2_SINGLE,
4550 EL_STEELWALL_SLIPPERY,
4555 EL_EMC_WALL_SLIPPERY_1,
4556 EL_EMC_WALL_SLIPPERY_2,
4557 EL_EMC_WALL_SLIPPERY_3,
4558 EL_EMC_WALL_SLIPPERY_4,
4579 static int ep_em_slippery_wall[] =
4584 static int ep_gfx_crumbled[] =
4595 static int ep_editor_cascade_active[] =
4597 EL_INTERNAL_CASCADE_BD_ACTIVE,
4598 EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
4599 EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
4600 EL_INTERNAL_CASCADE_EM_ACTIVE,
4601 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4602 EL_INTERNAL_CASCADE_RND_ACTIVE,
4603 EL_INTERNAL_CASCADE_SB_ACTIVE,
4604 EL_INTERNAL_CASCADE_SP_ACTIVE,
4605 EL_INTERNAL_CASCADE_DC_ACTIVE,
4606 EL_INTERNAL_CASCADE_DX_ACTIVE,
4607 EL_INTERNAL_CASCADE_MM_ACTIVE,
4608 EL_INTERNAL_CASCADE_DF_ACTIVE,
4609 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4610 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4611 EL_INTERNAL_CASCADE_CE_ACTIVE,
4612 EL_INTERNAL_CASCADE_GE_ACTIVE,
4613 EL_INTERNAL_CASCADE_ES_ACTIVE,
4614 EL_INTERNAL_CASCADE_REF_ACTIVE,
4615 EL_INTERNAL_CASCADE_USER_ACTIVE,
4616 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4621 static int ep_editor_cascade_inactive[] =
4623 EL_INTERNAL_CASCADE_BD,
4624 EL_INTERNAL_CASCADE_BD_NATIVE,
4625 EL_INTERNAL_CASCADE_BD_EFFECTS,
4626 EL_INTERNAL_CASCADE_EM,
4627 EL_INTERNAL_CASCADE_EMC,
4628 EL_INTERNAL_CASCADE_RND,
4629 EL_INTERNAL_CASCADE_SB,
4630 EL_INTERNAL_CASCADE_SP,
4631 EL_INTERNAL_CASCADE_DC,
4632 EL_INTERNAL_CASCADE_DX,
4633 EL_INTERNAL_CASCADE_MM,
4634 EL_INTERNAL_CASCADE_DF,
4635 EL_INTERNAL_CASCADE_CHARS,
4636 EL_INTERNAL_CASCADE_STEEL_CHARS,
4637 EL_INTERNAL_CASCADE_CE,
4638 EL_INTERNAL_CASCADE_GE,
4639 EL_INTERNAL_CASCADE_ES,
4640 EL_INTERNAL_CASCADE_REF,
4641 EL_INTERNAL_CASCADE_USER,
4642 EL_INTERNAL_CASCADE_DYNAMIC,
4647 static int ep_obsolete[] =
4651 EL_EM_KEY_1_FILE_OBSOLETE,
4652 EL_EM_KEY_2_FILE_OBSOLETE,
4653 EL_EM_KEY_3_FILE_OBSOLETE,
4654 EL_EM_KEY_4_FILE_OBSOLETE,
4655 EL_ENVELOPE_OBSOLETE,
4664 } element_properties[] =
4666 { ep_diggable, EP_DIGGABLE },
4667 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4668 { ep_dont_run_into, EP_DONT_RUN_INTO },
4669 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4670 { ep_dont_touch, EP_DONT_TOUCH },
4671 { ep_indestructible, EP_INDESTRUCTIBLE },
4672 { ep_slippery, EP_SLIPPERY },
4673 { ep_can_change, EP_CAN_CHANGE },
4674 { ep_can_move, EP_CAN_MOVE },
4675 { ep_can_fall, EP_CAN_FALL },
4676 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4677 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4678 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4679 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4680 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4681 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4682 { ep_walkable_over, EP_WALKABLE_OVER },
4683 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4684 { ep_walkable_under, EP_WALKABLE_UNDER },
4685 { ep_passable_over, EP_PASSABLE_OVER },
4686 { ep_passable_inside, EP_PASSABLE_INSIDE },
4687 { ep_passable_under, EP_PASSABLE_UNDER },
4688 { ep_droppable, EP_DROPPABLE },
4689 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4690 { ep_pushable, EP_PUSHABLE },
4691 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4692 { ep_protected, EP_PROTECTED },
4693 { ep_throwable, EP_THROWABLE },
4694 { ep_can_explode, EP_CAN_EXPLODE },
4695 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4697 { ep_empty_space, EP_EMPTY_SPACE },
4698 { ep_player, EP_PLAYER },
4699 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4700 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4701 { ep_switchable, EP_SWITCHABLE },
4702 { ep_bd_element, EP_BD_ELEMENT },
4703 { ep_sp_element, EP_SP_ELEMENT },
4704 { ep_sb_element, EP_SB_ELEMENT },
4706 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4707 { ep_food_penguin, EP_FOOD_PENGUIN },
4708 { ep_food_pig, EP_FOOD_PIG },
4709 { ep_historic_wall, EP_HISTORIC_WALL },
4710 { ep_historic_solid, EP_HISTORIC_SOLID },
4711 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4712 { ep_belt, EP_BELT },
4713 { ep_belt_active, EP_BELT_ACTIVE },
4714 { ep_belt_switch, EP_BELT_SWITCH },
4715 { ep_tube, EP_TUBE },
4716 { ep_acid_pool, EP_ACID_POOL },
4717 { ep_keygate, EP_KEYGATE },
4718 { ep_amoeboid, EP_AMOEBOID },
4719 { ep_amoebalive, EP_AMOEBALIVE },
4720 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4721 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4722 { ep_can_grow, EP_CAN_GROW },
4723 { ep_active_bomb, EP_ACTIVE_BOMB },
4724 { ep_inactive, EP_INACTIVE },
4726 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4728 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4730 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4731 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4733 { ep_obsolete, EP_OBSOLETE },
4740 // always start with reliable default values (element has no properties)
4741 // (but never initialize clipboard elements after the very first time)
4742 // (to be able to use clipboard elements between several levels)
4743 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4744 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4745 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4746 SET_PROPERTY(i, j, FALSE);
4748 // set all base element properties from above array definitions
4749 for (i = 0; element_properties[i].elements != NULL; i++)
4750 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4751 SET_PROPERTY((element_properties[i].elements)[j],
4752 element_properties[i].property, TRUE);
4754 // copy properties to some elements that are only stored in level file
4755 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4756 for (j = 0; copy_properties[j][0] != -1; j++)
4757 if (HAS_PROPERTY(copy_properties[j][0], i))
4758 for (k = 1; k <= 4; k++)
4759 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4761 // set static element properties that are not listed in array definitions
4762 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4763 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4765 clipboard_elements_initialized = TRUE;
4768 void InitElementPropertiesEngine(int engine_version)
4770 static int no_wall_properties[] =
4773 EP_COLLECTIBLE_ONLY,
4775 EP_DONT_COLLIDE_WITH,
4778 EP_CAN_SMASH_PLAYER,
4779 EP_CAN_SMASH_ENEMIES,
4780 EP_CAN_SMASH_EVERYTHING,
4785 EP_FOOD_DARK_YAMYAM,
4801 /* important: after initialization in InitElementPropertiesStatic(), the
4802 elements are not again initialized to a default value; therefore all
4803 changes have to make sure that they leave the element with a defined
4804 property (which means that conditional property changes must be set to
4805 a reliable default value before) */
4807 // resolve group elements
4808 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4809 ResolveGroupElement(EL_GROUP_START + i);
4811 // set all special, combined or engine dependent element properties
4812 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4814 // do not change (already initialized) clipboard elements here
4815 if (IS_CLIPBOARD_ELEMENT(i))
4818 // ---------- INACTIVE ----------------------------------------------------
4819 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4820 i <= EL_CHAR_END) ||
4821 (i >= EL_STEEL_CHAR_START &&
4822 i <= EL_STEEL_CHAR_END)));
4824 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4825 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4826 IS_WALKABLE_INSIDE(i) ||
4827 IS_WALKABLE_UNDER(i)));
4829 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4830 IS_PASSABLE_INSIDE(i) ||
4831 IS_PASSABLE_UNDER(i)));
4833 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4834 IS_PASSABLE_OVER(i)));
4836 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4837 IS_PASSABLE_INSIDE(i)));
4839 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4840 IS_PASSABLE_UNDER(i)));
4842 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4845 // ---------- COLLECTIBLE -------------------------------------------------
4846 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4850 // ---------- SNAPPABLE ---------------------------------------------------
4851 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4852 IS_COLLECTIBLE(i) ||
4856 // ---------- WALL --------------------------------------------------------
4857 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4859 for (j = 0; no_wall_properties[j] != -1; j++)
4860 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4861 i >= EL_FIRST_RUNTIME_UNREAL)
4862 SET_PROPERTY(i, EP_WALL, FALSE);
4864 if (IS_HISTORIC_WALL(i))
4865 SET_PROPERTY(i, EP_WALL, TRUE);
4867 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4868 if (engine_version < VERSION_IDENT(2,2,0,0))
4869 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4871 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4873 !IS_COLLECTIBLE(i)));
4875 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4876 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4877 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4879 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4882 // ---------- EXPLOSION_PROOF ---------------------------------------------
4884 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4885 else if (engine_version < VERSION_IDENT(2,2,0,0))
4886 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4888 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4892 if (IS_CUSTOM_ELEMENT(i))
4894 // these are additional properties which are initially false when set
4896 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4898 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4899 if (DONT_COLLIDE_WITH(i))
4900 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4902 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4903 if (CAN_SMASH_EVERYTHING(i))
4904 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4905 if (CAN_SMASH_ENEMIES(i))
4906 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4909 // ---------- CAN_SMASH ---------------------------------------------------
4910 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4911 CAN_SMASH_ENEMIES(i) ||
4912 CAN_SMASH_EVERYTHING(i)));
4914 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4915 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4916 EXPLODES_BY_FIRE(i)));
4918 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4919 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4920 EXPLODES_SMASHED(i)));
4922 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4923 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4924 EXPLODES_IMPACT(i)));
4926 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4927 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4929 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4930 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4931 i == EL_BLACK_ORB));
4933 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4934 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4936 IS_CUSTOM_ELEMENT(i)));
4938 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4939 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4940 i == EL_SP_ELECTRON));
4942 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4943 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4944 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4945 getMoveIntoAcidProperty(&level, i));
4947 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4948 if (MAYBE_DONT_COLLIDE_WITH(i))
4949 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4950 getDontCollideWithProperty(&level, i));
4952 // ---------- SP_PORT -----------------------------------------------------
4953 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4954 IS_PASSABLE_INSIDE(i)));
4956 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4957 for (j = 0; j < level.num_android_clone_elements; j++)
4958 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4960 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4962 // ---------- CAN_CHANGE --------------------------------------------------
4963 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4964 for (j = 0; j < element_info[i].num_change_pages; j++)
4965 if (element_info[i].change_page[j].can_change)
4966 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4968 // ---------- HAS_ACTION --------------------------------------------------
4969 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4970 for (j = 0; j < element_info[i].num_change_pages; j++)
4971 if (element_info[i].change_page[j].has_action)
4972 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4974 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4975 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4978 // ---------- GFX_CRUMBLED ------------------------------------------------
4979 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4980 element_info[i].crumbled[ACTION_DEFAULT] !=
4981 element_info[i].graphic[ACTION_DEFAULT]);
4983 // ---------- EDITOR_CASCADE ----------------------------------------------
4984 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4985 IS_EDITOR_CASCADE_INACTIVE(i)));
4988 // dynamically adjust element properties according to game engine version
4990 static int ep_em_slippery_wall[] =
4995 EL_EXPANDABLE_WALL_HORIZONTAL,
4996 EL_EXPANDABLE_WALL_VERTICAL,
4997 EL_EXPANDABLE_WALL_ANY,
4998 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4999 EL_EXPANDABLE_STEELWALL_VERTICAL,
5000 EL_EXPANDABLE_STEELWALL_ANY,
5001 EL_EXPANDABLE_STEELWALL_GROWING,
5005 static int ep_em_explodes_by_fire[] =
5008 EL_EM_DYNAMITE_ACTIVE,
5013 // special EM style gems behaviour
5014 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
5015 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
5016 level.em_slippery_gems);
5018 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
5019 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
5020 (level.em_slippery_gems &&
5021 engine_version > VERSION_IDENT(2,0,1,0)));
5023 // special EM style explosion behaviour regarding chain reactions
5024 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
5025 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
5026 level.em_explodes_by_fire);
5029 // this is needed because some graphics depend on element properties
5030 if (game_status == GAME_MODE_PLAYING)
5031 InitElementGraphicInfo();
5034 void InitElementPropertiesGfxElement(void)
5038 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5040 struct ElementInfo *ei = &element_info[i];
5042 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5046 static void InitGlobal(void)
5051 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5053 // check if element_name_info entry defined for each element in "main.h"
5054 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5055 Fail("undefined 'element_name_info' entry for element %d", i);
5057 element_info[i].token_name = element_name_info[i].token_name;
5058 element_info[i].class_name = element_name_info[i].class_name;
5059 element_info[i].editor_description = element_name_info[i].editor_description;
5062 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
5064 // check if global_anim_name_info defined for each entry in "main.h"
5065 if (i < NUM_GLOBAL_ANIM_TOKENS &&
5066 global_anim_name_info[i].token_name == NULL)
5067 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
5069 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
5072 // create hash to store URLs for global animations
5073 anim_url_hash = newSetupFileHash();
5075 // create hash from image config list
5076 image_config_hash = newSetupFileHash();
5077 for (i = 0; image_config[i].token != NULL; i++)
5078 setHashEntry(image_config_hash,
5079 image_config[i].token,
5080 image_config[i].value);
5082 // create hash from sound config list
5083 sound_config_hash = newSetupFileHash();
5084 for (i = 0; sound_config[i].token != NULL; i++)
5085 setHashEntry(sound_config_hash,
5086 sound_config[i].token,
5087 sound_config[i].value);
5089 // create hash from element token list
5090 element_token_hash = newSetupFileHash();
5091 for (i = 0; element_name_info[i].token_name != NULL; i++)
5092 setHashEntry(element_token_hash,
5093 element_name_info[i].token_name,
5096 // create hash from graphic token list
5097 graphic_token_hash = newSetupFileHash();
5098 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5099 if (strSuffix(image_config[i].value, ".png") ||
5100 strSuffix(image_config[i].value, ".pcx") ||
5101 strSuffix(image_config[i].value, ".wav") ||
5102 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5103 setHashEntry(graphic_token_hash,
5104 image_config[i].token,
5105 int2str(graphic++, 0));
5107 // create hash from font token list
5108 font_token_hash = newSetupFileHash();
5109 for (i = 0; font_info[i].token_name != NULL; i++)
5110 setHashEntry(font_token_hash,
5111 font_info[i].token_name,
5114 // set default filenames for all cloned graphics in static configuration
5115 for (i = 0; image_config[i].token != NULL; i++)
5117 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5119 char *token = image_config[i].token;
5120 char *token_clone_from = getStringCat2(token, ".clone_from");
5121 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5123 if (token_cloned != NULL)
5125 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5127 if (value_cloned != NULL)
5129 // set default filename in static configuration
5130 image_config[i].value = value_cloned;
5132 // set default filename in image config hash
5133 setHashEntry(image_config_hash, token, value_cloned);
5137 free(token_clone_from);
5141 // always start with reliable default values (all elements)
5142 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5143 ActiveElement[i] = i;
5145 // now add all entries that have an active state (active elements)
5146 for (i = 0; element_with_active_state[i].element != -1; i++)
5148 int element = element_with_active_state[i].element;
5149 int element_active = element_with_active_state[i].element_active;
5151 ActiveElement[element] = element_active;
5154 // always start with reliable default values (all buttons)
5155 for (i = 0; i < NUM_IMAGE_FILES; i++)
5156 ActiveButton[i] = i;
5158 // now add all entries that have an active state (active buttons)
5159 for (i = 0; button_with_active_state[i].button != -1; i++)
5161 int button = button_with_active_state[i].button;
5162 int button_active = button_with_active_state[i].button_active;
5164 ActiveButton[button] = button_active;
5167 // always start with reliable default values (all fonts)
5168 for (i = 0; i < NUM_FONTS; i++)
5171 // now add all entries that have an active state (active fonts)
5172 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5174 int font = font_with_active_state[i].font_nr;
5175 int font_active = font_with_active_state[i].font_nr_active;
5177 ActiveFont[font] = font_active;
5180 global.autoplay_leveldir = NULL;
5181 global.patchtapes_leveldir = NULL;
5182 global.convert_leveldir = NULL;
5183 global.dumplevel_leveldir = NULL;
5184 global.dumptape_leveldir = NULL;
5185 global.create_sketch_images_dir = NULL;
5186 global.create_collect_images_dir = NULL;
5188 global.frames_per_second = 0;
5189 global.show_frames_per_second = FALSE;
5191 global.border_status = GAME_MODE_LOADING;
5192 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5194 global.use_envelope_request = FALSE;
5196 global.user_names = NULL;
5199 static void Execute_Command(char *command)
5203 if (strEqual(command, "print graphicsinfo.conf"))
5205 Print("# You can configure additional/alternative image files here.\n");
5206 Print("# (The entries below are default and therefore commented out.)\n");
5208 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5210 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5213 for (i = 0; image_config[i].token != NULL; i++)
5214 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5215 image_config[i].value));
5219 else if (strEqual(command, "print soundsinfo.conf"))
5221 Print("# You can configure additional/alternative sound files here.\n");
5222 Print("# (The entries below are default and therefore commented out.)\n");
5224 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5226 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5229 for (i = 0; sound_config[i].token != NULL; i++)
5230 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5231 sound_config[i].value));
5235 else if (strEqual(command, "print musicinfo.conf"))
5237 Print("# You can configure additional/alternative music files here.\n");
5238 Print("# (The entries below are default and therefore commented out.)\n");
5240 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5242 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5245 for (i = 0; music_config[i].token != NULL; i++)
5246 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5247 music_config[i].value));
5251 else if (strEqual(command, "print editorsetup.conf"))
5253 Print("# You can configure your personal editor element list here.\n");
5254 Print("# (The entries below are default and therefore commented out.)\n");
5257 // this is needed to be able to check element list for cascade elements
5258 InitElementPropertiesStatic();
5259 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5261 PrintEditorElementList();
5265 else if (strEqual(command, "print helpanim.conf"))
5267 Print("# You can configure different element help animations here.\n");
5268 Print("# (The entries below are default and therefore commented out.)\n");
5271 for (i = 0; helpanim_config[i].token != NULL; i++)
5273 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5274 helpanim_config[i].value));
5276 if (strEqual(helpanim_config[i].token, "end"))
5282 else if (strEqual(command, "print helptext.conf"))
5284 Print("# You can configure different element help text here.\n");
5285 Print("# (The entries below are default and therefore commented out.)\n");
5288 for (i = 0; helptext_config[i].token != NULL; i++)
5289 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5290 helptext_config[i].value));
5294 else if (strPrefix(command, "dump level "))
5296 char *filename = &command[11];
5298 if (fileExists(filename))
5300 LoadLevelFromFilename(&level, filename);
5306 char *leveldir = getStringCopy(filename); // read command parameters
5307 char *level_nr = strchr(leveldir, ' ');
5309 if (level_nr == NULL)
5310 Fail("cannot open file '%s'", filename);
5314 global.dumplevel_leveldir = leveldir;
5315 global.dumplevel_level_nr = atoi(level_nr);
5317 program.headless = TRUE;
5319 else if (strPrefix(command, "dump tape "))
5321 char *filename = &command[10];
5323 if (fileExists(filename))
5325 LoadTapeFromFilename(filename);
5331 char *leveldir = getStringCopy(filename); // read command parameters
5332 char *level_nr = strchr(leveldir, ' ');
5334 if (level_nr == NULL)
5335 Fail("cannot open file '%s'", filename);
5339 global.dumptape_leveldir = leveldir;
5340 global.dumptape_level_nr = atoi(level_nr);
5342 program.headless = TRUE;
5344 else if (strPrefix(command, "autoplay ") ||
5345 strPrefix(command, "autoffwd ") ||
5346 strPrefix(command, "autowarp ") ||
5347 strPrefix(command, "autotest ") ||
5348 strPrefix(command, "autosave ") ||
5349 strPrefix(command, "autoupload ") ||
5350 strPrefix(command, "autofix "))
5352 char *arg_ptr = strchr(command, ' ');
5353 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5355 global.autoplay_mode =
5356 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5357 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5358 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5359 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5360 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5361 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5362 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5363 AUTOPLAY_MODE_NONE);
5365 while (*str_ptr != '\0') // continue parsing string
5367 // cut leading whitespace from string, replace it by string terminator
5368 while (*str_ptr == ' ' || *str_ptr == '\t')
5371 if (*str_ptr == '\0') // end of string reached
5374 if (global.autoplay_leveldir == NULL) // read level set string
5376 global.autoplay_leveldir = str_ptr;
5377 global.autoplay_all = TRUE; // default: play all tapes
5379 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5380 global.autoplay_level[i] = FALSE;
5382 else // read level number string
5384 int level_nr = atoi(str_ptr); // get level_nr value
5386 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5387 global.autoplay_level[level_nr] = TRUE;
5389 global.autoplay_all = FALSE;
5392 // advance string pointer to the next whitespace (or end of string)
5393 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5397 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5398 program.headless = TRUE;
5400 else if (strPrefix(command, "patch tapes "))
5402 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5404 // skip leading whitespace
5405 while (*str_ptr == ' ' || *str_ptr == '\t')
5408 if (*str_ptr == '\0')
5409 Fail("cannot find MODE in command '%s'", command);
5411 global.patchtapes_mode = str_ptr; // store patch mode
5413 // advance to next whitespace (or end of string)
5414 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5417 while (*str_ptr != '\0') // continue parsing string
5419 // cut leading whitespace from string, replace it by string terminator
5420 while (*str_ptr == ' ' || *str_ptr == '\t')
5423 if (*str_ptr == '\0') // end of string reached
5426 if (global.patchtapes_leveldir == NULL) // read level set string
5428 global.patchtapes_leveldir = str_ptr;
5429 global.patchtapes_all = TRUE; // default: patch all tapes
5431 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5432 global.patchtapes_level[i] = FALSE;
5434 else // read level number string
5436 int level_nr = atoi(str_ptr); // get level_nr value
5438 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5439 global.patchtapes_level[level_nr] = TRUE;
5441 global.patchtapes_all = FALSE;
5444 // advance string pointer to the next whitespace (or end of string)
5445 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5449 if (global.patchtapes_leveldir == NULL)
5451 if (strEqual(global.patchtapes_mode, "help"))
5452 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5454 Fail("cannot find LEVELDIR in command '%s'", command);
5457 program.headless = TRUE;
5459 else if (strPrefix(command, "convert "))
5461 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5462 char *str_ptr = strchr(str_copy, ' ');
5464 global.convert_leveldir = str_copy;
5465 global.convert_level_nr = -1;
5467 if (str_ptr != NULL) // level number follows
5469 *str_ptr++ = '\0'; // terminate leveldir string
5470 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5473 program.headless = TRUE;
5475 else if (strPrefix(command, "create sketch images "))
5477 global.create_sketch_images_dir = getStringCopy(&command[21]);
5479 if (access(global.create_sketch_images_dir, W_OK) != 0)
5480 Fail("image target directory '%s' not found or not writable",
5481 global.create_sketch_images_dir);
5483 else if (strPrefix(command, "create collect image "))
5485 global.create_collect_images_dir = getStringCopy(&command[21]);
5487 if (access(global.create_collect_images_dir, W_OK) != 0)
5488 Fail("image target directory '%s' not found or not writable",
5489 global.create_collect_images_dir);
5491 else if (strPrefix(command, "create CE image "))
5493 CreateCustomElementImages(&command[16]);
5499 FailWithHelp("unrecognized command '%s'", command);
5502 // disable networking if any valid command was recognized
5503 options.network = setup.network_mode = FALSE;
5506 static void InitSetup(void)
5508 LoadUserNames(); // global user names
5509 LoadUserSetup(); // global user number
5511 LoadSetup(); // global setup info
5513 // set some options from setup file
5515 if (setup.options.verbose)
5516 options.verbose = TRUE;
5518 if (setup.options.debug)
5519 options.debug = TRUE;
5521 if (!strEqual(setup.options.debug_mode, ARG_UNDEFINED_STRING))
5522 options.debug_mode = getStringCopy(setup.options.debug_mode);
5524 if (setup.debug.show_frames_per_second)
5525 global.show_frames_per_second = TRUE;
5528 static void InitGameInfo(void)
5530 game.restart_level = FALSE;
5531 game.request_active = FALSE;
5533 game.use_masked_elements_initial = FALSE;
5536 static void InitPlayerInfo(void)
5540 // choose default local player
5541 local_player = &stored_player[0];
5543 for (i = 0; i < MAX_PLAYERS; i++)
5545 stored_player[i].connected_locally = FALSE;
5546 stored_player[i].connected_network = FALSE;
5549 local_player->connected_locally = TRUE;
5552 static void InitArtworkInfo(void)
5557 static char *get_string_in_brackets(char *string)
5559 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5561 sprintf(string_in_brackets, "[%s]", string);
5563 return string_in_brackets;
5566 static char *get_level_id_suffix(int id_nr)
5568 char *id_suffix = checked_malloc(1 + 3 + 1);
5570 if (id_nr < 0 || id_nr > 999)
5573 sprintf(id_suffix, ".%03d", id_nr);
5578 static void InitArtworkConfig(void)
5580 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5582 NUM_GLOBAL_ANIM_TOKENS + 1];
5583 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5584 NUM_GLOBAL_ANIM_TOKENS + 1];
5585 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5586 NUM_GLOBAL_ANIM_TOKENS + 1];
5587 static char *action_id_suffix[NUM_ACTIONS + 1];
5588 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5589 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5590 static char *level_id_suffix[MAX_LEVELS + 1];
5591 static char *dummy[1] = { NULL };
5592 static char *ignore_generic_tokens[] =
5597 "program_copyright",
5602 static char **ignore_image_tokens;
5603 static char **ignore_sound_tokens;
5604 static char **ignore_music_tokens;
5605 int num_ignore_generic_tokens;
5606 int num_ignore_image_tokens;
5607 int num_ignore_sound_tokens;
5608 int num_ignore_music_tokens;
5611 // dynamically determine list of generic tokens to be ignored
5612 num_ignore_generic_tokens = 0;
5613 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5614 num_ignore_generic_tokens++;
5616 // dynamically determine list of image tokens to be ignored
5617 num_ignore_image_tokens = num_ignore_generic_tokens;
5618 for (i = 0; image_config_vars[i].token != NULL; i++)
5619 num_ignore_image_tokens++;
5620 ignore_image_tokens =
5621 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5622 for (i = 0; i < num_ignore_generic_tokens; i++)
5623 ignore_image_tokens[i] = ignore_generic_tokens[i];
5624 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5625 ignore_image_tokens[num_ignore_generic_tokens + i] =
5626 image_config_vars[i].token;
5627 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5629 // dynamically determine list of sound tokens to be ignored
5630 num_ignore_sound_tokens = num_ignore_generic_tokens;
5631 for (i = 0; sound_config_vars[i].token != NULL; i++)
5632 num_ignore_sound_tokens++;
5633 ignore_sound_tokens =
5634 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5635 for (i = 0; i < num_ignore_generic_tokens; i++)
5636 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5637 for (i = 0; i < num_ignore_sound_tokens - num_ignore_generic_tokens; i++)
5638 ignore_sound_tokens[num_ignore_generic_tokens + i] =
5639 sound_config_vars[i].token;
5640 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5642 // dynamically determine list of music tokens to be ignored
5643 num_ignore_music_tokens = num_ignore_generic_tokens;
5644 ignore_music_tokens =
5645 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5646 for (i = 0; i < num_ignore_generic_tokens; i++)
5647 ignore_music_tokens[i] = ignore_generic_tokens[i];
5648 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5650 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5651 image_id_prefix[i] = element_info[i].token_name;
5652 for (i = 0; i < NUM_FONTS; i++)
5653 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5654 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5655 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5656 global_anim_info[i].token_name;
5657 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5659 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5660 sound_id_prefix[i] = element_info[i].token_name;
5661 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5662 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5663 get_string_in_brackets(element_info[i].class_name);
5664 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5665 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5666 global_anim_info[i].token_name;
5667 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5669 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5670 music_id_prefix[i] = music_prefix_info[i].prefix;
5671 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5672 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5673 global_anim_info[i].token_name;
5674 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5676 for (i = 0; i < NUM_ACTIONS; i++)
5677 action_id_suffix[i] = element_action_info[i].suffix;
5678 action_id_suffix[NUM_ACTIONS] = NULL;
5680 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5681 direction_id_suffix[i] = element_direction_info[i].suffix;
5682 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5684 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5685 special_id_suffix[i] = special_suffix_info[i].suffix;
5686 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5688 for (i = 0; i < MAX_LEVELS; i++)
5689 level_id_suffix[i] = get_level_id_suffix(i);
5690 level_id_suffix[MAX_LEVELS] = NULL;
5692 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5693 image_id_prefix, action_id_suffix, direction_id_suffix,
5694 special_id_suffix, ignore_image_tokens);
5695 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5696 sound_id_prefix, action_id_suffix, dummy,
5697 special_id_suffix, ignore_sound_tokens);
5698 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5699 music_id_prefix, action_id_suffix, special_id_suffix,
5700 level_id_suffix, ignore_music_tokens);
5703 static void InitMixer(void)
5710 static void InitVideoOverlay(void)
5712 // if virtual buttons are not loaded from setup file, repeat initializing
5713 // virtual buttons grid with default values now that video is initialized
5714 if (!setup.touch.grid_initialized)
5717 InitTileCursorInfo();
5721 void InitGfxBuffers(void)
5723 static int win_xsize_last = -1;
5724 static int win_ysize_last = -1;
5726 // create additional image buffers for double-buffering and cross-fading
5728 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5730 // used to temporarily store the backbuffer -- only re-create if changed
5731 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5732 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5734 win_xsize_last = WIN_XSIZE;
5735 win_ysize_last = WIN_YSIZE;
5738 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5739 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5740 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5742 // initialize screen properties
5743 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5744 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5746 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5747 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5748 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5749 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5750 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5751 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5753 // required if door size definitions have changed
5754 InitGraphicCompatibilityInfo_Doors();
5756 InitGfxBuffers_BD();
5757 InitGfxBuffers_EM();
5758 InitGfxBuffers_SP();
5759 InitGfxBuffers_MM();
5762 static void InitGfx(void)
5764 struct GraphicInfo *graphic_info_last = graphic_info;
5765 char *filename_font_initial = NULL;
5766 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5767 char *image_token[NUM_INITIAL_IMAGES] =
5769 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5770 CONFIG_TOKEN_GLOBAL_BUSY,
5771 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5772 CONFIG_TOKEN_BACKGROUND,
5773 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5774 CONFIG_TOKEN_BACKGROUND_LOADING
5776 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5780 &init.busy_playfield
5782 Bitmap *bitmap_font_initial = NULL;
5783 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5786 // determine settings for initial font (for displaying startup messages)
5787 for (i = 0; image_config[i].token != NULL; i++)
5789 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5791 char font_token[128];
5794 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5795 len_font_token = strlen(font_token);
5797 if (strEqual(image_config[i].token, font_token))
5799 filename_font_initial = image_config[i].value;
5801 else if (strlen(image_config[i].token) > len_font_token &&
5802 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5804 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5805 font_initial[j].src_x = atoi(image_config[i].value);
5806 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5807 font_initial[j].src_y = atoi(image_config[i].value);
5808 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5809 font_initial[j].width = atoi(image_config[i].value);
5810 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5811 font_initial[j].height = atoi(image_config[i].value);
5816 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5818 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5819 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5822 if (filename_font_initial == NULL) // should not happen
5823 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5826 InitGfxCustomArtworkInfo();
5827 InitGfxOtherSettings();
5829 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5831 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5833 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5834 font_initial[j].bitmap = bitmap_font_initial;
5836 InitFontGraphicInfo();
5838 InitMenuDesignSettings_Static();
5840 // initialize settings for initial images with default values
5841 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5842 for (j = 0; j < NUM_GFX_ARGS; j++)
5844 get_graphic_parameter_value(image_config_suffix[j].value,
5845 image_config_suffix[j].token,
5846 image_config_suffix[j].type);
5848 // read settings for initial images from default custom artwork config
5849 char *gfx_config_filename = getPath3(options.graphics_directory,
5851 GRAPHICSINFO_FILENAME);
5853 if (fileExists(gfx_config_filename))
5855 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5857 if (setup_file_hash)
5859 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5861 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5865 filename_image_initial[i] = getStringCopy(filename);
5867 for (j = 0; image_config_suffix[j].token != NULL; j++)
5869 int type = image_config_suffix[j].type;
5870 char *suffix = image_config_suffix[j].token;
5871 char *token = getStringCat2(image_token[i], suffix);
5872 char *value = getHashEntry(setup_file_hash, token);
5874 checked_free(token);
5878 get_graphic_parameter_value(value, suffix, type);
5883 // read values from custom graphics config file
5884 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5886 freeSetupFileHash(setup_file_hash);
5890 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5892 if (filename_image_initial[i] == NULL)
5894 int len_token = strlen(image_token[i]);
5896 // read settings for initial images from static default artwork config
5897 for (j = 0; image_config[j].token != NULL; j++)
5899 if (strEqual(image_config[j].token, image_token[i]))
5901 filename_image_initial[i] = getStringCopy(image_config[j].value);
5903 else if (strlen(image_config[j].token) > len_token &&
5904 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5906 for (k = 0; image_config_suffix[k].token != NULL; k++)
5908 if (strEqual(&image_config[j].token[len_token],
5909 image_config_suffix[k].token))
5911 get_graphic_parameter_value(image_config[j].value,
5912 image_config_suffix[k].token,
5913 image_config_suffix[k].type);
5920 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5922 if (filename_image_initial[i] == NULL) // should not happen
5923 Fail("cannot get filename for '%s'", image_token[i]);
5925 image_initial[i].bitmaps =
5926 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5928 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5929 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5930 LoadCustomImage(filename_image_initial[i]);
5932 checked_free(filename_image_initial[i]);
5935 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5936 image_initial[i].use_image_size = TRUE;
5938 graphic_info = image_initial; // graphic == 0 => image_initial
5940 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5941 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5943 graphic_info = graphic_info_last;
5945 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5947 // set image size for busy animations
5948 init_busy[i]->width = image_initial[i].width;
5949 init_busy[i]->height = image_initial[i].height;
5952 SetLoadingBackgroundImage();
5954 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5958 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5959 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5960 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5961 InitGfxDrawTileCursorFunction(DrawTileCursor);
5962 InitGfxDrawEnvelopeRequestFunction(DrawEnvelopeRequestToScreen);
5964 gfx.fade_border_source_status = global.border_status;
5965 gfx.fade_border_target_status = global.border_status;
5966 gfx.masked_border_bitmap_ptr = backbuffer;
5968 // use copy of busy animation to prevent change while reloading artwork
5972 static void InitGfxBackground(void)
5974 fieldbuffer = bitmap_db_field;
5975 SetDrawtoField(DRAW_TO_BACKBUFFER);
5977 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5979 redraw_mask = REDRAW_ALL;
5982 static void InitSnd(void)
5984 InitSoundSettings_Static();
5986 // read settings for initial sounds from default custom artwork config
5987 char *snd_config_filename = getPath3(options.sounds_directory,
5989 SOUNDSINFO_FILENAME);
5991 if (fileExists(snd_config_filename))
5993 SetupFileHash *setup_file_hash = loadSetupFileHash(snd_config_filename);
5995 if (setup_file_hash)
5997 // read values from custom sounds config file
5998 InitSoundSettings_FromHash(setup_file_hash, FALSE);
6000 freeSetupFileHash(setup_file_hash);
6005 static void InitLevelInfo(void)
6007 LoadLevelInfo(); // global level info
6008 LoadLevelSetup_LastSeries(); // last played series info
6009 LoadLevelSetup_SeriesInfo(); // last played level info
6011 if (global.autoplay_leveldir &&
6012 global.autoplay_mode != AUTOPLAY_MODE_TEST)
6014 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
6015 global.autoplay_leveldir);
6016 if (leveldir_current == NULL)
6017 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
6020 SetLevelSetInfo(leveldir_current->identifier, level_nr);
6023 static void InitLevelArtworkInfo(void)
6025 LoadLevelArtworkInfo();
6028 static void InitImages(void)
6030 print_timestamp_init("InitImages");
6033 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6034 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6035 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6036 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6037 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6038 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6039 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6040 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6043 setLevelArtworkDir(artwork.gfx_first);
6046 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6047 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6048 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6049 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6050 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6051 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6052 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6053 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6057 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
6058 leveldir_current->identifier,
6059 artwork.gfx_current_identifier,
6060 artwork.gfx_current->identifier,
6061 leveldir_current->graphics_set,
6062 leveldir_current->graphics_path);
6065 UPDATE_BUSY_STATE();
6067 ReloadCustomImages();
6068 print_timestamp_time("ReloadCustomImages");
6070 UPDATE_BUSY_STATE();
6072 LoadCustomElementDescriptions();
6073 print_timestamp_time("LoadCustomElementDescriptions");
6075 UPDATE_BUSY_STATE();
6077 LoadMenuDesignSettings();
6078 print_timestamp_time("LoadMenuDesignSettings");
6080 UPDATE_BUSY_STATE();
6082 ReinitializeGraphics();
6083 print_timestamp_time("ReinitializeGraphics");
6085 LoadMenuDesignSettings_AfterGraphics();
6086 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
6088 UPDATE_BUSY_STATE();
6090 print_timestamp_done("InitImages");
6093 static void InitSound(void)
6095 print_timestamp_init("InitSound");
6097 // set artwork path to send it to the sound server process
6098 setLevelArtworkDir(artwork.snd_first);
6100 InitReloadCustomSounds();
6101 print_timestamp_time("InitReloadCustomSounds");
6103 LoadSoundSettings();
6104 print_timestamp_time("LoadSoundSettings");
6106 ReinitializeSounds();
6107 print_timestamp_time("ReinitializeSounds");
6109 print_timestamp_done("InitSound");
6112 static void InitMusic(void)
6114 print_timestamp_init("InitMusic");
6116 // set artwork path to send it to the sound server process
6117 setLevelArtworkDir(artwork.mus_first);
6119 InitReloadCustomMusic();
6120 print_timestamp_time("InitReloadCustomMusic");
6122 ReinitializeMusic();
6123 print_timestamp_time("ReinitializeMusic");
6125 print_timestamp_done("InitMusic");
6128 static void InitArtworkDone(void)
6130 if (program.headless)
6133 InitGlobalAnimations();
6136 static void InitNetworkSettings(void)
6138 boolean network_enabled = (options.network || setup.network_mode);
6139 char *network_server = (options.server_host != NULL ? options.server_host :
6140 setup.network_server_hostname);
6142 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6143 network_server = NULL;
6145 InitNetworkInfo(network_enabled,
6149 options.server_port);
6152 void InitNetworkServer(void)
6154 if (!network.enabled || network.connected)
6157 LimitScreenUpdates(FALSE);
6159 if (game_status == GAME_MODE_LOADING)
6162 if (!ConnectToServer(network.server_host, network.server_port))
6164 network.enabled = FALSE;
6166 setup.network_mode = FALSE;
6170 SendToServer_ProtocolVersion();
6171 SendToServer_PlayerName(setup.player_name);
6172 SendToServer_NrWanted(setup.network_player_nr + 1);
6174 network.connected = TRUE;
6177 // short time to recognize result of network initialization
6178 if (game_status == GAME_MODE_LOADING)
6179 Delay_WithScreenUpdates(1000);
6182 static boolean CheckArtworkConfigForCustomElements(char *filename)
6184 SetupFileHash *setup_file_hash;
6185 boolean redefined_ce_found = FALSE;
6187 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6189 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6191 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6193 char *token = HASH_ITERATION_TOKEN(itr);
6195 if (strPrefix(token, "custom_"))
6197 redefined_ce_found = TRUE;
6202 END_HASH_ITERATION(setup_file_hash, itr)
6204 freeSetupFileHash(setup_file_hash);
6207 return redefined_ce_found;
6210 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6212 char *filename_base, *filename_local;
6213 boolean redefined_ce_found = FALSE;
6215 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6218 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6219 "leveldir_current->identifier == '%s'",
6220 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6221 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6222 "leveldir_current->graphics_path == '%s'",
6223 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6224 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6225 "leveldir_current->graphics_set == '%s'",
6226 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6227 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6228 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6229 leveldir_current == NULL ? "[NULL]" :
6230 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6233 // first look for special artwork configured in level series config
6234 filename_base = getCustomArtworkLevelConfigFilename(type);
6237 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6238 "filename_base == '%s'", filename_base);
6241 if (fileExists(filename_base))
6242 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6244 filename_local = getCustomArtworkConfigFilename(type);
6247 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6248 "filename_local == '%s'", filename_local);
6251 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6252 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6255 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6256 "redefined_ce_found == %d", redefined_ce_found);
6259 return redefined_ce_found;
6262 static void InitOverrideArtwork(void)
6264 boolean redefined_ce_found = FALSE;
6266 // to check if this level set redefines any CEs, do not use overriding
6267 gfx.override_level_graphics = FALSE;
6268 gfx.override_level_sounds = FALSE;
6269 gfx.override_level_music = FALSE;
6271 // now check if this level set has definitions for custom elements
6272 if (setup.override_level_graphics == AUTO ||
6273 setup.override_level_sounds == AUTO ||
6274 setup.override_level_music == AUTO)
6275 redefined_ce_found =
6276 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6277 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6278 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6281 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6282 redefined_ce_found);
6285 if (redefined_ce_found)
6287 // this level set has CE definitions: change "AUTO" to "FALSE"
6288 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6289 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6290 gfx.override_level_music = (setup.override_level_music == TRUE);
6294 // this level set has no CE definitions: change "AUTO" to "TRUE"
6295 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6296 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6297 gfx.override_level_music = (setup.override_level_music != FALSE);
6301 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6302 gfx.override_level_graphics,
6303 gfx.override_level_sounds,
6304 gfx.override_level_music);
6308 static char *setNewArtworkIdentifier(int type)
6310 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6311 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6312 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6313 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6314 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6315 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6316 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6317 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6318 char *leveldir_identifier = leveldir_current->identifier;
6319 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6320 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6321 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6322 TreeInfo *custom_artwork_set =
6323 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6324 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6325 char *artwork_current_identifier;
6326 char *artwork_new_identifier = NULL; // default: nothing has changed
6328 // leveldir_current may be invalid (level group, parent link)
6329 if (!validLevelSeries(leveldir_current))
6332 /* 1st step: determine artwork set to be activated in descending order:
6333 --------------------------------------------------------------------
6334 1. setup artwork (when configured to override everything else)
6335 2. artwork set configured in "levelinfo.conf" of current level set
6336 (artwork in level directory will have priority when loading later)
6337 3. artwork in level directory (stored in artwork sub-directory)
6338 4. setup artwork (currently configured in setup menu) */
6340 if (setup_override_artwork)
6341 artwork_current_identifier = setup_artwork_set;
6342 else if (has_level_artwork_set)
6343 artwork_current_identifier = leveldir_artwork_set;
6344 else if (has_custom_artwork_set)
6345 artwork_current_identifier = leveldir_identifier;
6347 artwork_current_identifier = setup_artwork_set;
6349 /* 2nd step: check if it is really needed to reload artwork set
6350 ------------------------------------------------------------ */
6352 // ---------- reload if level set and also artwork set has changed ----------
6353 if (last_leveldir_identifier[type] != leveldir_identifier &&
6354 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6355 artwork_new_identifier = artwork_current_identifier;
6357 last_leveldir_identifier[type] = leveldir_identifier;
6358 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6360 // ---------- reload if "override artwork" setting has changed --------------
6361 if (last_override_level_artwork[type] != setup_override_artwork)
6362 artwork_new_identifier = artwork_current_identifier;
6364 last_override_level_artwork[type] = setup_override_artwork;
6366 // ---------- reload if current artwork identifier has changed --------------
6367 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6368 artwork_new_identifier = artwork_current_identifier;
6370 // (we cannot compare string pointers here, so copy string content itself)
6371 setString(&last_artwork_identifier[type], artwork_current_identifier);
6373 // ---------- set new artwork identifier ----------
6374 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6376 // ---------- do not reload directly after starting -------------------------
6377 if (!initialized[type])
6378 artwork_new_identifier = NULL;
6380 initialized[type] = TRUE;
6382 return artwork_new_identifier;
6385 static void InitArtworkIdentifier(void)
6387 setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6388 setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6389 setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6392 void ReloadCustomArtwork(int force_reload)
6394 int last_game_status = game_status; // save current game status
6395 char *gfx_new_identifier;
6396 char *snd_new_identifier;
6397 char *mus_new_identifier;
6398 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6399 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6400 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6401 boolean reload_needed;
6403 InitOverrideArtwork();
6405 AdjustGraphicsForEMC();
6406 AdjustSoundsForEMC();
6408 gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6409 snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6410 mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6412 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6413 snd_new_identifier != NULL || force_reload_snd ||
6414 mus_new_identifier != NULL || force_reload_mus);
6419 print_timestamp_init("ReloadCustomArtwork");
6421 SetGameStatus(GAME_MODE_LOADING);
6423 FadeOut(REDRAW_ALL);
6425 SetLoadingBackgroundImage();
6427 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6428 print_timestamp_time("ClearRectangleOnBackground");
6432 UPDATE_BUSY_STATE();
6434 InitMissingFileHash();
6436 if (gfx_new_identifier != NULL || force_reload_gfx)
6439 Debug("init:ReloadCustomArtwork",
6440 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6441 artwork.gfx_current_identifier,
6443 artwork.gfx_current->identifier,
6444 leveldir_current->graphics_set);
6448 print_timestamp_time("InitImages");
6451 if (snd_new_identifier != NULL || force_reload_snd)
6454 print_timestamp_time("InitSound");
6457 if (mus_new_identifier != NULL || force_reload_mus)
6460 print_timestamp_time("InitMusic");
6465 SetGameStatus(last_game_status); // restore current game status
6467 FadeOut(REDRAW_ALL);
6469 RedrawGlobalBorder();
6471 // force redraw of (open or closed) door graphics
6472 SetDoorState(DOOR_OPEN_ALL);
6473 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6475 FadeSetEnterScreen();
6476 FadeSkipNextFadeOut();
6478 print_timestamp_done("ReloadCustomArtwork");
6480 LimitScreenUpdates(FALSE);
6483 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6485 if (global.autoplay_leveldir == NULL)
6486 KeyboardAutoRepeatOff();
6489 void DisplayExitMessage(char *format, va_list ap)
6491 // also check for initialized video (headless flag may be temporarily unset)
6492 if (program.headless || !video.initialized)
6495 // check if draw buffer and fonts for exit message are already available
6496 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6499 int font_1 = FC_RED;
6500 int font_2 = FC_YELLOW;
6501 int font_3 = FC_BLUE;
6502 int font_width = getFontWidth(font_2);
6503 int font_height = getFontHeight(font_2);
6506 int sxsize = WIN_XSIZE - 2 * sx;
6507 int sysize = WIN_YSIZE - 2 * sy;
6508 int line_length = sxsize / font_width;
6509 int max_lines = sysize / font_height;
6510 int num_lines_printed;
6514 gfx.sxsize = sxsize;
6515 gfx.sysize = sysize;
6519 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6521 DrawTextSCentered(sy, font_1, "Fatal error:");
6522 sy += 3 * font_height;;
6525 DrawTextBufferVA(sx, sy, format, ap, font_2,
6526 line_length, line_length, max_lines,
6527 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6528 sy += (num_lines_printed + 3) * font_height;
6530 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6531 sy += 3 * font_height;
6534 DrawTextBuffer(sx, sy, program.log_filename, font_2,
6535 line_length, line_length, max_lines,
6536 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6538 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6540 redraw_mask = REDRAW_ALL;
6542 // force drawing exit message even if screen updates are currently limited
6543 LimitScreenUpdates(FALSE);
6547 // deactivate toons and global animations on error message screen
6548 setup.global_animations = FALSE;
6550 WaitForEventToContinue();
6554 // ============================================================================
6556 // ============================================================================
6560 print_timestamp_init("OpenAll");
6562 SetGameStatus(GAME_MODE_LOADING);
6566 InitGlobal(); // initialize some global variables
6568 InitRND(NEW_RANDOMIZE);
6569 InitSimpleRandom(NEW_RANDOMIZE);
6570 InitBetterRandom(NEW_RANDOMIZE);
6572 InitMissingFileHash();
6574 print_timestamp_time("[init global stuff]");
6578 print_timestamp_time("[init setup/config stuff (1)]");
6580 if (options.execute_command)
6581 Execute_Command(options.execute_command);
6583 InitNetworkSettings();
6587 if (network.serveronly)
6589 #if defined(PLATFORM_UNIX)
6590 NetworkServer(network.server_port, TRUE);
6592 Warn("networking only supported in Unix version");
6595 exit(0); // never reached, server loops forever
6599 print_timestamp_time("[init setup/config stuff (2)]");
6601 print_timestamp_time("[init setup/config stuff (3)]");
6602 InitArtworkInfo(); // needed before loading gfx, sound & music
6603 print_timestamp_time("[init setup/config stuff (4)]");
6604 InitArtworkConfig(); // needed before forking sound child process
6605 print_timestamp_time("[init setup/config stuff (5)]");
6607 print_timestamp_time("[init setup/config stuff (6)]");
6611 print_timestamp_time("[init setup/config stuff]");
6613 InitVideoDefaults();
6615 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6618 InitEventFilter(FilterMouseMotionEvents);
6620 print_timestamp_time("[init video stuff]");
6622 InitElementPropertiesStatic();
6623 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6624 InitElementPropertiesGfxElement();
6626 print_timestamp_time("[init element properties stuff]");
6631 print_timestamp_time("InitGfx");
6634 print_timestamp_time("InitLevelInfo");
6636 InitLevelArtworkInfo();
6637 print_timestamp_time("InitLevelArtworkInfo");
6639 InitOverrideArtwork(); // needs to know current level directory
6640 print_timestamp_time("InitOverrideArtwork");
6642 InitArtworkIdentifier(); // needs to know current level directory
6643 print_timestamp_time("InitArtworkIdentifier");
6645 InitImages(); // needs to know current level directory
6646 print_timestamp_time("InitImages");
6648 InitSound(); // needs to know current level directory
6649 print_timestamp_time("InitSound");
6651 InitMusic(); // needs to know current level directory
6652 print_timestamp_time("InitMusic");
6656 InitGfxBackground();
6663 if (global.autoplay_leveldir)
6668 else if (global.patchtapes_leveldir)
6673 else if (global.convert_leveldir)
6678 else if (global.dumplevel_leveldir)
6683 else if (global.dumptape_leveldir)
6688 else if (global.create_sketch_images_dir)
6690 CreateLevelSketchImages();
6693 else if (global.create_collect_images_dir)
6695 CreateCollectElementImages();
6699 InitNetworkServer();
6701 SetGameStatus(GAME_MODE_MAIN);
6703 FadeSetEnterScreen();
6704 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6705 FadeSkipNextFadeOut();
6707 print_timestamp_time("[post-artwork]");
6709 print_timestamp_done("OpenAll");
6711 if (setup.ask_for_remaining_tapes)
6712 setup.ask_for_uploading_tapes = TRUE;
6717 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6719 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6720 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6721 #if defined(PLATFORM_ANDROID)
6722 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6723 SDL_AndroidGetInternalStoragePath());
6724 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6725 SDL_AndroidGetExternalStoragePath());
6726 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6727 (SDL_AndroidGetExternalStorageState() &
6728 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6729 SDL_AndroidGetExternalStorageState() &
6730 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6735 static boolean WaitForApiThreads(void)
6737 DelayCounter thread_delay = { 10000 };
6739 if (program.api_thread_count == 0)
6742 // deactivate global animations (not accessible in game state "loading")
6743 setup.global_animations = FALSE;
6745 // set game state to "loading" to be able to show busy animation
6746 SetGameStatus(GAME_MODE_LOADING);
6748 ResetDelayCounter(&thread_delay);
6750 // wait for threads to finish (and fail on timeout)
6751 while (program.api_thread_count > 0)
6753 if (DelayReached(&thread_delay))
6755 Error("failed waiting for threads - TIMEOUT");
6760 UPDATE_BUSY_STATE();
6768 void CloseAllAndExit(int exit_value)
6770 WaitForApiThreads();
6775 CloseAudio(); // called after freeing sounds (needed for SDL)
6784 // set a flag to tell the network server thread to quit and wait for it
6785 // using SDL_WaitThread()
6787 // Code used with SDL 1.2:
6788 // if (network.server_thread) // terminate network server
6789 // SDL_KillThread(network.server_thread);
6791 CloseVideoDisplay();
6792 ClosePlatformDependentStuff();
6794 if (exit_value != 0 && !options.execute_command)
6796 // fall back to default level set (current set may have caused an error)
6797 SaveLevelSetup_LastSeries_Deactivate();
6799 // tell user where to find error log file which may contain more details
6800 // (error notification now directly displayed on screen inside R'n'D
6801 // NotifyUserAboutErrorFile(); // currently only works for Windows