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 unsigned int action_delay = 0;
142 unsigned int action_delay_value = GameFrameDelay;
143 int sync_frame = FrameCounter;
146 // prevent OS (Windows) from complaining about program not responding
149 if (game_status != GAME_MODE_LOADING && only_when_loading)
152 if (image_initial[graphic].bitmap == NULL || window == NULL)
155 if (!DelayReached(&action_delay, action_delay_value))
159 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
161 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
163 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
164 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
166 graphic_info = image_initial;
168 if (sync_frame % image_initial[graphic].anim_delay == 0)
172 int width = graphic_info[graphic].width;
173 int height = graphic_info[graphic].height;
174 int frame = getGraphicAnimationFrame(graphic, sync_frame);
176 ClearRectangleOnBackground(drawto, x, y, width, height);
178 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
179 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
181 BlitBitmap(drawto, window, x, y, width, height, x, y);
184 graphic_info = graphic_info_last;
189 static void DrawProgramInfo(void)
191 int font1_nr = FC_YELLOW;
192 int font2_nr = FC_RED;
193 int font2_height = getFontHeight(font2_nr);
196 int ypos3 = WIN_YSIZE - 20 - font2_height;
198 DrawInitText(getProgramInitString(), ypos1, font1_nr);
199 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
200 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
203 static void FreeGadgets(void)
205 FreeLevelEditorGadgets();
212 void InitGadgets(void)
214 static boolean gadgets_initialized = FALSE;
216 if (gadgets_initialized)
219 CreateLevelEditorGadgets();
223 CreateScreenGadgets();
225 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
227 gadgets_initialized = TRUE;
230 static void InitElementSmallImagesScaledUp(int graphic)
232 struct GraphicInfo *g = &graphic_info[graphic];
234 // create small and game tile sized bitmaps (and scale up, if needed)
235 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
238 static void InitElementSmallImages(void)
240 print_timestamp_init("InitElementSmallImages");
242 static int special_graphics[] =
256 IMG_EDITOR_ELEMENT_BORDER,
257 IMG_EDITOR_ELEMENT_BORDER_INPUT,
258 IMG_EDITOR_CASCADE_LIST,
259 IMG_EDITOR_CASCADE_LIST_ACTIVE,
262 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
263 int num_property_mappings = getImageListPropertyMappingSize();
266 print_timestamp_time("getImageListPropertyMapping/Size");
268 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
269 // initialize normal element images from static configuration
270 for (i = 0; element_to_graphic[i].element > -1; i++)
271 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
272 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
274 // initialize special element images from static configuration
275 for (i = 0; element_to_special_graphic[i].element > -1; i++)
276 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
277 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
279 // initialize element images from dynamic configuration
280 for (i = 0; i < num_property_mappings; i++)
281 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
282 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
283 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
285 // initialize special non-element images from above list
286 for (i = 0; special_graphics[i] > -1; i++)
287 InitElementSmallImagesScaledUp(special_graphics[i]);
288 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
290 print_timestamp_done("InitElementSmallImages");
293 static void InitScaledImagesScaledUp(int graphic)
295 struct GraphicInfo *g = &graphic_info[graphic];
297 ScaleImage(graphic, g->scale_up_factor);
300 static void InitScaledImages(void)
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
306 // scale normal images from static configuration, if not already scaled
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 InitScaledImagesScaledUp(i);
310 // scale images from dynamic configuration, if not already scaled
311 for (i = 0; i < num_property_mappings; i++)
312 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
315 static void InitBitmapPointers(void)
317 int num_images = getImageListSize();
320 // standard size bitmap may have changed -- update default bitmap pointer
321 for (i = 0; i < num_images; i++)
322 if (graphic_info[i].bitmaps)
323 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
326 void InitImageTextures(void)
328 static int texture_graphics[] =
330 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
331 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
332 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
333 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
334 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
335 IMG_MENU_BUTTON_TOUCH_BACK,
336 IMG_MENU_BUTTON_TOUCH_NEXT,
337 IMG_MENU_BUTTON_TOUCH_BACK2,
338 IMG_MENU_BUTTON_TOUCH_NEXT2,
343 FreeAllImageTextures();
345 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
346 CreateImageTextures(i);
348 for (i = 0; i < MAX_NUM_TOONS; i++)
349 CreateImageTextures(IMG_TOON_1 + i);
351 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
353 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
355 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
357 int graphic = global_anim_info[i].graphic[j][k];
359 if (graphic == IMG_UNDEFINED)
362 CreateImageTextures(graphic);
367 for (i = 0; texture_graphics[i] > -1; i++)
368 CreateImageTextures(texture_graphics[i]);
371 static int getFontBitmapID(int font_nr)
375 // (special case: do not use special font for GAME_MODE_LOADING)
376 if (game_status >= GAME_MODE_TITLE_INITIAL &&
377 game_status <= GAME_MODE_PSEUDO_PREVIEW)
378 special = game_status;
379 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
380 special = GFX_SPECIAL_ARG_MAIN;
381 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
382 special = GFX_SPECIAL_ARG_NAMES;
385 return font_info[font_nr].special_bitmap_id[special];
390 static int getFontFromToken(char *token)
392 char *value = getHashEntry(font_token_hash, token);
397 // if font not found, use reliable default value
398 return FONT_INITIAL_1;
401 static void InitFontGraphicInfo(void)
403 static struct FontBitmapInfo *font_bitmap_info = NULL;
404 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
405 int num_property_mappings = getImageListPropertyMappingSize();
406 int num_font_bitmaps = NUM_FONTS;
409 if (graphic_info == NULL) // still at startup phase
411 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
412 getFontBitmapID, getFontFromToken);
417 // ---------- initialize font graphic definitions ----------
419 // always start with reliable default values (normal font graphics)
420 for (i = 0; i < NUM_FONTS; i++)
421 font_info[i].graphic = IMG_FONT_INITIAL_1;
423 // initialize normal font/graphic mapping from static configuration
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
433 font_info[font_nr].graphic = graphic;
436 // always start with reliable default values (special font graphics)
437 for (i = 0; i < NUM_FONTS; i++)
439 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
441 font_info[i].special_graphic[j] = font_info[i].graphic;
442 font_info[i].special_bitmap_id[j] = i;
446 // initialize special font/graphic mapping from static configuration
447 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
449 int font_nr = font_to_graphic[i].font_nr;
450 int special = font_to_graphic[i].special;
451 int graphic = font_to_graphic[i].graphic;
452 int base_graphic = font2baseimg(font_nr);
454 if (IS_SPECIAL_GFX_ARG(special))
456 boolean base_redefined =
457 getImageListEntryFromImageID(base_graphic)->redefined;
458 boolean special_redefined =
459 getImageListEntryFromImageID(graphic)->redefined;
460 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
462 /* if the base font ("font.title_1", for example) has been redefined,
463 but not the special font ("font.title_1.LEVELS", for example), do not
464 use an existing (in this case considered obsolete) special font
465 anymore, but use the automatically determined default font */
466 /* special case: cloned special fonts must be explicitly redefined,
467 but are not automatically redefined by redefining base font */
468 if (base_redefined && !special_redefined && !special_cloned)
471 font_info[font_nr].special_graphic[special] = graphic;
472 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
477 // initialize special font/graphic mapping from dynamic configuration
478 for (i = 0; i < num_property_mappings; i++)
480 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
481 int special = property_mapping[i].ext3_index;
482 int graphic = property_mapping[i].artwork_index;
484 if (font_nr < 0 || font_nr >= NUM_FONTS)
487 if (IS_SPECIAL_GFX_ARG(special))
489 font_info[font_nr].special_graphic[special] = graphic;
490 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
495 /* correct special font/graphic mapping for cloned fonts for downwards
496 compatibility of PREVIEW fonts -- this is only needed for implicit
497 redefinition of special font by redefined base font, and only if other
498 fonts are cloned from this special font (like in the "Zelda" level set) */
499 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
501 int font_nr = font_to_graphic[i].font_nr;
502 int special = font_to_graphic[i].special;
503 int graphic = font_to_graphic[i].graphic;
505 if (IS_SPECIAL_GFX_ARG(special))
507 boolean special_redefined =
508 getImageListEntryFromImageID(graphic)->redefined;
509 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
511 if (special_cloned && !special_redefined)
515 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
517 int font_nr2 = font_to_graphic[j].font_nr;
518 int special2 = font_to_graphic[j].special;
519 int graphic2 = font_to_graphic[j].graphic;
521 if (IS_SPECIAL_GFX_ARG(special2) &&
522 graphic2 == graphic_info[graphic].clone_from)
524 font_info[font_nr].special_graphic[special] =
525 font_info[font_nr2].special_graphic[special2];
526 font_info[font_nr].special_bitmap_id[special] =
527 font_info[font_nr2].special_bitmap_id[special2];
534 // reset non-redefined ".active" font graphics if normal font is redefined
535 // (this different treatment is needed because normal and active fonts are
536 // independently defined ("active" is not a property of font definitions!)
537 for (i = 0; i < NUM_FONTS; i++)
539 int font_nr_base = i;
540 int font_nr_active = FONT_ACTIVE(font_nr_base);
542 // check only those fonts with exist as normal and ".active" variant
543 if (font_nr_base != font_nr_active)
545 int base_graphic = font_info[font_nr_base].graphic;
546 int active_graphic = font_info[font_nr_active].graphic;
547 boolean base_redefined =
548 getImageListEntryFromImageID(base_graphic)->redefined;
549 boolean active_redefined =
550 getImageListEntryFromImageID(active_graphic)->redefined;
552 /* if the base font ("font.menu_1", for example) has been redefined,
553 but not the active font ("font.menu_1.active", for example), do not
554 use an existing (in this case considered obsolete) active font
555 anymore, but use the automatically determined default font */
556 if (base_redefined && !active_redefined)
557 font_info[font_nr_active].graphic = base_graphic;
559 // now also check each "special" font (which may be the same as above)
560 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
562 int base_graphic = font_info[font_nr_base].special_graphic[j];
563 int active_graphic = font_info[font_nr_active].special_graphic[j];
564 boolean base_redefined =
565 getImageListEntryFromImageID(base_graphic)->redefined;
566 boolean active_redefined =
567 getImageListEntryFromImageID(active_graphic)->redefined;
569 // same as above, but check special graphic definitions, for example:
570 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
571 if (base_redefined && !active_redefined)
573 font_info[font_nr_active].special_graphic[j] =
574 font_info[font_nr_base].special_graphic[j];
575 font_info[font_nr_active].special_bitmap_id[j] =
576 font_info[font_nr_base].special_bitmap_id[j];
582 // ---------- initialize font bitmap array ----------
584 if (font_bitmap_info != NULL)
585 FreeFontInfo(font_bitmap_info);
588 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
590 // ---------- initialize font bitmap definitions ----------
592 for (i = 0; i < NUM_FONTS; i++)
594 if (i < NUM_INITIAL_FONTS)
596 font_bitmap_info[i] = font_initial[i];
600 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
602 int font_bitmap_id = font_info[i].special_bitmap_id[j];
603 int graphic = font_info[i].special_graphic[j];
605 // set 'graphic_info' for font entries, if uninitialized (guessed)
606 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
608 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
609 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
612 // copy font relevant information from graphics information
613 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
614 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
615 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
616 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
617 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
619 font_bitmap_info[font_bitmap_id].offset_x =
620 graphic_info[graphic].offset_x;
621 font_bitmap_info[font_bitmap_id].offset_y =
622 graphic_info[graphic].offset_y;
624 font_bitmap_info[font_bitmap_id].draw_xoffset =
625 graphic_info[graphic].draw_xoffset;
626 font_bitmap_info[font_bitmap_id].draw_yoffset =
627 graphic_info[graphic].draw_yoffset;
629 font_bitmap_info[font_bitmap_id].num_chars =
630 graphic_info[graphic].anim_frames;
631 font_bitmap_info[font_bitmap_id].num_chars_per_line =
632 graphic_info[graphic].anim_frames_per_line;
636 InitFontInfo(font_bitmap_info, num_font_bitmaps,
637 getFontBitmapID, getFontFromToken);
640 static void InitGlobalAnimGraphicInfo(void)
642 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
643 int num_property_mappings = getImageListPropertyMappingSize();
646 if (graphic_info == NULL) // still at startup phase
649 // always start with reliable default values (no global animations)
650 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
651 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
652 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
653 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
655 // initialize global animation definitions from static configuration
656 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
658 int j = GLOBAL_ANIM_ID_PART_BASE;
659 int k = GFX_SPECIAL_ARG_DEFAULT;
661 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
664 // initialize global animation definitions from dynamic configuration
665 for (i = 0; i < num_property_mappings; i++)
667 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
668 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
669 int special = property_mapping[i].ext3_index;
670 int graphic = property_mapping[i].artwork_index;
672 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
675 // set animation part to base part, if not specified
676 if (!IS_GLOBAL_ANIM_PART(part_nr))
677 part_nr = GLOBAL_ANIM_ID_PART_BASE;
679 // set animation screen to default, if not specified
680 if (!IS_SPECIAL_GFX_ARG(special))
681 special = GFX_SPECIAL_ARG_DEFAULT;
683 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
685 // fix default value for ".draw_masked" (for backward compatibility)
686 struct GraphicInfo *g = &graphic_info[graphic];
687 struct FileInfo *image = getImageListEntryFromImageID(graphic);
688 char **parameter_raw = image->parameter;
689 int p = GFX_ARG_DRAW_MASKED;
690 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
691 image_config_suffix[p].token,
692 image_config_suffix[p].type);
694 // if ".draw_masked" parameter is undefined, use default value "TRUE"
695 if (draw_masked == ARG_UNDEFINED_VALUE)
696 g->draw_masked = TRUE;
700 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
701 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
702 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
703 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
704 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
705 Debug("init:InitGlobalAnimGraphicInfo",
706 "anim %d, part %d, mode %d => %d",
707 i, j, k, global_anim_info[i].graphic[j][k]);
711 static void InitGlobalAnimSoundInfo(void)
713 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
714 int num_property_mappings = getSoundListPropertyMappingSize();
717 // always start with reliable default values (no global animation sounds)
718 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
719 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
720 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
721 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
723 // initialize global animation sound definitions from dynamic configuration
724 for (i = 0; i < num_property_mappings; i++)
726 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
727 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
728 int special = property_mapping[i].ext3_index;
729 int sound = property_mapping[i].artwork_index;
731 // sound uses control definition; map it to position of graphic (artwork)
732 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
734 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
737 // set animation part to base part, if not specified
738 if (!IS_GLOBAL_ANIM_PART(part_nr))
739 part_nr = GLOBAL_ANIM_ID_PART_BASE;
741 // set animation screen to default, if not specified
742 if (!IS_SPECIAL_GFX_ARG(special))
743 special = GFX_SPECIAL_ARG_DEFAULT;
745 global_anim_info[anim_nr].sound[part_nr][special] = sound;
749 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
750 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
751 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
752 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
753 Debug("init:InitGlobalAnimSoundInfo",
754 "anim %d, part %d, mode %d => %d",
755 i, j, k, global_anim_info[i].sound[j][k]);
759 static void InitGlobalAnimMusicInfo(void)
761 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
762 int num_property_mappings = getMusicListPropertyMappingSize();
765 // always start with reliable default values (no global animation music)
766 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
767 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
768 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
769 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
771 // initialize global animation music definitions from dynamic configuration
772 for (i = 0; i < num_property_mappings; i++)
774 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
775 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
776 int special = property_mapping[i].ext2_index;
777 int music = property_mapping[i].artwork_index;
779 // music uses control definition; map it to position of graphic (artwork)
780 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
782 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
785 // set animation part to base part, if not specified
786 if (!IS_GLOBAL_ANIM_PART(part_nr))
787 part_nr = GLOBAL_ANIM_ID_PART_BASE;
789 // set animation screen to default, if not specified
790 if (!IS_SPECIAL_GFX_ARG(special))
791 special = GFX_SPECIAL_ARG_DEFAULT;
793 global_anim_info[anim_nr].music[part_nr][special] = music;
797 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
798 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
799 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
800 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
801 Debug("init:InitGlobalAnimMusicInfo",
802 "anim %d, part %d, mode %d => %d",
803 i, j, k, global_anim_info[i].music[j][k]);
807 static void InitElementGraphicInfo(void)
809 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
810 int num_property_mappings = getImageListPropertyMappingSize();
813 if (graphic_info == NULL) // still at startup phase
816 // set values to -1 to identify later as "uninitialized" values
817 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
819 for (act = 0; act < NUM_ACTIONS; act++)
821 element_info[i].graphic[act] = -1;
822 element_info[i].crumbled[act] = -1;
824 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
826 element_info[i].direction_graphic[act][dir] = -1;
827 element_info[i].direction_crumbled[act][dir] = -1;
834 // initialize normal element/graphic mapping from static configuration
835 for (i = 0; element_to_graphic[i].element > -1; i++)
837 int element = element_to_graphic[i].element;
838 int action = element_to_graphic[i].action;
839 int direction = element_to_graphic[i].direction;
840 boolean crumbled = element_to_graphic[i].crumbled;
841 int graphic = element_to_graphic[i].graphic;
842 int base_graphic = el2baseimg(element);
844 if (graphic_info[graphic].bitmap == NULL)
847 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
850 boolean base_redefined =
851 getImageListEntryFromImageID(base_graphic)->redefined;
852 boolean act_dir_redefined =
853 getImageListEntryFromImageID(graphic)->redefined;
855 /* if the base graphic ("emerald", for example) has been redefined,
856 but not the action graphic ("emerald.falling", for example), do not
857 use an existing (in this case considered obsolete) action graphic
858 anymore, but use the automatically determined default graphic */
859 if (base_redefined && !act_dir_redefined)
864 action = ACTION_DEFAULT;
869 element_info[element].direction_crumbled[action][direction] = graphic;
871 element_info[element].crumbled[action] = graphic;
876 element_info[element].direction_graphic[action][direction] = graphic;
878 element_info[element].graphic[action] = graphic;
882 // initialize normal element/graphic mapping from dynamic configuration
883 for (i = 0; i < num_property_mappings; i++)
885 int element = property_mapping[i].base_index;
886 int action = property_mapping[i].ext1_index;
887 int direction = property_mapping[i].ext2_index;
888 int special = property_mapping[i].ext3_index;
889 int graphic = property_mapping[i].artwork_index;
890 boolean crumbled = FALSE;
892 if (special == GFX_SPECIAL_ARG_CRUMBLED)
898 if (graphic_info[graphic].bitmap == NULL)
901 if (element >= MAX_NUM_ELEMENTS || special != -1)
905 action = ACTION_DEFAULT;
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 element_info[element].direction_crumbled[action][dir] = -1;
914 element_info[element].direction_crumbled[action][direction] = graphic;
916 element_info[element].crumbled[action] = graphic;
921 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 element_info[element].direction_graphic[action][dir] = -1;
925 element_info[element].direction_graphic[action][direction] = graphic;
927 element_info[element].graphic[action] = graphic;
931 // now copy all graphics that are defined to be cloned from other graphics
932 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
934 int graphic = element_info[i].graphic[ACTION_DEFAULT];
935 int crumbled_like, diggable_like;
940 crumbled_like = graphic_info[graphic].crumbled_like;
941 diggable_like = graphic_info[graphic].diggable_like;
943 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
945 for (act = 0; act < NUM_ACTIONS; act++)
946 element_info[i].crumbled[act] =
947 element_info[crumbled_like].crumbled[act];
948 for (act = 0; act < NUM_ACTIONS; act++)
949 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
950 element_info[i].direction_crumbled[act][dir] =
951 element_info[crumbled_like].direction_crumbled[act][dir];
954 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
956 element_info[i].graphic[ACTION_DIGGING] =
957 element_info[diggable_like].graphic[ACTION_DIGGING];
958 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
959 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
960 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
964 // set hardcoded definitions for some runtime elements without graphic
965 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
967 // set hardcoded definitions for some internal elements without graphic
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 if (IS_EDITOR_CASCADE_INACTIVE(i))
971 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
972 else if (IS_EDITOR_CASCADE_ACTIVE(i))
973 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
976 // now set all undefined/invalid graphics to -1 to set to default after it
977 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
979 for (act = 0; act < NUM_ACTIONS; act++)
983 graphic = element_info[i].graphic[act];
984 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
985 element_info[i].graphic[act] = -1;
987 graphic = element_info[i].crumbled[act];
988 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
989 element_info[i].crumbled[act] = -1;
991 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
993 graphic = element_info[i].direction_graphic[act][dir];
994 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
995 element_info[i].direction_graphic[act][dir] = -1;
997 graphic = element_info[i].direction_crumbled[act][dir];
998 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
999 element_info[i].direction_crumbled[act][dir] = -1;
1004 UPDATE_BUSY_STATE();
1006 // adjust graphics with 2nd tile for movement according to direction
1007 // (do this before correcting '-1' values to minimize calculations)
1008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1010 for (act = 0; act < NUM_ACTIONS; act++)
1012 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1014 int graphic = element_info[i].direction_graphic[act][dir];
1015 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1017 if (act == ACTION_FALLING) // special case
1018 graphic = element_info[i].graphic[act];
1020 if (graphic != -1 &&
1021 graphic_info[graphic].double_movement &&
1022 graphic_info[graphic].swap_double_tiles != 0)
1024 struct GraphicInfo *g = &graphic_info[graphic];
1025 int src_x_front = g->src_x;
1026 int src_y_front = g->src_y;
1027 int src_x_back = g->src_x + g->offset2_x;
1028 int src_y_back = g->src_y + g->offset2_y;
1029 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1031 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1032 src_y_front < src_y_back);
1033 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1034 boolean swap_movement_tiles_autodetected =
1035 (!frames_are_ordered_diagonally &&
1036 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1037 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1038 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1039 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1041 // swap frontside and backside graphic tile coordinates, if needed
1042 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1044 // get current (wrong) backside tile coordinates
1045 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1047 // set frontside tile coordinates to backside tile coordinates
1048 g->src_x = src_x_back;
1049 g->src_y = src_y_back;
1051 // invert tile offset to point to new backside tile coordinates
1055 // do not swap front and backside tiles again after correction
1056 g->swap_double_tiles = 0;
1063 UPDATE_BUSY_STATE();
1065 // now set all '-1' values to element specific default values
1066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1069 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1070 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1071 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1073 if (default_graphic == -1)
1074 default_graphic = IMG_UNKNOWN;
1076 if (default_crumbled == -1)
1077 default_crumbled = default_graphic;
1079 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1081 default_direction_graphic[dir] =
1082 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1083 default_direction_crumbled[dir] =
1084 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1086 if (default_direction_graphic[dir] == -1)
1087 default_direction_graphic[dir] = default_graphic;
1089 if (default_direction_crumbled[dir] == -1)
1090 default_direction_crumbled[dir] = default_direction_graphic[dir];
1093 for (act = 0; act < NUM_ACTIONS; act++)
1095 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1096 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1097 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1098 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1099 act == ACTION_TURNING_FROM_RIGHT ||
1100 act == ACTION_TURNING_FROM_UP ||
1101 act == ACTION_TURNING_FROM_DOWN);
1103 // generic default action graphic (defined by "[default]" directive)
1104 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1105 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1106 int default_remove_graphic = IMG_EMPTY;
1108 if (act_remove && default_action_graphic != -1)
1109 default_remove_graphic = default_action_graphic;
1111 // look for special default action graphic (classic game specific)
1112 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1113 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1114 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1115 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1116 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1117 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1118 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1119 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1121 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1122 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1123 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1124 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1125 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1126 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1127 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1128 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1130 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1131 // !!! make this better !!!
1132 if (i == EL_EMPTY_SPACE)
1134 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1135 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1138 if (default_action_graphic == -1)
1139 default_action_graphic = default_graphic;
1141 if (default_action_crumbled == -1)
1142 default_action_crumbled = default_action_graphic;
1144 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1146 // use action graphic as the default direction graphic, if undefined
1147 int default_action_direction_graphic = element_info[i].graphic[act];
1148 int default_action_direction_crumbled = element_info[i].crumbled[act];
1150 // no graphic for current action -- use default direction graphic
1151 if (default_action_direction_graphic == -1)
1152 default_action_direction_graphic =
1153 (act_remove ? default_remove_graphic :
1155 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1156 default_action_graphic != default_graphic ?
1157 default_action_graphic :
1158 default_direction_graphic[dir]);
1160 if (element_info[i].direction_graphic[act][dir] == -1)
1161 element_info[i].direction_graphic[act][dir] =
1162 default_action_direction_graphic;
1164 if (default_action_direction_crumbled == -1)
1165 default_action_direction_crumbled =
1166 element_info[i].direction_graphic[act][dir];
1168 if (element_info[i].direction_crumbled[act][dir] == -1)
1169 element_info[i].direction_crumbled[act][dir] =
1170 default_action_direction_crumbled;
1173 // no graphic for this specific action -- use default action graphic
1174 if (element_info[i].graphic[act] == -1)
1175 element_info[i].graphic[act] =
1176 (act_remove ? default_remove_graphic :
1177 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1178 default_action_graphic);
1180 if (element_info[i].crumbled[act] == -1)
1181 element_info[i].crumbled[act] = element_info[i].graphic[act];
1185 UPDATE_BUSY_STATE();
1188 static void InitElementSpecialGraphicInfo(void)
1190 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1191 int num_property_mappings = getImageListPropertyMappingSize();
1194 // always start with reliable default values
1195 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1196 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1197 element_info[i].special_graphic[j] =
1198 element_info[i].graphic[ACTION_DEFAULT];
1200 // initialize special element/graphic mapping from static configuration
1201 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1203 int element = element_to_special_graphic[i].element;
1204 int special = element_to_special_graphic[i].special;
1205 int graphic = element_to_special_graphic[i].graphic;
1206 int base_graphic = el2baseimg(element);
1207 boolean base_redefined =
1208 getImageListEntryFromImageID(base_graphic)->redefined;
1209 boolean special_redefined =
1210 getImageListEntryFromImageID(graphic)->redefined;
1212 /* if the base graphic ("emerald", for example) has been redefined,
1213 but not the special graphic ("emerald.EDITOR", for example), do not
1214 use an existing (in this case considered obsolete) special graphic
1215 anymore, but use the automatically created (down-scaled) graphic */
1216 if (base_redefined && !special_redefined)
1219 element_info[element].special_graphic[special] = graphic;
1222 // initialize special element/graphic mapping from dynamic configuration
1223 for (i = 0; i < num_property_mappings; i++)
1225 int element = property_mapping[i].base_index;
1226 int action = property_mapping[i].ext1_index;
1227 int direction = property_mapping[i].ext2_index;
1228 int special = property_mapping[i].ext3_index;
1229 int graphic = property_mapping[i].artwork_index;
1231 // for action ".active", replace element with active element, if exists
1232 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1234 element = ELEMENT_ACTIVE(element);
1238 if (element >= MAX_NUM_ELEMENTS)
1241 // do not change special graphic if action or direction was specified
1242 if (action != -1 || direction != -1)
1245 if (IS_SPECIAL_GFX_ARG(special))
1246 element_info[element].special_graphic[special] = graphic;
1249 // now set all undefined/invalid graphics to default
1250 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1251 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1252 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1253 element_info[i].special_graphic[j] =
1254 element_info[i].graphic[ACTION_DEFAULT];
1257 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1259 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1260 return get_parameter_value(value_raw, suffix, type);
1262 if (strEqual(value_raw, ARG_UNDEFINED))
1263 return ARG_UNDEFINED_VALUE;
1265 if (type == TYPE_ELEMENT)
1267 char *value = getHashEntry(element_token_hash, value_raw);
1272 Warn("error found in config file:");
1273 Warn("- config file: '%s'", getImageConfigFilename());
1274 Warn("error: invalid element token '%s'", value_raw);
1275 Warn("custom graphic rejected for this element/action");
1276 Warn("fallback done to undefined element for this graphic");
1280 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1282 else if (type == TYPE_GRAPHIC)
1284 char *value = getHashEntry(graphic_token_hash, value_raw);
1285 int fallback_graphic = IMG_CHAR_EXCLAM;
1290 Warn("error found in config file:");
1291 Warn("- config file: '%s'", getImageConfigFilename());
1292 Warn("error: invalid graphic token '%s'", value_raw);
1293 Warn("custom graphic rejected for this element/action");
1294 Warn("fallback done to 'char_exclam' for this graphic");
1298 return (value != NULL ? atoi(value) : fallback_graphic);
1304 static int get_scaled_graphic_width(int graphic)
1306 int original_width = getOriginalImageWidthFromImageID(graphic);
1307 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1309 return original_width * scale_up_factor;
1312 static int get_scaled_graphic_height(int graphic)
1314 int original_height = getOriginalImageHeightFromImageID(graphic);
1315 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1317 return original_height * scale_up_factor;
1320 static void set_graphic_parameters_ext(int graphic, int *parameter,
1321 Bitmap **src_bitmaps)
1323 struct GraphicInfo *g = &graphic_info[graphic];
1324 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1325 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1326 int anim_frames_per_line = 1;
1328 // always start with reliable default values
1329 g->src_image_width = 0;
1330 g->src_image_height = 0;
1333 g->width = TILEX; // default for element graphics
1334 g->height = TILEY; // default for element graphics
1335 g->offset_x = 0; // one or both of these values ...
1336 g->offset_y = 0; // ... will be corrected later
1337 g->offset2_x = 0; // one or both of these values ...
1338 g->offset2_y = 0; // ... will be corrected later
1339 g->swap_double_tiles = -1; // auto-detect tile swapping
1340 g->crumbled_like = -1; // do not use clone element
1341 g->diggable_like = -1; // do not use clone element
1342 g->border_size = TILEX / 8; // "CRUMBLED" border size
1343 g->scale_up_factor = 1; // default: no scaling up
1344 g->tile_size = TILESIZE; // default: standard tile size
1345 g->clone_from = -1; // do not use clone graphic
1346 g->init_delay_fixed = 0;
1347 g->init_delay_random = 0;
1348 g->init_delay_action = -1;
1349 g->anim_delay_fixed = 0;
1350 g->anim_delay_random = 0;
1351 g->anim_delay_action = -1;
1352 g->post_delay_fixed = 0;
1353 g->post_delay_random = 0;
1354 g->post_delay_action = -1;
1355 g->init_event = ANIM_EVENT_UNDEFINED;
1356 g->anim_event = ANIM_EVENT_UNDEFINED;
1357 g->init_event_action = -1;
1358 g->anim_event_action = -1;
1359 g->draw_masked = FALSE;
1361 g->fade_mode = FADE_MODE_DEFAULT;
1365 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1366 g->align = ALIGN_CENTER; // default for title screens
1367 g->valign = VALIGN_MIDDLE; // default for title screens
1368 g->sort_priority = 0; // default for title screens
1370 g->style = STYLE_DEFAULT;
1372 g->bitmaps = src_bitmaps;
1373 g->bitmap = src_bitmap;
1375 // optional zoom factor for scaling up the image to a larger size
1376 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1377 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1378 if (g->scale_up_factor < 1)
1379 g->scale_up_factor = 1; // no scaling
1381 // optional tile size for using non-standard image size
1382 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1384 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1387 // CHECK: should tile sizes less than standard tile size be allowed?
1388 if (g->tile_size < TILESIZE)
1389 g->tile_size = TILESIZE; // standard tile size
1392 // when setting tile size, also set width and height accordingly
1393 g->width = g->tile_size;
1394 g->height = g->tile_size;
1397 if (g->use_image_size)
1399 // set new default bitmap size (with scaling, but without small images)
1400 g->width = get_scaled_graphic_width(graphic);
1401 g->height = get_scaled_graphic_height(graphic);
1404 // optional width and height of each animation frame
1405 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1406 g->width = parameter[GFX_ARG_WIDTH];
1407 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1408 g->height = parameter[GFX_ARG_HEIGHT];
1410 // optional x and y tile position of animation frame sequence
1411 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1412 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1413 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1414 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1416 // optional x and y pixel position of animation frame sequence
1417 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1418 g->src_x = parameter[GFX_ARG_X];
1419 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1420 g->src_y = parameter[GFX_ARG_Y];
1427 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1428 g->width, getTokenFromImageID(graphic), TILEX);
1431 g->width = TILEX; // will be checked to be inside bitmap later
1437 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1438 g->height, getTokenFromImageID(graphic), TILEY);
1441 g->height = TILEY; // will be checked to be inside bitmap later
1447 // get final bitmap size (with scaling, but without small images)
1448 int src_image_width = get_scaled_graphic_width(graphic);
1449 int src_image_height = get_scaled_graphic_height(graphic);
1451 if (src_image_width == 0 || src_image_height == 0)
1453 // only happens when loaded outside artwork system (like "global.busy")
1454 src_image_width = src_bitmap->width;
1455 src_image_height = src_bitmap->height;
1458 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1460 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1461 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1465 anim_frames_per_row = MAX(1, src_image_width / g->width);
1466 anim_frames_per_col = MAX(1, src_image_height / g->height);
1469 g->src_image_width = src_image_width;
1470 g->src_image_height = src_image_height;
1473 // correct x or y offset dependent of vertical or horizontal frame order
1474 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1476 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1477 parameter[GFX_ARG_OFFSET] : g->height);
1478 anim_frames_per_line = anim_frames_per_col;
1480 else // frames are ordered horizontally
1482 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1483 parameter[GFX_ARG_OFFSET] : g->width);
1484 anim_frames_per_line = anim_frames_per_row;
1487 // optionally, the x and y offset of frames can be specified directly
1488 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1489 g->offset_x = parameter[GFX_ARG_XOFFSET];
1490 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1491 g->offset_y = parameter[GFX_ARG_YOFFSET];
1493 // optionally, moving animations may have separate start and end graphics
1494 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1496 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1497 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1499 // correct x or y offset2 dependent of vertical or horizontal frame order
1500 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1501 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1502 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1503 else // frames are ordered horizontally
1504 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1505 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1507 // optionally, the x and y offset of 2nd graphic can be specified directly
1508 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1509 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1510 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1511 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1513 // optionally, the second movement tile can be specified as start tile
1514 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1515 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1517 // automatically determine correct number of frames, if not defined
1518 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1519 g->anim_frames = parameter[GFX_ARG_FRAMES];
1520 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1521 g->anim_frames = anim_frames_per_row;
1522 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1523 g->anim_frames = anim_frames_per_col;
1527 if (g->anim_frames < 1) // frames must be at least 1
1530 g->anim_frames_per_line =
1531 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1532 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1534 g->anim_delay = parameter[GFX_ARG_DELAY];
1535 if (g->anim_delay < 1) // delay must be at least 1
1538 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1540 // automatically determine correct start frame, if not defined
1541 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1542 g->anim_start_frame = 0;
1543 else if (g->anim_mode & ANIM_REVERSE)
1544 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1546 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1548 // animation synchronized with global frame counter, not move position
1549 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1551 // optional element for cloning crumble graphics
1552 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1553 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1555 // optional element for cloning digging graphics
1556 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1557 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1559 // optional border size for "crumbling" diggable graphics
1560 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1561 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1563 // used for global animations and player "boring" and "sleeping" actions
1564 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1565 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1566 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1567 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1568 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1569 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1570 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1571 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1572 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1573 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1574 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1575 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1577 // used for global animations
1578 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1579 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1580 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1581 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1582 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1583 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1584 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1585 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1586 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1587 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1588 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1589 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1590 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1591 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1593 // used for toon animations and global animations
1594 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1595 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1596 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1597 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1598 g->direction = parameter[GFX_ARG_DIRECTION];
1599 g->position = parameter[GFX_ARG_POSITION];
1600 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1601 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1603 if (g->step_delay < 1) // delay must be at least 1
1606 // this is only used for drawing font characters
1607 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1608 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1610 // use a different default value for global animations and toons
1611 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1612 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1613 g->draw_masked = TRUE;
1615 // this is used for drawing envelopes, global animations and toons
1616 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1617 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1619 // used for toon animations and global animations
1620 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1621 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1623 // optional graphic for cloning all graphics settings
1624 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1625 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1627 // optional settings for drawing title screens and title messages
1628 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1629 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1630 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1631 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1632 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1633 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1634 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1635 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1636 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1637 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1638 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1639 g->align = parameter[GFX_ARG_ALIGN];
1640 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1641 g->valign = parameter[GFX_ARG_VALIGN];
1642 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1643 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1645 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1646 g->class = parameter[GFX_ARG_CLASS];
1647 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1648 g->style = parameter[GFX_ARG_STYLE];
1650 // this is only used for drawing menu buttons and text
1651 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1652 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1653 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1654 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1657 static void set_graphic_parameters(int graphic)
1659 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1660 char **parameter_raw = image->parameter;
1661 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1662 int parameter[NUM_GFX_ARGS];
1665 // if fallback to default artwork is done, also use the default parameters
1666 if (image->fallback_to_default)
1667 parameter_raw = image->default_parameter;
1669 // get integer values from string parameters
1670 for (i = 0; i < NUM_GFX_ARGS; i++)
1671 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1672 image_config_suffix[i].token,
1673 image_config_suffix[i].type);
1675 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1677 UPDATE_BUSY_STATE();
1680 static void set_cloned_graphic_parameters(int graphic)
1682 int fallback_graphic = IMG_CHAR_EXCLAM;
1683 int max_num_images = getImageListSize();
1684 int clone_graphic = graphic_info[graphic].clone_from;
1685 int num_references_followed = 1;
1687 while (graphic_info[clone_graphic].clone_from != -1 &&
1688 num_references_followed < max_num_images)
1690 clone_graphic = graphic_info[clone_graphic].clone_from;
1692 num_references_followed++;
1695 if (num_references_followed >= max_num_images)
1698 Warn("error found in config file:");
1699 Warn("- config file: '%s'", getImageConfigFilename());
1700 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1701 Warn("error: loop discovered when resolving cloned graphics");
1702 Warn("custom graphic rejected for this element/action");
1704 if (graphic == fallback_graphic)
1705 Fail("no fallback graphic available");
1707 Warn("fallback done to 'char_exclam' for this graphic");
1710 graphic_info[graphic] = graphic_info[fallback_graphic];
1714 graphic_info[graphic] = graphic_info[clone_graphic];
1715 graphic_info[graphic].clone_from = clone_graphic;
1719 static void InitGraphicInfo(void)
1721 int fallback_graphic = IMG_CHAR_EXCLAM;
1722 int num_images = getImageListSize();
1725 // use image size as default values for width and height for these images
1726 static int full_size_graphics[] =
1729 IMG_GLOBAL_BORDER_MAIN,
1730 IMG_GLOBAL_BORDER_SCORES,
1731 IMG_GLOBAL_BORDER_EDITOR,
1732 IMG_GLOBAL_BORDER_PLAYING,
1735 IMG_BACKGROUND_ENVELOPE_1,
1736 IMG_BACKGROUND_ENVELOPE_2,
1737 IMG_BACKGROUND_ENVELOPE_3,
1738 IMG_BACKGROUND_ENVELOPE_4,
1739 IMG_BACKGROUND_REQUEST,
1742 IMG_BACKGROUND_LOADING_INITIAL,
1743 IMG_BACKGROUND_LOADING,
1744 IMG_BACKGROUND_TITLE_INITIAL,
1745 IMG_BACKGROUND_TITLE,
1746 IMG_BACKGROUND_MAIN,
1747 IMG_BACKGROUND_NAMES,
1748 IMG_BACKGROUND_LEVELS,
1749 IMG_BACKGROUND_LEVELNR,
1750 IMG_BACKGROUND_SCORES,
1751 IMG_BACKGROUND_SCOREINFO,
1752 IMG_BACKGROUND_EDITOR,
1753 IMG_BACKGROUND_INFO,
1754 IMG_BACKGROUND_INFO_ELEMENTS,
1755 IMG_BACKGROUND_INFO_MUSIC,
1756 IMG_BACKGROUND_INFO_CREDITS,
1757 IMG_BACKGROUND_INFO_PROGRAM,
1758 IMG_BACKGROUND_INFO_VERSION,
1759 IMG_BACKGROUND_INFO_LEVELSET,
1760 IMG_BACKGROUND_SETUP,
1761 IMG_BACKGROUND_PLAYING,
1762 IMG_BACKGROUND_DOOR,
1763 IMG_BACKGROUND_TAPE,
1764 IMG_BACKGROUND_PANEL,
1765 IMG_BACKGROUND_PALETTE,
1766 IMG_BACKGROUND_TOOLBOX,
1768 IMG_TITLESCREEN_INITIAL_1,
1769 IMG_TITLESCREEN_INITIAL_2,
1770 IMG_TITLESCREEN_INITIAL_3,
1771 IMG_TITLESCREEN_INITIAL_4,
1772 IMG_TITLESCREEN_INITIAL_5,
1779 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1780 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1781 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1782 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1783 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1784 IMG_BACKGROUND_TITLEMESSAGE_1,
1785 IMG_BACKGROUND_TITLEMESSAGE_2,
1786 IMG_BACKGROUND_TITLEMESSAGE_3,
1787 IMG_BACKGROUND_TITLEMESSAGE_4,
1788 IMG_BACKGROUND_TITLEMESSAGE_5,
1793 FreeGlobalAnimEventInfo();
1795 checked_free(graphic_info);
1797 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1799 // initialize "use_image_size" flag with default value
1800 for (i = 0; i < num_images; i++)
1801 graphic_info[i].use_image_size = FALSE;
1803 // initialize "use_image_size" flag from static configuration above
1804 for (i = 0; full_size_graphics[i] != -1; i++)
1805 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1807 // first set all graphic paramaters ...
1808 for (i = 0; i < num_images; i++)
1809 set_graphic_parameters(i);
1811 // ... then copy these parameters for cloned graphics
1812 for (i = 0; i < num_images; i++)
1813 if (graphic_info[i].clone_from != -1)
1814 set_cloned_graphic_parameters(i);
1816 for (i = 0; i < num_images; i++)
1818 Bitmap *src_bitmap = graphic_info[i].bitmap;
1822 int src_bitmap_width, src_bitmap_height;
1824 // now check if no animation frames are outside of the loaded image
1826 if (graphic_info[i].bitmap == NULL)
1827 continue; // skip check for optional images that are undefined
1829 // get image size (this can differ from the standard element tile size!)
1830 width = graphic_info[i].width;
1831 height = graphic_info[i].height;
1833 // get final bitmap size (with scaling, but without small images)
1834 src_bitmap_width = graphic_info[i].src_image_width;
1835 src_bitmap_height = graphic_info[i].src_image_height;
1837 // check if first animation frame is inside specified bitmap
1839 // do not use getGraphicSourceXY() here to get position of first frame;
1840 // this avoids calculating wrong start position for out-of-bounds frame
1841 src_x = graphic_info[i].src_x;
1842 src_y = graphic_info[i].src_y;
1844 if (program.headless)
1847 if (src_x < 0 || src_y < 0 ||
1848 src_x + width > src_bitmap_width ||
1849 src_y + height > src_bitmap_height)
1852 Warn("error found in config file:");
1853 Warn("- config file: '%s'", getImageConfigFilename());
1854 Warn("- config token: '%s'", getTokenFromImageID(i));
1855 Warn("- image file: '%s'", src_bitmap->source_filename);
1856 Warn("- frame size: %d, %d", width, height);
1857 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1858 src_x, src_y, src_bitmap_width, src_bitmap_height);
1859 Warn("custom graphic rejected for this element/action");
1861 if (i == fallback_graphic)
1862 Fail("no fallback graphic available");
1864 Warn("fallback done to 'char_exclam' for this graphic");
1867 graphic_info[i] = graphic_info[fallback_graphic];
1869 // if first frame out of bounds, do not check last frame anymore
1873 // check if last animation frame is inside specified bitmap
1875 last_frame = graphic_info[i].anim_frames - 1;
1876 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1878 if (src_x < 0 || src_y < 0 ||
1879 src_x + width > src_bitmap_width ||
1880 src_y + height > src_bitmap_height)
1883 Warn("error found in config file:");
1884 Warn("- config file: '%s'", getImageConfigFilename());
1885 Warn("- config token: '%s'", getTokenFromImageID(i));
1886 Warn("- image file: '%s'", src_bitmap->source_filename);
1887 Warn("- frame size: %d, %d", width, height);
1888 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1889 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1890 Warn("custom graphic rejected for this element/action");
1892 if (i == fallback_graphic)
1893 Fail("no fallback graphic available");
1895 Warn("fallback done to 'char_exclam' for this graphic");
1898 graphic_info[i] = graphic_info[fallback_graphic];
1903 static void InitGraphicCompatibilityInfo(void)
1905 struct FileInfo *fi_global_door =
1906 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1907 int num_images = getImageListSize();
1910 /* the following compatibility handling is needed for the following case:
1911 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1912 graphics mainly used for door and panel graphics, like editor, tape and
1913 in-game buttons with hard-coded bitmap positions and button sizes; as
1914 these graphics now have individual definitions, redefining "global.door"
1915 to change all these graphics at once like before does not work anymore
1916 (because all those individual definitions still have their default values);
1917 to solve this, remap all those individual definitions that are not
1918 redefined to the new bitmap of "global.door" if it was redefined */
1920 // special compatibility handling if image "global.door" was redefined
1921 if (fi_global_door->redefined)
1923 for (i = 0; i < num_images; i++)
1925 struct FileInfo *fi = getImageListEntryFromImageID(i);
1927 // process only those images that still use the default settings
1930 // process all images which default to same image as "global.door"
1931 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1933 // skip all images that are cloned from images that default to same
1934 // image as "global.door", but that are redefined to something else
1935 if (graphic_info[i].clone_from != -1)
1937 int cloned_graphic = graphic_info[i].clone_from;
1939 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
1944 Debug("init:InitGraphicCompatibilityInfo",
1945 "special treatment needed for token '%s'", fi->token);
1948 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1949 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1955 // special compatibility handling for "Snake Bite" graphics set
1956 if (strPrefix(leveldir_current->identifier, "snake_bite"))
1958 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
1960 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
1961 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
1963 ClearRectangle(bitmap, 2, 66, 32, 480);
1964 ClearRectangle(bitmap, 514, 66, 32, 480);
1967 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
1968 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
1969 if (strPrefix(leveldir_current->graphics_set, "jue") && !supports_score_info)
1987 int mode_old = GAME_MODE_SCORES;
1988 int mode_new = GAME_MODE_SCOREINFO;
1991 // adjust title screens on score info page
1992 for (i = 0; font_title[i] != -1; i++)
1994 struct FontInfo *fi = &font_info[font_title[i]];
1996 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
1997 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2000 // adjust vertical text and button positions on scores page
2001 for (i = 0; font_text[i] != -1; i++)
2003 for (j = 0; j < 2; j++)
2005 boolean jue0 = strEqual(leveldir_current->graphics_set, "jue0");
2006 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2007 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2008 int font_yoffset = (jue0 ? 10 : 5);
2010 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2014 // adjust page offsets on score info page
2015 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2016 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2019 InitGraphicCompatibilityInfo_Doors();
2022 static void InitElementSoundInfo(void)
2024 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2025 int num_property_mappings = getSoundListPropertyMappingSize();
2028 // set values to -1 to identify later as "uninitialized" values
2029 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2030 for (act = 0; act < NUM_ACTIONS; act++)
2031 element_info[i].sound[act] = -1;
2033 // initialize element/sound mapping from static configuration
2034 for (i = 0; element_to_sound[i].element > -1; i++)
2036 int element = element_to_sound[i].element;
2037 int action = element_to_sound[i].action;
2038 int sound = element_to_sound[i].sound;
2039 boolean is_class = element_to_sound[i].is_class;
2042 action = ACTION_DEFAULT;
2045 element_info[element].sound[action] = sound;
2047 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2048 if (strEqual(element_info[j].class_name,
2049 element_info[element].class_name))
2050 element_info[j].sound[action] = sound;
2053 // initialize element class/sound mapping from dynamic configuration
2054 for (i = 0; i < num_property_mappings; i++)
2056 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2057 int action = property_mapping[i].ext1_index;
2058 int sound = property_mapping[i].artwork_index;
2060 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2064 action = ACTION_DEFAULT;
2066 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2067 if (strEqual(element_info[j].class_name,
2068 element_info[element_class].class_name))
2069 element_info[j].sound[action] = sound;
2072 // initialize element/sound mapping from dynamic configuration
2073 for (i = 0; i < num_property_mappings; i++)
2075 int element = property_mapping[i].base_index;
2076 int action = property_mapping[i].ext1_index;
2077 int sound = property_mapping[i].artwork_index;
2079 if (element >= MAX_NUM_ELEMENTS)
2083 action = ACTION_DEFAULT;
2085 element_info[element].sound[action] = sound;
2088 // now set all '-1' values to element specific default values
2089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2091 for (act = 0; act < NUM_ACTIONS; act++)
2093 // generic default action sound (defined by "[default]" directive)
2094 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2096 // look for special default action sound (classic game specific)
2097 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2098 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2099 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2100 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2101 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2102 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2103 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2104 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2106 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2107 // !!! make this better !!!
2108 if (i == EL_EMPTY_SPACE)
2109 default_action_sound = element_info[EL_DEFAULT].sound[act];
2111 // no sound for this specific action -- use default action sound
2112 if (element_info[i].sound[act] == -1)
2113 element_info[i].sound[act] = default_action_sound;
2117 // copy sound settings to some elements that are only stored in level file
2118 // in native R'n'D levels, but are used by game engine in native EM levels
2119 for (i = 0; copy_properties[i][0] != -1; i++)
2120 for (j = 1; j <= 4; j++)
2121 for (act = 0; act < NUM_ACTIONS; act++)
2122 element_info[copy_properties[i][j]].sound[act] =
2123 element_info[copy_properties[i][0]].sound[act];
2126 static void InitGameModeSoundInfo(void)
2130 // set values to -1 to identify later as "uninitialized" values
2131 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2134 // initialize gamemode/sound mapping from static configuration
2135 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2137 int gamemode = gamemode_to_sound[i].gamemode;
2138 int sound = gamemode_to_sound[i].sound;
2141 gamemode = GAME_MODE_DEFAULT;
2143 menu.sound[gamemode] = sound;
2146 // now set all '-1' values to levelset specific default values
2147 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2148 if (menu.sound[i] == -1)
2149 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2152 static void set_sound_parameters(int sound, char **parameter_raw)
2154 int parameter[NUM_SND_ARGS];
2157 // get integer values from string parameters
2158 for (i = 0; i < NUM_SND_ARGS; i++)
2160 get_parameter_value(parameter_raw[i],
2161 sound_config_suffix[i].token,
2162 sound_config_suffix[i].type);
2164 // explicit loop mode setting in configuration overrides default value
2165 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2166 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2168 // sound volume to change the original volume when loading the sound file
2169 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2171 // sound priority to give certain sounds a higher or lower priority
2172 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2175 static void InitSoundInfo(void)
2177 int *sound_effect_properties;
2178 int num_sounds = getSoundListSize();
2181 checked_free(sound_info);
2183 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2184 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2186 // initialize sound effect for all elements to "no sound"
2187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2188 for (j = 0; j < NUM_ACTIONS; j++)
2189 element_info[i].sound[j] = SND_UNDEFINED;
2191 for (i = 0; i < num_sounds; i++)
2193 struct FileInfo *sound = getSoundListEntry(i);
2194 int len_effect_text = strlen(sound->token);
2196 sound_effect_properties[i] = ACTION_OTHER;
2197 sound_info[i].loop = FALSE; // default: play sound only once
2199 // determine all loop sounds and identify certain sound classes
2201 for (j = 0; element_action_info[j].suffix; j++)
2203 int len_action_text = strlen(element_action_info[j].suffix);
2205 if (len_action_text < len_effect_text &&
2206 strEqual(&sound->token[len_effect_text - len_action_text],
2207 element_action_info[j].suffix))
2209 sound_effect_properties[i] = element_action_info[j].value;
2210 sound_info[i].loop = element_action_info[j].is_loop_sound;
2216 // associate elements and some selected sound actions
2218 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2220 if (element_info[j].class_name)
2222 int len_class_text = strlen(element_info[j].class_name);
2224 if (len_class_text + 1 < len_effect_text &&
2225 strncmp(sound->token,
2226 element_info[j].class_name, len_class_text) == 0 &&
2227 sound->token[len_class_text] == '.')
2229 int sound_action_value = sound_effect_properties[i];
2231 element_info[j].sound[sound_action_value] = i;
2236 set_sound_parameters(i, sound->parameter);
2239 free(sound_effect_properties);
2242 static void InitGameModeMusicInfo(void)
2244 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2245 int num_property_mappings = getMusicListPropertyMappingSize();
2246 int default_levelset_music = -1;
2249 // set values to -1 to identify later as "uninitialized" values
2250 for (i = 0; i < MAX_LEVELS; i++)
2251 levelset.music[i] = -1;
2252 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2255 // initialize gamemode/music mapping from static configuration
2256 for (i = 0; gamemode_to_music[i].music > -1; i++)
2258 int gamemode = gamemode_to_music[i].gamemode;
2259 int music = gamemode_to_music[i].music;
2262 gamemode = GAME_MODE_DEFAULT;
2264 menu.music[gamemode] = music;
2267 // initialize gamemode/music mapping from dynamic configuration
2268 for (i = 0; i < num_property_mappings; i++)
2270 int prefix = property_mapping[i].base_index;
2271 int gamemode = property_mapping[i].ext2_index;
2272 int level = property_mapping[i].ext3_index;
2273 int music = property_mapping[i].artwork_index;
2275 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2279 gamemode = GAME_MODE_DEFAULT;
2281 // level specific music only allowed for in-game music
2282 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2283 gamemode = GAME_MODE_PLAYING;
2288 default_levelset_music = music;
2291 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2292 levelset.music[level] = music;
2293 if (gamemode != GAME_MODE_PLAYING)
2294 menu.music[gamemode] = music;
2297 // now set all '-1' values to menu specific default values
2298 // (undefined values of "levelset.music[]" might stay at "-1" to
2299 // allow dynamic selection of music files from music directory!)
2300 for (i = 0; i < MAX_LEVELS; i++)
2301 if (levelset.music[i] == -1)
2302 levelset.music[i] = default_levelset_music;
2303 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2304 if (menu.music[i] == -1)
2305 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2308 static void set_music_parameters(int music, char **parameter_raw)
2310 int parameter[NUM_MUS_ARGS];
2313 // get integer values from string parameters
2314 for (i = 0; i < NUM_MUS_ARGS; i++)
2316 get_parameter_value(parameter_raw[i],
2317 music_config_suffix[i].token,
2318 music_config_suffix[i].type);
2320 // explicit loop mode setting in configuration overrides default value
2321 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2322 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2325 static void InitMusicInfo(void)
2327 int num_music = getMusicListSize();
2330 checked_free(music_info);
2332 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2334 for (i = 0; i < num_music; i++)
2336 struct FileInfo *music = getMusicListEntry(i);
2337 int len_music_text = strlen(music->token);
2339 music_info[i].loop = TRUE; // default: play music in loop mode
2341 // determine all loop music
2343 for (j = 0; music_prefix_info[j].prefix; j++)
2345 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2347 if (len_prefix_text < len_music_text &&
2348 strncmp(music->token,
2349 music_prefix_info[j].prefix, len_prefix_text) == 0)
2351 music_info[i].loop = music_prefix_info[j].is_loop_music;
2357 set_music_parameters(i, music->parameter);
2362 static void InitGameInfoFromArtworkInfo(void)
2364 // special case: store initial value of custom artwork setting
2365 game.use_masked_elements_initial = game.use_masked_elements;
2368 static void ReinitializeGraphics(void)
2370 print_timestamp_init("ReinitializeGraphics");
2372 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2374 InitGraphicInfo(); // graphic properties mapping
2375 print_timestamp_time("InitGraphicInfo");
2376 InitElementGraphicInfo(); // element game graphic mapping
2377 print_timestamp_time("InitElementGraphicInfo");
2378 InitElementSpecialGraphicInfo(); // element special graphic mapping
2379 print_timestamp_time("InitElementSpecialGraphicInfo");
2381 InitElementSmallImages(); // scale elements to all needed sizes
2382 print_timestamp_time("InitElementSmallImages");
2383 InitScaledImages(); // scale all other images, if needed
2384 print_timestamp_time("InitScaledImages");
2385 InitBitmapPointers(); // set standard size bitmap pointers
2386 print_timestamp_time("InitBitmapPointers");
2387 InitFontGraphicInfo(); // initialize text drawing functions
2388 print_timestamp_time("InitFontGraphicInfo");
2389 InitGlobalAnimGraphicInfo(); // initialize global animation config
2390 print_timestamp_time("InitGlobalAnimGraphicInfo");
2392 InitImageTextures(); // create textures for certain images
2393 print_timestamp_time("InitImageTextures");
2395 InitGraphicInfo_EM(); // graphic mapping for EM engine
2396 print_timestamp_time("InitGraphicInfo_EM");
2398 InitGraphicCompatibilityInfo();
2399 print_timestamp_time("InitGraphicCompatibilityInfo");
2402 print_timestamp_time("InitGadgets");
2404 print_timestamp_time("InitDoors");
2406 InitGameInfoFromArtworkInfo();
2408 print_timestamp_done("ReinitializeGraphics");
2411 static void ReinitializeSounds(void)
2413 InitSoundInfo(); // sound properties mapping
2414 InitElementSoundInfo(); // element game sound mapping
2415 InitGameModeSoundInfo(); // game mode sound mapping
2416 InitGlobalAnimSoundInfo(); // global animation sound settings
2418 InitPlayLevelSound(); // internal game sound settings
2421 static void ReinitializeMusic(void)
2423 InitMusicInfo(); // music properties mapping
2424 InitGameModeMusicInfo(); // game mode music mapping
2425 InitGlobalAnimMusicInfo(); // global animation music settings
2428 static int get_special_property_bit(int element, int property_bit_nr)
2430 struct PropertyBitInfo
2436 static struct PropertyBitInfo pb_can_move_into_acid[] =
2438 // the player may be able fall into acid when gravity is activated
2443 { EL_SP_MURPHY, 0 },
2444 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2446 // all elements that can move may be able to also move into acid
2449 { EL_BUG_RIGHT, 1 },
2452 { EL_SPACESHIP, 2 },
2453 { EL_SPACESHIP_LEFT, 2 },
2454 { EL_SPACESHIP_RIGHT, 2 },
2455 { EL_SPACESHIP_UP, 2 },
2456 { EL_SPACESHIP_DOWN, 2 },
2457 { EL_BD_BUTTERFLY, 3 },
2458 { EL_BD_BUTTERFLY_LEFT, 3 },
2459 { EL_BD_BUTTERFLY_RIGHT, 3 },
2460 { EL_BD_BUTTERFLY_UP, 3 },
2461 { EL_BD_BUTTERFLY_DOWN, 3 },
2462 { EL_BD_FIREFLY, 4 },
2463 { EL_BD_FIREFLY_LEFT, 4 },
2464 { EL_BD_FIREFLY_RIGHT, 4 },
2465 { EL_BD_FIREFLY_UP, 4 },
2466 { EL_BD_FIREFLY_DOWN, 4 },
2468 { EL_YAMYAM_LEFT, 5 },
2469 { EL_YAMYAM_RIGHT, 5 },
2470 { EL_YAMYAM_UP, 5 },
2471 { EL_YAMYAM_DOWN, 5 },
2472 { EL_DARK_YAMYAM, 6 },
2475 { EL_PACMAN_LEFT, 8 },
2476 { EL_PACMAN_RIGHT, 8 },
2477 { EL_PACMAN_UP, 8 },
2478 { EL_PACMAN_DOWN, 8 },
2480 { EL_MOLE_LEFT, 9 },
2481 { EL_MOLE_RIGHT, 9 },
2483 { EL_MOLE_DOWN, 9 },
2487 { EL_SATELLITE, 13 },
2488 { EL_SP_SNIKSNAK, 14 },
2489 { EL_SP_ELECTRON, 15 },
2492 { EL_SPRING_LEFT, 17 },
2493 { EL_SPRING_RIGHT, 17 },
2494 { EL_EMC_ANDROID, 18 },
2499 static struct PropertyBitInfo pb_dont_collide_with[] =
2501 { EL_SP_SNIKSNAK, 0 },
2502 { EL_SP_ELECTRON, 1 },
2510 struct PropertyBitInfo *pb_info;
2513 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2514 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2519 struct PropertyBitInfo *pb_info = NULL;
2522 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2523 if (pb_definition[i].bit_nr == property_bit_nr)
2524 pb_info = pb_definition[i].pb_info;
2526 if (pb_info == NULL)
2529 for (i = 0; pb_info[i].element != -1; i++)
2530 if (pb_info[i].element == element)
2531 return pb_info[i].bit_nr;
2536 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2537 boolean property_value)
2539 int bit_nr = get_special_property_bit(element, property_bit_nr);
2544 *bitfield |= (1 << bit_nr);
2546 *bitfield &= ~(1 << bit_nr);
2550 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2552 int bit_nr = get_special_property_bit(element, property_bit_nr);
2555 return ((*bitfield & (1 << bit_nr)) != 0);
2560 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2562 static int group_nr;
2563 static struct ElementGroupInfo *group;
2564 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2567 if (actual_group == NULL) // not yet initialized
2570 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2572 Warn("recursion too deep when resolving group element %d",
2573 group_element - EL_GROUP_START + 1);
2575 // replace element which caused too deep recursion by question mark
2576 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2581 if (recursion_depth == 0) // initialization
2583 group = actual_group;
2584 group_nr = GROUP_NR(group_element);
2586 group->num_elements_resolved = 0;
2587 group->choice_pos = 0;
2589 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2590 element_info[i].in_group[group_nr] = FALSE;
2593 for (i = 0; i < actual_group->num_elements; i++)
2595 int element = actual_group->element[i];
2597 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2600 if (IS_GROUP_ELEMENT(element))
2601 ResolveGroupElementExt(element, recursion_depth + 1);
2604 group->element_resolved[group->num_elements_resolved++] = element;
2605 element_info[element].in_group[group_nr] = TRUE;
2610 void ResolveGroupElement(int group_element)
2612 ResolveGroupElementExt(group_element, 0);
2615 void InitElementPropertiesStatic(void)
2617 static boolean clipboard_elements_initialized = FALSE;
2619 static int ep_diggable[] =
2624 EL_SP_BUGGY_BASE_ACTIVATING,
2627 EL_INVISIBLE_SAND_ACTIVE,
2630 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2631 // (if amoeba can grow into anything diggable, maybe keep these out)
2636 EL_SP_BUGGY_BASE_ACTIVE,
2643 static int ep_collectible_only[] =
2665 EL_DYNABOMB_INCREASE_NUMBER,
2666 EL_DYNABOMB_INCREASE_SIZE,
2667 EL_DYNABOMB_INCREASE_POWER,
2685 // !!! handle separately !!!
2686 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2692 static int ep_dont_run_into[] =
2694 // same elements as in 'ep_dont_touch'
2700 // same elements as in 'ep_dont_collide_with'
2712 // !!! maybe this should better be handled by 'ep_diggable' !!!
2717 EL_SP_BUGGY_BASE_ACTIVE,
2724 static int ep_dont_collide_with[] =
2726 // same elements as in 'ep_dont_touch'
2743 static int ep_dont_touch[] =
2753 static int ep_indestructible[] =
2757 EL_ACID_POOL_TOPLEFT,
2758 EL_ACID_POOL_TOPRIGHT,
2759 EL_ACID_POOL_BOTTOMLEFT,
2760 EL_ACID_POOL_BOTTOM,
2761 EL_ACID_POOL_BOTTOMRIGHT,
2762 EL_SP_HARDWARE_GRAY,
2763 EL_SP_HARDWARE_GREEN,
2764 EL_SP_HARDWARE_BLUE,
2766 EL_SP_HARDWARE_YELLOW,
2767 EL_SP_HARDWARE_BASE_1,
2768 EL_SP_HARDWARE_BASE_2,
2769 EL_SP_HARDWARE_BASE_3,
2770 EL_SP_HARDWARE_BASE_4,
2771 EL_SP_HARDWARE_BASE_5,
2772 EL_SP_HARDWARE_BASE_6,
2773 EL_INVISIBLE_STEELWALL,
2774 EL_INVISIBLE_STEELWALL_ACTIVE,
2775 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2776 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2777 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2778 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2779 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2780 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2781 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2782 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2783 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2784 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2785 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2786 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2788 EL_LIGHT_SWITCH_ACTIVE,
2789 EL_SIGN_EXCLAMATION,
2790 EL_SIGN_RADIOACTIVITY,
2797 EL_SIGN_ENTRY_FORBIDDEN,
2798 EL_SIGN_EMERGENCY_EXIT,
2806 EL_STEEL_EXIT_CLOSED,
2808 EL_STEEL_EXIT_OPENING,
2809 EL_STEEL_EXIT_CLOSING,
2810 EL_EM_STEEL_EXIT_CLOSED,
2811 EL_EM_STEEL_EXIT_OPEN,
2812 EL_EM_STEEL_EXIT_OPENING,
2813 EL_EM_STEEL_EXIT_CLOSING,
2814 EL_DC_STEELWALL_1_LEFT,
2815 EL_DC_STEELWALL_1_RIGHT,
2816 EL_DC_STEELWALL_1_TOP,
2817 EL_DC_STEELWALL_1_BOTTOM,
2818 EL_DC_STEELWALL_1_HORIZONTAL,
2819 EL_DC_STEELWALL_1_VERTICAL,
2820 EL_DC_STEELWALL_1_TOPLEFT,
2821 EL_DC_STEELWALL_1_TOPRIGHT,
2822 EL_DC_STEELWALL_1_BOTTOMLEFT,
2823 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2824 EL_DC_STEELWALL_1_TOPLEFT_2,
2825 EL_DC_STEELWALL_1_TOPRIGHT_2,
2826 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2827 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2828 EL_DC_STEELWALL_2_LEFT,
2829 EL_DC_STEELWALL_2_RIGHT,
2830 EL_DC_STEELWALL_2_TOP,
2831 EL_DC_STEELWALL_2_BOTTOM,
2832 EL_DC_STEELWALL_2_HORIZONTAL,
2833 EL_DC_STEELWALL_2_VERTICAL,
2834 EL_DC_STEELWALL_2_MIDDLE,
2835 EL_DC_STEELWALL_2_SINGLE,
2836 EL_STEELWALL_SLIPPERY,
2850 EL_GATE_1_GRAY_ACTIVE,
2851 EL_GATE_2_GRAY_ACTIVE,
2852 EL_GATE_3_GRAY_ACTIVE,
2853 EL_GATE_4_GRAY_ACTIVE,
2862 EL_EM_GATE_1_GRAY_ACTIVE,
2863 EL_EM_GATE_2_GRAY_ACTIVE,
2864 EL_EM_GATE_3_GRAY_ACTIVE,
2865 EL_EM_GATE_4_GRAY_ACTIVE,
2874 EL_EMC_GATE_5_GRAY_ACTIVE,
2875 EL_EMC_GATE_6_GRAY_ACTIVE,
2876 EL_EMC_GATE_7_GRAY_ACTIVE,
2877 EL_EMC_GATE_8_GRAY_ACTIVE,
2879 EL_DC_GATE_WHITE_GRAY,
2880 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2881 EL_DC_GATE_FAKE_GRAY,
2883 EL_SWITCHGATE_OPENING,
2884 EL_SWITCHGATE_CLOSED,
2885 EL_SWITCHGATE_CLOSING,
2886 EL_DC_SWITCHGATE_SWITCH_UP,
2887 EL_DC_SWITCHGATE_SWITCH_DOWN,
2889 EL_TIMEGATE_OPENING,
2891 EL_TIMEGATE_CLOSING,
2892 EL_DC_TIMEGATE_SWITCH,
2893 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2897 EL_TUBE_VERTICAL_LEFT,
2898 EL_TUBE_VERTICAL_RIGHT,
2899 EL_TUBE_HORIZONTAL_UP,
2900 EL_TUBE_HORIZONTAL_DOWN,
2905 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2906 EL_EXPANDABLE_STEELWALL_VERTICAL,
2907 EL_EXPANDABLE_STEELWALL_ANY,
2912 static int ep_slippery[] =
2926 EL_ROBOT_WHEEL_ACTIVE,
2932 EL_ACID_POOL_TOPLEFT,
2933 EL_ACID_POOL_TOPRIGHT,
2943 EL_STEELWALL_SLIPPERY,
2946 EL_EMC_WALL_SLIPPERY_1,
2947 EL_EMC_WALL_SLIPPERY_2,
2948 EL_EMC_WALL_SLIPPERY_3,
2949 EL_EMC_WALL_SLIPPERY_4,
2951 EL_EMC_MAGIC_BALL_ACTIVE,
2956 static int ep_can_change[] =
2961 static int ep_can_move[] =
2963 // same elements as in 'pb_can_move_into_acid'
2986 static int ep_can_fall[] =
3001 EL_QUICKSAND_FAST_FULL,
3003 EL_BD_MAGIC_WALL_FULL,
3004 EL_DC_MAGIC_WALL_FULL,
3018 static int ep_can_smash_player[] =
3044 static int ep_can_smash_enemies[] =
3053 static int ep_can_smash_everything[] =
3062 static int ep_explodes_by_fire[] =
3064 // same elements as in 'ep_explodes_impact'
3069 // same elements as in 'ep_explodes_smashed'
3079 EL_EM_DYNAMITE_ACTIVE,
3080 EL_DYNABOMB_PLAYER_1_ACTIVE,
3081 EL_DYNABOMB_PLAYER_2_ACTIVE,
3082 EL_DYNABOMB_PLAYER_3_ACTIVE,
3083 EL_DYNABOMB_PLAYER_4_ACTIVE,
3084 EL_DYNABOMB_INCREASE_NUMBER,
3085 EL_DYNABOMB_INCREASE_SIZE,
3086 EL_DYNABOMB_INCREASE_POWER,
3087 EL_SP_DISK_RED_ACTIVE,
3101 static int ep_explodes_smashed[] =
3103 // same elements as in 'ep_explodes_impact'
3117 static int ep_explodes_impact[] =
3126 static int ep_walkable_over[] =
3146 EL_SOKOBAN_FIELD_EMPTY,
3153 EL_EM_STEEL_EXIT_OPEN,
3154 EL_EM_STEEL_EXIT_OPENING,
3163 EL_GATE_1_GRAY_ACTIVE,
3164 EL_GATE_2_GRAY_ACTIVE,
3165 EL_GATE_3_GRAY_ACTIVE,
3166 EL_GATE_4_GRAY_ACTIVE,
3174 static int ep_walkable_inside[] =
3179 EL_TUBE_VERTICAL_LEFT,
3180 EL_TUBE_VERTICAL_RIGHT,
3181 EL_TUBE_HORIZONTAL_UP,
3182 EL_TUBE_HORIZONTAL_DOWN,
3191 static int ep_walkable_under[] =
3196 static int ep_passable_over[] =
3206 EL_EM_GATE_1_GRAY_ACTIVE,
3207 EL_EM_GATE_2_GRAY_ACTIVE,
3208 EL_EM_GATE_3_GRAY_ACTIVE,
3209 EL_EM_GATE_4_GRAY_ACTIVE,
3218 EL_EMC_GATE_5_GRAY_ACTIVE,
3219 EL_EMC_GATE_6_GRAY_ACTIVE,
3220 EL_EMC_GATE_7_GRAY_ACTIVE,
3221 EL_EMC_GATE_8_GRAY_ACTIVE,
3223 EL_DC_GATE_WHITE_GRAY,
3224 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3231 static int ep_passable_inside[] =
3237 EL_SP_PORT_HORIZONTAL,
3238 EL_SP_PORT_VERTICAL,
3240 EL_SP_GRAVITY_PORT_LEFT,
3241 EL_SP_GRAVITY_PORT_RIGHT,
3242 EL_SP_GRAVITY_PORT_UP,
3243 EL_SP_GRAVITY_PORT_DOWN,
3244 EL_SP_GRAVITY_ON_PORT_LEFT,
3245 EL_SP_GRAVITY_ON_PORT_RIGHT,
3246 EL_SP_GRAVITY_ON_PORT_UP,
3247 EL_SP_GRAVITY_ON_PORT_DOWN,
3248 EL_SP_GRAVITY_OFF_PORT_LEFT,
3249 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3250 EL_SP_GRAVITY_OFF_PORT_UP,
3251 EL_SP_GRAVITY_OFF_PORT_DOWN,
3256 static int ep_passable_under[] =
3261 static int ep_droppable[] =
3266 static int ep_explodes_1x1_old[] =
3271 static int ep_pushable[] =
3283 EL_SOKOBAN_FIELD_FULL,
3292 static int ep_explodes_cross_old[] =
3297 static int ep_protected[] =
3299 // same elements as in 'ep_walkable_inside'
3303 EL_TUBE_VERTICAL_LEFT,
3304 EL_TUBE_VERTICAL_RIGHT,
3305 EL_TUBE_HORIZONTAL_UP,
3306 EL_TUBE_HORIZONTAL_DOWN,
3312 // same elements as in 'ep_passable_over'
3321 EL_EM_GATE_1_GRAY_ACTIVE,
3322 EL_EM_GATE_2_GRAY_ACTIVE,
3323 EL_EM_GATE_3_GRAY_ACTIVE,
3324 EL_EM_GATE_4_GRAY_ACTIVE,
3333 EL_EMC_GATE_5_GRAY_ACTIVE,
3334 EL_EMC_GATE_6_GRAY_ACTIVE,
3335 EL_EMC_GATE_7_GRAY_ACTIVE,
3336 EL_EMC_GATE_8_GRAY_ACTIVE,
3338 EL_DC_GATE_WHITE_GRAY,
3339 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3343 // same elements as in 'ep_passable_inside'
3348 EL_SP_PORT_HORIZONTAL,
3349 EL_SP_PORT_VERTICAL,
3351 EL_SP_GRAVITY_PORT_LEFT,
3352 EL_SP_GRAVITY_PORT_RIGHT,
3353 EL_SP_GRAVITY_PORT_UP,
3354 EL_SP_GRAVITY_PORT_DOWN,
3355 EL_SP_GRAVITY_ON_PORT_LEFT,
3356 EL_SP_GRAVITY_ON_PORT_RIGHT,
3357 EL_SP_GRAVITY_ON_PORT_UP,
3358 EL_SP_GRAVITY_ON_PORT_DOWN,
3359 EL_SP_GRAVITY_OFF_PORT_LEFT,
3360 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3361 EL_SP_GRAVITY_OFF_PORT_UP,
3362 EL_SP_GRAVITY_OFF_PORT_DOWN,
3367 static int ep_throwable[] =
3372 static int ep_can_explode[] =
3374 // same elements as in 'ep_explodes_impact'
3379 // same elements as in 'ep_explodes_smashed'
3385 // elements that can explode by explosion or by dragonfire
3389 EL_EM_DYNAMITE_ACTIVE,
3390 EL_DYNABOMB_PLAYER_1_ACTIVE,
3391 EL_DYNABOMB_PLAYER_2_ACTIVE,
3392 EL_DYNABOMB_PLAYER_3_ACTIVE,
3393 EL_DYNABOMB_PLAYER_4_ACTIVE,
3394 EL_DYNABOMB_INCREASE_NUMBER,
3395 EL_DYNABOMB_INCREASE_SIZE,
3396 EL_DYNABOMB_INCREASE_POWER,
3397 EL_SP_DISK_RED_ACTIVE,
3405 // elements that can explode only by explosion
3411 static int ep_gravity_reachable[] =
3417 EL_INVISIBLE_SAND_ACTIVE,
3422 EL_SP_PORT_HORIZONTAL,
3423 EL_SP_PORT_VERTICAL,
3425 EL_SP_GRAVITY_PORT_LEFT,
3426 EL_SP_GRAVITY_PORT_RIGHT,
3427 EL_SP_GRAVITY_PORT_UP,
3428 EL_SP_GRAVITY_PORT_DOWN,
3429 EL_SP_GRAVITY_ON_PORT_LEFT,
3430 EL_SP_GRAVITY_ON_PORT_RIGHT,
3431 EL_SP_GRAVITY_ON_PORT_UP,
3432 EL_SP_GRAVITY_ON_PORT_DOWN,
3433 EL_SP_GRAVITY_OFF_PORT_LEFT,
3434 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3435 EL_SP_GRAVITY_OFF_PORT_UP,
3436 EL_SP_GRAVITY_OFF_PORT_DOWN,
3442 static int ep_empty_space[] =
3465 static int ep_player[] =
3472 EL_SOKOBAN_FIELD_PLAYER,
3478 static int ep_can_pass_magic_wall[] =
3492 static int ep_can_pass_dc_magic_wall[] =
3508 static int ep_switchable[] =
3512 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3513 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3514 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3515 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3516 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3517 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3518 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3519 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3520 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3521 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3522 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3523 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3524 EL_SWITCHGATE_SWITCH_UP,
3525 EL_SWITCHGATE_SWITCH_DOWN,
3526 EL_DC_SWITCHGATE_SWITCH_UP,
3527 EL_DC_SWITCHGATE_SWITCH_DOWN,
3529 EL_LIGHT_SWITCH_ACTIVE,
3531 EL_DC_TIMEGATE_SWITCH,
3532 EL_BALLOON_SWITCH_LEFT,
3533 EL_BALLOON_SWITCH_RIGHT,
3534 EL_BALLOON_SWITCH_UP,
3535 EL_BALLOON_SWITCH_DOWN,
3536 EL_BALLOON_SWITCH_ANY,
3537 EL_BALLOON_SWITCH_NONE,
3540 EL_EMC_MAGIC_BALL_SWITCH,
3541 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3546 static int ep_bd_element[] =
3580 static int ep_sp_element[] =
3582 // should always be valid
3585 // standard classic Supaplex elements
3592 EL_SP_HARDWARE_GRAY,
3600 EL_SP_GRAVITY_PORT_RIGHT,
3601 EL_SP_GRAVITY_PORT_DOWN,
3602 EL_SP_GRAVITY_PORT_LEFT,
3603 EL_SP_GRAVITY_PORT_UP,
3608 EL_SP_PORT_VERTICAL,
3609 EL_SP_PORT_HORIZONTAL,
3615 EL_SP_HARDWARE_BASE_1,
3616 EL_SP_HARDWARE_GREEN,
3617 EL_SP_HARDWARE_BLUE,
3619 EL_SP_HARDWARE_YELLOW,
3620 EL_SP_HARDWARE_BASE_2,
3621 EL_SP_HARDWARE_BASE_3,
3622 EL_SP_HARDWARE_BASE_4,
3623 EL_SP_HARDWARE_BASE_5,
3624 EL_SP_HARDWARE_BASE_6,
3628 // additional elements that appeared in newer Supaplex levels
3631 // additional gravity port elements (not switching, but setting gravity)
3632 EL_SP_GRAVITY_ON_PORT_LEFT,
3633 EL_SP_GRAVITY_ON_PORT_RIGHT,
3634 EL_SP_GRAVITY_ON_PORT_UP,
3635 EL_SP_GRAVITY_ON_PORT_DOWN,
3636 EL_SP_GRAVITY_OFF_PORT_LEFT,
3637 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3638 EL_SP_GRAVITY_OFF_PORT_UP,
3639 EL_SP_GRAVITY_OFF_PORT_DOWN,
3641 // more than one Murphy in a level results in an inactive clone
3644 // runtime Supaplex elements
3645 EL_SP_DISK_RED_ACTIVE,
3646 EL_SP_TERMINAL_ACTIVE,
3647 EL_SP_BUGGY_BASE_ACTIVATING,
3648 EL_SP_BUGGY_BASE_ACTIVE,
3655 static int ep_sb_element[] =
3660 EL_SOKOBAN_FIELD_EMPTY,
3661 EL_SOKOBAN_FIELD_FULL,
3662 EL_SOKOBAN_FIELD_PLAYER,
3667 EL_INVISIBLE_STEELWALL,
3672 static int ep_gem[] =
3684 static int ep_food_dark_yamyam[] =
3712 static int ep_food_penguin[] =
3726 static int ep_food_pig[] =
3738 static int ep_historic_wall[] =
3749 EL_GATE_1_GRAY_ACTIVE,
3750 EL_GATE_2_GRAY_ACTIVE,
3751 EL_GATE_3_GRAY_ACTIVE,
3752 EL_GATE_4_GRAY_ACTIVE,
3761 EL_EM_GATE_1_GRAY_ACTIVE,
3762 EL_EM_GATE_2_GRAY_ACTIVE,
3763 EL_EM_GATE_3_GRAY_ACTIVE,
3764 EL_EM_GATE_4_GRAY_ACTIVE,
3771 EL_EXPANDABLE_WALL_HORIZONTAL,
3772 EL_EXPANDABLE_WALL_VERTICAL,
3773 EL_EXPANDABLE_WALL_ANY,
3774 EL_EXPANDABLE_WALL_GROWING,
3775 EL_BD_EXPANDABLE_WALL,
3782 EL_SP_HARDWARE_GRAY,
3783 EL_SP_HARDWARE_GREEN,
3784 EL_SP_HARDWARE_BLUE,
3786 EL_SP_HARDWARE_YELLOW,
3787 EL_SP_HARDWARE_BASE_1,
3788 EL_SP_HARDWARE_BASE_2,
3789 EL_SP_HARDWARE_BASE_3,
3790 EL_SP_HARDWARE_BASE_4,
3791 EL_SP_HARDWARE_BASE_5,
3792 EL_SP_HARDWARE_BASE_6,
3794 EL_SP_TERMINAL_ACTIVE,
3797 EL_INVISIBLE_STEELWALL,
3798 EL_INVISIBLE_STEELWALL_ACTIVE,
3800 EL_INVISIBLE_WALL_ACTIVE,
3801 EL_STEELWALL_SLIPPERY,
3818 static int ep_historic_solid[] =
3822 EL_EXPANDABLE_WALL_HORIZONTAL,
3823 EL_EXPANDABLE_WALL_VERTICAL,
3824 EL_EXPANDABLE_WALL_ANY,
3825 EL_BD_EXPANDABLE_WALL,
3838 EL_QUICKSAND_FILLING,
3839 EL_QUICKSAND_EMPTYING,
3841 EL_MAGIC_WALL_ACTIVE,
3842 EL_MAGIC_WALL_EMPTYING,
3843 EL_MAGIC_WALL_FILLING,
3847 EL_BD_MAGIC_WALL_ACTIVE,
3848 EL_BD_MAGIC_WALL_EMPTYING,
3849 EL_BD_MAGIC_WALL_FULL,
3850 EL_BD_MAGIC_WALL_FILLING,
3851 EL_BD_MAGIC_WALL_DEAD,
3860 EL_SP_TERMINAL_ACTIVE,
3864 EL_INVISIBLE_WALL_ACTIVE,
3865 EL_SWITCHGATE_SWITCH_UP,
3866 EL_SWITCHGATE_SWITCH_DOWN,
3868 EL_TIMEGATE_SWITCH_ACTIVE,
3880 // the following elements are a direct copy of "indestructible" elements,
3881 // except "EL_ACID", which is "indestructible", but not "solid"!
3886 EL_ACID_POOL_TOPLEFT,
3887 EL_ACID_POOL_TOPRIGHT,
3888 EL_ACID_POOL_BOTTOMLEFT,
3889 EL_ACID_POOL_BOTTOM,
3890 EL_ACID_POOL_BOTTOMRIGHT,
3891 EL_SP_HARDWARE_GRAY,
3892 EL_SP_HARDWARE_GREEN,
3893 EL_SP_HARDWARE_BLUE,
3895 EL_SP_HARDWARE_YELLOW,
3896 EL_SP_HARDWARE_BASE_1,
3897 EL_SP_HARDWARE_BASE_2,
3898 EL_SP_HARDWARE_BASE_3,
3899 EL_SP_HARDWARE_BASE_4,
3900 EL_SP_HARDWARE_BASE_5,
3901 EL_SP_HARDWARE_BASE_6,
3902 EL_INVISIBLE_STEELWALL,
3903 EL_INVISIBLE_STEELWALL_ACTIVE,
3904 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3905 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3906 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3907 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3908 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3909 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3910 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3911 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3912 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3913 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3914 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3915 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3917 EL_LIGHT_SWITCH_ACTIVE,
3918 EL_SIGN_EXCLAMATION,
3919 EL_SIGN_RADIOACTIVITY,
3926 EL_SIGN_ENTRY_FORBIDDEN,
3927 EL_SIGN_EMERGENCY_EXIT,
3935 EL_STEEL_EXIT_CLOSED,
3937 EL_STEEL_EXIT_OPENING,
3938 EL_STEEL_EXIT_CLOSING,
3939 EL_EM_STEEL_EXIT_CLOSED,
3940 EL_EM_STEEL_EXIT_OPEN,
3941 EL_EM_STEEL_EXIT_OPENING,
3942 EL_EM_STEEL_EXIT_CLOSING,
3943 EL_DC_STEELWALL_1_LEFT,
3944 EL_DC_STEELWALL_1_RIGHT,
3945 EL_DC_STEELWALL_1_TOP,
3946 EL_DC_STEELWALL_1_BOTTOM,
3947 EL_DC_STEELWALL_1_HORIZONTAL,
3948 EL_DC_STEELWALL_1_VERTICAL,
3949 EL_DC_STEELWALL_1_TOPLEFT,
3950 EL_DC_STEELWALL_1_TOPRIGHT,
3951 EL_DC_STEELWALL_1_BOTTOMLEFT,
3952 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3953 EL_DC_STEELWALL_1_TOPLEFT_2,
3954 EL_DC_STEELWALL_1_TOPRIGHT_2,
3955 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3956 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3957 EL_DC_STEELWALL_2_LEFT,
3958 EL_DC_STEELWALL_2_RIGHT,
3959 EL_DC_STEELWALL_2_TOP,
3960 EL_DC_STEELWALL_2_BOTTOM,
3961 EL_DC_STEELWALL_2_HORIZONTAL,
3962 EL_DC_STEELWALL_2_VERTICAL,
3963 EL_DC_STEELWALL_2_MIDDLE,
3964 EL_DC_STEELWALL_2_SINGLE,
3965 EL_STEELWALL_SLIPPERY,
3979 EL_GATE_1_GRAY_ACTIVE,
3980 EL_GATE_2_GRAY_ACTIVE,
3981 EL_GATE_3_GRAY_ACTIVE,
3982 EL_GATE_4_GRAY_ACTIVE,
3991 EL_EM_GATE_1_GRAY_ACTIVE,
3992 EL_EM_GATE_2_GRAY_ACTIVE,
3993 EL_EM_GATE_3_GRAY_ACTIVE,
3994 EL_EM_GATE_4_GRAY_ACTIVE,
4003 EL_EMC_GATE_5_GRAY_ACTIVE,
4004 EL_EMC_GATE_6_GRAY_ACTIVE,
4005 EL_EMC_GATE_7_GRAY_ACTIVE,
4006 EL_EMC_GATE_8_GRAY_ACTIVE,
4008 EL_DC_GATE_WHITE_GRAY,
4009 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4010 EL_DC_GATE_FAKE_GRAY,
4012 EL_SWITCHGATE_OPENING,
4013 EL_SWITCHGATE_CLOSED,
4014 EL_SWITCHGATE_CLOSING,
4015 EL_DC_SWITCHGATE_SWITCH_UP,
4016 EL_DC_SWITCHGATE_SWITCH_DOWN,
4018 EL_TIMEGATE_OPENING,
4020 EL_TIMEGATE_CLOSING,
4021 EL_DC_TIMEGATE_SWITCH,
4022 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4026 EL_TUBE_VERTICAL_LEFT,
4027 EL_TUBE_VERTICAL_RIGHT,
4028 EL_TUBE_HORIZONTAL_UP,
4029 EL_TUBE_HORIZONTAL_DOWN,
4034 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4035 EL_EXPANDABLE_STEELWALL_VERTICAL,
4036 EL_EXPANDABLE_STEELWALL_ANY,
4041 static int ep_classic_enemy[] =
4058 static int ep_belt[] =
4060 EL_CONVEYOR_BELT_1_LEFT,
4061 EL_CONVEYOR_BELT_1_MIDDLE,
4062 EL_CONVEYOR_BELT_1_RIGHT,
4063 EL_CONVEYOR_BELT_2_LEFT,
4064 EL_CONVEYOR_BELT_2_MIDDLE,
4065 EL_CONVEYOR_BELT_2_RIGHT,
4066 EL_CONVEYOR_BELT_3_LEFT,
4067 EL_CONVEYOR_BELT_3_MIDDLE,
4068 EL_CONVEYOR_BELT_3_RIGHT,
4069 EL_CONVEYOR_BELT_4_LEFT,
4070 EL_CONVEYOR_BELT_4_MIDDLE,
4071 EL_CONVEYOR_BELT_4_RIGHT,
4076 static int ep_belt_active[] =
4078 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4079 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4080 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4081 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4082 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4083 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4084 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4085 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4086 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4087 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4088 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4089 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4094 static int ep_belt_switch[] =
4096 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4097 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4098 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4099 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4100 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4101 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4102 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4103 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4104 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4105 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4106 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4107 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4112 static int ep_tube[] =
4119 EL_TUBE_HORIZONTAL_UP,
4120 EL_TUBE_HORIZONTAL_DOWN,
4122 EL_TUBE_VERTICAL_LEFT,
4123 EL_TUBE_VERTICAL_RIGHT,
4129 static int ep_acid_pool[] =
4131 EL_ACID_POOL_TOPLEFT,
4132 EL_ACID_POOL_TOPRIGHT,
4133 EL_ACID_POOL_BOTTOMLEFT,
4134 EL_ACID_POOL_BOTTOM,
4135 EL_ACID_POOL_BOTTOMRIGHT,
4140 static int ep_keygate[] =
4150 EL_GATE_1_GRAY_ACTIVE,
4151 EL_GATE_2_GRAY_ACTIVE,
4152 EL_GATE_3_GRAY_ACTIVE,
4153 EL_GATE_4_GRAY_ACTIVE,
4162 EL_EM_GATE_1_GRAY_ACTIVE,
4163 EL_EM_GATE_2_GRAY_ACTIVE,
4164 EL_EM_GATE_3_GRAY_ACTIVE,
4165 EL_EM_GATE_4_GRAY_ACTIVE,
4174 EL_EMC_GATE_5_GRAY_ACTIVE,
4175 EL_EMC_GATE_6_GRAY_ACTIVE,
4176 EL_EMC_GATE_7_GRAY_ACTIVE,
4177 EL_EMC_GATE_8_GRAY_ACTIVE,
4179 EL_DC_GATE_WHITE_GRAY,
4180 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4185 static int ep_amoeboid[] =
4197 static int ep_amoebalive[] =
4208 static int ep_has_editor_content[] =
4214 EL_SOKOBAN_FIELD_PLAYER,
4231 static int ep_can_turn_each_move[] =
4233 // !!! do something with this one !!!
4237 static int ep_can_grow[] =
4251 static int ep_active_bomb[] =
4254 EL_EM_DYNAMITE_ACTIVE,
4255 EL_DYNABOMB_PLAYER_1_ACTIVE,
4256 EL_DYNABOMB_PLAYER_2_ACTIVE,
4257 EL_DYNABOMB_PLAYER_3_ACTIVE,
4258 EL_DYNABOMB_PLAYER_4_ACTIVE,
4259 EL_SP_DISK_RED_ACTIVE,
4264 static int ep_inactive[] =
4290 EL_QUICKSAND_FAST_EMPTY,
4313 EL_GATE_1_GRAY_ACTIVE,
4314 EL_GATE_2_GRAY_ACTIVE,
4315 EL_GATE_3_GRAY_ACTIVE,
4316 EL_GATE_4_GRAY_ACTIVE,
4325 EL_EM_GATE_1_GRAY_ACTIVE,
4326 EL_EM_GATE_2_GRAY_ACTIVE,
4327 EL_EM_GATE_3_GRAY_ACTIVE,
4328 EL_EM_GATE_4_GRAY_ACTIVE,
4337 EL_EMC_GATE_5_GRAY_ACTIVE,
4338 EL_EMC_GATE_6_GRAY_ACTIVE,
4339 EL_EMC_GATE_7_GRAY_ACTIVE,
4340 EL_EMC_GATE_8_GRAY_ACTIVE,
4342 EL_DC_GATE_WHITE_GRAY,
4343 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4344 EL_DC_GATE_FAKE_GRAY,
4347 EL_INVISIBLE_STEELWALL,
4355 EL_WALL_EMERALD_YELLOW,
4356 EL_DYNABOMB_INCREASE_NUMBER,
4357 EL_DYNABOMB_INCREASE_SIZE,
4358 EL_DYNABOMB_INCREASE_POWER,
4362 EL_SOKOBAN_FIELD_EMPTY,
4363 EL_SOKOBAN_FIELD_FULL,
4364 EL_WALL_EMERALD_RED,
4365 EL_WALL_EMERALD_PURPLE,
4366 EL_ACID_POOL_TOPLEFT,
4367 EL_ACID_POOL_TOPRIGHT,
4368 EL_ACID_POOL_BOTTOMLEFT,
4369 EL_ACID_POOL_BOTTOM,
4370 EL_ACID_POOL_BOTTOMRIGHT,
4374 EL_BD_MAGIC_WALL_DEAD,
4376 EL_DC_MAGIC_WALL_DEAD,
4377 EL_AMOEBA_TO_DIAMOND,
4385 EL_SP_GRAVITY_PORT_RIGHT,
4386 EL_SP_GRAVITY_PORT_DOWN,
4387 EL_SP_GRAVITY_PORT_LEFT,
4388 EL_SP_GRAVITY_PORT_UP,
4389 EL_SP_PORT_HORIZONTAL,
4390 EL_SP_PORT_VERTICAL,
4401 EL_SP_HARDWARE_GRAY,
4402 EL_SP_HARDWARE_GREEN,
4403 EL_SP_HARDWARE_BLUE,
4405 EL_SP_HARDWARE_YELLOW,
4406 EL_SP_HARDWARE_BASE_1,
4407 EL_SP_HARDWARE_BASE_2,
4408 EL_SP_HARDWARE_BASE_3,
4409 EL_SP_HARDWARE_BASE_4,
4410 EL_SP_HARDWARE_BASE_5,
4411 EL_SP_HARDWARE_BASE_6,
4412 EL_SP_GRAVITY_ON_PORT_LEFT,
4413 EL_SP_GRAVITY_ON_PORT_RIGHT,
4414 EL_SP_GRAVITY_ON_PORT_UP,
4415 EL_SP_GRAVITY_ON_PORT_DOWN,
4416 EL_SP_GRAVITY_OFF_PORT_LEFT,
4417 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4418 EL_SP_GRAVITY_OFF_PORT_UP,
4419 EL_SP_GRAVITY_OFF_PORT_DOWN,
4420 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4421 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4422 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4423 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4424 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4425 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4426 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4427 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4428 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4429 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4430 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4431 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4432 EL_SIGN_EXCLAMATION,
4433 EL_SIGN_RADIOACTIVITY,
4440 EL_SIGN_ENTRY_FORBIDDEN,
4441 EL_SIGN_EMERGENCY_EXIT,
4449 EL_DC_STEELWALL_1_LEFT,
4450 EL_DC_STEELWALL_1_RIGHT,
4451 EL_DC_STEELWALL_1_TOP,
4452 EL_DC_STEELWALL_1_BOTTOM,
4453 EL_DC_STEELWALL_1_HORIZONTAL,
4454 EL_DC_STEELWALL_1_VERTICAL,
4455 EL_DC_STEELWALL_1_TOPLEFT,
4456 EL_DC_STEELWALL_1_TOPRIGHT,
4457 EL_DC_STEELWALL_1_BOTTOMLEFT,
4458 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4459 EL_DC_STEELWALL_1_TOPLEFT_2,
4460 EL_DC_STEELWALL_1_TOPRIGHT_2,
4461 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4462 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4463 EL_DC_STEELWALL_2_LEFT,
4464 EL_DC_STEELWALL_2_RIGHT,
4465 EL_DC_STEELWALL_2_TOP,
4466 EL_DC_STEELWALL_2_BOTTOM,
4467 EL_DC_STEELWALL_2_HORIZONTAL,
4468 EL_DC_STEELWALL_2_VERTICAL,
4469 EL_DC_STEELWALL_2_MIDDLE,
4470 EL_DC_STEELWALL_2_SINGLE,
4471 EL_STEELWALL_SLIPPERY,
4476 EL_EMC_WALL_SLIPPERY_1,
4477 EL_EMC_WALL_SLIPPERY_2,
4478 EL_EMC_WALL_SLIPPERY_3,
4479 EL_EMC_WALL_SLIPPERY_4,
4500 static int ep_em_slippery_wall[] =
4505 static int ep_gfx_crumbled[] =
4516 static int ep_editor_cascade_active[] =
4518 EL_INTERNAL_CASCADE_BD_ACTIVE,
4519 EL_INTERNAL_CASCADE_EM_ACTIVE,
4520 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4521 EL_INTERNAL_CASCADE_RND_ACTIVE,
4522 EL_INTERNAL_CASCADE_SB_ACTIVE,
4523 EL_INTERNAL_CASCADE_SP_ACTIVE,
4524 EL_INTERNAL_CASCADE_DC_ACTIVE,
4525 EL_INTERNAL_CASCADE_DX_ACTIVE,
4526 EL_INTERNAL_CASCADE_MM_ACTIVE,
4527 EL_INTERNAL_CASCADE_DF_ACTIVE,
4528 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4529 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4530 EL_INTERNAL_CASCADE_CE_ACTIVE,
4531 EL_INTERNAL_CASCADE_GE_ACTIVE,
4532 EL_INTERNAL_CASCADE_ES_ACTIVE,
4533 EL_INTERNAL_CASCADE_REF_ACTIVE,
4534 EL_INTERNAL_CASCADE_USER_ACTIVE,
4535 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4540 static int ep_editor_cascade_inactive[] =
4542 EL_INTERNAL_CASCADE_BD,
4543 EL_INTERNAL_CASCADE_EM,
4544 EL_INTERNAL_CASCADE_EMC,
4545 EL_INTERNAL_CASCADE_RND,
4546 EL_INTERNAL_CASCADE_SB,
4547 EL_INTERNAL_CASCADE_SP,
4548 EL_INTERNAL_CASCADE_DC,
4549 EL_INTERNAL_CASCADE_DX,
4550 EL_INTERNAL_CASCADE_MM,
4551 EL_INTERNAL_CASCADE_DF,
4552 EL_INTERNAL_CASCADE_CHARS,
4553 EL_INTERNAL_CASCADE_STEEL_CHARS,
4554 EL_INTERNAL_CASCADE_CE,
4555 EL_INTERNAL_CASCADE_GE,
4556 EL_INTERNAL_CASCADE_ES,
4557 EL_INTERNAL_CASCADE_REF,
4558 EL_INTERNAL_CASCADE_USER,
4559 EL_INTERNAL_CASCADE_DYNAMIC,
4564 static int ep_obsolete[] =
4568 EL_EM_KEY_1_FILE_OBSOLETE,
4569 EL_EM_KEY_2_FILE_OBSOLETE,
4570 EL_EM_KEY_3_FILE_OBSOLETE,
4571 EL_EM_KEY_4_FILE_OBSOLETE,
4572 EL_ENVELOPE_OBSOLETE,
4581 } element_properties[] =
4583 { ep_diggable, EP_DIGGABLE },
4584 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4585 { ep_dont_run_into, EP_DONT_RUN_INTO },
4586 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4587 { ep_dont_touch, EP_DONT_TOUCH },
4588 { ep_indestructible, EP_INDESTRUCTIBLE },
4589 { ep_slippery, EP_SLIPPERY },
4590 { ep_can_change, EP_CAN_CHANGE },
4591 { ep_can_move, EP_CAN_MOVE },
4592 { ep_can_fall, EP_CAN_FALL },
4593 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4594 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4595 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4596 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4597 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4598 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4599 { ep_walkable_over, EP_WALKABLE_OVER },
4600 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4601 { ep_walkable_under, EP_WALKABLE_UNDER },
4602 { ep_passable_over, EP_PASSABLE_OVER },
4603 { ep_passable_inside, EP_PASSABLE_INSIDE },
4604 { ep_passable_under, EP_PASSABLE_UNDER },
4605 { ep_droppable, EP_DROPPABLE },
4606 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4607 { ep_pushable, EP_PUSHABLE },
4608 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4609 { ep_protected, EP_PROTECTED },
4610 { ep_throwable, EP_THROWABLE },
4611 { ep_can_explode, EP_CAN_EXPLODE },
4612 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4614 { ep_empty_space, EP_EMPTY_SPACE },
4615 { ep_player, EP_PLAYER },
4616 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4617 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4618 { ep_switchable, EP_SWITCHABLE },
4619 { ep_bd_element, EP_BD_ELEMENT },
4620 { ep_sp_element, EP_SP_ELEMENT },
4621 { ep_sb_element, EP_SB_ELEMENT },
4623 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4624 { ep_food_penguin, EP_FOOD_PENGUIN },
4625 { ep_food_pig, EP_FOOD_PIG },
4626 { ep_historic_wall, EP_HISTORIC_WALL },
4627 { ep_historic_solid, EP_HISTORIC_SOLID },
4628 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4629 { ep_belt, EP_BELT },
4630 { ep_belt_active, EP_BELT_ACTIVE },
4631 { ep_belt_switch, EP_BELT_SWITCH },
4632 { ep_tube, EP_TUBE },
4633 { ep_acid_pool, EP_ACID_POOL },
4634 { ep_keygate, EP_KEYGATE },
4635 { ep_amoeboid, EP_AMOEBOID },
4636 { ep_amoebalive, EP_AMOEBALIVE },
4637 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4638 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4639 { ep_can_grow, EP_CAN_GROW },
4640 { ep_active_bomb, EP_ACTIVE_BOMB },
4641 { ep_inactive, EP_INACTIVE },
4643 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4645 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4647 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4648 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4650 { ep_obsolete, EP_OBSOLETE },
4657 // always start with reliable default values (element has no properties)
4658 // (but never initialize clipboard elements after the very first time)
4659 // (to be able to use clipboard elements between several levels)
4660 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4661 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4662 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4663 SET_PROPERTY(i, j, FALSE);
4665 // set all base element properties from above array definitions
4666 for (i = 0; element_properties[i].elements != NULL; i++)
4667 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4668 SET_PROPERTY((element_properties[i].elements)[j],
4669 element_properties[i].property, TRUE);
4671 // copy properties to some elements that are only stored in level file
4672 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4673 for (j = 0; copy_properties[j][0] != -1; j++)
4674 if (HAS_PROPERTY(copy_properties[j][0], i))
4675 for (k = 1; k <= 4; k++)
4676 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4678 // set static element properties that are not listed in array definitions
4679 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4680 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4682 clipboard_elements_initialized = TRUE;
4685 void InitElementPropertiesEngine(int engine_version)
4687 static int no_wall_properties[] =
4690 EP_COLLECTIBLE_ONLY,
4692 EP_DONT_COLLIDE_WITH,
4695 EP_CAN_SMASH_PLAYER,
4696 EP_CAN_SMASH_ENEMIES,
4697 EP_CAN_SMASH_EVERYTHING,
4702 EP_FOOD_DARK_YAMYAM,
4718 /* important: after initialization in InitElementPropertiesStatic(), the
4719 elements are not again initialized to a default value; therefore all
4720 changes have to make sure that they leave the element with a defined
4721 property (which means that conditional property changes must be set to
4722 a reliable default value before) */
4724 // resolve group elements
4725 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4726 ResolveGroupElement(EL_GROUP_START + i);
4728 // set all special, combined or engine dependent element properties
4729 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4731 // do not change (already initialized) clipboard elements here
4732 if (IS_CLIPBOARD_ELEMENT(i))
4735 // ---------- INACTIVE ----------------------------------------------------
4736 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4737 i <= EL_CHAR_END) ||
4738 (i >= EL_STEEL_CHAR_START &&
4739 i <= EL_STEEL_CHAR_END)));
4741 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4742 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4743 IS_WALKABLE_INSIDE(i) ||
4744 IS_WALKABLE_UNDER(i)));
4746 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4747 IS_PASSABLE_INSIDE(i) ||
4748 IS_PASSABLE_UNDER(i)));
4750 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4751 IS_PASSABLE_OVER(i)));
4753 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4754 IS_PASSABLE_INSIDE(i)));
4756 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4757 IS_PASSABLE_UNDER(i)));
4759 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4762 // ---------- COLLECTIBLE -------------------------------------------------
4763 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4767 // ---------- SNAPPABLE ---------------------------------------------------
4768 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4769 IS_COLLECTIBLE(i) ||
4773 // ---------- WALL --------------------------------------------------------
4774 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4776 for (j = 0; no_wall_properties[j] != -1; j++)
4777 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4778 i >= EL_FIRST_RUNTIME_UNREAL)
4779 SET_PROPERTY(i, EP_WALL, FALSE);
4781 if (IS_HISTORIC_WALL(i))
4782 SET_PROPERTY(i, EP_WALL, TRUE);
4784 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4785 if (engine_version < VERSION_IDENT(2,2,0,0))
4786 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4788 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4790 !IS_COLLECTIBLE(i)));
4792 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4793 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4794 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4796 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4799 // ---------- EXPLOSION_PROOF ---------------------------------------------
4801 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4802 else if (engine_version < VERSION_IDENT(2,2,0,0))
4803 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4805 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4809 if (IS_CUSTOM_ELEMENT(i))
4811 // these are additional properties which are initially false when set
4813 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4815 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4816 if (DONT_COLLIDE_WITH(i))
4817 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4819 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4820 if (CAN_SMASH_EVERYTHING(i))
4821 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4822 if (CAN_SMASH_ENEMIES(i))
4823 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4826 // ---------- CAN_SMASH ---------------------------------------------------
4827 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4828 CAN_SMASH_ENEMIES(i) ||
4829 CAN_SMASH_EVERYTHING(i)));
4831 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4832 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4833 EXPLODES_BY_FIRE(i)));
4835 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4836 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4837 EXPLODES_SMASHED(i)));
4839 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4840 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4841 EXPLODES_IMPACT(i)));
4843 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4844 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4846 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4847 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4848 i == EL_BLACK_ORB));
4850 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4851 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4853 IS_CUSTOM_ELEMENT(i)));
4855 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4856 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4857 i == EL_SP_ELECTRON));
4859 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4860 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4861 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4862 getMoveIntoAcidProperty(&level, i));
4864 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4865 if (MAYBE_DONT_COLLIDE_WITH(i))
4866 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4867 getDontCollideWithProperty(&level, i));
4869 // ---------- SP_PORT -----------------------------------------------------
4870 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4871 IS_PASSABLE_INSIDE(i)));
4873 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4874 for (j = 0; j < level.num_android_clone_elements; j++)
4875 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4877 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4879 // ---------- CAN_CHANGE --------------------------------------------------
4880 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4881 for (j = 0; j < element_info[i].num_change_pages; j++)
4882 if (element_info[i].change_page[j].can_change)
4883 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4885 // ---------- HAS_ACTION --------------------------------------------------
4886 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4887 for (j = 0; j < element_info[i].num_change_pages; j++)
4888 if (element_info[i].change_page[j].has_action)
4889 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4891 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4892 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4895 // ---------- GFX_CRUMBLED ------------------------------------------------
4896 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4897 element_info[i].crumbled[ACTION_DEFAULT] !=
4898 element_info[i].graphic[ACTION_DEFAULT]);
4900 // ---------- EDITOR_CASCADE ----------------------------------------------
4901 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4902 IS_EDITOR_CASCADE_INACTIVE(i)));
4905 // dynamically adjust element properties according to game engine version
4907 static int ep_em_slippery_wall[] =
4912 EL_EXPANDABLE_WALL_HORIZONTAL,
4913 EL_EXPANDABLE_WALL_VERTICAL,
4914 EL_EXPANDABLE_WALL_ANY,
4915 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4916 EL_EXPANDABLE_STEELWALL_VERTICAL,
4917 EL_EXPANDABLE_STEELWALL_ANY,
4918 EL_EXPANDABLE_STEELWALL_GROWING,
4922 static int ep_em_explodes_by_fire[] =
4925 EL_EM_DYNAMITE_ACTIVE,
4930 // special EM style gems behaviour
4931 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4932 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4933 level.em_slippery_gems);
4935 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4936 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4937 (level.em_slippery_gems &&
4938 engine_version > VERSION_IDENT(2,0,1,0)));
4940 // special EM style explosion behaviour regarding chain reactions
4941 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4942 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4943 level.em_explodes_by_fire);
4946 // this is needed because some graphics depend on element properties
4947 if (game_status == GAME_MODE_PLAYING)
4948 InitElementGraphicInfo();
4951 void InitElementPropertiesGfxElement(void)
4955 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4957 struct ElementInfo *ei = &element_info[i];
4959 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4963 static void InitGlobal(void)
4968 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4970 // check if element_name_info entry defined for each element in "main.h"
4971 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4972 Fail("undefined 'element_name_info' entry for element %d", i);
4974 element_info[i].token_name = element_name_info[i].token_name;
4975 element_info[i].class_name = element_name_info[i].class_name;
4976 element_info[i].editor_description= element_name_info[i].editor_description;
4979 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4981 // check if global_anim_name_info defined for each entry in "main.h"
4982 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4983 global_anim_name_info[i].token_name == NULL)
4984 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4986 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4989 // create hash to store URLs for global animations
4990 anim_url_hash = newSetupFileHash();
4992 // create hash from image config list
4993 image_config_hash = newSetupFileHash();
4994 for (i = 0; image_config[i].token != NULL; i++)
4995 setHashEntry(image_config_hash,
4996 image_config[i].token,
4997 image_config[i].value);
4999 // create hash from element token list
5000 element_token_hash = newSetupFileHash();
5001 for (i = 0; element_name_info[i].token_name != NULL; i++)
5002 setHashEntry(element_token_hash,
5003 element_name_info[i].token_name,
5006 // create hash from graphic token list
5007 graphic_token_hash = newSetupFileHash();
5008 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5009 if (strSuffix(image_config[i].value, ".png") ||
5010 strSuffix(image_config[i].value, ".pcx") ||
5011 strSuffix(image_config[i].value, ".wav") ||
5012 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5013 setHashEntry(graphic_token_hash,
5014 image_config[i].token,
5015 int2str(graphic++, 0));
5017 // create hash from font token list
5018 font_token_hash = newSetupFileHash();
5019 for (i = 0; font_info[i].token_name != NULL; i++)
5020 setHashEntry(font_token_hash,
5021 font_info[i].token_name,
5024 // set default filenames for all cloned graphics in static configuration
5025 for (i = 0; image_config[i].token != NULL; i++)
5027 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5029 char *token = image_config[i].token;
5030 char *token_clone_from = getStringCat2(token, ".clone_from");
5031 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5033 if (token_cloned != NULL)
5035 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5037 if (value_cloned != NULL)
5039 // set default filename in static configuration
5040 image_config[i].value = value_cloned;
5042 // set default filename in image config hash
5043 setHashEntry(image_config_hash, token, value_cloned);
5047 free(token_clone_from);
5051 // always start with reliable default values (all elements)
5052 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5053 ActiveElement[i] = i;
5055 // now add all entries that have an active state (active elements)
5056 for (i = 0; element_with_active_state[i].element != -1; i++)
5058 int element = element_with_active_state[i].element;
5059 int element_active = element_with_active_state[i].element_active;
5061 ActiveElement[element] = element_active;
5064 // always start with reliable default values (all buttons)
5065 for (i = 0; i < NUM_IMAGE_FILES; i++)
5066 ActiveButton[i] = i;
5068 // now add all entries that have an active state (active buttons)
5069 for (i = 0; button_with_active_state[i].button != -1; i++)
5071 int button = button_with_active_state[i].button;
5072 int button_active = button_with_active_state[i].button_active;
5074 ActiveButton[button] = button_active;
5077 // always start with reliable default values (all fonts)
5078 for (i = 0; i < NUM_FONTS; i++)
5081 // now add all entries that have an active state (active fonts)
5082 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5084 int font = font_with_active_state[i].font_nr;
5085 int font_active = font_with_active_state[i].font_nr_active;
5087 ActiveFont[font] = font_active;
5090 global.autoplay_leveldir = NULL;
5091 global.patchtapes_leveldir = NULL;
5092 global.convert_leveldir = NULL;
5093 global.dumplevel_leveldir = NULL;
5094 global.dumptape_leveldir = NULL;
5095 global.create_sketch_images_dir = NULL;
5096 global.create_collect_images_dir = NULL;
5098 global.frames_per_second = 0;
5099 global.show_frames_per_second = FALSE;
5101 global.border_status = GAME_MODE_LOADING;
5102 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5104 global.use_envelope_request = FALSE;
5106 global.user_names = NULL;
5109 static void Execute_Command(char *command)
5113 if (strEqual(command, "print graphicsinfo.conf"))
5115 Print("# You can configure additional/alternative image files here.\n");
5116 Print("# (The entries below are default and therefore commented out.)\n");
5118 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5120 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5123 for (i = 0; image_config[i].token != NULL; i++)
5124 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5125 image_config[i].value));
5129 else if (strEqual(command, "print soundsinfo.conf"))
5131 Print("# You can configure additional/alternative sound files here.\n");
5132 Print("# (The entries below are default and therefore commented out.)\n");
5134 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5136 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5139 for (i = 0; sound_config[i].token != NULL; i++)
5140 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5141 sound_config[i].value));
5145 else if (strEqual(command, "print musicinfo.conf"))
5147 Print("# You can configure additional/alternative music files here.\n");
5148 Print("# (The entries below are default and therefore commented out.)\n");
5150 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5152 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5155 for (i = 0; music_config[i].token != NULL; i++)
5156 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5157 music_config[i].value));
5161 else if (strEqual(command, "print editorsetup.conf"))
5163 Print("# You can configure your personal editor element list here.\n");
5164 Print("# (The entries below are default and therefore commented out.)\n");
5167 // this is needed to be able to check element list for cascade elements
5168 InitElementPropertiesStatic();
5169 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5171 PrintEditorElementList();
5175 else if (strEqual(command, "print helpanim.conf"))
5177 Print("# You can configure different element help animations here.\n");
5178 Print("# (The entries below are default and therefore commented out.)\n");
5181 for (i = 0; helpanim_config[i].token != NULL; i++)
5183 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5184 helpanim_config[i].value));
5186 if (strEqual(helpanim_config[i].token, "end"))
5192 else if (strEqual(command, "print helptext.conf"))
5194 Print("# You can configure different element help text here.\n");
5195 Print("# (The entries below are default and therefore commented out.)\n");
5198 for (i = 0; helptext_config[i].token != NULL; i++)
5199 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5200 helptext_config[i].value));
5204 else if (strPrefix(command, "dump level "))
5206 char *filename = &command[11];
5208 if (fileExists(filename))
5210 LoadLevelFromFilename(&level, filename);
5216 char *leveldir = getStringCopy(filename); // read command parameters
5217 char *level_nr = strchr(leveldir, ' ');
5219 if (level_nr == NULL)
5220 Fail("cannot open file '%s'", filename);
5224 global.dumplevel_leveldir = leveldir;
5225 global.dumplevel_level_nr = atoi(level_nr);
5227 program.headless = TRUE;
5229 else if (strPrefix(command, "dump tape "))
5231 char *filename = &command[10];
5233 if (fileExists(filename))
5235 LoadTapeFromFilename(filename);
5241 char *leveldir = getStringCopy(filename); // read command parameters
5242 char *level_nr = strchr(leveldir, ' ');
5244 if (level_nr == NULL)
5245 Fail("cannot open file '%s'", filename);
5249 global.dumptape_leveldir = leveldir;
5250 global.dumptape_level_nr = atoi(level_nr);
5252 program.headless = TRUE;
5254 else if (strPrefix(command, "autoplay ") ||
5255 strPrefix(command, "autoffwd ") ||
5256 strPrefix(command, "autowarp ") ||
5257 strPrefix(command, "autotest ") ||
5258 strPrefix(command, "autosave ") ||
5259 strPrefix(command, "autoupload ") ||
5260 strPrefix(command, "autofix "))
5262 char *arg_ptr = strchr(command, ' ');
5263 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5265 global.autoplay_mode =
5266 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5267 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5268 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5269 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5270 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5271 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5272 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5273 AUTOPLAY_MODE_NONE);
5275 while (*str_ptr != '\0') // continue parsing string
5277 // cut leading whitespace from string, replace it by string terminator
5278 while (*str_ptr == ' ' || *str_ptr == '\t')
5281 if (*str_ptr == '\0') // end of string reached
5284 if (global.autoplay_leveldir == NULL) // read level set string
5286 global.autoplay_leveldir = str_ptr;
5287 global.autoplay_all = TRUE; // default: play all tapes
5289 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5290 global.autoplay_level[i] = FALSE;
5292 else // read level number string
5294 int level_nr = atoi(str_ptr); // get level_nr value
5296 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5297 global.autoplay_level[level_nr] = TRUE;
5299 global.autoplay_all = FALSE;
5302 // advance string pointer to the next whitespace (or end of string)
5303 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5307 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5308 program.headless = TRUE;
5310 else if (strPrefix(command, "patch tapes "))
5312 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5314 // skip leading whitespace
5315 while (*str_ptr == ' ' || *str_ptr == '\t')
5318 if (*str_ptr == '\0')
5319 Fail("cannot find MODE in command '%s'", command);
5321 global.patchtapes_mode = str_ptr; // store patch mode
5323 // advance to next whitespace (or end of string)
5324 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5327 while (*str_ptr != '\0') // continue parsing string
5329 // cut leading whitespace from string, replace it by string terminator
5330 while (*str_ptr == ' ' || *str_ptr == '\t')
5333 if (*str_ptr == '\0') // end of string reached
5336 if (global.patchtapes_leveldir == NULL) // read level set string
5338 global.patchtapes_leveldir = str_ptr;
5339 global.patchtapes_all = TRUE; // default: patch all tapes
5341 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5342 global.patchtapes_level[i] = FALSE;
5344 else // read level number string
5346 int level_nr = atoi(str_ptr); // get level_nr value
5348 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5349 global.patchtapes_level[level_nr] = TRUE;
5351 global.patchtapes_all = FALSE;
5354 // advance string pointer to the next whitespace (or end of string)
5355 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5359 if (global.patchtapes_leveldir == NULL)
5361 if (strEqual(global.patchtapes_mode, "help"))
5362 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5364 Fail("cannot find LEVELDIR in command '%s'", command);
5367 program.headless = TRUE;
5369 else if (strPrefix(command, "convert "))
5371 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5372 char *str_ptr = strchr(str_copy, ' ');
5374 global.convert_leveldir = str_copy;
5375 global.convert_level_nr = -1;
5377 if (str_ptr != NULL) // level number follows
5379 *str_ptr++ = '\0'; // terminate leveldir string
5380 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5383 program.headless = TRUE;
5385 else if (strPrefix(command, "create sketch images "))
5387 global.create_sketch_images_dir = getStringCopy(&command[21]);
5389 if (access(global.create_sketch_images_dir, W_OK) != 0)
5390 Fail("image target directory '%s' not found or not writable",
5391 global.create_sketch_images_dir);
5393 else if (strPrefix(command, "create collect image "))
5395 global.create_collect_images_dir = getStringCopy(&command[21]);
5397 if (access(global.create_collect_images_dir, W_OK) != 0)
5398 Fail("image target directory '%s' not found or not writable",
5399 global.create_collect_images_dir);
5401 else if (strPrefix(command, "create CE image "))
5403 CreateCustomElementImages(&command[16]);
5409 FailWithHelp("unrecognized command '%s'", command);
5412 // disable networking if any valid command was recognized
5413 options.network = setup.network_mode = FALSE;
5416 static void InitSetup(void)
5418 LoadUserNames(); // global user names
5419 LoadUserSetup(); // global user number
5421 LoadSetup(); // global setup info
5423 // set some options from setup file
5425 if (setup.options.verbose)
5426 options.verbose = TRUE;
5428 if (setup.debug.show_frames_per_second)
5429 global.show_frames_per_second = TRUE;
5432 static void InitGameInfo(void)
5434 game.restart_level = FALSE;
5435 game.restart_game_message = NULL;
5437 game.request_active = FALSE;
5438 game.request_active_or_moving = FALSE;
5440 game.use_masked_elements_initial = FALSE;
5443 static void InitPlayerInfo(void)
5447 // choose default local player
5448 local_player = &stored_player[0];
5450 for (i = 0; i < MAX_PLAYERS; i++)
5452 stored_player[i].connected_locally = FALSE;
5453 stored_player[i].connected_network = FALSE;
5456 local_player->connected_locally = TRUE;
5459 static void InitArtworkInfo(void)
5464 static char *get_string_in_brackets(char *string)
5466 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5468 sprintf(string_in_brackets, "[%s]", string);
5470 return string_in_brackets;
5473 static char *get_level_id_suffix(int id_nr)
5475 char *id_suffix = checked_malloc(1 + 3 + 1);
5477 if (id_nr < 0 || id_nr > 999)
5480 sprintf(id_suffix, ".%03d", id_nr);
5485 static void InitArtworkConfig(void)
5487 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5489 NUM_GLOBAL_ANIM_TOKENS + 1];
5490 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5491 NUM_GLOBAL_ANIM_TOKENS + 1];
5492 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5493 NUM_GLOBAL_ANIM_TOKENS + 1];
5494 static char *action_id_suffix[NUM_ACTIONS + 1];
5495 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5496 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5497 static char *level_id_suffix[MAX_LEVELS + 1];
5498 static char *dummy[1] = { NULL };
5499 static char *ignore_generic_tokens[] =
5504 "program_copyright",
5509 static char **ignore_image_tokens;
5510 static char **ignore_sound_tokens;
5511 static char **ignore_music_tokens;
5512 int num_ignore_generic_tokens;
5513 int num_ignore_image_tokens;
5514 int num_ignore_sound_tokens;
5515 int num_ignore_music_tokens;
5518 // dynamically determine list of generic tokens to be ignored
5519 num_ignore_generic_tokens = 0;
5520 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5521 num_ignore_generic_tokens++;
5523 // dynamically determine list of image tokens to be ignored
5524 num_ignore_image_tokens = num_ignore_generic_tokens;
5525 for (i = 0; image_config_vars[i].token != NULL; i++)
5526 num_ignore_image_tokens++;
5527 ignore_image_tokens =
5528 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5529 for (i = 0; i < num_ignore_generic_tokens; i++)
5530 ignore_image_tokens[i] = ignore_generic_tokens[i];
5531 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5532 ignore_image_tokens[num_ignore_generic_tokens + i] =
5533 image_config_vars[i].token;
5534 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5536 // dynamically determine list of sound tokens to be ignored
5537 num_ignore_sound_tokens = num_ignore_generic_tokens;
5538 ignore_sound_tokens =
5539 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5540 for (i = 0; i < num_ignore_generic_tokens; i++)
5541 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5542 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5544 // dynamically determine list of music tokens to be ignored
5545 num_ignore_music_tokens = num_ignore_generic_tokens;
5546 ignore_music_tokens =
5547 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5548 for (i = 0; i < num_ignore_generic_tokens; i++)
5549 ignore_music_tokens[i] = ignore_generic_tokens[i];
5550 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5552 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5553 image_id_prefix[i] = element_info[i].token_name;
5554 for (i = 0; i < NUM_FONTS; i++)
5555 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5556 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5557 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5558 global_anim_info[i].token_name;
5559 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5561 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5562 sound_id_prefix[i] = element_info[i].token_name;
5563 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5564 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5565 get_string_in_brackets(element_info[i].class_name);
5566 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5567 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5568 global_anim_info[i].token_name;
5569 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5571 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5572 music_id_prefix[i] = music_prefix_info[i].prefix;
5573 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5574 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5575 global_anim_info[i].token_name;
5576 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5578 for (i = 0; i < NUM_ACTIONS; i++)
5579 action_id_suffix[i] = element_action_info[i].suffix;
5580 action_id_suffix[NUM_ACTIONS] = NULL;
5582 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5583 direction_id_suffix[i] = element_direction_info[i].suffix;
5584 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5586 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5587 special_id_suffix[i] = special_suffix_info[i].suffix;
5588 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5590 for (i = 0; i < MAX_LEVELS; i++)
5591 level_id_suffix[i] = get_level_id_suffix(i);
5592 level_id_suffix[MAX_LEVELS] = NULL;
5594 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5595 image_id_prefix, action_id_suffix, direction_id_suffix,
5596 special_id_suffix, ignore_image_tokens);
5597 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5598 sound_id_prefix, action_id_suffix, dummy,
5599 special_id_suffix, ignore_sound_tokens);
5600 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5601 music_id_prefix, action_id_suffix, special_id_suffix,
5602 level_id_suffix, ignore_music_tokens);
5605 static void InitMixer(void)
5612 static void InitVideoOverlay(void)
5614 // if virtual buttons are not loaded from setup file, repeat initializing
5615 // virtual buttons grid with default values now that video is initialized
5616 if (!setup.touch.grid_initialized)
5619 InitTileCursorInfo();
5623 void InitGfxBuffers(void)
5625 static int win_xsize_last = -1;
5626 static int win_ysize_last = -1;
5628 // create additional image buffers for double-buffering and cross-fading
5630 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5632 // used to temporarily store the backbuffer -- only re-create if changed
5633 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5634 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5636 win_xsize_last = WIN_XSIZE;
5637 win_ysize_last = WIN_YSIZE;
5640 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5641 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5642 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5643 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5645 // initialize screen properties
5646 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5647 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5649 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5650 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5651 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5652 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5653 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5654 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5656 // required if door size definitions have changed
5657 InitGraphicCompatibilityInfo_Doors();
5659 InitGfxBuffers_EM();
5660 InitGfxBuffers_SP();
5663 static void InitGfx(void)
5665 struct GraphicInfo *graphic_info_last = graphic_info;
5666 char *filename_font_initial = NULL;
5667 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5668 char *image_token[NUM_INITIAL_IMAGES] =
5670 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5671 CONFIG_TOKEN_GLOBAL_BUSY,
5672 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5673 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5674 CONFIG_TOKEN_BACKGROUND_LOADING
5676 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5680 &init.busy_playfield
5682 Bitmap *bitmap_font_initial = NULL;
5683 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5686 // determine settings for initial font (for displaying startup messages)
5687 for (i = 0; image_config[i].token != NULL; i++)
5689 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5691 char font_token[128];
5694 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5695 len_font_token = strlen(font_token);
5697 if (strEqual(image_config[i].token, font_token))
5699 filename_font_initial = image_config[i].value;
5701 else if (strlen(image_config[i].token) > len_font_token &&
5702 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5704 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5705 font_initial[j].src_x = atoi(image_config[i].value);
5706 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5707 font_initial[j].src_y = atoi(image_config[i].value);
5708 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5709 font_initial[j].width = atoi(image_config[i].value);
5710 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5711 font_initial[j].height = atoi(image_config[i].value);
5716 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5718 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5719 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5722 if (filename_font_initial == NULL) // should not happen
5723 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5726 InitGfxCustomArtworkInfo();
5727 InitGfxOtherSettings();
5729 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5731 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5733 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5734 font_initial[j].bitmap = bitmap_font_initial;
5736 InitFontGraphicInfo();
5740 DrawInitTextHead("Loading graphics");
5742 InitMenuDesignSettings_Static();
5744 // initialize settings for initial images with default values
5745 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5746 for (j = 0; j < NUM_GFX_ARGS; j++)
5748 get_graphic_parameter_value(image_config_suffix[j].value,
5749 image_config_suffix[j].token,
5750 image_config_suffix[j].type);
5752 // read settings for initial images from default custom artwork config
5753 char *gfx_config_filename = getPath3(options.graphics_directory,
5755 GRAPHICSINFO_FILENAME);
5757 if (fileExists(gfx_config_filename))
5759 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5761 if (setup_file_hash)
5763 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5765 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5769 filename_image_initial[i] = getStringCopy(filename);
5771 for (j = 0; image_config_suffix[j].token != NULL; j++)
5773 int type = image_config_suffix[j].type;
5774 char *suffix = image_config_suffix[j].token;
5775 char *token = getStringCat2(image_token[i], suffix);
5776 char *value = getHashEntry(setup_file_hash, token);
5778 checked_free(token);
5782 get_graphic_parameter_value(value, suffix, type);
5787 // read values from custom graphics config file
5788 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5790 freeSetupFileHash(setup_file_hash);
5794 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5796 if (filename_image_initial[i] == NULL)
5798 int len_token = strlen(image_token[i]);
5800 // read settings for initial images from static default artwork config
5801 for (j = 0; image_config[j].token != NULL; j++)
5803 if (strEqual(image_config[j].token, image_token[i]))
5805 filename_image_initial[i] = getStringCopy(image_config[j].value);
5807 else if (strlen(image_config[j].token) > len_token &&
5808 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5810 for (k = 0; image_config_suffix[k].token != NULL; k++)
5812 if (strEqual(&image_config[j].token[len_token],
5813 image_config_suffix[k].token))
5815 get_graphic_parameter_value(image_config[j].value,
5816 image_config_suffix[k].token,
5817 image_config_suffix[k].type);
5824 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5826 if (filename_image_initial[i] == NULL) // should not happen
5827 Fail("cannot get filename for '%s'", image_token[i]);
5829 image_initial[i].bitmaps =
5830 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5832 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5833 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5834 LoadCustomImage(filename_image_initial[i]);
5836 checked_free(filename_image_initial[i]);
5839 graphic_info = image_initial; // graphic == 0 => image_initial
5841 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5842 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5844 graphic_info = graphic_info_last;
5846 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5848 // set image size for busy animations
5849 init_busy[i]->width = image_initial[i].width;
5850 init_busy[i]->height = image_initial[i].height;
5853 SetLoadingBackgroundImage();
5855 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5857 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5858 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5859 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5860 InitGfxDrawTileCursorFunction(DrawTileCursor);
5862 gfx.fade_border_source_status = global.border_status;
5863 gfx.fade_border_target_status = global.border_status;
5864 gfx.masked_border_bitmap_ptr = backbuffer;
5866 // use copy of busy animation to prevent change while reloading artwork
5870 static void InitGfxBackground(void)
5872 fieldbuffer = bitmap_db_field;
5873 SetDrawtoField(DRAW_TO_BACKBUFFER);
5875 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5877 redraw_mask = REDRAW_ALL;
5880 static void InitLevelInfo(void)
5882 LoadLevelInfo(); // global level info
5883 LoadLevelSetup_LastSeries(); // last played series info
5884 LoadLevelSetup_SeriesInfo(); // last played level info
5886 if (global.autoplay_leveldir &&
5887 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5889 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5890 global.autoplay_leveldir);
5891 if (leveldir_current == NULL)
5892 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5895 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5898 static void InitLevelArtworkInfo(void)
5900 LoadLevelArtworkInfo();
5903 static void InitImages(void)
5905 print_timestamp_init("InitImages");
5908 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5909 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5910 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5911 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5912 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5913 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5914 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5915 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5918 setLevelArtworkDir(artwork.gfx_first);
5921 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5922 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5923 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5924 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5925 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5926 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5927 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5928 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5932 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5933 leveldir_current->identifier,
5934 artwork.gfx_current_identifier,
5935 artwork.gfx_current->identifier,
5936 leveldir_current->graphics_set,
5937 leveldir_current->graphics_path);
5940 UPDATE_BUSY_STATE();
5942 ReloadCustomImages();
5943 print_timestamp_time("ReloadCustomImages");
5945 UPDATE_BUSY_STATE();
5947 LoadCustomElementDescriptions();
5948 print_timestamp_time("LoadCustomElementDescriptions");
5950 UPDATE_BUSY_STATE();
5952 LoadMenuDesignSettings();
5953 print_timestamp_time("LoadMenuDesignSettings");
5955 UPDATE_BUSY_STATE();
5957 ReinitializeGraphics();
5958 print_timestamp_time("ReinitializeGraphics");
5960 LoadMenuDesignSettings_AfterGraphics();
5961 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5963 UPDATE_BUSY_STATE();
5965 print_timestamp_done("InitImages");
5968 static void InitSound(char *identifier)
5970 print_timestamp_init("InitSound");
5972 if (identifier == NULL)
5973 identifier = artwork.snd_current->identifier;
5975 // set artwork path to send it to the sound server process
5976 setLevelArtworkDir(artwork.snd_first);
5978 InitReloadCustomSounds(identifier);
5979 print_timestamp_time("InitReloadCustomSounds");
5981 ReinitializeSounds();
5982 print_timestamp_time("ReinitializeSounds");
5984 print_timestamp_done("InitSound");
5987 static void InitMusic(char *identifier)
5989 print_timestamp_init("InitMusic");
5991 if (identifier == NULL)
5992 identifier = artwork.mus_current->identifier;
5994 // set artwork path to send it to the sound server process
5995 setLevelArtworkDir(artwork.mus_first);
5997 InitReloadCustomMusic(identifier);
5998 print_timestamp_time("InitReloadCustomMusic");
6000 ReinitializeMusic();
6001 print_timestamp_time("ReinitializeMusic");
6003 print_timestamp_done("InitMusic");
6006 static void InitArtworkDone(void)
6008 if (program.headless)
6011 InitGlobalAnimations();
6014 static void InitNetworkSettings(void)
6016 boolean network_enabled = (options.network || setup.network_mode);
6017 char *network_server = (options.server_host != NULL ? options.server_host :
6018 setup.network_server_hostname);
6020 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6021 network_server = NULL;
6023 InitNetworkInfo(network_enabled,
6027 options.server_port);
6030 void InitNetworkServer(void)
6032 if (!network.enabled || network.connected)
6035 LimitScreenUpdates(FALSE);
6037 if (game_status == GAME_MODE_LOADING)
6040 if (!ConnectToServer(network.server_host, network.server_port))
6042 network.enabled = FALSE;
6044 setup.network_mode = FALSE;
6048 SendToServer_ProtocolVersion();
6049 SendToServer_PlayerName(setup.player_name);
6050 SendToServer_NrWanted(setup.network_player_nr + 1);
6052 network.connected = TRUE;
6055 // short time to recognize result of network initialization
6056 if (game_status == GAME_MODE_LOADING)
6057 Delay_WithScreenUpdates(1000);
6060 static boolean CheckArtworkConfigForCustomElements(char *filename)
6062 SetupFileHash *setup_file_hash;
6063 boolean redefined_ce_found = FALSE;
6065 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6067 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6069 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6071 char *token = HASH_ITERATION_TOKEN(itr);
6073 if (strPrefix(token, "custom_"))
6075 redefined_ce_found = TRUE;
6080 END_HASH_ITERATION(setup_file_hash, itr)
6082 freeSetupFileHash(setup_file_hash);
6085 return redefined_ce_found;
6088 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6090 char *filename_base, *filename_local;
6091 boolean redefined_ce_found = FALSE;
6093 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6096 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6097 "leveldir_current->identifier == '%s'",
6098 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6099 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6100 "leveldir_current->graphics_path == '%s'",
6101 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6102 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6103 "leveldir_current->graphics_set == '%s'",
6104 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6105 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6106 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6107 leveldir_current == NULL ? "[NULL]" :
6108 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6111 // first look for special artwork configured in level series config
6112 filename_base = getCustomArtworkLevelConfigFilename(type);
6115 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6116 "filename_base == '%s'", filename_base);
6119 if (fileExists(filename_base))
6120 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6122 filename_local = getCustomArtworkConfigFilename(type);
6125 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6126 "filename_local == '%s'", filename_local);
6129 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6130 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6133 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6134 "redefined_ce_found == %d", redefined_ce_found);
6137 return redefined_ce_found;
6140 static void InitOverrideArtwork(void)
6142 boolean redefined_ce_found = FALSE;
6144 // to check if this level set redefines any CEs, do not use overriding
6145 gfx.override_level_graphics = FALSE;
6146 gfx.override_level_sounds = FALSE;
6147 gfx.override_level_music = FALSE;
6149 // now check if this level set has definitions for custom elements
6150 if (setup.override_level_graphics == AUTO ||
6151 setup.override_level_sounds == AUTO ||
6152 setup.override_level_music == AUTO)
6153 redefined_ce_found =
6154 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6155 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6156 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6159 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6160 redefined_ce_found);
6163 if (redefined_ce_found)
6165 // this level set has CE definitions: change "AUTO" to "FALSE"
6166 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6167 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6168 gfx.override_level_music = (setup.override_level_music == TRUE);
6172 // this level set has no CE definitions: change "AUTO" to "TRUE"
6173 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6174 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6175 gfx.override_level_music = (setup.override_level_music != FALSE);
6179 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6180 gfx.override_level_graphics,
6181 gfx.override_level_sounds,
6182 gfx.override_level_music);
6186 static char *getNewArtworkIdentifier(int type)
6188 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6189 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6190 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6191 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6192 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6193 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6194 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6195 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6196 char *leveldir_identifier = leveldir_current->identifier;
6197 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6198 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6199 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6200 TreeInfo *custom_artwork_set =
6201 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6202 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6203 char *artwork_current_identifier;
6204 char *artwork_new_identifier = NULL; // default: nothing has changed
6206 // leveldir_current may be invalid (level group, parent link)
6207 if (!validLevelSeries(leveldir_current))
6210 /* 1st step: determine artwork set to be activated in descending order:
6211 --------------------------------------------------------------------
6212 1. setup artwork (when configured to override everything else)
6213 2. artwork set configured in "levelinfo.conf" of current level set
6214 (artwork in level directory will have priority when loading later)
6215 3. artwork in level directory (stored in artwork sub-directory)
6216 4. setup artwork (currently configured in setup menu) */
6218 if (setup_override_artwork)
6219 artwork_current_identifier = setup_artwork_set;
6220 else if (has_level_artwork_set)
6221 artwork_current_identifier = leveldir_artwork_set;
6222 else if (has_custom_artwork_set)
6223 artwork_current_identifier = leveldir_identifier;
6225 artwork_current_identifier = setup_artwork_set;
6227 /* 2nd step: check if it is really needed to reload artwork set
6228 ------------------------------------------------------------ */
6230 // ---------- reload if level set and also artwork set has changed ----------
6231 if (last_leveldir_identifier[type] != leveldir_identifier &&
6232 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6233 artwork_new_identifier = artwork_current_identifier;
6235 last_leveldir_identifier[type] = leveldir_identifier;
6236 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6238 // ---------- reload if "override artwork" setting has changed --------------
6239 if (last_override_level_artwork[type] != setup_override_artwork)
6240 artwork_new_identifier = artwork_current_identifier;
6242 last_override_level_artwork[type] = setup_override_artwork;
6244 // ---------- reload if current artwork identifier has changed --------------
6245 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6246 artwork_new_identifier = artwork_current_identifier;
6248 // (we cannot compare string pointers here, so copy string content itself)
6249 setString(&last_artwork_identifier[type], artwork_current_identifier);
6251 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6253 // ---------- do not reload directly after starting -------------------------
6254 if (!initialized[type])
6255 artwork_new_identifier = NULL;
6257 initialized[type] = TRUE;
6259 return artwork_new_identifier;
6262 void ReloadCustomArtwork(int force_reload)
6264 int last_game_status = game_status; // save current game status
6265 char *gfx_new_identifier;
6266 char *snd_new_identifier;
6267 char *mus_new_identifier;
6268 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6269 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6270 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6271 boolean reload_needed;
6273 InitOverrideArtwork();
6275 AdjustGraphicsForEMC();
6276 AdjustSoundsForEMC();
6278 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6279 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6280 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6282 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6283 snd_new_identifier != NULL || force_reload_snd ||
6284 mus_new_identifier != NULL || force_reload_mus);
6289 print_timestamp_init("ReloadCustomArtwork");
6291 SetGameStatus(GAME_MODE_LOADING);
6293 FadeOut(REDRAW_ALL);
6295 SetLoadingBackgroundImage();
6297 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6298 print_timestamp_time("ClearRectangleOnBackground");
6302 UPDATE_BUSY_STATE();
6304 if (gfx_new_identifier != NULL || force_reload_gfx)
6307 Debug("init:ReloadCustomArtwork",
6308 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6309 artwork.gfx_current_identifier,
6311 artwork.gfx_current->identifier,
6312 leveldir_current->graphics_set);
6316 print_timestamp_time("InitImages");
6319 if (snd_new_identifier != NULL || force_reload_snd)
6321 InitSound(snd_new_identifier);
6322 print_timestamp_time("InitSound");
6325 if (mus_new_identifier != NULL || force_reload_mus)
6327 InitMusic(mus_new_identifier);
6328 print_timestamp_time("InitMusic");
6333 SetGameStatus(last_game_status); // restore current game status
6335 FadeOut(REDRAW_ALL);
6337 RedrawGlobalBorder();
6339 // force redraw of (open or closed) door graphics
6340 SetDoorState(DOOR_OPEN_ALL);
6341 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6343 FadeSetEnterScreen();
6344 FadeSkipNextFadeOut();
6346 print_timestamp_done("ReloadCustomArtwork");
6348 LimitScreenUpdates(FALSE);
6351 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6353 if (global.autoplay_leveldir == NULL)
6354 KeyboardAutoRepeatOff();
6357 void DisplayExitMessage(char *format, va_list ap)
6359 // also check for initialized video (headless flag may be temporarily unset)
6360 if (program.headless || !video.initialized)
6363 // check if draw buffer and fonts for exit message are already available
6364 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6367 int font_1 = FC_RED;
6368 int font_2 = FC_YELLOW;
6369 int font_3 = FC_BLUE;
6370 int font_width = getFontWidth(font_2);
6371 int font_height = getFontHeight(font_2);
6374 int sxsize = WIN_XSIZE - 2 * sx;
6375 int sysize = WIN_YSIZE - 2 * sy;
6376 int line_length = sxsize / font_width;
6377 int max_lines = sysize / font_height;
6378 int num_lines_printed;
6382 gfx.sxsize = sxsize;
6383 gfx.sysize = sysize;
6387 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6389 DrawTextSCentered(sy, font_1, "Fatal error:");
6390 sy += 3 * font_height;;
6393 DrawTextBufferVA(sx, sy, format, ap, font_2,
6394 line_length, line_length, max_lines,
6395 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6396 sy += (num_lines_printed + 3) * font_height;
6398 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6399 sy += 3 * font_height;
6402 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6403 line_length, line_length, max_lines,
6404 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6406 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6408 redraw_mask = REDRAW_ALL;
6410 // force drawing exit message even if screen updates are currently limited
6411 LimitScreenUpdates(FALSE);
6415 // deactivate toons on error message screen
6416 setup.toons = FALSE;
6418 WaitForEventToContinue();
6422 // ============================================================================
6424 // ============================================================================
6428 print_timestamp_init("OpenAll");
6430 SetGameStatus(GAME_MODE_LOADING);
6434 InitGlobal(); // initialize some global variables
6436 InitRND(NEW_RANDOMIZE);
6437 InitSimpleRandom(NEW_RANDOMIZE);
6438 InitBetterRandom(NEW_RANDOMIZE);
6440 print_timestamp_time("[init global stuff]");
6444 print_timestamp_time("[init setup/config stuff (1)]");
6446 if (options.execute_command)
6447 Execute_Command(options.execute_command);
6449 InitNetworkSettings();
6453 if (network.serveronly)
6455 #if defined(PLATFORM_UNIX)
6456 NetworkServer(network.server_port, TRUE);
6458 Warn("networking only supported in Unix version");
6461 exit(0); // never reached, server loops forever
6465 print_timestamp_time("[init setup/config stuff (2)]");
6467 print_timestamp_time("[init setup/config stuff (3)]");
6468 InitArtworkInfo(); // needed before loading gfx, sound & music
6469 print_timestamp_time("[init setup/config stuff (4)]");
6470 InitArtworkConfig(); // needed before forking sound child process
6471 print_timestamp_time("[init setup/config stuff (5)]");
6473 print_timestamp_time("[init setup/config stuff (6)]");
6477 print_timestamp_time("[init setup/config stuff]");
6479 InitVideoDefaults();
6481 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6484 InitEventFilter(FilterMouseMotionEvents);
6486 print_timestamp_time("[init video stuff]");
6488 InitElementPropertiesStatic();
6489 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6490 InitElementPropertiesGfxElement();
6492 print_timestamp_time("[init element properties stuff]");
6496 print_timestamp_time("InitGfx");
6499 print_timestamp_time("InitLevelInfo");
6501 InitLevelArtworkInfo();
6502 print_timestamp_time("InitLevelArtworkInfo");
6504 InitOverrideArtwork(); // needs to know current level directory
6505 print_timestamp_time("InitOverrideArtwork");
6507 InitImages(); // needs to know current level directory
6508 print_timestamp_time("InitImages");
6510 InitSound(NULL); // needs to know current level directory
6511 print_timestamp_time("InitSound");
6513 InitMusic(NULL); // needs to know current level directory
6514 print_timestamp_time("InitMusic");
6518 InitGfxBackground();
6524 if (global.autoplay_leveldir)
6529 else if (global.patchtapes_leveldir)
6534 else if (global.convert_leveldir)
6539 else if (global.dumplevel_leveldir)
6544 else if (global.dumptape_leveldir)
6549 else if (global.create_sketch_images_dir)
6551 CreateLevelSketchImages();
6554 else if (global.create_collect_images_dir)
6556 CreateCollectElementImages();
6560 InitNetworkServer();
6562 SetGameStatus(GAME_MODE_MAIN);
6564 FadeSetEnterScreen();
6565 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6566 FadeSkipNextFadeOut();
6568 print_timestamp_time("[post-artwork]");
6570 print_timestamp_done("OpenAll");
6572 if (setup.ask_for_remaining_tapes)
6573 setup.ask_for_uploading_tapes = TRUE;
6578 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6580 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6581 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6582 #if defined(PLATFORM_ANDROID)
6583 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6584 SDL_AndroidGetInternalStoragePath());
6585 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6586 SDL_AndroidGetExternalStoragePath());
6587 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6588 (SDL_AndroidGetExternalStorageState() &
6589 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6590 SDL_AndroidGetExternalStorageState() &
6591 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6596 static boolean WaitForApiThreads(void)
6598 unsigned int thread_delay = 0;
6599 unsigned int thread_delay_value = 10000;
6601 if (program.api_thread_count == 0)
6604 // deactivate global animations (not accessible in game state "loading")
6605 setup.toons = FALSE;
6607 // set game state to "loading" to be able to show busy animation
6608 SetGameStatus(GAME_MODE_LOADING);
6610 ResetDelayCounter(&thread_delay);
6612 // wait for threads to finish (and fail on timeout)
6613 while (program.api_thread_count > 0)
6615 if (DelayReached(&thread_delay, thread_delay_value))
6617 Error("failed waiting for threads - TIMEOUT");
6622 UPDATE_BUSY_STATE();
6630 void CloseAllAndExit(int exit_value)
6632 WaitForApiThreads();
6637 CloseAudio(); // called after freeing sounds (needed for SDL)
6645 // set a flag to tell the network server thread to quit and wait for it
6646 // using SDL_WaitThread()
6648 // Code used with SDL 1.2:
6649 // if (network.server_thread) // terminate network server
6650 // SDL_KillThread(network.server_thread);
6652 CloseVideoDisplay();
6653 ClosePlatformDependentStuff();
6655 if (exit_value != 0 && !options.execute_command)
6657 // fall back to default level set (current set may have caused an error)
6658 SaveLevelSetup_LastSeries_Deactivate();
6660 // tell user where to find error log file which may contain more details
6661 // (error notification now directly displayed on screen inside R'n'D
6662 // NotifyUserAboutErrorFile(); // currently only works for Windows