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_LOADING_INITIAL "background.LOADING_INITIAL"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
43 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
44 #define INITIAL_IMG_GLOBAL_BUSY 1
45 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD 2
47 #define NUM_INITIAL_IMAGES_BUSY 3
49 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 3
50 #define INITIAL_IMG_BACKGROUND_LOADING 4
52 #define NUM_INITIAL_IMAGES 5
55 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
56 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
58 static int copy_properties[][5] =
62 EL_BUG_LEFT, EL_BUG_RIGHT,
63 EL_BUG_UP, EL_BUG_DOWN
67 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
68 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
72 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
73 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
77 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
78 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
82 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
83 EL_PACMAN_UP, EL_PACMAN_DOWN
87 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
88 EL_YAMYAM_UP, EL_YAMYAM_DOWN
92 EL_MOLE_LEFT, EL_MOLE_RIGHT,
93 EL_MOLE_UP, EL_MOLE_DOWN
97 EL_SPRING_LEFT, EL_SPRING_RIGHT,
98 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
107 // forward declaration for internal use
108 static int get_graphic_parameter_value(char *, char *, int);
111 static void SetLoadingBackgroundImage(void)
113 struct GraphicInfo *graphic_info_last = graphic_info;
114 int background_image = (game_status_last_screen == -1 ?
115 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
116 INITIAL_IMG_BACKGROUND_LOADING);
118 graphic_info = image_initial;
120 SetDrawDeactivationMask(REDRAW_NONE);
121 SetDrawBackgroundMask(REDRAW_ALL);
123 SetWindowBackgroundImage(background_image);
125 graphic_info = graphic_info_last;
128 static void DrawInitAnim(boolean only_when_loading)
130 struct GraphicInfo *graphic_info_last = graphic_info;
131 int graphic = (game_status_last_screen == -1 ?
132 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
133 game_status == GAME_MODE_LOADING ?
134 INITIAL_IMG_GLOBAL_BUSY :
135 INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
136 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
137 &init_last.busy_initial :
138 game_status == GAME_MODE_LOADING ?
140 &init_last.busy_playfield);
141 static DelayCounter action_delay = { 0 };
142 int sync_frame = FrameCounter;
145 action_delay.value = GameFrameDelay;
147 // prevent OS (Windows) from complaining about program not responding
150 if (game_status != GAME_MODE_LOADING && only_when_loading)
153 if (image_initial[graphic].bitmap == NULL || window == NULL)
156 if (!DelayReached(&action_delay))
160 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
162 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
164 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
165 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
167 graphic_info = image_initial;
169 if (sync_frame % image_initial[graphic].anim_delay == 0)
173 int width = graphic_info[graphic].width;
174 int height = graphic_info[graphic].height;
175 int frame = getGraphicAnimationFrame(graphic, sync_frame);
177 ClearRectangleOnBackground(drawto, x, y, width, height);
179 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
180 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
182 BlitBitmap(drawto, window, x, y, width, height, x, y);
185 graphic_info = graphic_info_last;
190 static void DrawProgramInfo(void)
192 int font1_nr = FC_YELLOW;
193 int font2_nr = FC_RED;
194 int font2_height = getFontHeight(font2_nr);
197 int ypos3 = WIN_YSIZE - 20 - font2_height;
199 DrawInitText(getProgramInitString(), ypos1, font1_nr);
200 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
201 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
204 static void FreeGadgets(void)
206 FreeLevelEditorGadgets();
213 void InitGadgets(void)
215 static boolean gadgets_initialized = FALSE;
217 if (gadgets_initialized)
220 CreateLevelEditorGadgets();
224 CreateScreenGadgets();
226 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
228 gadgets_initialized = TRUE;
231 static void InitElementSmallImagesScaledUp(int graphic)
233 struct GraphicInfo *g = &graphic_info[graphic];
235 // create small and game tile sized bitmaps (and scale up, if needed)
236 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
239 static void InitElementSmallImages(void)
241 print_timestamp_init("InitElementSmallImages");
243 static int special_graphics[] =
257 IMG_EDITOR_ELEMENT_BORDER,
258 IMG_EDITOR_ELEMENT_BORDER_INPUT,
259 IMG_EDITOR_CASCADE_LIST,
260 IMG_EDITOR_CASCADE_LIST_ACTIVE,
263 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
264 int num_property_mappings = getImageListPropertyMappingSize();
267 print_timestamp_time("getImageListPropertyMapping/Size");
269 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
270 // initialize normal element images from static configuration
271 for (i = 0; element_to_graphic[i].element > -1; i++)
272 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
273 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
275 // initialize special element images from static configuration
276 for (i = 0; element_to_special_graphic[i].element > -1; i++)
277 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
278 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
280 // initialize element images from dynamic configuration
281 for (i = 0; i < num_property_mappings; i++)
282 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
283 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
284 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
286 // initialize special non-element images from above list
287 for (i = 0; special_graphics[i] > -1; i++)
288 InitElementSmallImagesScaledUp(special_graphics[i]);
289 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
291 print_timestamp_done("InitElementSmallImages");
294 static void InitScaledImagesScaledUp(int graphic)
296 struct GraphicInfo *g = &graphic_info[graphic];
298 ScaleImage(graphic, g->scale_up_factor);
301 static void InitScaledImages(void)
303 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
304 int num_property_mappings = getImageListPropertyMappingSize();
307 // scale normal images from static configuration, if not already scaled
308 for (i = 0; i < NUM_IMAGE_FILES; i++)
309 InitScaledImagesScaledUp(i);
311 // scale images from dynamic configuration, if not already scaled
312 for (i = 0; i < num_property_mappings; i++)
313 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
316 static void InitBitmapPointers(void)
318 int num_images = getImageListSize();
321 // standard size bitmap may have changed -- update default bitmap pointer
322 for (i = 0; i < num_images; i++)
323 if (graphic_info[i].bitmaps)
324 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
327 void InitImageTextures(void)
329 static int texture_graphics[] =
331 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
332 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
333 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
334 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
335 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
336 IMG_MENU_BUTTON_TOUCH_BACK,
337 IMG_MENU_BUTTON_TOUCH_NEXT,
338 IMG_MENU_BUTTON_TOUCH_BACK2,
339 IMG_MENU_BUTTON_TOUCH_NEXT2,
344 FreeAllImageTextures();
346 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
347 CreateImageTextures(i);
349 for (i = 0; i < MAX_NUM_TOONS; i++)
350 CreateImageTextures(IMG_TOON_1 + i);
352 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
354 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
356 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
358 int graphic = global_anim_info[i].graphic[j][k];
360 if (graphic == IMG_UNDEFINED)
363 CreateImageTextures(graphic);
368 for (i = 0; texture_graphics[i] > -1; i++)
369 CreateImageTextures(texture_graphics[i]);
372 static int getFontBitmapID(int font_nr)
376 // (special case: do not use special font for GAME_MODE_LOADING)
377 if (game_status >= GAME_MODE_TITLE_INITIAL &&
378 game_status <= GAME_MODE_PSEUDO_PREVIEW)
379 special = game_status;
380 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
381 special = GFX_SPECIAL_ARG_MAIN;
382 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
383 special = GFX_SPECIAL_ARG_NAMES;
386 return font_info[font_nr].special_bitmap_id[special];
391 static int getFontFromToken(char *token)
393 char *value = getHashEntry(font_token_hash, token);
398 // if font not found, use reliable default value
399 return FONT_INITIAL_1;
402 static void InitFontGraphicInfo(void)
404 static struct FontBitmapInfo *font_bitmap_info = NULL;
405 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
406 int num_property_mappings = getImageListPropertyMappingSize();
407 int num_font_bitmaps = NUM_FONTS;
410 if (graphic_info == NULL) // still at startup phase
412 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
413 getFontBitmapID, getFontFromToken);
418 // ---------- initialize font graphic definitions ----------
420 // always start with reliable default values (normal font graphics)
421 for (i = 0; i < NUM_FONTS; i++)
422 font_info[i].graphic = IMG_FONT_INITIAL_1;
424 // initialize normal font/graphic mapping from static configuration
425 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
427 int font_nr = font_to_graphic[i].font_nr;
428 int special = font_to_graphic[i].special;
429 int graphic = font_to_graphic[i].graphic;
434 font_info[font_nr].graphic = graphic;
437 // always start with reliable default values (special font graphics)
438 for (i = 0; i < NUM_FONTS; i++)
440 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
442 font_info[i].special_graphic[j] = font_info[i].graphic;
443 font_info[i].special_bitmap_id[j] = i;
447 // initialize special font/graphic mapping from static configuration
448 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
450 int font_nr = font_to_graphic[i].font_nr;
451 int special = font_to_graphic[i].special;
452 int graphic = font_to_graphic[i].graphic;
453 int base_graphic = font2baseimg(font_nr);
455 if (IS_SPECIAL_GFX_ARG(special))
457 boolean base_redefined =
458 getImageListEntryFromImageID(base_graphic)->redefined;
459 boolean special_redefined =
460 getImageListEntryFromImageID(graphic)->redefined;
461 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
463 /* if the base font ("font.title_1", for example) has been redefined,
464 but not the special font ("font.title_1.LEVELS", for example), do not
465 use an existing (in this case considered obsolete) special font
466 anymore, but use the automatically determined default font */
467 /* special case: cloned special fonts must be explicitly redefined,
468 but are not automatically redefined by redefining base font */
469 if (base_redefined && !special_redefined && !special_cloned)
472 font_info[font_nr].special_graphic[special] = graphic;
473 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
478 // initialize special font/graphic mapping from dynamic configuration
479 for (i = 0; i < num_property_mappings; i++)
481 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
482 int special = property_mapping[i].ext3_index;
483 int graphic = property_mapping[i].artwork_index;
485 if (font_nr < 0 || font_nr >= NUM_FONTS)
488 if (IS_SPECIAL_GFX_ARG(special))
490 font_info[font_nr].special_graphic[special] = graphic;
491 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
496 /* correct special font/graphic mapping for cloned fonts for downwards
497 compatibility of PREVIEW fonts -- this is only needed for implicit
498 redefinition of special font by redefined base font, and only if other
499 fonts are cloned from this special font (like in the "Zelda" level set) */
500 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
502 int font_nr = font_to_graphic[i].font_nr;
503 int special = font_to_graphic[i].special;
504 int graphic = font_to_graphic[i].graphic;
506 if (IS_SPECIAL_GFX_ARG(special))
508 boolean special_redefined =
509 getImageListEntryFromImageID(graphic)->redefined;
510 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
512 if (special_cloned && !special_redefined)
516 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
518 int font_nr2 = font_to_graphic[j].font_nr;
519 int special2 = font_to_graphic[j].special;
520 int graphic2 = font_to_graphic[j].graphic;
522 if (IS_SPECIAL_GFX_ARG(special2) &&
523 graphic2 == graphic_info[graphic].clone_from)
525 font_info[font_nr].special_graphic[special] =
526 font_info[font_nr2].special_graphic[special2];
527 font_info[font_nr].special_bitmap_id[special] =
528 font_info[font_nr2].special_bitmap_id[special2];
535 // reset non-redefined ".active" font graphics if normal font is redefined
536 // (this different treatment is needed because normal and active fonts are
537 // independently defined ("active" is not a property of font definitions!)
538 for (i = 0; i < NUM_FONTS; i++)
540 int font_nr_base = i;
541 int font_nr_active = FONT_ACTIVE(font_nr_base);
543 // check only those fonts with exist as normal and ".active" variant
544 if (font_nr_base != font_nr_active)
546 int base_graphic = font_info[font_nr_base].graphic;
547 int active_graphic = font_info[font_nr_active].graphic;
548 boolean base_redefined =
549 getImageListEntryFromImageID(base_graphic)->redefined;
550 boolean active_redefined =
551 getImageListEntryFromImageID(active_graphic)->redefined;
553 /* if the base font ("font.menu_1", for example) has been redefined,
554 but not the active font ("font.menu_1.active", for example), do not
555 use an existing (in this case considered obsolete) active font
556 anymore, but use the automatically determined default font */
557 if (base_redefined && !active_redefined)
558 font_info[font_nr_active].graphic = base_graphic;
560 // now also check each "special" font (which may be the same as above)
561 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
563 int base_graphic = font_info[font_nr_base].special_graphic[j];
564 int active_graphic = font_info[font_nr_active].special_graphic[j];
565 boolean base_redefined =
566 getImageListEntryFromImageID(base_graphic)->redefined;
567 boolean active_redefined =
568 getImageListEntryFromImageID(active_graphic)->redefined;
570 // same as above, but check special graphic definitions, for example:
571 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
572 if (base_redefined && !active_redefined)
574 font_info[font_nr_active].special_graphic[j] =
575 font_info[font_nr_base].special_graphic[j];
576 font_info[font_nr_active].special_bitmap_id[j] =
577 font_info[font_nr_base].special_bitmap_id[j];
583 // ---------- initialize font bitmap array ----------
585 if (font_bitmap_info != NULL)
586 FreeFontInfo(font_bitmap_info);
589 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
591 // ---------- initialize font bitmap definitions ----------
593 for (i = 0; i < NUM_FONTS; i++)
595 if (i < NUM_INITIAL_FONTS)
597 font_bitmap_info[i] = font_initial[i];
601 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
603 int font_bitmap_id = font_info[i].special_bitmap_id[j];
604 int graphic = font_info[i].special_graphic[j];
606 // set 'graphic_info' for font entries, if uninitialized (guessed)
607 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
609 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
610 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
613 // copy font relevant information from graphics information
614 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
615 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
616 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
617 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
618 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
620 font_bitmap_info[font_bitmap_id].offset_x =
621 graphic_info[graphic].offset_x;
622 font_bitmap_info[font_bitmap_id].offset_y =
623 graphic_info[graphic].offset_y;
625 font_bitmap_info[font_bitmap_id].draw_xoffset =
626 graphic_info[graphic].draw_xoffset;
627 font_bitmap_info[font_bitmap_id].draw_yoffset =
628 graphic_info[graphic].draw_yoffset;
630 font_bitmap_info[font_bitmap_id].num_chars =
631 graphic_info[graphic].anim_frames;
632 font_bitmap_info[font_bitmap_id].num_chars_per_line =
633 graphic_info[graphic].anim_frames_per_line;
637 InitFontInfo(font_bitmap_info, num_font_bitmaps,
638 getFontBitmapID, getFontFromToken);
641 static void InitGlobalAnimGraphicInfo(void)
643 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
644 int num_property_mappings = getImageListPropertyMappingSize();
647 if (graphic_info == NULL) // still at startup phase
650 // always start with reliable default values (no global animations)
651 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
652 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
653 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
654 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
656 // initialize global animation definitions from static configuration
657 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
659 int j = GLOBAL_ANIM_ID_PART_BASE;
660 int k = GFX_SPECIAL_ARG_DEFAULT;
662 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
665 // initialize global animation definitions from dynamic configuration
666 for (i = 0; i < num_property_mappings; i++)
668 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
669 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
670 int special = property_mapping[i].ext3_index;
671 int graphic = property_mapping[i].artwork_index;
673 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
676 // set animation part to base part, if not specified
677 if (!IS_GLOBAL_ANIM_PART(part_nr))
678 part_nr = GLOBAL_ANIM_ID_PART_BASE;
680 // set animation screen to default, if not specified
681 if (!IS_SPECIAL_GFX_ARG(special))
682 special = GFX_SPECIAL_ARG_DEFAULT;
684 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
686 // fix default value for ".draw_masked" (for backward compatibility)
687 struct GraphicInfo *g = &graphic_info[graphic];
688 struct FileInfo *image = getImageListEntryFromImageID(graphic);
689 char **parameter_raw = image->parameter;
690 int p = GFX_ARG_DRAW_MASKED;
691 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
692 image_config_suffix[p].token,
693 image_config_suffix[p].type);
695 // if ".draw_masked" parameter is undefined, use default value "TRUE"
696 if (draw_masked == ARG_UNDEFINED_VALUE)
697 g->draw_masked = TRUE;
701 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
702 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
703 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
704 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
705 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
706 Debug("init:InitGlobalAnimGraphicInfo",
707 "anim %d, part %d, mode %d => %d",
708 i, j, k, global_anim_info[i].graphic[j][k]);
712 static void InitGlobalAnimSoundInfo(void)
714 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
715 int num_property_mappings = getSoundListPropertyMappingSize();
718 // always start with reliable default values (no global animation sounds)
719 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
720 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
721 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
722 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
724 // initialize global animation sound definitions from dynamic configuration
725 for (i = 0; i < num_property_mappings; i++)
727 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
728 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
729 int special = property_mapping[i].ext3_index;
730 int sound = property_mapping[i].artwork_index;
732 // sound uses control definition; map it to position of graphic (artwork)
733 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
735 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
738 // set animation part to base part, if not specified
739 if (!IS_GLOBAL_ANIM_PART(part_nr))
740 part_nr = GLOBAL_ANIM_ID_PART_BASE;
742 // set animation screen to default, if not specified
743 if (!IS_SPECIAL_GFX_ARG(special))
744 special = GFX_SPECIAL_ARG_DEFAULT;
746 global_anim_info[anim_nr].sound[part_nr][special] = sound;
750 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
754 Debug("init:InitGlobalAnimSoundInfo",
755 "anim %d, part %d, mode %d => %d",
756 i, j, k, global_anim_info[i].sound[j][k]);
760 static void InitGlobalAnimMusicInfo(void)
762 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
763 int num_property_mappings = getMusicListPropertyMappingSize();
766 // always start with reliable default values (no global animation music)
767 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
768 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
769 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
770 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
772 // initialize global animation music definitions from dynamic configuration
773 for (i = 0; i < num_property_mappings; i++)
775 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
776 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
777 int special = property_mapping[i].ext2_index;
778 int music = property_mapping[i].artwork_index;
780 // music uses control definition; map it to position of graphic (artwork)
781 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
783 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
786 // set animation part to base part, if not specified
787 if (!IS_GLOBAL_ANIM_PART(part_nr))
788 part_nr = GLOBAL_ANIM_ID_PART_BASE;
790 // set animation screen to default, if not specified
791 if (!IS_SPECIAL_GFX_ARG(special))
792 special = GFX_SPECIAL_ARG_DEFAULT;
794 global_anim_info[anim_nr].music[part_nr][special] = music;
798 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
799 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
800 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
801 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
802 Debug("init:InitGlobalAnimMusicInfo",
803 "anim %d, part %d, mode %d => %d",
804 i, j, k, global_anim_info[i].music[j][k]);
808 static void InitElementGraphicInfo(void)
810 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
811 int num_property_mappings = getImageListPropertyMappingSize();
814 if (graphic_info == NULL) // still at startup phase
817 // set values to -1 to identify later as "uninitialized" values
818 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820 for (act = 0; act < NUM_ACTIONS; act++)
822 element_info[i].graphic[act] = -1;
823 element_info[i].crumbled[act] = -1;
825 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
827 element_info[i].direction_graphic[act][dir] = -1;
828 element_info[i].direction_crumbled[act][dir] = -1;
835 // initialize normal element/graphic mapping from static configuration
836 for (i = 0; element_to_graphic[i].element > -1; i++)
838 int element = element_to_graphic[i].element;
839 int action = element_to_graphic[i].action;
840 int direction = element_to_graphic[i].direction;
841 boolean crumbled = element_to_graphic[i].crumbled;
842 int graphic = element_to_graphic[i].graphic;
843 int base_graphic = el2baseimg(element);
845 if (graphic_info[graphic].bitmap == NULL)
848 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
851 boolean base_redefined =
852 getImageListEntryFromImageID(base_graphic)->redefined;
853 boolean act_dir_redefined =
854 getImageListEntryFromImageID(graphic)->redefined;
856 /* if the base graphic ("emerald", for example) has been redefined,
857 but not the action graphic ("emerald.falling", for example), do not
858 use an existing (in this case considered obsolete) action graphic
859 anymore, but use the automatically determined default graphic */
860 if (base_redefined && !act_dir_redefined)
865 action = ACTION_DEFAULT;
870 element_info[element].direction_crumbled[action][direction] = graphic;
872 element_info[element].crumbled[action] = graphic;
877 element_info[element].direction_graphic[action][direction] = graphic;
879 element_info[element].graphic[action] = graphic;
883 // initialize normal element/graphic mapping from dynamic configuration
884 for (i = 0; i < num_property_mappings; i++)
886 int element = property_mapping[i].base_index;
887 int action = property_mapping[i].ext1_index;
888 int direction = property_mapping[i].ext2_index;
889 int special = property_mapping[i].ext3_index;
890 int graphic = property_mapping[i].artwork_index;
891 boolean crumbled = FALSE;
893 if (special == GFX_SPECIAL_ARG_CRUMBLED)
899 if (graphic_info[graphic].bitmap == NULL)
902 if (element >= MAX_NUM_ELEMENTS || special != -1)
906 action = ACTION_DEFAULT;
911 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
912 element_info[element].direction_crumbled[action][dir] = -1;
915 element_info[element].direction_crumbled[action][direction] = graphic;
917 element_info[element].crumbled[action] = graphic;
922 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
923 element_info[element].direction_graphic[action][dir] = -1;
926 element_info[element].direction_graphic[action][direction] = graphic;
928 element_info[element].graphic[action] = graphic;
932 // now copy all graphics that are defined to be cloned from other graphics
933 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
935 int graphic = element_info[i].graphic[ACTION_DEFAULT];
936 int crumbled_like, diggable_like;
941 crumbled_like = graphic_info[graphic].crumbled_like;
942 diggable_like = graphic_info[graphic].diggable_like;
944 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
946 for (act = 0; act < NUM_ACTIONS; act++)
947 element_info[i].crumbled[act] =
948 element_info[crumbled_like].crumbled[act];
949 for (act = 0; act < NUM_ACTIONS; act++)
950 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
951 element_info[i].direction_crumbled[act][dir] =
952 element_info[crumbled_like].direction_crumbled[act][dir];
955 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
957 element_info[i].graphic[ACTION_DIGGING] =
958 element_info[diggable_like].graphic[ACTION_DIGGING];
959 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
960 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
961 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
965 // set hardcoded definitions for some runtime elements without graphic
966 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
968 // set hardcoded definitions for some internal elements without graphic
969 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
971 if (IS_EDITOR_CASCADE_INACTIVE(i))
972 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
973 else if (IS_EDITOR_CASCADE_ACTIVE(i))
974 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
977 // now set all undefined/invalid graphics to -1 to set to default after it
978 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
980 for (act = 0; act < NUM_ACTIONS; act++)
984 graphic = element_info[i].graphic[act];
985 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
986 element_info[i].graphic[act] = -1;
988 graphic = element_info[i].crumbled[act];
989 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
990 element_info[i].crumbled[act] = -1;
992 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
994 graphic = element_info[i].direction_graphic[act][dir];
995 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
996 element_info[i].direction_graphic[act][dir] = -1;
998 graphic = element_info[i].direction_crumbled[act][dir];
999 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1000 element_info[i].direction_crumbled[act][dir] = -1;
1005 UPDATE_BUSY_STATE();
1007 // adjust graphics with 2nd tile for movement according to direction
1008 // (do this before correcting '-1' values to minimize calculations)
1009 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1011 for (act = 0; act < NUM_ACTIONS; act++)
1013 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1015 int graphic = element_info[i].direction_graphic[act][dir];
1016 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1018 if (act == ACTION_FALLING) // special case
1019 graphic = element_info[i].graphic[act];
1021 if (graphic != -1 &&
1022 graphic_info[graphic].double_movement &&
1023 graphic_info[graphic].swap_double_tiles != 0)
1025 struct GraphicInfo *g = &graphic_info[graphic];
1026 int src_x_front = g->src_x;
1027 int src_y_front = g->src_y;
1028 int src_x_back = g->src_x + g->offset2_x;
1029 int src_y_back = g->src_y + g->offset2_y;
1030 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1032 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1033 src_y_front < src_y_back);
1034 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1035 boolean swap_movement_tiles_autodetected =
1036 (!frames_are_ordered_diagonally &&
1037 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1038 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1039 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1040 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1042 // swap frontside and backside graphic tile coordinates, if needed
1043 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1045 // get current (wrong) backside tile coordinates
1046 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1048 // set frontside tile coordinates to backside tile coordinates
1049 g->src_x = src_x_back;
1050 g->src_y = src_y_back;
1052 // invert tile offset to point to new backside tile coordinates
1056 // do not swap front and backside tiles again after correction
1057 g->swap_double_tiles = 0;
1064 UPDATE_BUSY_STATE();
1066 // now set all '-1' values to element specific default values
1067 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1069 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1070 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1071 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1072 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1074 if (default_graphic == -1)
1075 default_graphic = IMG_UNKNOWN;
1077 if (default_crumbled == -1)
1078 default_crumbled = default_graphic;
1080 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1082 default_direction_graphic[dir] =
1083 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1084 default_direction_crumbled[dir] =
1085 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1087 if (default_direction_graphic[dir] == -1)
1088 default_direction_graphic[dir] = default_graphic;
1090 if (default_direction_crumbled[dir] == -1)
1091 default_direction_crumbled[dir] = default_direction_graphic[dir];
1094 for (act = 0; act < NUM_ACTIONS; act++)
1096 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1097 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1098 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1099 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1100 act == ACTION_TURNING_FROM_RIGHT ||
1101 act == ACTION_TURNING_FROM_UP ||
1102 act == ACTION_TURNING_FROM_DOWN);
1104 // generic default action graphic (defined by "[default]" directive)
1105 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1106 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1107 int default_remove_graphic = IMG_EMPTY;
1109 if (act_remove && default_action_graphic != -1)
1110 default_remove_graphic = default_action_graphic;
1112 // look for special default action graphic (classic game specific)
1113 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1114 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1115 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1116 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1117 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1118 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1119 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1120 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1122 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1123 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1124 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1125 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1126 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1127 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1128 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1129 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1131 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1132 // !!! make this better !!!
1133 if (i == EL_EMPTY_SPACE)
1135 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1136 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1139 if (default_action_graphic == -1)
1140 default_action_graphic = default_graphic;
1142 if (default_action_crumbled == -1)
1143 default_action_crumbled = default_action_graphic;
1145 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1147 // use action graphic as the default direction graphic, if undefined
1148 int default_action_direction_graphic = element_info[i].graphic[act];
1149 int default_action_direction_crumbled = element_info[i].crumbled[act];
1151 // no graphic for current action -- use default direction graphic
1152 if (default_action_direction_graphic == -1)
1153 default_action_direction_graphic =
1154 (act_remove ? default_remove_graphic :
1156 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1157 default_action_graphic != default_graphic ?
1158 default_action_graphic :
1159 default_direction_graphic[dir]);
1161 if (element_info[i].direction_graphic[act][dir] == -1)
1162 element_info[i].direction_graphic[act][dir] =
1163 default_action_direction_graphic;
1165 if (default_action_direction_crumbled == -1)
1166 default_action_direction_crumbled =
1167 element_info[i].direction_graphic[act][dir];
1169 if (element_info[i].direction_crumbled[act][dir] == -1)
1170 element_info[i].direction_crumbled[act][dir] =
1171 default_action_direction_crumbled;
1174 // no graphic for this specific action -- use default action graphic
1175 if (element_info[i].graphic[act] == -1)
1176 element_info[i].graphic[act] =
1177 (act_remove ? default_remove_graphic :
1178 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1179 default_action_graphic);
1181 if (element_info[i].crumbled[act] == -1)
1182 element_info[i].crumbled[act] = element_info[i].graphic[act];
1186 UPDATE_BUSY_STATE();
1189 static void InitElementSpecialGraphicInfo(void)
1191 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1192 int num_property_mappings = getImageListPropertyMappingSize();
1195 // always start with reliable default values
1196 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1197 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1198 element_info[i].special_graphic[j] =
1199 element_info[i].graphic[ACTION_DEFAULT];
1201 // initialize special element/graphic mapping from static configuration
1202 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1204 int element = element_to_special_graphic[i].element;
1205 int special = element_to_special_graphic[i].special;
1206 int graphic = element_to_special_graphic[i].graphic;
1207 int base_graphic = el2baseimg(element);
1208 boolean base_redefined =
1209 getImageListEntryFromImageID(base_graphic)->redefined;
1210 boolean special_redefined =
1211 getImageListEntryFromImageID(graphic)->redefined;
1213 /* if the base graphic ("emerald", for example) has been redefined,
1214 but not the special graphic ("emerald.EDITOR", for example), do not
1215 use an existing (in this case considered obsolete) special graphic
1216 anymore, but use the automatically created (down-scaled) graphic */
1217 if (base_redefined && !special_redefined)
1220 element_info[element].special_graphic[special] = graphic;
1223 // initialize special element/graphic mapping from dynamic configuration
1224 for (i = 0; i < num_property_mappings; i++)
1226 int element = property_mapping[i].base_index;
1227 int action = property_mapping[i].ext1_index;
1228 int direction = property_mapping[i].ext2_index;
1229 int special = property_mapping[i].ext3_index;
1230 int graphic = property_mapping[i].artwork_index;
1232 // for action ".active", replace element with active element, if exists
1233 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1235 element = ELEMENT_ACTIVE(element);
1239 if (element >= MAX_NUM_ELEMENTS)
1242 // do not change special graphic if action or direction was specified
1243 if (action != -1 || direction != -1)
1246 if (IS_SPECIAL_GFX_ARG(special))
1247 element_info[element].special_graphic[special] = graphic;
1250 // now set all undefined/invalid graphics to default
1251 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1252 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1253 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1254 element_info[i].special_graphic[j] =
1255 element_info[i].graphic[ACTION_DEFAULT];
1258 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1260 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1261 return get_parameter_value(value_raw, suffix, type);
1263 if (strEqual(value_raw, ARG_UNDEFINED))
1264 return ARG_UNDEFINED_VALUE;
1266 if (type == TYPE_ELEMENT)
1268 char *value = getHashEntry(element_token_hash, value_raw);
1273 Warn("error found in config file:");
1274 Warn("- config file: '%s'", getImageConfigFilename());
1275 Warn("error: invalid element token '%s'", value_raw);
1276 Warn("custom graphic rejected for this element/action");
1277 Warn("fallback done to undefined element for this graphic");
1281 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1283 else if (type == TYPE_GRAPHIC)
1285 char *value = getHashEntry(graphic_token_hash, value_raw);
1286 int fallback_graphic = IMG_CHAR_EXCLAM;
1291 Warn("error found in config file:");
1292 Warn("- config file: '%s'", getImageConfigFilename());
1293 Warn("error: invalid graphic token '%s'", value_raw);
1294 Warn("custom graphic rejected for this element/action");
1295 Warn("fallback done to 'char_exclam' for this graphic");
1299 return (value != NULL ? atoi(value) : fallback_graphic);
1305 static int get_scaled_graphic_width(int graphic)
1307 int original_width = getOriginalImageWidthFromImageID(graphic);
1308 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1310 return original_width * scale_up_factor;
1313 static int get_scaled_graphic_height(int graphic)
1315 int original_height = getOriginalImageHeightFromImageID(graphic);
1316 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1318 return original_height * scale_up_factor;
1321 static void set_graphic_parameters_ext(int graphic, int *parameter,
1322 Bitmap **src_bitmaps)
1324 struct GraphicInfo *g = &graphic_info[graphic];
1325 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1326 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1327 int anim_frames_per_line = 1;
1329 // always start with reliable default values
1330 g->src_image_width = 0;
1331 g->src_image_height = 0;
1334 g->width = TILEX; // default for element graphics
1335 g->height = TILEY; // default for element graphics
1336 g->offset_x = 0; // one or both of these values ...
1337 g->offset_y = 0; // ... will be corrected later
1338 g->offset2_x = 0; // one or both of these values ...
1339 g->offset2_y = 0; // ... will be corrected later
1340 g->swap_double_tiles = -1; // auto-detect tile swapping
1341 g->crumbled_like = -1; // do not use clone element
1342 g->diggable_like = -1; // do not use clone element
1343 g->border_size = TILEX / 8; // "CRUMBLED" border size
1344 g->scale_up_factor = 1; // default: no scaling up
1345 g->tile_size = TILESIZE; // default: standard tile size
1346 g->clone_from = -1; // do not use clone graphic
1347 g->init_delay_fixed = 0;
1348 g->init_delay_random = 0;
1349 g->init_delay_action = -1;
1350 g->anim_delay_fixed = 0;
1351 g->anim_delay_random = 0;
1352 g->anim_delay_action = -1;
1353 g->post_delay_fixed = 0;
1354 g->post_delay_random = 0;
1355 g->post_delay_action = -1;
1356 g->init_event = ANIM_EVENT_UNDEFINED;
1357 g->anim_event = ANIM_EVENT_UNDEFINED;
1358 g->init_event_action = -1;
1359 g->anim_event_action = -1;
1360 g->draw_masked = FALSE;
1362 g->fade_mode = FADE_MODE_DEFAULT;
1366 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1367 g->align = ALIGN_CENTER; // default for title screens
1368 g->valign = VALIGN_MIDDLE; // default for title screens
1369 g->sort_priority = 0; // default for title screens
1371 g->style = STYLE_DEFAULT;
1373 g->bitmaps = src_bitmaps;
1374 g->bitmap = src_bitmap;
1376 // optional zoom factor for scaling up the image to a larger size
1377 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1378 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1379 if (g->scale_up_factor < 1)
1380 g->scale_up_factor = 1; // no scaling
1382 // optional tile size for using non-standard image size
1383 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1385 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1388 // CHECK: should tile sizes less than standard tile size be allowed?
1389 if (g->tile_size < TILESIZE)
1390 g->tile_size = TILESIZE; // standard tile size
1393 // when setting tile size, also set width and height accordingly
1394 g->width = g->tile_size;
1395 g->height = g->tile_size;
1398 if (g->use_image_size)
1400 // set new default bitmap size (with scaling, but without small images)
1401 g->width = get_scaled_graphic_width(graphic);
1402 g->height = get_scaled_graphic_height(graphic);
1405 // optional width and height of each animation frame
1406 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1407 g->width = parameter[GFX_ARG_WIDTH];
1408 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1409 g->height = parameter[GFX_ARG_HEIGHT];
1411 // optional x and y tile position of animation frame sequence
1412 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1413 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1414 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1415 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1417 // optional x and y pixel position of animation frame sequence
1418 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1419 g->src_x = parameter[GFX_ARG_X];
1420 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1421 g->src_y = parameter[GFX_ARG_Y];
1428 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1429 g->width, getTokenFromImageID(graphic), TILEX);
1432 g->width = TILEX; // will be checked to be inside bitmap later
1438 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1439 g->height, getTokenFromImageID(graphic), TILEY);
1442 g->height = TILEY; // will be checked to be inside bitmap later
1448 // get final bitmap size (with scaling, but without small images)
1449 int src_image_width = get_scaled_graphic_width(graphic);
1450 int src_image_height = get_scaled_graphic_height(graphic);
1452 if (src_image_width == 0 || src_image_height == 0)
1454 // only happens when loaded outside artwork system (like "global.busy")
1455 src_image_width = src_bitmap->width;
1456 src_image_height = src_bitmap->height;
1459 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1461 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1462 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1466 anim_frames_per_row = MAX(1, src_image_width / g->width);
1467 anim_frames_per_col = MAX(1, src_image_height / g->height);
1470 g->src_image_width = src_image_width;
1471 g->src_image_height = src_image_height;
1474 // correct x or y offset dependent of vertical or horizontal frame order
1475 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1477 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1478 parameter[GFX_ARG_OFFSET] : g->height);
1479 anim_frames_per_line = anim_frames_per_col;
1481 else // frames are ordered horizontally
1483 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1484 parameter[GFX_ARG_OFFSET] : g->width);
1485 anim_frames_per_line = anim_frames_per_row;
1488 // optionally, the x and y offset of frames can be specified directly
1489 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1490 g->offset_x = parameter[GFX_ARG_XOFFSET];
1491 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1492 g->offset_y = parameter[GFX_ARG_YOFFSET];
1494 // optionally, moving animations may have separate start and end graphics
1495 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1497 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1498 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1500 // correct x or y offset2 dependent of vertical or horizontal frame order
1501 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1502 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1503 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1504 else // frames are ordered horizontally
1505 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1506 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1508 // optionally, the x and y offset of 2nd graphic can be specified directly
1509 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1510 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1511 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1512 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1514 // optionally, the second movement tile can be specified as start tile
1515 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1516 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1518 // automatically determine correct number of frames, if not defined
1519 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1520 g->anim_frames = parameter[GFX_ARG_FRAMES];
1521 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1522 g->anim_frames = anim_frames_per_row;
1523 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1524 g->anim_frames = anim_frames_per_col;
1528 if (g->anim_frames < 1) // frames must be at least 1
1531 g->anim_frames_per_line =
1532 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1533 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1535 g->anim_delay = parameter[GFX_ARG_DELAY];
1536 if (g->anim_delay < 1) // delay must be at least 1
1539 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1541 // automatically determine correct start frame, if not defined
1542 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1543 g->anim_start_frame = 0;
1544 else if (g->anim_mode & ANIM_REVERSE)
1545 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1547 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1549 // animation synchronized with global frame counter, not move position
1550 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1552 // optional element for cloning crumble graphics
1553 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1554 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1556 // optional element for cloning digging graphics
1557 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1558 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1560 // optional border size for "crumbling" diggable graphics
1561 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1562 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1564 // used for global animations and player "boring" and "sleeping" actions
1565 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1566 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1567 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1568 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1569 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1570 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1571 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1572 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1573 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1574 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1575 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1576 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1578 // used for global animations
1579 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1580 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1581 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1582 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1583 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1584 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1585 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1586 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1587 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1588 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1589 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1590 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1591 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1592 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1594 // used for toon animations and global animations
1595 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1596 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1597 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1598 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1599 g->direction = parameter[GFX_ARG_DIRECTION];
1600 g->position = parameter[GFX_ARG_POSITION];
1601 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1602 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1604 if (g->step_delay < 1) // delay must be at least 1
1607 // this is only used for drawing font characters
1608 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1609 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1611 // use a different default value for global animations and toons
1612 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1613 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1614 g->draw_masked = TRUE;
1616 // this is used for drawing envelopes, global animations and toons
1617 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1618 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1620 // used for toon animations and global animations
1621 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1622 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1624 // optional graphic for cloning all graphics settings
1625 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1626 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1628 // optional settings for drawing title screens and title messages
1629 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1630 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1631 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1632 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1633 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1634 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1635 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1636 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1637 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1638 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1639 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1640 g->align = parameter[GFX_ARG_ALIGN];
1641 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1642 g->valign = parameter[GFX_ARG_VALIGN];
1643 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1644 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1646 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1647 g->class = parameter[GFX_ARG_CLASS];
1648 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1649 g->style = parameter[GFX_ARG_STYLE];
1651 // this is only used for drawing menu buttons and text
1652 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1653 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1654 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1655 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1658 static void set_graphic_parameters(int graphic)
1660 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1661 char **parameter_raw = image->parameter;
1662 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1663 int parameter[NUM_GFX_ARGS];
1666 // if fallback to default artwork is done, also use the default parameters
1667 if (image->fallback_to_default)
1668 parameter_raw = image->default_parameter;
1670 // get integer values from string parameters
1671 for (i = 0; i < NUM_GFX_ARGS; i++)
1672 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1673 image_config_suffix[i].token,
1674 image_config_suffix[i].type);
1676 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1678 UPDATE_BUSY_STATE();
1681 static void set_cloned_graphic_parameters(int graphic)
1683 int fallback_graphic = IMG_CHAR_EXCLAM;
1684 int max_num_images = getImageListSize();
1685 int clone_graphic = graphic_info[graphic].clone_from;
1686 int num_references_followed = 1;
1688 while (graphic_info[clone_graphic].clone_from != -1 &&
1689 num_references_followed < max_num_images)
1691 clone_graphic = graphic_info[clone_graphic].clone_from;
1693 num_references_followed++;
1696 if (num_references_followed >= max_num_images)
1699 Warn("error found in config file:");
1700 Warn("- config file: '%s'", getImageConfigFilename());
1701 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1702 Warn("error: loop discovered when resolving cloned graphics");
1703 Warn("custom graphic rejected for this element/action");
1705 if (graphic == fallback_graphic)
1706 Fail("no fallback graphic available");
1708 Warn("fallback done to 'char_exclam' for this graphic");
1711 graphic_info[graphic] = graphic_info[fallback_graphic];
1715 graphic_info[graphic] = graphic_info[clone_graphic];
1716 graphic_info[graphic].clone_from = clone_graphic;
1720 static void InitGraphicInfo(void)
1722 int fallback_graphic = IMG_CHAR_EXCLAM;
1723 int num_images = getImageListSize();
1726 // use image size as default values for width and height for these images
1727 static int full_size_graphics[] =
1730 IMG_GLOBAL_BORDER_MAIN,
1731 IMG_GLOBAL_BORDER_SCORES,
1732 IMG_GLOBAL_BORDER_EDITOR,
1733 IMG_GLOBAL_BORDER_PLAYING,
1736 IMG_BACKGROUND_ENVELOPE_1,
1737 IMG_BACKGROUND_ENVELOPE_2,
1738 IMG_BACKGROUND_ENVELOPE_3,
1739 IMG_BACKGROUND_ENVELOPE_4,
1740 IMG_BACKGROUND_REQUEST,
1743 IMG_BACKGROUND_LOADING_INITIAL,
1744 IMG_BACKGROUND_LOADING,
1745 IMG_BACKGROUND_TITLE_INITIAL,
1746 IMG_BACKGROUND_TITLE,
1747 IMG_BACKGROUND_MAIN,
1748 IMG_BACKGROUND_NAMES,
1749 IMG_BACKGROUND_LEVELS,
1750 IMG_BACKGROUND_LEVELNR,
1751 IMG_BACKGROUND_SCORES,
1752 IMG_BACKGROUND_SCOREINFO,
1753 IMG_BACKGROUND_EDITOR,
1754 IMG_BACKGROUND_INFO,
1755 IMG_BACKGROUND_INFO_ELEMENTS,
1756 IMG_BACKGROUND_INFO_MUSIC,
1757 IMG_BACKGROUND_INFO_CREDITS,
1758 IMG_BACKGROUND_INFO_PROGRAM,
1759 IMG_BACKGROUND_INFO_VERSION,
1760 IMG_BACKGROUND_INFO_LEVELSET,
1761 IMG_BACKGROUND_SETUP,
1762 IMG_BACKGROUND_PLAYING,
1763 IMG_BACKGROUND_DOOR,
1764 IMG_BACKGROUND_TAPE,
1765 IMG_BACKGROUND_PANEL,
1766 IMG_BACKGROUND_PALETTE,
1767 IMG_BACKGROUND_TOOLBOX,
1769 IMG_TITLESCREEN_INITIAL_1,
1770 IMG_TITLESCREEN_INITIAL_2,
1771 IMG_TITLESCREEN_INITIAL_3,
1772 IMG_TITLESCREEN_INITIAL_4,
1773 IMG_TITLESCREEN_INITIAL_5,
1780 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1781 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1782 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1783 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1784 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1785 IMG_BACKGROUND_TITLEMESSAGE_1,
1786 IMG_BACKGROUND_TITLEMESSAGE_2,
1787 IMG_BACKGROUND_TITLEMESSAGE_3,
1788 IMG_BACKGROUND_TITLEMESSAGE_4,
1789 IMG_BACKGROUND_TITLEMESSAGE_5,
1794 FreeGlobalAnimEventInfo();
1796 checked_free(graphic_info);
1798 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1800 // initialize "use_image_size" flag with default value
1801 for (i = 0; i < num_images; i++)
1802 graphic_info[i].use_image_size = FALSE;
1804 // initialize "use_image_size" flag from static configuration above
1805 for (i = 0; full_size_graphics[i] != -1; i++)
1806 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1808 // first set all graphic paramaters ...
1809 for (i = 0; i < num_images; i++)
1810 set_graphic_parameters(i);
1812 // ... then copy these parameters for cloned graphics
1813 for (i = 0; i < num_images; i++)
1814 if (graphic_info[i].clone_from != -1)
1815 set_cloned_graphic_parameters(i);
1817 for (i = 0; i < num_images; i++)
1819 Bitmap *src_bitmap = graphic_info[i].bitmap;
1823 int src_bitmap_width, src_bitmap_height;
1825 // now check if no animation frames are outside of the loaded image
1827 if (graphic_info[i].bitmap == NULL)
1828 continue; // skip check for optional images that are undefined
1830 // get image size (this can differ from the standard element tile size!)
1831 width = graphic_info[i].width;
1832 height = graphic_info[i].height;
1834 // get final bitmap size (with scaling, but without small images)
1835 src_bitmap_width = graphic_info[i].src_image_width;
1836 src_bitmap_height = graphic_info[i].src_image_height;
1838 // check if first animation frame is inside specified bitmap
1840 // do not use getGraphicSourceXY() here to get position of first frame;
1841 // this avoids calculating wrong start position for out-of-bounds frame
1842 src_x = graphic_info[i].src_x;
1843 src_y = graphic_info[i].src_y;
1845 if (program.headless)
1848 if (src_x < 0 || src_y < 0 ||
1849 src_x + width > src_bitmap_width ||
1850 src_y + height > src_bitmap_height)
1853 Warn("error found in config file:");
1854 Warn("- config file: '%s'", getImageConfigFilename());
1855 Warn("- config token: '%s'", getTokenFromImageID(i));
1856 Warn("- image file: '%s'", src_bitmap->source_filename);
1857 Warn("- frame size: %d, %d", width, height);
1858 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1859 src_x, src_y, src_bitmap_width, src_bitmap_height);
1860 Warn("custom graphic rejected for this element/action");
1862 if (i == fallback_graphic)
1863 Fail("no fallback graphic available");
1865 Warn("fallback done to 'char_exclam' for this graphic");
1868 graphic_info[i] = graphic_info[fallback_graphic];
1870 // if first frame out of bounds, do not check last frame anymore
1874 // check if last animation frame is inside specified bitmap
1876 last_frame = graphic_info[i].anim_frames - 1;
1877 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1879 if (src_x < 0 || src_y < 0 ||
1880 src_x + width > src_bitmap_width ||
1881 src_y + height > src_bitmap_height)
1884 Warn("error found in config file:");
1885 Warn("- config file: '%s'", getImageConfigFilename());
1886 Warn("- config token: '%s'", getTokenFromImageID(i));
1887 Warn("- image file: '%s'", src_bitmap->source_filename);
1888 Warn("- frame size: %d, %d", width, height);
1889 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1890 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1891 Warn("custom graphic rejected for this element/action");
1893 if (i == fallback_graphic)
1894 Fail("no fallback graphic available");
1896 Warn("fallback done to 'char_exclam' for this graphic");
1899 graphic_info[i] = graphic_info[fallback_graphic];
1904 static void InitGraphicCompatibilityInfo(void)
1906 struct FileInfo *fi_global_door =
1907 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1908 int num_images = getImageListSize();
1911 /* the following compatibility handling is needed for the following case:
1912 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1913 graphics mainly used for door and panel graphics, like editor, tape and
1914 in-game buttons with hard-coded bitmap positions and button sizes; as
1915 these graphics now have individual definitions, redefining "global.door"
1916 to change all these graphics at once like before does not work anymore
1917 (because all those individual definitions still have their default values);
1918 to solve this, remap all those individual definitions that are not
1919 redefined to the new bitmap of "global.door" if it was redefined */
1921 // special compatibility handling if image "global.door" was redefined
1922 if (fi_global_door->redefined)
1924 for (i = 0; i < num_images; i++)
1926 struct FileInfo *fi = getImageListEntryFromImageID(i);
1928 // process only those images that still use the default settings
1931 // process all images which default to same image as "global.door"
1932 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1934 // skip all images that are cloned from images that default to same
1935 // image as "global.door", but that are redefined to something else
1936 if (graphic_info[i].clone_from != -1)
1938 int cloned_graphic = graphic_info[i].clone_from;
1940 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
1945 Debug("init:InitGraphicCompatibilityInfo",
1946 "special treatment needed for token '%s'", fi->token);
1949 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1950 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1956 // special compatibility handling for "Snake Bite" graphics set
1957 if (strPrefix(leveldir_current->identifier, "snake_bite"))
1959 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
1961 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
1962 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
1964 ClearRectangle(bitmap, 2, 66, 32, 480);
1965 ClearRectangle(bitmap, 514, 66, 32, 480);
1968 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
1969 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
1970 if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
1988 int mode_old = GAME_MODE_SCORES;
1989 int mode_new = GAME_MODE_SCOREINFO;
1992 // adjust title screens on score info page
1993 for (i = 0; font_title[i] != -1; i++)
1995 struct FontInfo *fi = &font_info[font_title[i]];
1997 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
1998 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2001 // adjust vertical text and button positions on scores page
2002 for (i = 0; font_text[i] != -1; i++)
2004 for (j = 0; j < 2; j++)
2006 boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2007 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2008 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2009 int font_yoffset = (jue0 ? 10 : 5);
2011 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2015 // adjust page offsets on score info page
2016 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2017 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2020 InitGraphicCompatibilityInfo_Doors();
2023 static void InitElementSoundInfo(void)
2025 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2026 int num_property_mappings = getSoundListPropertyMappingSize();
2029 // set values to -1 to identify later as "uninitialized" values
2030 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2031 for (act = 0; act < NUM_ACTIONS; act++)
2032 element_info[i].sound[act] = -1;
2034 // initialize element/sound mapping from static configuration
2035 for (i = 0; element_to_sound[i].element > -1; i++)
2037 int element = element_to_sound[i].element;
2038 int action = element_to_sound[i].action;
2039 int sound = element_to_sound[i].sound;
2040 boolean is_class = element_to_sound[i].is_class;
2043 action = ACTION_DEFAULT;
2046 element_info[element].sound[action] = sound;
2048 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2049 if (strEqual(element_info[j].class_name,
2050 element_info[element].class_name))
2051 element_info[j].sound[action] = sound;
2054 // initialize element class/sound mapping from dynamic configuration
2055 for (i = 0; i < num_property_mappings; i++)
2057 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2058 int action = property_mapping[i].ext1_index;
2059 int sound = property_mapping[i].artwork_index;
2061 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2065 action = ACTION_DEFAULT;
2067 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2068 if (strEqual(element_info[j].class_name,
2069 element_info[element_class].class_name))
2070 element_info[j].sound[action] = sound;
2073 // initialize element/sound mapping from dynamic configuration
2074 for (i = 0; i < num_property_mappings; i++)
2076 int element = property_mapping[i].base_index;
2077 int action = property_mapping[i].ext1_index;
2078 int sound = property_mapping[i].artwork_index;
2080 if (element >= MAX_NUM_ELEMENTS)
2084 action = ACTION_DEFAULT;
2086 element_info[element].sound[action] = sound;
2089 // now set all '-1' values to element specific default values
2090 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2092 for (act = 0; act < NUM_ACTIONS; act++)
2094 // generic default action sound (defined by "[default]" directive)
2095 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2097 // look for special default action sound (classic game specific)
2098 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2099 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2100 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2101 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2102 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2103 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2104 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2105 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2107 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2108 // !!! make this better !!!
2109 if (i == EL_EMPTY_SPACE)
2110 default_action_sound = element_info[EL_DEFAULT].sound[act];
2112 // no sound for this specific action -- use default action sound
2113 if (element_info[i].sound[act] == -1)
2114 element_info[i].sound[act] = default_action_sound;
2118 // copy sound settings to some elements that are only stored in level file
2119 // in native R'n'D levels, but are used by game engine in native EM levels
2120 for (i = 0; copy_properties[i][0] != -1; i++)
2121 for (j = 1; j <= 4; j++)
2122 for (act = 0; act < NUM_ACTIONS; act++)
2123 element_info[copy_properties[i][j]].sound[act] =
2124 element_info[copy_properties[i][0]].sound[act];
2127 static void InitGameModeSoundInfo(void)
2131 // set values to -1 to identify later as "uninitialized" values
2132 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2135 // initialize gamemode/sound mapping from static configuration
2136 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2138 int gamemode = gamemode_to_sound[i].gamemode;
2139 int sound = gamemode_to_sound[i].sound;
2142 gamemode = GAME_MODE_DEFAULT;
2144 menu.sound[gamemode] = sound;
2147 // now set all '-1' values to levelset specific default values
2148 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2149 if (menu.sound[i] == -1)
2150 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2153 static void set_sound_parameters(int sound, char **parameter_raw)
2155 int parameter[NUM_SND_ARGS];
2158 // get integer values from string parameters
2159 for (i = 0; i < NUM_SND_ARGS; i++)
2161 get_parameter_value(parameter_raw[i],
2162 sound_config_suffix[i].token,
2163 sound_config_suffix[i].type);
2165 // explicit loop mode setting in configuration overrides default value
2166 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2167 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2169 // sound volume to change the original volume when loading the sound file
2170 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2172 // sound priority to give certain sounds a higher or lower priority
2173 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2176 static void InitSoundInfo(void)
2178 int *sound_effect_properties;
2179 int num_sounds = getSoundListSize();
2182 checked_free(sound_info);
2184 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2185 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2187 // initialize sound effect for all elements to "no sound"
2188 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2189 for (j = 0; j < NUM_ACTIONS; j++)
2190 element_info[i].sound[j] = SND_UNDEFINED;
2192 for (i = 0; i < num_sounds; i++)
2194 struct FileInfo *sound = getSoundListEntry(i);
2195 int len_effect_text = strlen(sound->token);
2197 sound_effect_properties[i] = ACTION_OTHER;
2198 sound_info[i].loop = FALSE; // default: play sound only once
2200 // determine all loop sounds and identify certain sound classes
2202 for (j = 0; element_action_info[j].suffix; j++)
2204 int len_action_text = strlen(element_action_info[j].suffix);
2206 if (len_action_text < len_effect_text &&
2207 strEqual(&sound->token[len_effect_text - len_action_text],
2208 element_action_info[j].suffix))
2210 sound_effect_properties[i] = element_action_info[j].value;
2211 sound_info[i].loop = element_action_info[j].is_loop_sound;
2217 // associate elements and some selected sound actions
2219 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2221 if (element_info[j].class_name)
2223 int len_class_text = strlen(element_info[j].class_name);
2225 if (len_class_text + 1 < len_effect_text &&
2226 strncmp(sound->token,
2227 element_info[j].class_name, len_class_text) == 0 &&
2228 sound->token[len_class_text] == '.')
2230 int sound_action_value = sound_effect_properties[i];
2232 element_info[j].sound[sound_action_value] = i;
2237 set_sound_parameters(i, sound->parameter);
2240 free(sound_effect_properties);
2243 static void InitGameModeMusicInfo(void)
2245 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2246 int num_property_mappings = getMusicListPropertyMappingSize();
2247 int default_levelset_music = -1;
2250 // set values to -1 to identify later as "uninitialized" values
2251 for (i = 0; i < MAX_LEVELS; i++)
2252 levelset.music[i] = -1;
2253 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2256 // initialize gamemode/music mapping from static configuration
2257 for (i = 0; gamemode_to_music[i].music > -1; i++)
2259 int gamemode = gamemode_to_music[i].gamemode;
2260 int music = gamemode_to_music[i].music;
2263 gamemode = GAME_MODE_DEFAULT;
2265 menu.music[gamemode] = music;
2268 // initialize gamemode/music mapping from dynamic configuration
2269 for (i = 0; i < num_property_mappings; i++)
2271 int prefix = property_mapping[i].base_index;
2272 int gamemode = property_mapping[i].ext2_index;
2273 int level = property_mapping[i].ext3_index;
2274 int music = property_mapping[i].artwork_index;
2276 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2280 gamemode = GAME_MODE_DEFAULT;
2282 // level specific music only allowed for in-game music
2283 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2284 gamemode = GAME_MODE_PLAYING;
2289 default_levelset_music = music;
2292 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2293 levelset.music[level] = music;
2294 if (gamemode != GAME_MODE_PLAYING)
2295 menu.music[gamemode] = music;
2298 // now set all '-1' values to menu specific default values
2299 // (undefined values of "levelset.music[]" might stay at "-1" to
2300 // allow dynamic selection of music files from music directory!)
2301 for (i = 0; i < MAX_LEVELS; i++)
2302 if (levelset.music[i] == -1)
2303 levelset.music[i] = default_levelset_music;
2304 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2305 if (menu.music[i] == -1)
2306 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2309 static void set_music_parameters(int music, char **parameter_raw)
2311 int parameter[NUM_MUS_ARGS];
2314 // get integer values from string parameters
2315 for (i = 0; i < NUM_MUS_ARGS; i++)
2317 get_parameter_value(parameter_raw[i],
2318 music_config_suffix[i].token,
2319 music_config_suffix[i].type);
2321 // explicit loop mode setting in configuration overrides default value
2322 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2323 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2326 static void InitMusicInfo(void)
2328 int num_music = getMusicListSize();
2331 checked_free(music_info);
2333 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2335 for (i = 0; i < num_music; i++)
2337 struct FileInfo *music = getMusicListEntry(i);
2338 int len_music_text = strlen(music->token);
2340 music_info[i].loop = TRUE; // default: play music in loop mode
2342 // determine all loop music
2344 for (j = 0; music_prefix_info[j].prefix; j++)
2346 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2348 if (len_prefix_text < len_music_text &&
2349 strncmp(music->token,
2350 music_prefix_info[j].prefix, len_prefix_text) == 0)
2352 music_info[i].loop = music_prefix_info[j].is_loop_music;
2358 set_music_parameters(i, music->parameter);
2363 static void InitGameInfoFromArtworkInfo(void)
2365 // special case: store initial value of custom artwork setting
2366 game.use_masked_elements_initial = game.use_masked_elements;
2369 static void ReinitializeGraphics(void)
2371 print_timestamp_init("ReinitializeGraphics");
2373 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2375 InitGraphicInfo(); // graphic properties mapping
2376 print_timestamp_time("InitGraphicInfo");
2377 InitElementGraphicInfo(); // element game graphic mapping
2378 print_timestamp_time("InitElementGraphicInfo");
2379 InitElementSpecialGraphicInfo(); // element special graphic mapping
2380 print_timestamp_time("InitElementSpecialGraphicInfo");
2382 InitElementSmallImages(); // scale elements to all needed sizes
2383 print_timestamp_time("InitElementSmallImages");
2384 InitScaledImages(); // scale all other images, if needed
2385 print_timestamp_time("InitScaledImages");
2386 InitBitmapPointers(); // set standard size bitmap pointers
2387 print_timestamp_time("InitBitmapPointers");
2388 InitFontGraphicInfo(); // initialize text drawing functions
2389 print_timestamp_time("InitFontGraphicInfo");
2390 InitGlobalAnimGraphicInfo(); // initialize global animation config
2391 print_timestamp_time("InitGlobalAnimGraphicInfo");
2393 InitImageTextures(); // create textures for certain images
2394 print_timestamp_time("InitImageTextures");
2396 InitGraphicInfo_EM(); // graphic mapping for EM engine
2397 print_timestamp_time("InitGraphicInfo_EM");
2399 InitGraphicCompatibilityInfo();
2400 print_timestamp_time("InitGraphicCompatibilityInfo");
2403 print_timestamp_time("InitGadgets");
2405 print_timestamp_time("InitDoors");
2407 InitGameInfoFromArtworkInfo();
2409 print_timestamp_done("ReinitializeGraphics");
2412 static void ReinitializeSounds(void)
2414 InitSoundInfo(); // sound properties mapping
2415 InitElementSoundInfo(); // element game sound mapping
2416 InitGameModeSoundInfo(); // game mode sound mapping
2417 InitGlobalAnimSoundInfo(); // global animation sound settings
2419 InitPlayLevelSound(); // internal game sound settings
2422 static void ReinitializeMusic(void)
2424 InitMusicInfo(); // music properties mapping
2425 InitGameModeMusicInfo(); // game mode music mapping
2426 InitGlobalAnimMusicInfo(); // global animation music settings
2429 static int get_special_property_bit(int element, int property_bit_nr)
2431 struct PropertyBitInfo
2437 static struct PropertyBitInfo pb_can_move_into_acid[] =
2439 // the player may be able fall into acid when gravity is activated
2444 { EL_SP_MURPHY, 0 },
2445 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2447 // all elements that can move may be able to also move into acid
2450 { EL_BUG_RIGHT, 1 },
2453 { EL_SPACESHIP, 2 },
2454 { EL_SPACESHIP_LEFT, 2 },
2455 { EL_SPACESHIP_RIGHT, 2 },
2456 { EL_SPACESHIP_UP, 2 },
2457 { EL_SPACESHIP_DOWN, 2 },
2458 { EL_BD_BUTTERFLY, 3 },
2459 { EL_BD_BUTTERFLY_LEFT, 3 },
2460 { EL_BD_BUTTERFLY_RIGHT, 3 },
2461 { EL_BD_BUTTERFLY_UP, 3 },
2462 { EL_BD_BUTTERFLY_DOWN, 3 },
2463 { EL_BD_FIREFLY, 4 },
2464 { EL_BD_FIREFLY_LEFT, 4 },
2465 { EL_BD_FIREFLY_RIGHT, 4 },
2466 { EL_BD_FIREFLY_UP, 4 },
2467 { EL_BD_FIREFLY_DOWN, 4 },
2469 { EL_YAMYAM_LEFT, 5 },
2470 { EL_YAMYAM_RIGHT, 5 },
2471 { EL_YAMYAM_UP, 5 },
2472 { EL_YAMYAM_DOWN, 5 },
2473 { EL_DARK_YAMYAM, 6 },
2476 { EL_PACMAN_LEFT, 8 },
2477 { EL_PACMAN_RIGHT, 8 },
2478 { EL_PACMAN_UP, 8 },
2479 { EL_PACMAN_DOWN, 8 },
2481 { EL_MOLE_LEFT, 9 },
2482 { EL_MOLE_RIGHT, 9 },
2484 { EL_MOLE_DOWN, 9 },
2488 { EL_SATELLITE, 13 },
2489 { EL_SP_SNIKSNAK, 14 },
2490 { EL_SP_ELECTRON, 15 },
2493 { EL_SPRING_LEFT, 17 },
2494 { EL_SPRING_RIGHT, 17 },
2495 { EL_EMC_ANDROID, 18 },
2500 static struct PropertyBitInfo pb_dont_collide_with[] =
2502 { EL_SP_SNIKSNAK, 0 },
2503 { EL_SP_ELECTRON, 1 },
2511 struct PropertyBitInfo *pb_info;
2514 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2515 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2520 struct PropertyBitInfo *pb_info = NULL;
2523 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2524 if (pb_definition[i].bit_nr == property_bit_nr)
2525 pb_info = pb_definition[i].pb_info;
2527 if (pb_info == NULL)
2530 for (i = 0; pb_info[i].element != -1; i++)
2531 if (pb_info[i].element == element)
2532 return pb_info[i].bit_nr;
2537 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2538 boolean property_value)
2540 int bit_nr = get_special_property_bit(element, property_bit_nr);
2545 *bitfield |= (1 << bit_nr);
2547 *bitfield &= ~(1 << bit_nr);
2551 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2553 int bit_nr = get_special_property_bit(element, property_bit_nr);
2556 return ((*bitfield & (1 << bit_nr)) != 0);
2561 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2563 static int group_nr;
2564 static struct ElementGroupInfo *group;
2565 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2568 if (actual_group == NULL) // not yet initialized
2571 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2573 Warn("recursion too deep when resolving group element %d",
2574 group_element - EL_GROUP_START + 1);
2576 // replace element which caused too deep recursion by question mark
2577 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2582 if (recursion_depth == 0) // initialization
2584 group = actual_group;
2585 group_nr = GROUP_NR(group_element);
2587 group->num_elements_resolved = 0;
2588 group->choice_pos = 0;
2590 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2591 element_info[i].in_group[group_nr] = FALSE;
2594 for (i = 0; i < actual_group->num_elements; i++)
2596 int element = actual_group->element[i];
2598 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2601 if (IS_GROUP_ELEMENT(element))
2602 ResolveGroupElementExt(element, recursion_depth + 1);
2605 group->element_resolved[group->num_elements_resolved++] = element;
2606 element_info[element].in_group[group_nr] = TRUE;
2611 void ResolveGroupElement(int group_element)
2613 ResolveGroupElementExt(group_element, 0);
2616 void InitElementPropertiesStatic(void)
2618 static boolean clipboard_elements_initialized = FALSE;
2620 static int ep_diggable[] =
2625 EL_SP_BUGGY_BASE_ACTIVATING,
2628 EL_INVISIBLE_SAND_ACTIVE,
2631 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2632 // (if amoeba can grow into anything diggable, maybe keep these out)
2637 EL_SP_BUGGY_BASE_ACTIVE,
2644 static int ep_collectible_only[] =
2666 EL_DYNABOMB_INCREASE_NUMBER,
2667 EL_DYNABOMB_INCREASE_SIZE,
2668 EL_DYNABOMB_INCREASE_POWER,
2686 // !!! handle separately !!!
2687 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2693 static int ep_dont_run_into[] =
2695 // same elements as in 'ep_dont_touch'
2701 // same elements as in 'ep_dont_collide_with'
2713 // !!! maybe this should better be handled by 'ep_diggable' !!!
2718 EL_SP_BUGGY_BASE_ACTIVE,
2725 static int ep_dont_collide_with[] =
2727 // same elements as in 'ep_dont_touch'
2744 static int ep_dont_touch[] =
2754 static int ep_indestructible[] =
2758 EL_ACID_POOL_TOPLEFT,
2759 EL_ACID_POOL_TOPRIGHT,
2760 EL_ACID_POOL_BOTTOMLEFT,
2761 EL_ACID_POOL_BOTTOM,
2762 EL_ACID_POOL_BOTTOMRIGHT,
2763 EL_SP_HARDWARE_GRAY,
2764 EL_SP_HARDWARE_GREEN,
2765 EL_SP_HARDWARE_BLUE,
2767 EL_SP_HARDWARE_YELLOW,
2768 EL_SP_HARDWARE_BASE_1,
2769 EL_SP_HARDWARE_BASE_2,
2770 EL_SP_HARDWARE_BASE_3,
2771 EL_SP_HARDWARE_BASE_4,
2772 EL_SP_HARDWARE_BASE_5,
2773 EL_SP_HARDWARE_BASE_6,
2774 EL_INVISIBLE_STEELWALL,
2775 EL_INVISIBLE_STEELWALL_ACTIVE,
2776 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2777 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2778 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2779 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2780 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2781 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2782 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2783 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2784 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2785 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2786 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2787 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2789 EL_LIGHT_SWITCH_ACTIVE,
2790 EL_SIGN_EXCLAMATION,
2791 EL_SIGN_RADIOACTIVITY,
2798 EL_SIGN_ENTRY_FORBIDDEN,
2799 EL_SIGN_EMERGENCY_EXIT,
2807 EL_STEEL_EXIT_CLOSED,
2809 EL_STEEL_EXIT_OPENING,
2810 EL_STEEL_EXIT_CLOSING,
2811 EL_EM_STEEL_EXIT_CLOSED,
2812 EL_EM_STEEL_EXIT_OPEN,
2813 EL_EM_STEEL_EXIT_OPENING,
2814 EL_EM_STEEL_EXIT_CLOSING,
2815 EL_DC_STEELWALL_1_LEFT,
2816 EL_DC_STEELWALL_1_RIGHT,
2817 EL_DC_STEELWALL_1_TOP,
2818 EL_DC_STEELWALL_1_BOTTOM,
2819 EL_DC_STEELWALL_1_HORIZONTAL,
2820 EL_DC_STEELWALL_1_VERTICAL,
2821 EL_DC_STEELWALL_1_TOPLEFT,
2822 EL_DC_STEELWALL_1_TOPRIGHT,
2823 EL_DC_STEELWALL_1_BOTTOMLEFT,
2824 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2825 EL_DC_STEELWALL_1_TOPLEFT_2,
2826 EL_DC_STEELWALL_1_TOPRIGHT_2,
2827 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2828 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2829 EL_DC_STEELWALL_2_LEFT,
2830 EL_DC_STEELWALL_2_RIGHT,
2831 EL_DC_STEELWALL_2_TOP,
2832 EL_DC_STEELWALL_2_BOTTOM,
2833 EL_DC_STEELWALL_2_HORIZONTAL,
2834 EL_DC_STEELWALL_2_VERTICAL,
2835 EL_DC_STEELWALL_2_MIDDLE,
2836 EL_DC_STEELWALL_2_SINGLE,
2837 EL_STEELWALL_SLIPPERY,
2851 EL_GATE_1_GRAY_ACTIVE,
2852 EL_GATE_2_GRAY_ACTIVE,
2853 EL_GATE_3_GRAY_ACTIVE,
2854 EL_GATE_4_GRAY_ACTIVE,
2863 EL_EM_GATE_1_GRAY_ACTIVE,
2864 EL_EM_GATE_2_GRAY_ACTIVE,
2865 EL_EM_GATE_3_GRAY_ACTIVE,
2866 EL_EM_GATE_4_GRAY_ACTIVE,
2875 EL_EMC_GATE_5_GRAY_ACTIVE,
2876 EL_EMC_GATE_6_GRAY_ACTIVE,
2877 EL_EMC_GATE_7_GRAY_ACTIVE,
2878 EL_EMC_GATE_8_GRAY_ACTIVE,
2880 EL_DC_GATE_WHITE_GRAY,
2881 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2882 EL_DC_GATE_FAKE_GRAY,
2884 EL_SWITCHGATE_OPENING,
2885 EL_SWITCHGATE_CLOSED,
2886 EL_SWITCHGATE_CLOSING,
2887 EL_DC_SWITCHGATE_SWITCH_UP,
2888 EL_DC_SWITCHGATE_SWITCH_DOWN,
2890 EL_TIMEGATE_OPENING,
2892 EL_TIMEGATE_CLOSING,
2893 EL_DC_TIMEGATE_SWITCH,
2894 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2898 EL_TUBE_VERTICAL_LEFT,
2899 EL_TUBE_VERTICAL_RIGHT,
2900 EL_TUBE_HORIZONTAL_UP,
2901 EL_TUBE_HORIZONTAL_DOWN,
2906 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2907 EL_EXPANDABLE_STEELWALL_VERTICAL,
2908 EL_EXPANDABLE_STEELWALL_ANY,
2913 static int ep_slippery[] =
2927 EL_ROBOT_WHEEL_ACTIVE,
2933 EL_ACID_POOL_TOPLEFT,
2934 EL_ACID_POOL_TOPRIGHT,
2944 EL_STEELWALL_SLIPPERY,
2947 EL_EMC_WALL_SLIPPERY_1,
2948 EL_EMC_WALL_SLIPPERY_2,
2949 EL_EMC_WALL_SLIPPERY_3,
2950 EL_EMC_WALL_SLIPPERY_4,
2952 EL_EMC_MAGIC_BALL_ACTIVE,
2957 static int ep_can_change[] =
2962 static int ep_can_move[] =
2964 // same elements as in 'pb_can_move_into_acid'
2987 static int ep_can_fall[] =
3002 EL_QUICKSAND_FAST_FULL,
3004 EL_BD_MAGIC_WALL_FULL,
3005 EL_DC_MAGIC_WALL_FULL,
3019 static int ep_can_smash_player[] =
3045 static int ep_can_smash_enemies[] =
3054 static int ep_can_smash_everything[] =
3063 static int ep_explodes_by_fire[] =
3065 // same elements as in 'ep_explodes_impact'
3070 // same elements as in 'ep_explodes_smashed'
3080 EL_EM_DYNAMITE_ACTIVE,
3081 EL_DYNABOMB_PLAYER_1_ACTIVE,
3082 EL_DYNABOMB_PLAYER_2_ACTIVE,
3083 EL_DYNABOMB_PLAYER_3_ACTIVE,
3084 EL_DYNABOMB_PLAYER_4_ACTIVE,
3085 EL_DYNABOMB_INCREASE_NUMBER,
3086 EL_DYNABOMB_INCREASE_SIZE,
3087 EL_DYNABOMB_INCREASE_POWER,
3088 EL_SP_DISK_RED_ACTIVE,
3102 static int ep_explodes_smashed[] =
3104 // same elements as in 'ep_explodes_impact'
3118 static int ep_explodes_impact[] =
3127 static int ep_walkable_over[] =
3147 EL_SOKOBAN_FIELD_EMPTY,
3154 EL_EM_STEEL_EXIT_OPEN,
3155 EL_EM_STEEL_EXIT_OPENING,
3164 EL_GATE_1_GRAY_ACTIVE,
3165 EL_GATE_2_GRAY_ACTIVE,
3166 EL_GATE_3_GRAY_ACTIVE,
3167 EL_GATE_4_GRAY_ACTIVE,
3175 static int ep_walkable_inside[] =
3180 EL_TUBE_VERTICAL_LEFT,
3181 EL_TUBE_VERTICAL_RIGHT,
3182 EL_TUBE_HORIZONTAL_UP,
3183 EL_TUBE_HORIZONTAL_DOWN,
3192 static int ep_walkable_under[] =
3197 static int ep_passable_over[] =
3207 EL_EM_GATE_1_GRAY_ACTIVE,
3208 EL_EM_GATE_2_GRAY_ACTIVE,
3209 EL_EM_GATE_3_GRAY_ACTIVE,
3210 EL_EM_GATE_4_GRAY_ACTIVE,
3219 EL_EMC_GATE_5_GRAY_ACTIVE,
3220 EL_EMC_GATE_6_GRAY_ACTIVE,
3221 EL_EMC_GATE_7_GRAY_ACTIVE,
3222 EL_EMC_GATE_8_GRAY_ACTIVE,
3224 EL_DC_GATE_WHITE_GRAY,
3225 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3232 static int ep_passable_inside[] =
3238 EL_SP_PORT_HORIZONTAL,
3239 EL_SP_PORT_VERTICAL,
3241 EL_SP_GRAVITY_PORT_LEFT,
3242 EL_SP_GRAVITY_PORT_RIGHT,
3243 EL_SP_GRAVITY_PORT_UP,
3244 EL_SP_GRAVITY_PORT_DOWN,
3245 EL_SP_GRAVITY_ON_PORT_LEFT,
3246 EL_SP_GRAVITY_ON_PORT_RIGHT,
3247 EL_SP_GRAVITY_ON_PORT_UP,
3248 EL_SP_GRAVITY_ON_PORT_DOWN,
3249 EL_SP_GRAVITY_OFF_PORT_LEFT,
3250 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3251 EL_SP_GRAVITY_OFF_PORT_UP,
3252 EL_SP_GRAVITY_OFF_PORT_DOWN,
3257 static int ep_passable_under[] =
3262 static int ep_droppable[] =
3267 static int ep_explodes_1x1_old[] =
3272 static int ep_pushable[] =
3284 EL_SOKOBAN_FIELD_FULL,
3293 static int ep_explodes_cross_old[] =
3298 static int ep_protected[] =
3300 // same elements as in 'ep_walkable_inside'
3304 EL_TUBE_VERTICAL_LEFT,
3305 EL_TUBE_VERTICAL_RIGHT,
3306 EL_TUBE_HORIZONTAL_UP,
3307 EL_TUBE_HORIZONTAL_DOWN,
3313 // same elements as in 'ep_passable_over'
3322 EL_EM_GATE_1_GRAY_ACTIVE,
3323 EL_EM_GATE_2_GRAY_ACTIVE,
3324 EL_EM_GATE_3_GRAY_ACTIVE,
3325 EL_EM_GATE_4_GRAY_ACTIVE,
3334 EL_EMC_GATE_5_GRAY_ACTIVE,
3335 EL_EMC_GATE_6_GRAY_ACTIVE,
3336 EL_EMC_GATE_7_GRAY_ACTIVE,
3337 EL_EMC_GATE_8_GRAY_ACTIVE,
3339 EL_DC_GATE_WHITE_GRAY,
3340 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3344 // same elements as in 'ep_passable_inside'
3349 EL_SP_PORT_HORIZONTAL,
3350 EL_SP_PORT_VERTICAL,
3352 EL_SP_GRAVITY_PORT_LEFT,
3353 EL_SP_GRAVITY_PORT_RIGHT,
3354 EL_SP_GRAVITY_PORT_UP,
3355 EL_SP_GRAVITY_PORT_DOWN,
3356 EL_SP_GRAVITY_ON_PORT_LEFT,
3357 EL_SP_GRAVITY_ON_PORT_RIGHT,
3358 EL_SP_GRAVITY_ON_PORT_UP,
3359 EL_SP_GRAVITY_ON_PORT_DOWN,
3360 EL_SP_GRAVITY_OFF_PORT_LEFT,
3361 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3362 EL_SP_GRAVITY_OFF_PORT_UP,
3363 EL_SP_GRAVITY_OFF_PORT_DOWN,
3368 static int ep_throwable[] =
3373 static int ep_can_explode[] =
3375 // same elements as in 'ep_explodes_impact'
3380 // same elements as in 'ep_explodes_smashed'
3386 // elements that can explode by explosion or by dragonfire
3390 EL_EM_DYNAMITE_ACTIVE,
3391 EL_DYNABOMB_PLAYER_1_ACTIVE,
3392 EL_DYNABOMB_PLAYER_2_ACTIVE,
3393 EL_DYNABOMB_PLAYER_3_ACTIVE,
3394 EL_DYNABOMB_PLAYER_4_ACTIVE,
3395 EL_DYNABOMB_INCREASE_NUMBER,
3396 EL_DYNABOMB_INCREASE_SIZE,
3397 EL_DYNABOMB_INCREASE_POWER,
3398 EL_SP_DISK_RED_ACTIVE,
3406 // elements that can explode only by explosion
3412 static int ep_gravity_reachable[] =
3418 EL_INVISIBLE_SAND_ACTIVE,
3423 EL_SP_PORT_HORIZONTAL,
3424 EL_SP_PORT_VERTICAL,
3426 EL_SP_GRAVITY_PORT_LEFT,
3427 EL_SP_GRAVITY_PORT_RIGHT,
3428 EL_SP_GRAVITY_PORT_UP,
3429 EL_SP_GRAVITY_PORT_DOWN,
3430 EL_SP_GRAVITY_ON_PORT_LEFT,
3431 EL_SP_GRAVITY_ON_PORT_RIGHT,
3432 EL_SP_GRAVITY_ON_PORT_UP,
3433 EL_SP_GRAVITY_ON_PORT_DOWN,
3434 EL_SP_GRAVITY_OFF_PORT_LEFT,
3435 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3436 EL_SP_GRAVITY_OFF_PORT_UP,
3437 EL_SP_GRAVITY_OFF_PORT_DOWN,
3443 static int ep_empty_space[] =
3466 static int ep_player[] =
3473 EL_SOKOBAN_FIELD_PLAYER,
3479 static int ep_can_pass_magic_wall[] =
3493 static int ep_can_pass_dc_magic_wall[] =
3509 static int ep_switchable[] =
3513 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3516 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3519 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3525 EL_SWITCHGATE_SWITCH_UP,
3526 EL_SWITCHGATE_SWITCH_DOWN,
3527 EL_DC_SWITCHGATE_SWITCH_UP,
3528 EL_DC_SWITCHGATE_SWITCH_DOWN,
3530 EL_LIGHT_SWITCH_ACTIVE,
3532 EL_DC_TIMEGATE_SWITCH,
3533 EL_BALLOON_SWITCH_LEFT,
3534 EL_BALLOON_SWITCH_RIGHT,
3535 EL_BALLOON_SWITCH_UP,
3536 EL_BALLOON_SWITCH_DOWN,
3537 EL_BALLOON_SWITCH_ANY,
3538 EL_BALLOON_SWITCH_NONE,
3541 EL_EMC_MAGIC_BALL_SWITCH,
3542 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3547 static int ep_bd_element[] =
3581 static int ep_sp_element[] =
3583 // should always be valid
3586 // standard classic Supaplex elements
3593 EL_SP_HARDWARE_GRAY,
3601 EL_SP_GRAVITY_PORT_RIGHT,
3602 EL_SP_GRAVITY_PORT_DOWN,
3603 EL_SP_GRAVITY_PORT_LEFT,
3604 EL_SP_GRAVITY_PORT_UP,
3609 EL_SP_PORT_VERTICAL,
3610 EL_SP_PORT_HORIZONTAL,
3616 EL_SP_HARDWARE_BASE_1,
3617 EL_SP_HARDWARE_GREEN,
3618 EL_SP_HARDWARE_BLUE,
3620 EL_SP_HARDWARE_YELLOW,
3621 EL_SP_HARDWARE_BASE_2,
3622 EL_SP_HARDWARE_BASE_3,
3623 EL_SP_HARDWARE_BASE_4,
3624 EL_SP_HARDWARE_BASE_5,
3625 EL_SP_HARDWARE_BASE_6,
3629 // additional elements that appeared in newer Supaplex levels
3632 // additional gravity port elements (not switching, but setting gravity)
3633 EL_SP_GRAVITY_ON_PORT_LEFT,
3634 EL_SP_GRAVITY_ON_PORT_RIGHT,
3635 EL_SP_GRAVITY_ON_PORT_UP,
3636 EL_SP_GRAVITY_ON_PORT_DOWN,
3637 EL_SP_GRAVITY_OFF_PORT_LEFT,
3638 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3639 EL_SP_GRAVITY_OFF_PORT_UP,
3640 EL_SP_GRAVITY_OFF_PORT_DOWN,
3642 // more than one Murphy in a level results in an inactive clone
3645 // runtime Supaplex elements
3646 EL_SP_DISK_RED_ACTIVE,
3647 EL_SP_TERMINAL_ACTIVE,
3648 EL_SP_BUGGY_BASE_ACTIVATING,
3649 EL_SP_BUGGY_BASE_ACTIVE,
3656 static int ep_sb_element[] =
3661 EL_SOKOBAN_FIELD_EMPTY,
3662 EL_SOKOBAN_FIELD_FULL,
3663 EL_SOKOBAN_FIELD_PLAYER,
3668 EL_INVISIBLE_STEELWALL,
3673 static int ep_gem[] =
3685 static int ep_food_dark_yamyam[] =
3713 static int ep_food_penguin[] =
3727 static int ep_food_pig[] =
3739 static int ep_historic_wall[] =
3750 EL_GATE_1_GRAY_ACTIVE,
3751 EL_GATE_2_GRAY_ACTIVE,
3752 EL_GATE_3_GRAY_ACTIVE,
3753 EL_GATE_4_GRAY_ACTIVE,
3762 EL_EM_GATE_1_GRAY_ACTIVE,
3763 EL_EM_GATE_2_GRAY_ACTIVE,
3764 EL_EM_GATE_3_GRAY_ACTIVE,
3765 EL_EM_GATE_4_GRAY_ACTIVE,
3772 EL_EXPANDABLE_WALL_HORIZONTAL,
3773 EL_EXPANDABLE_WALL_VERTICAL,
3774 EL_EXPANDABLE_WALL_ANY,
3775 EL_EXPANDABLE_WALL_GROWING,
3776 EL_BD_EXPANDABLE_WALL,
3783 EL_SP_HARDWARE_GRAY,
3784 EL_SP_HARDWARE_GREEN,
3785 EL_SP_HARDWARE_BLUE,
3787 EL_SP_HARDWARE_YELLOW,
3788 EL_SP_HARDWARE_BASE_1,
3789 EL_SP_HARDWARE_BASE_2,
3790 EL_SP_HARDWARE_BASE_3,
3791 EL_SP_HARDWARE_BASE_4,
3792 EL_SP_HARDWARE_BASE_5,
3793 EL_SP_HARDWARE_BASE_6,
3795 EL_SP_TERMINAL_ACTIVE,
3798 EL_INVISIBLE_STEELWALL,
3799 EL_INVISIBLE_STEELWALL_ACTIVE,
3801 EL_INVISIBLE_WALL_ACTIVE,
3802 EL_STEELWALL_SLIPPERY,
3819 static int ep_historic_solid[] =
3823 EL_EXPANDABLE_WALL_HORIZONTAL,
3824 EL_EXPANDABLE_WALL_VERTICAL,
3825 EL_EXPANDABLE_WALL_ANY,
3826 EL_BD_EXPANDABLE_WALL,
3839 EL_QUICKSAND_FILLING,
3840 EL_QUICKSAND_EMPTYING,
3842 EL_MAGIC_WALL_ACTIVE,
3843 EL_MAGIC_WALL_EMPTYING,
3844 EL_MAGIC_WALL_FILLING,
3848 EL_BD_MAGIC_WALL_ACTIVE,
3849 EL_BD_MAGIC_WALL_EMPTYING,
3850 EL_BD_MAGIC_WALL_FULL,
3851 EL_BD_MAGIC_WALL_FILLING,
3852 EL_BD_MAGIC_WALL_DEAD,
3861 EL_SP_TERMINAL_ACTIVE,
3865 EL_INVISIBLE_WALL_ACTIVE,
3866 EL_SWITCHGATE_SWITCH_UP,
3867 EL_SWITCHGATE_SWITCH_DOWN,
3869 EL_TIMEGATE_SWITCH_ACTIVE,
3881 // the following elements are a direct copy of "indestructible" elements,
3882 // except "EL_ACID", which is "indestructible", but not "solid"!
3887 EL_ACID_POOL_TOPLEFT,
3888 EL_ACID_POOL_TOPRIGHT,
3889 EL_ACID_POOL_BOTTOMLEFT,
3890 EL_ACID_POOL_BOTTOM,
3891 EL_ACID_POOL_BOTTOMRIGHT,
3892 EL_SP_HARDWARE_GRAY,
3893 EL_SP_HARDWARE_GREEN,
3894 EL_SP_HARDWARE_BLUE,
3896 EL_SP_HARDWARE_YELLOW,
3897 EL_SP_HARDWARE_BASE_1,
3898 EL_SP_HARDWARE_BASE_2,
3899 EL_SP_HARDWARE_BASE_3,
3900 EL_SP_HARDWARE_BASE_4,
3901 EL_SP_HARDWARE_BASE_5,
3902 EL_SP_HARDWARE_BASE_6,
3903 EL_INVISIBLE_STEELWALL,
3904 EL_INVISIBLE_STEELWALL_ACTIVE,
3905 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3906 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3907 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3908 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3909 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3910 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3911 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3912 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3913 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3914 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3915 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3916 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3918 EL_LIGHT_SWITCH_ACTIVE,
3919 EL_SIGN_EXCLAMATION,
3920 EL_SIGN_RADIOACTIVITY,
3927 EL_SIGN_ENTRY_FORBIDDEN,
3928 EL_SIGN_EMERGENCY_EXIT,
3936 EL_STEEL_EXIT_CLOSED,
3938 EL_STEEL_EXIT_OPENING,
3939 EL_STEEL_EXIT_CLOSING,
3940 EL_EM_STEEL_EXIT_CLOSED,
3941 EL_EM_STEEL_EXIT_OPEN,
3942 EL_EM_STEEL_EXIT_OPENING,
3943 EL_EM_STEEL_EXIT_CLOSING,
3944 EL_DC_STEELWALL_1_LEFT,
3945 EL_DC_STEELWALL_1_RIGHT,
3946 EL_DC_STEELWALL_1_TOP,
3947 EL_DC_STEELWALL_1_BOTTOM,
3948 EL_DC_STEELWALL_1_HORIZONTAL,
3949 EL_DC_STEELWALL_1_VERTICAL,
3950 EL_DC_STEELWALL_1_TOPLEFT,
3951 EL_DC_STEELWALL_1_TOPRIGHT,
3952 EL_DC_STEELWALL_1_BOTTOMLEFT,
3953 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3954 EL_DC_STEELWALL_1_TOPLEFT_2,
3955 EL_DC_STEELWALL_1_TOPRIGHT_2,
3956 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3957 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3958 EL_DC_STEELWALL_2_LEFT,
3959 EL_DC_STEELWALL_2_RIGHT,
3960 EL_DC_STEELWALL_2_TOP,
3961 EL_DC_STEELWALL_2_BOTTOM,
3962 EL_DC_STEELWALL_2_HORIZONTAL,
3963 EL_DC_STEELWALL_2_VERTICAL,
3964 EL_DC_STEELWALL_2_MIDDLE,
3965 EL_DC_STEELWALL_2_SINGLE,
3966 EL_STEELWALL_SLIPPERY,
3980 EL_GATE_1_GRAY_ACTIVE,
3981 EL_GATE_2_GRAY_ACTIVE,
3982 EL_GATE_3_GRAY_ACTIVE,
3983 EL_GATE_4_GRAY_ACTIVE,
3992 EL_EM_GATE_1_GRAY_ACTIVE,
3993 EL_EM_GATE_2_GRAY_ACTIVE,
3994 EL_EM_GATE_3_GRAY_ACTIVE,
3995 EL_EM_GATE_4_GRAY_ACTIVE,
4004 EL_EMC_GATE_5_GRAY_ACTIVE,
4005 EL_EMC_GATE_6_GRAY_ACTIVE,
4006 EL_EMC_GATE_7_GRAY_ACTIVE,
4007 EL_EMC_GATE_8_GRAY_ACTIVE,
4009 EL_DC_GATE_WHITE_GRAY,
4010 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4011 EL_DC_GATE_FAKE_GRAY,
4013 EL_SWITCHGATE_OPENING,
4014 EL_SWITCHGATE_CLOSED,
4015 EL_SWITCHGATE_CLOSING,
4016 EL_DC_SWITCHGATE_SWITCH_UP,
4017 EL_DC_SWITCHGATE_SWITCH_DOWN,
4019 EL_TIMEGATE_OPENING,
4021 EL_TIMEGATE_CLOSING,
4022 EL_DC_TIMEGATE_SWITCH,
4023 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4027 EL_TUBE_VERTICAL_LEFT,
4028 EL_TUBE_VERTICAL_RIGHT,
4029 EL_TUBE_HORIZONTAL_UP,
4030 EL_TUBE_HORIZONTAL_DOWN,
4035 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4036 EL_EXPANDABLE_STEELWALL_VERTICAL,
4037 EL_EXPANDABLE_STEELWALL_ANY,
4042 static int ep_classic_enemy[] =
4059 static int ep_belt[] =
4061 EL_CONVEYOR_BELT_1_LEFT,
4062 EL_CONVEYOR_BELT_1_MIDDLE,
4063 EL_CONVEYOR_BELT_1_RIGHT,
4064 EL_CONVEYOR_BELT_2_LEFT,
4065 EL_CONVEYOR_BELT_2_MIDDLE,
4066 EL_CONVEYOR_BELT_2_RIGHT,
4067 EL_CONVEYOR_BELT_3_LEFT,
4068 EL_CONVEYOR_BELT_3_MIDDLE,
4069 EL_CONVEYOR_BELT_3_RIGHT,
4070 EL_CONVEYOR_BELT_4_LEFT,
4071 EL_CONVEYOR_BELT_4_MIDDLE,
4072 EL_CONVEYOR_BELT_4_RIGHT,
4077 static int ep_belt_active[] =
4079 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4080 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4081 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4082 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4083 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4084 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4085 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4086 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4087 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4088 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4089 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4090 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4095 static int ep_belt_switch[] =
4097 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4098 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4099 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4100 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4101 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4102 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4103 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4104 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4105 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4106 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4107 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4108 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4113 static int ep_tube[] =
4120 EL_TUBE_HORIZONTAL_UP,
4121 EL_TUBE_HORIZONTAL_DOWN,
4123 EL_TUBE_VERTICAL_LEFT,
4124 EL_TUBE_VERTICAL_RIGHT,
4130 static int ep_acid_pool[] =
4132 EL_ACID_POOL_TOPLEFT,
4133 EL_ACID_POOL_TOPRIGHT,
4134 EL_ACID_POOL_BOTTOMLEFT,
4135 EL_ACID_POOL_BOTTOM,
4136 EL_ACID_POOL_BOTTOMRIGHT,
4141 static int ep_keygate[] =
4151 EL_GATE_1_GRAY_ACTIVE,
4152 EL_GATE_2_GRAY_ACTIVE,
4153 EL_GATE_3_GRAY_ACTIVE,
4154 EL_GATE_4_GRAY_ACTIVE,
4163 EL_EM_GATE_1_GRAY_ACTIVE,
4164 EL_EM_GATE_2_GRAY_ACTIVE,
4165 EL_EM_GATE_3_GRAY_ACTIVE,
4166 EL_EM_GATE_4_GRAY_ACTIVE,
4175 EL_EMC_GATE_5_GRAY_ACTIVE,
4176 EL_EMC_GATE_6_GRAY_ACTIVE,
4177 EL_EMC_GATE_7_GRAY_ACTIVE,
4178 EL_EMC_GATE_8_GRAY_ACTIVE,
4180 EL_DC_GATE_WHITE_GRAY,
4181 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4186 static int ep_amoeboid[] =
4198 static int ep_amoebalive[] =
4209 static int ep_has_editor_content[] =
4215 EL_SOKOBAN_FIELD_PLAYER,
4232 static int ep_can_turn_each_move[] =
4234 // !!! do something with this one !!!
4238 static int ep_can_grow[] =
4252 static int ep_active_bomb[] =
4255 EL_EM_DYNAMITE_ACTIVE,
4256 EL_DYNABOMB_PLAYER_1_ACTIVE,
4257 EL_DYNABOMB_PLAYER_2_ACTIVE,
4258 EL_DYNABOMB_PLAYER_3_ACTIVE,
4259 EL_DYNABOMB_PLAYER_4_ACTIVE,
4260 EL_SP_DISK_RED_ACTIVE,
4265 static int ep_inactive[] =
4291 EL_QUICKSAND_FAST_EMPTY,
4314 EL_GATE_1_GRAY_ACTIVE,
4315 EL_GATE_2_GRAY_ACTIVE,
4316 EL_GATE_3_GRAY_ACTIVE,
4317 EL_GATE_4_GRAY_ACTIVE,
4326 EL_EM_GATE_1_GRAY_ACTIVE,
4327 EL_EM_GATE_2_GRAY_ACTIVE,
4328 EL_EM_GATE_3_GRAY_ACTIVE,
4329 EL_EM_GATE_4_GRAY_ACTIVE,
4338 EL_EMC_GATE_5_GRAY_ACTIVE,
4339 EL_EMC_GATE_6_GRAY_ACTIVE,
4340 EL_EMC_GATE_7_GRAY_ACTIVE,
4341 EL_EMC_GATE_8_GRAY_ACTIVE,
4343 EL_DC_GATE_WHITE_GRAY,
4344 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4345 EL_DC_GATE_FAKE_GRAY,
4348 EL_INVISIBLE_STEELWALL,
4356 EL_WALL_EMERALD_YELLOW,
4357 EL_DYNABOMB_INCREASE_NUMBER,
4358 EL_DYNABOMB_INCREASE_SIZE,
4359 EL_DYNABOMB_INCREASE_POWER,
4363 EL_SOKOBAN_FIELD_EMPTY,
4364 EL_SOKOBAN_FIELD_FULL,
4365 EL_WALL_EMERALD_RED,
4366 EL_WALL_EMERALD_PURPLE,
4367 EL_ACID_POOL_TOPLEFT,
4368 EL_ACID_POOL_TOPRIGHT,
4369 EL_ACID_POOL_BOTTOMLEFT,
4370 EL_ACID_POOL_BOTTOM,
4371 EL_ACID_POOL_BOTTOMRIGHT,
4375 EL_BD_MAGIC_WALL_DEAD,
4377 EL_DC_MAGIC_WALL_DEAD,
4378 EL_AMOEBA_TO_DIAMOND,
4386 EL_SP_GRAVITY_PORT_RIGHT,
4387 EL_SP_GRAVITY_PORT_DOWN,
4388 EL_SP_GRAVITY_PORT_LEFT,
4389 EL_SP_GRAVITY_PORT_UP,
4390 EL_SP_PORT_HORIZONTAL,
4391 EL_SP_PORT_VERTICAL,
4402 EL_SP_HARDWARE_GRAY,
4403 EL_SP_HARDWARE_GREEN,
4404 EL_SP_HARDWARE_BLUE,
4406 EL_SP_HARDWARE_YELLOW,
4407 EL_SP_HARDWARE_BASE_1,
4408 EL_SP_HARDWARE_BASE_2,
4409 EL_SP_HARDWARE_BASE_3,
4410 EL_SP_HARDWARE_BASE_4,
4411 EL_SP_HARDWARE_BASE_5,
4412 EL_SP_HARDWARE_BASE_6,
4413 EL_SP_GRAVITY_ON_PORT_LEFT,
4414 EL_SP_GRAVITY_ON_PORT_RIGHT,
4415 EL_SP_GRAVITY_ON_PORT_UP,
4416 EL_SP_GRAVITY_ON_PORT_DOWN,
4417 EL_SP_GRAVITY_OFF_PORT_LEFT,
4418 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4419 EL_SP_GRAVITY_OFF_PORT_UP,
4420 EL_SP_GRAVITY_OFF_PORT_DOWN,
4421 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4422 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4423 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4424 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4425 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4426 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4427 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4428 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4429 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4430 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4431 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4432 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4433 EL_SIGN_EXCLAMATION,
4434 EL_SIGN_RADIOACTIVITY,
4441 EL_SIGN_ENTRY_FORBIDDEN,
4442 EL_SIGN_EMERGENCY_EXIT,
4450 EL_DC_STEELWALL_1_LEFT,
4451 EL_DC_STEELWALL_1_RIGHT,
4452 EL_DC_STEELWALL_1_TOP,
4453 EL_DC_STEELWALL_1_BOTTOM,
4454 EL_DC_STEELWALL_1_HORIZONTAL,
4455 EL_DC_STEELWALL_1_VERTICAL,
4456 EL_DC_STEELWALL_1_TOPLEFT,
4457 EL_DC_STEELWALL_1_TOPRIGHT,
4458 EL_DC_STEELWALL_1_BOTTOMLEFT,
4459 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4460 EL_DC_STEELWALL_1_TOPLEFT_2,
4461 EL_DC_STEELWALL_1_TOPRIGHT_2,
4462 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4463 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4464 EL_DC_STEELWALL_2_LEFT,
4465 EL_DC_STEELWALL_2_RIGHT,
4466 EL_DC_STEELWALL_2_TOP,
4467 EL_DC_STEELWALL_2_BOTTOM,
4468 EL_DC_STEELWALL_2_HORIZONTAL,
4469 EL_DC_STEELWALL_2_VERTICAL,
4470 EL_DC_STEELWALL_2_MIDDLE,
4471 EL_DC_STEELWALL_2_SINGLE,
4472 EL_STEELWALL_SLIPPERY,
4477 EL_EMC_WALL_SLIPPERY_1,
4478 EL_EMC_WALL_SLIPPERY_2,
4479 EL_EMC_WALL_SLIPPERY_3,
4480 EL_EMC_WALL_SLIPPERY_4,
4501 static int ep_em_slippery_wall[] =
4506 static int ep_gfx_crumbled[] =
4517 static int ep_editor_cascade_active[] =
4519 EL_INTERNAL_CASCADE_BD_ACTIVE,
4520 EL_INTERNAL_CASCADE_EM_ACTIVE,
4521 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4522 EL_INTERNAL_CASCADE_RND_ACTIVE,
4523 EL_INTERNAL_CASCADE_SB_ACTIVE,
4524 EL_INTERNAL_CASCADE_SP_ACTIVE,
4525 EL_INTERNAL_CASCADE_DC_ACTIVE,
4526 EL_INTERNAL_CASCADE_DX_ACTIVE,
4527 EL_INTERNAL_CASCADE_MM_ACTIVE,
4528 EL_INTERNAL_CASCADE_DF_ACTIVE,
4529 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4530 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4531 EL_INTERNAL_CASCADE_CE_ACTIVE,
4532 EL_INTERNAL_CASCADE_GE_ACTIVE,
4533 EL_INTERNAL_CASCADE_ES_ACTIVE,
4534 EL_INTERNAL_CASCADE_REF_ACTIVE,
4535 EL_INTERNAL_CASCADE_USER_ACTIVE,
4536 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4541 static int ep_editor_cascade_inactive[] =
4543 EL_INTERNAL_CASCADE_BD,
4544 EL_INTERNAL_CASCADE_EM,
4545 EL_INTERNAL_CASCADE_EMC,
4546 EL_INTERNAL_CASCADE_RND,
4547 EL_INTERNAL_CASCADE_SB,
4548 EL_INTERNAL_CASCADE_SP,
4549 EL_INTERNAL_CASCADE_DC,
4550 EL_INTERNAL_CASCADE_DX,
4551 EL_INTERNAL_CASCADE_MM,
4552 EL_INTERNAL_CASCADE_DF,
4553 EL_INTERNAL_CASCADE_CHARS,
4554 EL_INTERNAL_CASCADE_STEEL_CHARS,
4555 EL_INTERNAL_CASCADE_CE,
4556 EL_INTERNAL_CASCADE_GE,
4557 EL_INTERNAL_CASCADE_ES,
4558 EL_INTERNAL_CASCADE_REF,
4559 EL_INTERNAL_CASCADE_USER,
4560 EL_INTERNAL_CASCADE_DYNAMIC,
4565 static int ep_obsolete[] =
4569 EL_EM_KEY_1_FILE_OBSOLETE,
4570 EL_EM_KEY_2_FILE_OBSOLETE,
4571 EL_EM_KEY_3_FILE_OBSOLETE,
4572 EL_EM_KEY_4_FILE_OBSOLETE,
4573 EL_ENVELOPE_OBSOLETE,
4582 } element_properties[] =
4584 { ep_diggable, EP_DIGGABLE },
4585 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4586 { ep_dont_run_into, EP_DONT_RUN_INTO },
4587 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4588 { ep_dont_touch, EP_DONT_TOUCH },
4589 { ep_indestructible, EP_INDESTRUCTIBLE },
4590 { ep_slippery, EP_SLIPPERY },
4591 { ep_can_change, EP_CAN_CHANGE },
4592 { ep_can_move, EP_CAN_MOVE },
4593 { ep_can_fall, EP_CAN_FALL },
4594 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4595 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4596 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4597 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4598 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4599 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4600 { ep_walkable_over, EP_WALKABLE_OVER },
4601 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4602 { ep_walkable_under, EP_WALKABLE_UNDER },
4603 { ep_passable_over, EP_PASSABLE_OVER },
4604 { ep_passable_inside, EP_PASSABLE_INSIDE },
4605 { ep_passable_under, EP_PASSABLE_UNDER },
4606 { ep_droppable, EP_DROPPABLE },
4607 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4608 { ep_pushable, EP_PUSHABLE },
4609 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4610 { ep_protected, EP_PROTECTED },
4611 { ep_throwable, EP_THROWABLE },
4612 { ep_can_explode, EP_CAN_EXPLODE },
4613 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4615 { ep_empty_space, EP_EMPTY_SPACE },
4616 { ep_player, EP_PLAYER },
4617 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4618 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4619 { ep_switchable, EP_SWITCHABLE },
4620 { ep_bd_element, EP_BD_ELEMENT },
4621 { ep_sp_element, EP_SP_ELEMENT },
4622 { ep_sb_element, EP_SB_ELEMENT },
4624 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4625 { ep_food_penguin, EP_FOOD_PENGUIN },
4626 { ep_food_pig, EP_FOOD_PIG },
4627 { ep_historic_wall, EP_HISTORIC_WALL },
4628 { ep_historic_solid, EP_HISTORIC_SOLID },
4629 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4630 { ep_belt, EP_BELT },
4631 { ep_belt_active, EP_BELT_ACTIVE },
4632 { ep_belt_switch, EP_BELT_SWITCH },
4633 { ep_tube, EP_TUBE },
4634 { ep_acid_pool, EP_ACID_POOL },
4635 { ep_keygate, EP_KEYGATE },
4636 { ep_amoeboid, EP_AMOEBOID },
4637 { ep_amoebalive, EP_AMOEBALIVE },
4638 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4639 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4640 { ep_can_grow, EP_CAN_GROW },
4641 { ep_active_bomb, EP_ACTIVE_BOMB },
4642 { ep_inactive, EP_INACTIVE },
4644 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4646 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4648 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4649 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4651 { ep_obsolete, EP_OBSOLETE },
4658 // always start with reliable default values (element has no properties)
4659 // (but never initialize clipboard elements after the very first time)
4660 // (to be able to use clipboard elements between several levels)
4661 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4662 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4663 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4664 SET_PROPERTY(i, j, FALSE);
4666 // set all base element properties from above array definitions
4667 for (i = 0; element_properties[i].elements != NULL; i++)
4668 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4669 SET_PROPERTY((element_properties[i].elements)[j],
4670 element_properties[i].property, TRUE);
4672 // copy properties to some elements that are only stored in level file
4673 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4674 for (j = 0; copy_properties[j][0] != -1; j++)
4675 if (HAS_PROPERTY(copy_properties[j][0], i))
4676 for (k = 1; k <= 4; k++)
4677 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4679 // set static element properties that are not listed in array definitions
4680 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4681 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4683 clipboard_elements_initialized = TRUE;
4686 void InitElementPropertiesEngine(int engine_version)
4688 static int no_wall_properties[] =
4691 EP_COLLECTIBLE_ONLY,
4693 EP_DONT_COLLIDE_WITH,
4696 EP_CAN_SMASH_PLAYER,
4697 EP_CAN_SMASH_ENEMIES,
4698 EP_CAN_SMASH_EVERYTHING,
4703 EP_FOOD_DARK_YAMYAM,
4719 /* important: after initialization in InitElementPropertiesStatic(), the
4720 elements are not again initialized to a default value; therefore all
4721 changes have to make sure that they leave the element with a defined
4722 property (which means that conditional property changes must be set to
4723 a reliable default value before) */
4725 // resolve group elements
4726 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4727 ResolveGroupElement(EL_GROUP_START + i);
4729 // set all special, combined or engine dependent element properties
4730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4732 // do not change (already initialized) clipboard elements here
4733 if (IS_CLIPBOARD_ELEMENT(i))
4736 // ---------- INACTIVE ----------------------------------------------------
4737 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4738 i <= EL_CHAR_END) ||
4739 (i >= EL_STEEL_CHAR_START &&
4740 i <= EL_STEEL_CHAR_END)));
4742 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4743 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4744 IS_WALKABLE_INSIDE(i) ||
4745 IS_WALKABLE_UNDER(i)));
4747 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4748 IS_PASSABLE_INSIDE(i) ||
4749 IS_PASSABLE_UNDER(i)));
4751 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4752 IS_PASSABLE_OVER(i)));
4754 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4755 IS_PASSABLE_INSIDE(i)));
4757 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4758 IS_PASSABLE_UNDER(i)));
4760 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4763 // ---------- COLLECTIBLE -------------------------------------------------
4764 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4768 // ---------- SNAPPABLE ---------------------------------------------------
4769 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4770 IS_COLLECTIBLE(i) ||
4774 // ---------- WALL --------------------------------------------------------
4775 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4777 for (j = 0; no_wall_properties[j] != -1; j++)
4778 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4779 i >= EL_FIRST_RUNTIME_UNREAL)
4780 SET_PROPERTY(i, EP_WALL, FALSE);
4782 if (IS_HISTORIC_WALL(i))
4783 SET_PROPERTY(i, EP_WALL, TRUE);
4785 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4786 if (engine_version < VERSION_IDENT(2,2,0,0))
4787 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4789 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4791 !IS_COLLECTIBLE(i)));
4793 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4794 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4795 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4797 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4800 // ---------- EXPLOSION_PROOF ---------------------------------------------
4802 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4803 else if (engine_version < VERSION_IDENT(2,2,0,0))
4804 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4806 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4810 if (IS_CUSTOM_ELEMENT(i))
4812 // these are additional properties which are initially false when set
4814 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4816 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4817 if (DONT_COLLIDE_WITH(i))
4818 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4820 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4821 if (CAN_SMASH_EVERYTHING(i))
4822 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4823 if (CAN_SMASH_ENEMIES(i))
4824 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4827 // ---------- CAN_SMASH ---------------------------------------------------
4828 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4829 CAN_SMASH_ENEMIES(i) ||
4830 CAN_SMASH_EVERYTHING(i)));
4832 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4833 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4834 EXPLODES_BY_FIRE(i)));
4836 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4837 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4838 EXPLODES_SMASHED(i)));
4840 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4841 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4842 EXPLODES_IMPACT(i)));
4844 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4845 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4847 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4848 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4849 i == EL_BLACK_ORB));
4851 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4852 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4854 IS_CUSTOM_ELEMENT(i)));
4856 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4857 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4858 i == EL_SP_ELECTRON));
4860 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4861 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4862 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4863 getMoveIntoAcidProperty(&level, i));
4865 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4866 if (MAYBE_DONT_COLLIDE_WITH(i))
4867 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4868 getDontCollideWithProperty(&level, i));
4870 // ---------- SP_PORT -----------------------------------------------------
4871 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4872 IS_PASSABLE_INSIDE(i)));
4874 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4875 for (j = 0; j < level.num_android_clone_elements; j++)
4876 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4878 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4880 // ---------- CAN_CHANGE --------------------------------------------------
4881 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4882 for (j = 0; j < element_info[i].num_change_pages; j++)
4883 if (element_info[i].change_page[j].can_change)
4884 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4886 // ---------- HAS_ACTION --------------------------------------------------
4887 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4888 for (j = 0; j < element_info[i].num_change_pages; j++)
4889 if (element_info[i].change_page[j].has_action)
4890 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4892 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4893 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4896 // ---------- GFX_CRUMBLED ------------------------------------------------
4897 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4898 element_info[i].crumbled[ACTION_DEFAULT] !=
4899 element_info[i].graphic[ACTION_DEFAULT]);
4901 // ---------- EDITOR_CASCADE ----------------------------------------------
4902 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4903 IS_EDITOR_CASCADE_INACTIVE(i)));
4906 // dynamically adjust element properties according to game engine version
4908 static int ep_em_slippery_wall[] =
4913 EL_EXPANDABLE_WALL_HORIZONTAL,
4914 EL_EXPANDABLE_WALL_VERTICAL,
4915 EL_EXPANDABLE_WALL_ANY,
4916 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4917 EL_EXPANDABLE_STEELWALL_VERTICAL,
4918 EL_EXPANDABLE_STEELWALL_ANY,
4919 EL_EXPANDABLE_STEELWALL_GROWING,
4923 static int ep_em_explodes_by_fire[] =
4926 EL_EM_DYNAMITE_ACTIVE,
4931 // special EM style gems behaviour
4932 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4933 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4934 level.em_slippery_gems);
4936 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4937 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4938 (level.em_slippery_gems &&
4939 engine_version > VERSION_IDENT(2,0,1,0)));
4941 // special EM style explosion behaviour regarding chain reactions
4942 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4943 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4944 level.em_explodes_by_fire);
4947 // this is needed because some graphics depend on element properties
4948 if (game_status == GAME_MODE_PLAYING)
4949 InitElementGraphicInfo();
4952 void InitElementPropertiesGfxElement(void)
4956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4958 struct ElementInfo *ei = &element_info[i];
4960 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4964 static void InitGlobal(void)
4969 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4971 // check if element_name_info entry defined for each element in "main.h"
4972 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4973 Fail("undefined 'element_name_info' entry for element %d", i);
4975 element_info[i].token_name = element_name_info[i].token_name;
4976 element_info[i].class_name = element_name_info[i].class_name;
4977 element_info[i].editor_description= element_name_info[i].editor_description;
4980 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4982 // check if global_anim_name_info defined for each entry in "main.h"
4983 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4984 global_anim_name_info[i].token_name == NULL)
4985 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4987 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4990 // create hash to store URLs for global animations
4991 anim_url_hash = newSetupFileHash();
4993 // create hash from image config list
4994 image_config_hash = newSetupFileHash();
4995 for (i = 0; image_config[i].token != NULL; i++)
4996 setHashEntry(image_config_hash,
4997 image_config[i].token,
4998 image_config[i].value);
5000 // create hash from element token list
5001 element_token_hash = newSetupFileHash();
5002 for (i = 0; element_name_info[i].token_name != NULL; i++)
5003 setHashEntry(element_token_hash,
5004 element_name_info[i].token_name,
5007 // create hash from graphic token list
5008 graphic_token_hash = newSetupFileHash();
5009 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5010 if (strSuffix(image_config[i].value, ".png") ||
5011 strSuffix(image_config[i].value, ".pcx") ||
5012 strSuffix(image_config[i].value, ".wav") ||
5013 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5014 setHashEntry(graphic_token_hash,
5015 image_config[i].token,
5016 int2str(graphic++, 0));
5018 // create hash from font token list
5019 font_token_hash = newSetupFileHash();
5020 for (i = 0; font_info[i].token_name != NULL; i++)
5021 setHashEntry(font_token_hash,
5022 font_info[i].token_name,
5025 // set default filenames for all cloned graphics in static configuration
5026 for (i = 0; image_config[i].token != NULL; i++)
5028 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5030 char *token = image_config[i].token;
5031 char *token_clone_from = getStringCat2(token, ".clone_from");
5032 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5034 if (token_cloned != NULL)
5036 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5038 if (value_cloned != NULL)
5040 // set default filename in static configuration
5041 image_config[i].value = value_cloned;
5043 // set default filename in image config hash
5044 setHashEntry(image_config_hash, token, value_cloned);
5048 free(token_clone_from);
5052 // always start with reliable default values (all elements)
5053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5054 ActiveElement[i] = i;
5056 // now add all entries that have an active state (active elements)
5057 for (i = 0; element_with_active_state[i].element != -1; i++)
5059 int element = element_with_active_state[i].element;
5060 int element_active = element_with_active_state[i].element_active;
5062 ActiveElement[element] = element_active;
5065 // always start with reliable default values (all buttons)
5066 for (i = 0; i < NUM_IMAGE_FILES; i++)
5067 ActiveButton[i] = i;
5069 // now add all entries that have an active state (active buttons)
5070 for (i = 0; button_with_active_state[i].button != -1; i++)
5072 int button = button_with_active_state[i].button;
5073 int button_active = button_with_active_state[i].button_active;
5075 ActiveButton[button] = button_active;
5078 // always start with reliable default values (all fonts)
5079 for (i = 0; i < NUM_FONTS; i++)
5082 // now add all entries that have an active state (active fonts)
5083 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5085 int font = font_with_active_state[i].font_nr;
5086 int font_active = font_with_active_state[i].font_nr_active;
5088 ActiveFont[font] = font_active;
5091 global.autoplay_leveldir = NULL;
5092 global.patchtapes_leveldir = NULL;
5093 global.convert_leveldir = NULL;
5094 global.dumplevel_leveldir = NULL;
5095 global.dumptape_leveldir = NULL;
5096 global.create_sketch_images_dir = NULL;
5097 global.create_collect_images_dir = NULL;
5099 global.frames_per_second = 0;
5100 global.show_frames_per_second = FALSE;
5102 global.border_status = GAME_MODE_LOADING;
5103 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5105 global.use_envelope_request = FALSE;
5107 global.user_names = NULL;
5110 static void Execute_Command(char *command)
5114 if (strEqual(command, "print graphicsinfo.conf"))
5116 Print("# You can configure additional/alternative image files here.\n");
5117 Print("# (The entries below are default and therefore commented out.)\n");
5119 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5121 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5124 for (i = 0; image_config[i].token != NULL; i++)
5125 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5126 image_config[i].value));
5130 else if (strEqual(command, "print soundsinfo.conf"))
5132 Print("# You can configure additional/alternative sound files here.\n");
5133 Print("# (The entries below are default and therefore commented out.)\n");
5135 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5137 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5140 for (i = 0; sound_config[i].token != NULL; i++)
5141 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5142 sound_config[i].value));
5146 else if (strEqual(command, "print musicinfo.conf"))
5148 Print("# You can configure additional/alternative music files here.\n");
5149 Print("# (The entries below are default and therefore commented out.)\n");
5151 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5153 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5156 for (i = 0; music_config[i].token != NULL; i++)
5157 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5158 music_config[i].value));
5162 else if (strEqual(command, "print editorsetup.conf"))
5164 Print("# You can configure your personal editor element list here.\n");
5165 Print("# (The entries below are default and therefore commented out.)\n");
5168 // this is needed to be able to check element list for cascade elements
5169 InitElementPropertiesStatic();
5170 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5172 PrintEditorElementList();
5176 else if (strEqual(command, "print helpanim.conf"))
5178 Print("# You can configure different element help animations here.\n");
5179 Print("# (The entries below are default and therefore commented out.)\n");
5182 for (i = 0; helpanim_config[i].token != NULL; i++)
5184 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5185 helpanim_config[i].value));
5187 if (strEqual(helpanim_config[i].token, "end"))
5193 else if (strEqual(command, "print helptext.conf"))
5195 Print("# You can configure different element help text here.\n");
5196 Print("# (The entries below are default and therefore commented out.)\n");
5199 for (i = 0; helptext_config[i].token != NULL; i++)
5200 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5201 helptext_config[i].value));
5205 else if (strPrefix(command, "dump level "))
5207 char *filename = &command[11];
5209 if (fileExists(filename))
5211 LoadLevelFromFilename(&level, filename);
5217 char *leveldir = getStringCopy(filename); // read command parameters
5218 char *level_nr = strchr(leveldir, ' ');
5220 if (level_nr == NULL)
5221 Fail("cannot open file '%s'", filename);
5225 global.dumplevel_leveldir = leveldir;
5226 global.dumplevel_level_nr = atoi(level_nr);
5228 program.headless = TRUE;
5230 else if (strPrefix(command, "dump tape "))
5232 char *filename = &command[10];
5234 if (fileExists(filename))
5236 LoadTapeFromFilename(filename);
5242 char *leveldir = getStringCopy(filename); // read command parameters
5243 char *level_nr = strchr(leveldir, ' ');
5245 if (level_nr == NULL)
5246 Fail("cannot open file '%s'", filename);
5250 global.dumptape_leveldir = leveldir;
5251 global.dumptape_level_nr = atoi(level_nr);
5253 program.headless = TRUE;
5255 else if (strPrefix(command, "autoplay ") ||
5256 strPrefix(command, "autoffwd ") ||
5257 strPrefix(command, "autowarp ") ||
5258 strPrefix(command, "autotest ") ||
5259 strPrefix(command, "autosave ") ||
5260 strPrefix(command, "autoupload ") ||
5261 strPrefix(command, "autofix "))
5263 char *arg_ptr = strchr(command, ' ');
5264 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5266 global.autoplay_mode =
5267 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5268 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5269 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5270 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5271 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5272 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5273 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5274 AUTOPLAY_MODE_NONE);
5276 while (*str_ptr != '\0') // continue parsing string
5278 // cut leading whitespace from string, replace it by string terminator
5279 while (*str_ptr == ' ' || *str_ptr == '\t')
5282 if (*str_ptr == '\0') // end of string reached
5285 if (global.autoplay_leveldir == NULL) // read level set string
5287 global.autoplay_leveldir = str_ptr;
5288 global.autoplay_all = TRUE; // default: play all tapes
5290 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5291 global.autoplay_level[i] = FALSE;
5293 else // read level number string
5295 int level_nr = atoi(str_ptr); // get level_nr value
5297 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5298 global.autoplay_level[level_nr] = TRUE;
5300 global.autoplay_all = FALSE;
5303 // advance string pointer to the next whitespace (or end of string)
5304 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5308 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5309 program.headless = TRUE;
5311 else if (strPrefix(command, "patch tapes "))
5313 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5315 // skip leading whitespace
5316 while (*str_ptr == ' ' || *str_ptr == '\t')
5319 if (*str_ptr == '\0')
5320 Fail("cannot find MODE in command '%s'", command);
5322 global.patchtapes_mode = str_ptr; // store patch mode
5324 // advance to next whitespace (or end of string)
5325 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5328 while (*str_ptr != '\0') // continue parsing string
5330 // cut leading whitespace from string, replace it by string terminator
5331 while (*str_ptr == ' ' || *str_ptr == '\t')
5334 if (*str_ptr == '\0') // end of string reached
5337 if (global.patchtapes_leveldir == NULL) // read level set string
5339 global.patchtapes_leveldir = str_ptr;
5340 global.patchtapes_all = TRUE; // default: patch all tapes
5342 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5343 global.patchtapes_level[i] = FALSE;
5345 else // read level number string
5347 int level_nr = atoi(str_ptr); // get level_nr value
5349 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5350 global.patchtapes_level[level_nr] = TRUE;
5352 global.patchtapes_all = FALSE;
5355 // advance string pointer to the next whitespace (or end of string)
5356 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5360 if (global.patchtapes_leveldir == NULL)
5362 if (strEqual(global.patchtapes_mode, "help"))
5363 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5365 Fail("cannot find LEVELDIR in command '%s'", command);
5368 program.headless = TRUE;
5370 else if (strPrefix(command, "convert "))
5372 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5373 char *str_ptr = strchr(str_copy, ' ');
5375 global.convert_leveldir = str_copy;
5376 global.convert_level_nr = -1;
5378 if (str_ptr != NULL) // level number follows
5380 *str_ptr++ = '\0'; // terminate leveldir string
5381 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5384 program.headless = TRUE;
5386 else if (strPrefix(command, "create sketch images "))
5388 global.create_sketch_images_dir = getStringCopy(&command[21]);
5390 if (access(global.create_sketch_images_dir, W_OK) != 0)
5391 Fail("image target directory '%s' not found or not writable",
5392 global.create_sketch_images_dir);
5394 else if (strPrefix(command, "create collect image "))
5396 global.create_collect_images_dir = getStringCopy(&command[21]);
5398 if (access(global.create_collect_images_dir, W_OK) != 0)
5399 Fail("image target directory '%s' not found or not writable",
5400 global.create_collect_images_dir);
5402 else if (strPrefix(command, "create CE image "))
5404 CreateCustomElementImages(&command[16]);
5410 FailWithHelp("unrecognized command '%s'", command);
5413 // disable networking if any valid command was recognized
5414 options.network = setup.network_mode = FALSE;
5417 static void InitSetup(void)
5419 LoadUserNames(); // global user names
5420 LoadUserSetup(); // global user number
5422 LoadSetup(); // global setup info
5424 // set some options from setup file
5426 if (setup.options.verbose)
5427 options.verbose = TRUE;
5429 if (setup.debug.show_frames_per_second)
5430 global.show_frames_per_second = TRUE;
5433 static void InitGameInfo(void)
5435 game.restart_level = FALSE;
5436 game.restart_game_message = NULL;
5438 game.request_active = FALSE;
5439 game.request_active_or_moving = FALSE;
5441 game.use_masked_elements_initial = FALSE;
5444 static void InitPlayerInfo(void)
5448 // choose default local player
5449 local_player = &stored_player[0];
5451 for (i = 0; i < MAX_PLAYERS; i++)
5453 stored_player[i].connected_locally = FALSE;
5454 stored_player[i].connected_network = FALSE;
5457 local_player->connected_locally = TRUE;
5460 static void InitArtworkInfo(void)
5465 static char *get_string_in_brackets(char *string)
5467 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5469 sprintf(string_in_brackets, "[%s]", string);
5471 return string_in_brackets;
5474 static char *get_level_id_suffix(int id_nr)
5476 char *id_suffix = checked_malloc(1 + 3 + 1);
5478 if (id_nr < 0 || id_nr > 999)
5481 sprintf(id_suffix, ".%03d", id_nr);
5486 static void InitArtworkConfig(void)
5488 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5490 NUM_GLOBAL_ANIM_TOKENS + 1];
5491 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5492 NUM_GLOBAL_ANIM_TOKENS + 1];
5493 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5494 NUM_GLOBAL_ANIM_TOKENS + 1];
5495 static char *action_id_suffix[NUM_ACTIONS + 1];
5496 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5497 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5498 static char *level_id_suffix[MAX_LEVELS + 1];
5499 static char *dummy[1] = { NULL };
5500 static char *ignore_generic_tokens[] =
5505 "program_copyright",
5510 static char **ignore_image_tokens;
5511 static char **ignore_sound_tokens;
5512 static char **ignore_music_tokens;
5513 int num_ignore_generic_tokens;
5514 int num_ignore_image_tokens;
5515 int num_ignore_sound_tokens;
5516 int num_ignore_music_tokens;
5519 // dynamically determine list of generic tokens to be ignored
5520 num_ignore_generic_tokens = 0;
5521 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5522 num_ignore_generic_tokens++;
5524 // dynamically determine list of image tokens to be ignored
5525 num_ignore_image_tokens = num_ignore_generic_tokens;
5526 for (i = 0; image_config_vars[i].token != NULL; i++)
5527 num_ignore_image_tokens++;
5528 ignore_image_tokens =
5529 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5530 for (i = 0; i < num_ignore_generic_tokens; i++)
5531 ignore_image_tokens[i] = ignore_generic_tokens[i];
5532 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5533 ignore_image_tokens[num_ignore_generic_tokens + i] =
5534 image_config_vars[i].token;
5535 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5537 // dynamically determine list of sound tokens to be ignored
5538 num_ignore_sound_tokens = num_ignore_generic_tokens;
5539 ignore_sound_tokens =
5540 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5541 for (i = 0; i < num_ignore_generic_tokens; i++)
5542 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5543 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5545 // dynamically determine list of music tokens to be ignored
5546 num_ignore_music_tokens = num_ignore_generic_tokens;
5547 ignore_music_tokens =
5548 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5549 for (i = 0; i < num_ignore_generic_tokens; i++)
5550 ignore_music_tokens[i] = ignore_generic_tokens[i];
5551 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5553 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5554 image_id_prefix[i] = element_info[i].token_name;
5555 for (i = 0; i < NUM_FONTS; i++)
5556 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5557 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5558 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5559 global_anim_info[i].token_name;
5560 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5562 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5563 sound_id_prefix[i] = element_info[i].token_name;
5564 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5565 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5566 get_string_in_brackets(element_info[i].class_name);
5567 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5568 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5569 global_anim_info[i].token_name;
5570 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5572 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5573 music_id_prefix[i] = music_prefix_info[i].prefix;
5574 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5575 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5576 global_anim_info[i].token_name;
5577 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5579 for (i = 0; i < NUM_ACTIONS; i++)
5580 action_id_suffix[i] = element_action_info[i].suffix;
5581 action_id_suffix[NUM_ACTIONS] = NULL;
5583 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5584 direction_id_suffix[i] = element_direction_info[i].suffix;
5585 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5587 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5588 special_id_suffix[i] = special_suffix_info[i].suffix;
5589 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5591 for (i = 0; i < MAX_LEVELS; i++)
5592 level_id_suffix[i] = get_level_id_suffix(i);
5593 level_id_suffix[MAX_LEVELS] = NULL;
5595 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5596 image_id_prefix, action_id_suffix, direction_id_suffix,
5597 special_id_suffix, ignore_image_tokens);
5598 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5599 sound_id_prefix, action_id_suffix, dummy,
5600 special_id_suffix, ignore_sound_tokens);
5601 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5602 music_id_prefix, action_id_suffix, special_id_suffix,
5603 level_id_suffix, ignore_music_tokens);
5606 static void InitMixer(void)
5613 static void InitVideoOverlay(void)
5615 // if virtual buttons are not loaded from setup file, repeat initializing
5616 // virtual buttons grid with default values now that video is initialized
5617 if (!setup.touch.grid_initialized)
5620 InitTileCursorInfo();
5624 void InitGfxBuffers(void)
5626 static int win_xsize_last = -1;
5627 static int win_ysize_last = -1;
5629 // create additional image buffers for double-buffering and cross-fading
5631 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5633 // used to temporarily store the backbuffer -- only re-create if changed
5634 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5635 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5637 win_xsize_last = WIN_XSIZE;
5638 win_ysize_last = WIN_YSIZE;
5641 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5642 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5643 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5644 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5646 // initialize screen properties
5647 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5648 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5650 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5651 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5652 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5653 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5654 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5655 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5657 // required if door size definitions have changed
5658 InitGraphicCompatibilityInfo_Doors();
5660 InitGfxBuffers_EM();
5661 InitGfxBuffers_SP();
5664 static void InitGfx(void)
5666 struct GraphicInfo *graphic_info_last = graphic_info;
5667 char *filename_font_initial = NULL;
5668 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5669 char *image_token[NUM_INITIAL_IMAGES] =
5671 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5672 CONFIG_TOKEN_GLOBAL_BUSY,
5673 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5674 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5675 CONFIG_TOKEN_BACKGROUND_LOADING
5677 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5681 &init.busy_playfield
5683 Bitmap *bitmap_font_initial = NULL;
5684 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5687 // determine settings for initial font (for displaying startup messages)
5688 for (i = 0; image_config[i].token != NULL; i++)
5690 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5692 char font_token[128];
5695 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5696 len_font_token = strlen(font_token);
5698 if (strEqual(image_config[i].token, font_token))
5700 filename_font_initial = image_config[i].value;
5702 else if (strlen(image_config[i].token) > len_font_token &&
5703 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5705 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5706 font_initial[j].src_x = atoi(image_config[i].value);
5707 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5708 font_initial[j].src_y = atoi(image_config[i].value);
5709 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5710 font_initial[j].width = atoi(image_config[i].value);
5711 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5712 font_initial[j].height = atoi(image_config[i].value);
5717 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5719 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5720 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5723 if (filename_font_initial == NULL) // should not happen
5724 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5727 InitGfxCustomArtworkInfo();
5728 InitGfxOtherSettings();
5730 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5732 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5734 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5735 font_initial[j].bitmap = bitmap_font_initial;
5737 InitFontGraphicInfo();
5741 DrawInitTextHead("Loading graphics");
5743 InitMenuDesignSettings_Static();
5745 // initialize settings for initial images with default values
5746 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5747 for (j = 0; j < NUM_GFX_ARGS; j++)
5749 get_graphic_parameter_value(image_config_suffix[j].value,
5750 image_config_suffix[j].token,
5751 image_config_suffix[j].type);
5753 // read settings for initial images from default custom artwork config
5754 char *gfx_config_filename = getPath3(options.graphics_directory,
5756 GRAPHICSINFO_FILENAME);
5758 if (fileExists(gfx_config_filename))
5760 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5762 if (setup_file_hash)
5764 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5766 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5770 filename_image_initial[i] = getStringCopy(filename);
5772 for (j = 0; image_config_suffix[j].token != NULL; j++)
5774 int type = image_config_suffix[j].type;
5775 char *suffix = image_config_suffix[j].token;
5776 char *token = getStringCat2(image_token[i], suffix);
5777 char *value = getHashEntry(setup_file_hash, token);
5779 checked_free(token);
5783 get_graphic_parameter_value(value, suffix, type);
5788 // read values from custom graphics config file
5789 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5791 freeSetupFileHash(setup_file_hash);
5795 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5797 if (filename_image_initial[i] == NULL)
5799 int len_token = strlen(image_token[i]);
5801 // read settings for initial images from static default artwork config
5802 for (j = 0; image_config[j].token != NULL; j++)
5804 if (strEqual(image_config[j].token, image_token[i]))
5806 filename_image_initial[i] = getStringCopy(image_config[j].value);
5808 else if (strlen(image_config[j].token) > len_token &&
5809 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5811 for (k = 0; image_config_suffix[k].token != NULL; k++)
5813 if (strEqual(&image_config[j].token[len_token],
5814 image_config_suffix[k].token))
5816 get_graphic_parameter_value(image_config[j].value,
5817 image_config_suffix[k].token,
5818 image_config_suffix[k].type);
5825 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5827 if (filename_image_initial[i] == NULL) // should not happen
5828 Fail("cannot get filename for '%s'", image_token[i]);
5830 image_initial[i].bitmaps =
5831 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5833 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5834 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5835 LoadCustomImage(filename_image_initial[i]);
5837 checked_free(filename_image_initial[i]);
5840 graphic_info = image_initial; // graphic == 0 => image_initial
5842 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5843 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5845 graphic_info = graphic_info_last;
5847 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5849 // set image size for busy animations
5850 init_busy[i]->width = image_initial[i].width;
5851 init_busy[i]->height = image_initial[i].height;
5854 SetLoadingBackgroundImage();
5856 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5858 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5859 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5860 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5861 InitGfxDrawTileCursorFunction(DrawTileCursor);
5863 gfx.fade_border_source_status = global.border_status;
5864 gfx.fade_border_target_status = global.border_status;
5865 gfx.masked_border_bitmap_ptr = backbuffer;
5867 // use copy of busy animation to prevent change while reloading artwork
5871 static void InitGfxBackground(void)
5873 fieldbuffer = bitmap_db_field;
5874 SetDrawtoField(DRAW_TO_BACKBUFFER);
5876 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5878 redraw_mask = REDRAW_ALL;
5881 static void InitLevelInfo(void)
5883 LoadLevelInfo(); // global level info
5884 LoadLevelSetup_LastSeries(); // last played series info
5885 LoadLevelSetup_SeriesInfo(); // last played level info
5887 if (global.autoplay_leveldir &&
5888 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5890 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5891 global.autoplay_leveldir);
5892 if (leveldir_current == NULL)
5893 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5896 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5899 static void InitLevelArtworkInfo(void)
5901 LoadLevelArtworkInfo();
5904 static void InitImages(void)
5906 print_timestamp_init("InitImages");
5909 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5910 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5911 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5912 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5913 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5914 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5915 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5916 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5919 setLevelArtworkDir(artwork.gfx_first);
5922 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5923 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5924 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5925 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5926 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5927 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5928 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5929 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5933 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5934 leveldir_current->identifier,
5935 artwork.gfx_current_identifier,
5936 artwork.gfx_current->identifier,
5937 leveldir_current->graphics_set,
5938 leveldir_current->graphics_path);
5941 UPDATE_BUSY_STATE();
5943 ReloadCustomImages();
5944 print_timestamp_time("ReloadCustomImages");
5946 UPDATE_BUSY_STATE();
5948 LoadCustomElementDescriptions();
5949 print_timestamp_time("LoadCustomElementDescriptions");
5951 UPDATE_BUSY_STATE();
5953 LoadMenuDesignSettings();
5954 print_timestamp_time("LoadMenuDesignSettings");
5956 UPDATE_BUSY_STATE();
5958 ReinitializeGraphics();
5959 print_timestamp_time("ReinitializeGraphics");
5961 LoadMenuDesignSettings_AfterGraphics();
5962 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5964 UPDATE_BUSY_STATE();
5966 print_timestamp_done("InitImages");
5969 static void InitSound(char *identifier)
5971 print_timestamp_init("InitSound");
5973 if (identifier == NULL)
5974 identifier = artwork.snd_current->identifier;
5976 // set artwork path to send it to the sound server process
5977 setLevelArtworkDir(artwork.snd_first);
5979 InitReloadCustomSounds(identifier);
5980 print_timestamp_time("InitReloadCustomSounds");
5982 ReinitializeSounds();
5983 print_timestamp_time("ReinitializeSounds");
5985 print_timestamp_done("InitSound");
5988 static void InitMusic(char *identifier)
5990 print_timestamp_init("InitMusic");
5992 if (identifier == NULL)
5993 identifier = artwork.mus_current->identifier;
5995 // set artwork path to send it to the sound server process
5996 setLevelArtworkDir(artwork.mus_first);
5998 InitReloadCustomMusic(identifier);
5999 print_timestamp_time("InitReloadCustomMusic");
6001 ReinitializeMusic();
6002 print_timestamp_time("ReinitializeMusic");
6004 print_timestamp_done("InitMusic");
6007 static void InitArtworkDone(void)
6009 if (program.headless)
6012 InitGlobalAnimations();
6015 static void InitNetworkSettings(void)
6017 boolean network_enabled = (options.network || setup.network_mode);
6018 char *network_server = (options.server_host != NULL ? options.server_host :
6019 setup.network_server_hostname);
6021 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6022 network_server = NULL;
6024 InitNetworkInfo(network_enabled,
6028 options.server_port);
6031 void InitNetworkServer(void)
6033 if (!network.enabled || network.connected)
6036 LimitScreenUpdates(FALSE);
6038 if (game_status == GAME_MODE_LOADING)
6041 if (!ConnectToServer(network.server_host, network.server_port))
6043 network.enabled = FALSE;
6045 setup.network_mode = FALSE;
6049 SendToServer_ProtocolVersion();
6050 SendToServer_PlayerName(setup.player_name);
6051 SendToServer_NrWanted(setup.network_player_nr + 1);
6053 network.connected = TRUE;
6056 // short time to recognize result of network initialization
6057 if (game_status == GAME_MODE_LOADING)
6058 Delay_WithScreenUpdates(1000);
6061 static boolean CheckArtworkConfigForCustomElements(char *filename)
6063 SetupFileHash *setup_file_hash;
6064 boolean redefined_ce_found = FALSE;
6066 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6068 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6070 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6072 char *token = HASH_ITERATION_TOKEN(itr);
6074 if (strPrefix(token, "custom_"))
6076 redefined_ce_found = TRUE;
6081 END_HASH_ITERATION(setup_file_hash, itr)
6083 freeSetupFileHash(setup_file_hash);
6086 return redefined_ce_found;
6089 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6091 char *filename_base, *filename_local;
6092 boolean redefined_ce_found = FALSE;
6094 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6097 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6098 "leveldir_current->identifier == '%s'",
6099 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6100 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6101 "leveldir_current->graphics_path == '%s'",
6102 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6103 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6104 "leveldir_current->graphics_set == '%s'",
6105 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6106 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6107 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6108 leveldir_current == NULL ? "[NULL]" :
6109 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6112 // first look for special artwork configured in level series config
6113 filename_base = getCustomArtworkLevelConfigFilename(type);
6116 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6117 "filename_base == '%s'", filename_base);
6120 if (fileExists(filename_base))
6121 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6123 filename_local = getCustomArtworkConfigFilename(type);
6126 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6127 "filename_local == '%s'", filename_local);
6130 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6131 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6134 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6135 "redefined_ce_found == %d", redefined_ce_found);
6138 return redefined_ce_found;
6141 static void InitOverrideArtwork(void)
6143 boolean redefined_ce_found = FALSE;
6145 // to check if this level set redefines any CEs, do not use overriding
6146 gfx.override_level_graphics = FALSE;
6147 gfx.override_level_sounds = FALSE;
6148 gfx.override_level_music = FALSE;
6150 // now check if this level set has definitions for custom elements
6151 if (setup.override_level_graphics == AUTO ||
6152 setup.override_level_sounds == AUTO ||
6153 setup.override_level_music == AUTO)
6154 redefined_ce_found =
6155 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6156 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6157 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6160 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6161 redefined_ce_found);
6164 if (redefined_ce_found)
6166 // this level set has CE definitions: change "AUTO" to "FALSE"
6167 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6168 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6169 gfx.override_level_music = (setup.override_level_music == TRUE);
6173 // this level set has no CE definitions: change "AUTO" to "TRUE"
6174 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6175 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6176 gfx.override_level_music = (setup.override_level_music != FALSE);
6180 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6181 gfx.override_level_graphics,
6182 gfx.override_level_sounds,
6183 gfx.override_level_music);
6187 static char *setNewArtworkIdentifier(int type)
6189 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6190 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6191 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6192 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6193 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6194 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6195 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6196 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6197 char *leveldir_identifier = leveldir_current->identifier;
6198 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6199 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6200 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6201 TreeInfo *custom_artwork_set =
6202 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6203 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6204 char *artwork_current_identifier;
6205 char *artwork_new_identifier = NULL; // default: nothing has changed
6207 // leveldir_current may be invalid (level group, parent link)
6208 if (!validLevelSeries(leveldir_current))
6211 /* 1st step: determine artwork set to be activated in descending order:
6212 --------------------------------------------------------------------
6213 1. setup artwork (when configured to override everything else)
6214 2. artwork set configured in "levelinfo.conf" of current level set
6215 (artwork in level directory will have priority when loading later)
6216 3. artwork in level directory (stored in artwork sub-directory)
6217 4. setup artwork (currently configured in setup menu) */
6219 if (setup_override_artwork)
6220 artwork_current_identifier = setup_artwork_set;
6221 else if (has_level_artwork_set)
6222 artwork_current_identifier = leveldir_artwork_set;
6223 else if (has_custom_artwork_set)
6224 artwork_current_identifier = leveldir_identifier;
6226 artwork_current_identifier = setup_artwork_set;
6228 /* 2nd step: check if it is really needed to reload artwork set
6229 ------------------------------------------------------------ */
6231 // ---------- reload if level set and also artwork set has changed ----------
6232 if (last_leveldir_identifier[type] != leveldir_identifier &&
6233 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6234 artwork_new_identifier = artwork_current_identifier;
6236 last_leveldir_identifier[type] = leveldir_identifier;
6237 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6239 // ---------- reload if "override artwork" setting has changed --------------
6240 if (last_override_level_artwork[type] != setup_override_artwork)
6241 artwork_new_identifier = artwork_current_identifier;
6243 last_override_level_artwork[type] = setup_override_artwork;
6245 // ---------- reload if current artwork identifier has changed --------------
6246 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6247 artwork_new_identifier = artwork_current_identifier;
6249 // (we cannot compare string pointers here, so copy string content itself)
6250 setString(&last_artwork_identifier[type], artwork_current_identifier);
6252 // ---------- set new artwork identifier ----------
6253 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6255 // ---------- do not reload directly after starting -------------------------
6256 if (!initialized[type])
6257 artwork_new_identifier = NULL;
6259 initialized[type] = TRUE;
6261 return artwork_new_identifier;
6264 static void InitArtworkIdentifier(void)
6266 setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6267 setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6268 setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6271 void ReloadCustomArtwork(int force_reload)
6273 int last_game_status = game_status; // save current game status
6274 char *gfx_new_identifier;
6275 char *snd_new_identifier;
6276 char *mus_new_identifier;
6277 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6278 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6279 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6280 boolean reload_needed;
6282 InitOverrideArtwork();
6284 AdjustGraphicsForEMC();
6285 AdjustSoundsForEMC();
6287 gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6288 snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6289 mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6291 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6292 snd_new_identifier != NULL || force_reload_snd ||
6293 mus_new_identifier != NULL || force_reload_mus);
6298 print_timestamp_init("ReloadCustomArtwork");
6300 SetGameStatus(GAME_MODE_LOADING);
6302 FadeOut(REDRAW_ALL);
6304 SetLoadingBackgroundImage();
6306 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6307 print_timestamp_time("ClearRectangleOnBackground");
6311 UPDATE_BUSY_STATE();
6313 InitMissingFileHash();
6315 if (gfx_new_identifier != NULL || force_reload_gfx)
6318 Debug("init:ReloadCustomArtwork",
6319 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6320 artwork.gfx_current_identifier,
6322 artwork.gfx_current->identifier,
6323 leveldir_current->graphics_set);
6327 print_timestamp_time("InitImages");
6330 if (snd_new_identifier != NULL || force_reload_snd)
6332 InitSound(snd_new_identifier);
6333 print_timestamp_time("InitSound");
6336 if (mus_new_identifier != NULL || force_reload_mus)
6338 InitMusic(mus_new_identifier);
6339 print_timestamp_time("InitMusic");
6344 SetGameStatus(last_game_status); // restore current game status
6346 FadeOut(REDRAW_ALL);
6348 RedrawGlobalBorder();
6350 // force redraw of (open or closed) door graphics
6351 SetDoorState(DOOR_OPEN_ALL);
6352 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6354 FadeSetEnterScreen();
6355 FadeSkipNextFadeOut();
6357 print_timestamp_done("ReloadCustomArtwork");
6359 LimitScreenUpdates(FALSE);
6362 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6364 if (global.autoplay_leveldir == NULL)
6365 KeyboardAutoRepeatOff();
6368 void DisplayExitMessage(char *format, va_list ap)
6370 // also check for initialized video (headless flag may be temporarily unset)
6371 if (program.headless || !video.initialized)
6374 // check if draw buffer and fonts for exit message are already available
6375 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6378 int font_1 = FC_RED;
6379 int font_2 = FC_YELLOW;
6380 int font_3 = FC_BLUE;
6381 int font_width = getFontWidth(font_2);
6382 int font_height = getFontHeight(font_2);
6385 int sxsize = WIN_XSIZE - 2 * sx;
6386 int sysize = WIN_YSIZE - 2 * sy;
6387 int line_length = sxsize / font_width;
6388 int max_lines = sysize / font_height;
6389 int num_lines_printed;
6393 gfx.sxsize = sxsize;
6394 gfx.sysize = sysize;
6398 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6400 DrawTextSCentered(sy, font_1, "Fatal error:");
6401 sy += 3 * font_height;;
6404 DrawTextBufferVA(sx, sy, format, ap, font_2,
6405 line_length, line_length, max_lines,
6406 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6407 sy += (num_lines_printed + 3) * font_height;
6409 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6410 sy += 3 * font_height;
6413 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6414 line_length, line_length, max_lines,
6415 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6417 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6419 redraw_mask = REDRAW_ALL;
6421 // force drawing exit message even if screen updates are currently limited
6422 LimitScreenUpdates(FALSE);
6426 // deactivate toons on error message screen
6427 setup.toons = FALSE;
6429 WaitForEventToContinue();
6433 // ============================================================================
6435 // ============================================================================
6439 print_timestamp_init("OpenAll");
6441 SetGameStatus(GAME_MODE_LOADING);
6445 InitGlobal(); // initialize some global variables
6447 InitRND(NEW_RANDOMIZE);
6448 InitSimpleRandom(NEW_RANDOMIZE);
6449 InitBetterRandom(NEW_RANDOMIZE);
6451 InitMissingFileHash();
6453 print_timestamp_time("[init global stuff]");
6457 print_timestamp_time("[init setup/config stuff (1)]");
6459 if (options.execute_command)
6460 Execute_Command(options.execute_command);
6462 InitNetworkSettings();
6466 if (network.serveronly)
6468 #if defined(PLATFORM_UNIX)
6469 NetworkServer(network.server_port, TRUE);
6471 Warn("networking only supported in Unix version");
6474 exit(0); // never reached, server loops forever
6478 print_timestamp_time("[init setup/config stuff (2)]");
6480 print_timestamp_time("[init setup/config stuff (3)]");
6481 InitArtworkInfo(); // needed before loading gfx, sound & music
6482 print_timestamp_time("[init setup/config stuff (4)]");
6483 InitArtworkConfig(); // needed before forking sound child process
6484 print_timestamp_time("[init setup/config stuff (5)]");
6486 print_timestamp_time("[init setup/config stuff (6)]");
6490 print_timestamp_time("[init setup/config stuff]");
6492 InitVideoDefaults();
6494 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6497 InitEventFilter(FilterMouseMotionEvents);
6499 print_timestamp_time("[init video stuff]");
6501 InitElementPropertiesStatic();
6502 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6503 InitElementPropertiesGfxElement();
6505 print_timestamp_time("[init element properties stuff]");
6509 print_timestamp_time("InitGfx");
6512 print_timestamp_time("InitLevelInfo");
6514 InitLevelArtworkInfo();
6515 print_timestamp_time("InitLevelArtworkInfo");
6517 InitOverrideArtwork(); // needs to know current level directory
6518 print_timestamp_time("InitOverrideArtwork");
6520 InitArtworkIdentifier(); // needs to know current level directory
6521 print_timestamp_time("InitArtworkIdentifier");
6523 InitImages(); // needs to know current level directory
6524 print_timestamp_time("InitImages");
6526 InitSound(NULL); // needs to know current level directory
6527 print_timestamp_time("InitSound");
6529 InitMusic(NULL); // needs to know current level directory
6530 print_timestamp_time("InitMusic");
6534 InitGfxBackground();
6540 if (global.autoplay_leveldir)
6545 else if (global.patchtapes_leveldir)
6550 else if (global.convert_leveldir)
6555 else if (global.dumplevel_leveldir)
6560 else if (global.dumptape_leveldir)
6565 else if (global.create_sketch_images_dir)
6567 CreateLevelSketchImages();
6570 else if (global.create_collect_images_dir)
6572 CreateCollectElementImages();
6576 InitNetworkServer();
6578 SetGameStatus(GAME_MODE_MAIN);
6580 FadeSetEnterScreen();
6581 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6582 FadeSkipNextFadeOut();
6584 print_timestamp_time("[post-artwork]");
6586 print_timestamp_done("OpenAll");
6588 if (setup.ask_for_remaining_tapes)
6589 setup.ask_for_uploading_tapes = TRUE;
6594 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6596 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6597 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6598 #if defined(PLATFORM_ANDROID)
6599 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6600 SDL_AndroidGetInternalStoragePath());
6601 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6602 SDL_AndroidGetExternalStoragePath());
6603 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6604 (SDL_AndroidGetExternalStorageState() &
6605 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6606 SDL_AndroidGetExternalStorageState() &
6607 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6612 static boolean WaitForApiThreads(void)
6614 DelayCounter thread_delay = { 10000 };
6616 if (program.api_thread_count == 0)
6619 // deactivate global animations (not accessible in game state "loading")
6620 setup.toons = FALSE;
6622 // set game state to "loading" to be able to show busy animation
6623 SetGameStatus(GAME_MODE_LOADING);
6625 ResetDelayCounter(&thread_delay);
6627 // wait for threads to finish (and fail on timeout)
6628 while (program.api_thread_count > 0)
6630 if (DelayReached(&thread_delay))
6632 Error("failed waiting for threads - TIMEOUT");
6637 UPDATE_BUSY_STATE();
6645 void CloseAllAndExit(int exit_value)
6647 WaitForApiThreads();
6652 CloseAudio(); // called after freeing sounds (needed for SDL)
6660 // set a flag to tell the network server thread to quit and wait for it
6661 // using SDL_WaitThread()
6663 // Code used with SDL 1.2:
6664 // if (network.server_thread) // terminate network server
6665 // SDL_KillThread(network.server_thread);
6667 CloseVideoDisplay();
6668 ClosePlatformDependentStuff();
6670 if (exit_value != 0 && !options.execute_command)
6672 // fall back to default level set (current set may have caused an error)
6673 SaveLevelSetup_LastSeries_Deactivate();
6675 // tell user where to find error log file which may contain more details
6676 // (error notification now directly displayed on screen inside R'n'D
6677 // NotifyUserAboutErrorFile(); // currently only works for Windows