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 "global.busy"
38 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
39 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
41 #define INITIAL_IMG_GLOBAL_BUSY 0
42 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 1
43 #define INITIAL_IMG_BACKGROUND_LOADING 2
45 #define NUM_INITIAL_IMAGES 3
48 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
49 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
51 static int copy_properties[][5] =
55 EL_BUG_LEFT, EL_BUG_RIGHT,
56 EL_BUG_UP, EL_BUG_DOWN
60 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
61 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
65 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
66 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
70 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
71 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
75 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
76 EL_PACMAN_UP, EL_PACMAN_DOWN
80 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
81 EL_YAMYAM_UP, EL_YAMYAM_DOWN
85 EL_MOLE_LEFT, EL_MOLE_RIGHT,
86 EL_MOLE_UP, EL_MOLE_DOWN
90 EL_SPRING_LEFT, EL_SPRING_RIGHT,
91 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
100 // forward declaration for internal use
101 static int get_graphic_parameter_value(char *, char *, int);
104 static void SetLoadingBackgroundImage(void)
106 struct GraphicInfo *graphic_info_last = graphic_info;
107 int background_image = (game_status_last_screen == -1 ?
108 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
109 INITIAL_IMG_BACKGROUND_LOADING);
111 graphic_info = image_initial;
113 SetDrawDeactivationMask(REDRAW_NONE);
114 SetDrawBackgroundMask(REDRAW_ALL);
116 SetWindowBackgroundImage(background_image);
118 graphic_info = graphic_info_last;
121 static void DrawInitAnim(void)
123 struct GraphicInfo *graphic_info_last = graphic_info;
125 static unsigned int action_delay = 0;
126 unsigned int action_delay_value = GameFrameDelay;
127 int sync_frame = FrameCounter;
130 // prevent OS (Windows) from complaining about program not responding
133 if (game_status != GAME_MODE_LOADING)
136 if (image_initial[INITIAL_IMG_GLOBAL_BUSY].bitmap == NULL || window == NULL)
139 if (!DelayReached(&action_delay, action_delay_value))
142 if (init_last.busy.x == -1)
143 init_last.busy.x = WIN_XSIZE / 2;
144 if (init_last.busy.y == -1)
145 init_last.busy.y = WIN_YSIZE / 2;
147 x = ALIGNED_TEXT_XPOS(&init_last.busy);
148 y = ALIGNED_TEXT_YPOS(&init_last.busy);
150 graphic_info = image_initial; // graphic == 0 => image_initial
152 if (sync_frame % image_initial[INITIAL_IMG_GLOBAL_BUSY].anim_delay == 0)
156 int width = graphic_info[graphic].width;
157 int height = graphic_info[graphic].height;
158 int frame = getGraphicAnimationFrame(graphic, sync_frame);
160 ClearRectangleOnBackground(drawto, x, y, width, height);
162 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
163 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
165 BlitBitmap(drawto, window, x, y, width, height, x, y);
168 graphic_info = graphic_info_last;
173 static void DrawProgramInfo(void)
175 int font1_nr = FC_YELLOW;
176 int font2_nr = FC_RED;
177 int font2_height = getFontHeight(font2_nr);
180 int ypos3 = WIN_YSIZE - 20 - font2_height;
182 DrawInitText(getProgramInitString(), ypos1, font1_nr);
183 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
184 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
187 static void FreeGadgets(void)
189 FreeLevelEditorGadgets();
196 void InitGadgets(void)
198 static boolean gadgets_initialized = FALSE;
200 if (gadgets_initialized)
203 CreateLevelEditorGadgets();
207 CreateScreenGadgets();
209 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
211 gadgets_initialized = TRUE;
214 static void InitElementSmallImagesScaledUp(int graphic)
216 struct GraphicInfo *g = &graphic_info[graphic];
218 // create small and game tile sized bitmaps (and scale up, if needed)
219 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
222 static void InitElementSmallImages(void)
224 print_timestamp_init("InitElementSmallImages");
226 static int special_graphics[] =
240 IMG_EDITOR_ELEMENT_BORDER,
241 IMG_EDITOR_ELEMENT_BORDER_INPUT,
242 IMG_EDITOR_CASCADE_LIST,
243 IMG_EDITOR_CASCADE_LIST_ACTIVE,
246 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
247 int num_property_mappings = getImageListPropertyMappingSize();
250 print_timestamp_time("getImageListPropertyMapping/Size");
252 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
253 // initialize normal element images from static configuration
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
256 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
258 // initialize special element images from static configuration
259 for (i = 0; element_to_special_graphic[i].element > -1; i++)
260 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
263 // initialize element images from dynamic configuration
264 for (i = 0; i < num_property_mappings; i++)
265 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
266 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
267 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
269 // initialize special non-element images from above list
270 for (i = 0; special_graphics[i] > -1; i++)
271 InitElementSmallImagesScaledUp(special_graphics[i]);
272 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
274 print_timestamp_done("InitElementSmallImages");
277 static void InitScaledImagesScaledUp(int graphic)
279 struct GraphicInfo *g = &graphic_info[graphic];
281 ScaleImage(graphic, g->scale_up_factor);
284 static void InitScaledImages(void)
286 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
287 int num_property_mappings = getImageListPropertyMappingSize();
290 // scale normal images from static configuration, if not already scaled
291 for (i = 0; i < NUM_IMAGE_FILES; i++)
292 InitScaledImagesScaledUp(i);
294 // scale images from dynamic configuration, if not already scaled
295 for (i = 0; i < num_property_mappings; i++)
296 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
299 static void InitBitmapPointers(void)
301 int num_images = getImageListSize();
304 // standard size bitmap may have changed -- update default bitmap pointer
305 for (i = 0; i < num_images; i++)
306 if (graphic_info[i].bitmaps)
307 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
310 void InitImageTextures(void)
312 static int texture_graphics[] =
314 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
315 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
316 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
317 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
318 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
319 IMG_MENU_BUTTON_TOUCH_BACK,
320 IMG_MENU_BUTTON_TOUCH_NEXT,
321 IMG_MENU_BUTTON_TOUCH_BACK2,
322 IMG_MENU_BUTTON_TOUCH_NEXT2,
327 FreeAllImageTextures();
329 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
330 CreateImageTextures(i);
332 for (i = 0; i < MAX_NUM_TOONS; i++)
333 CreateImageTextures(IMG_TOON_1 + i);
335 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
337 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
339 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
341 int graphic = global_anim_info[i].graphic[j][k];
343 if (graphic == IMG_UNDEFINED)
346 CreateImageTextures(graphic);
351 for (i = 0; texture_graphics[i] > -1; i++)
352 CreateImageTextures(texture_graphics[i]);
355 static int getFontBitmapID(int font_nr)
359 // (special case: do not use special font for GAME_MODE_LOADING)
360 if (game_status >= GAME_MODE_TITLE_INITIAL &&
361 game_status <= GAME_MODE_PSEUDO_PREVIEW)
362 special = game_status;
363 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
364 special = GFX_SPECIAL_ARG_MAIN;
365 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
366 special = GFX_SPECIAL_ARG_NAMES;
369 return font_info[font_nr].special_bitmap_id[special];
374 static int getFontFromToken(char *token)
376 char *value = getHashEntry(font_token_hash, token);
381 // if font not found, use reliable default value
382 return FONT_INITIAL_1;
385 static void InitFontGraphicInfo(void)
387 static struct FontBitmapInfo *font_bitmap_info = NULL;
388 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
389 int num_property_mappings = getImageListPropertyMappingSize();
390 int num_font_bitmaps = NUM_FONTS;
393 if (graphic_info == NULL) // still at startup phase
395 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
396 getFontBitmapID, getFontFromToken);
401 // ---------- initialize font graphic definitions ----------
403 // always start with reliable default values (normal font graphics)
404 for (i = 0; i < NUM_FONTS; i++)
405 font_info[i].graphic = IMG_FONT_INITIAL_1;
407 // initialize normal font/graphic mapping from static configuration
408 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
410 int font_nr = font_to_graphic[i].font_nr;
411 int special = font_to_graphic[i].special;
412 int graphic = font_to_graphic[i].graphic;
417 font_info[font_nr].graphic = graphic;
420 // always start with reliable default values (special font graphics)
421 for (i = 0; i < NUM_FONTS; i++)
423 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
425 font_info[i].special_graphic[j] = font_info[i].graphic;
426 font_info[i].special_bitmap_id[j] = i;
430 // initialize special font/graphic mapping from static configuration
431 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
433 int font_nr = font_to_graphic[i].font_nr;
434 int special = font_to_graphic[i].special;
435 int graphic = font_to_graphic[i].graphic;
436 int base_graphic = font2baseimg(font_nr);
438 if (IS_SPECIAL_GFX_ARG(special))
440 boolean base_redefined =
441 getImageListEntryFromImageID(base_graphic)->redefined;
442 boolean special_redefined =
443 getImageListEntryFromImageID(graphic)->redefined;
444 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
446 /* if the base font ("font.title_1", for example) has been redefined,
447 but not the special font ("font.title_1.LEVELS", for example), do not
448 use an existing (in this case considered obsolete) special font
449 anymore, but use the automatically determined default font */
450 /* special case: cloned special fonts must be explicitly redefined,
451 but are not automatically redefined by redefining base font */
452 if (base_redefined && !special_redefined && !special_cloned)
455 font_info[font_nr].special_graphic[special] = graphic;
456 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
461 // initialize special font/graphic mapping from dynamic configuration
462 for (i = 0; i < num_property_mappings; i++)
464 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
465 int special = property_mapping[i].ext3_index;
466 int graphic = property_mapping[i].artwork_index;
468 if (font_nr < 0 || font_nr >= NUM_FONTS)
471 if (IS_SPECIAL_GFX_ARG(special))
473 font_info[font_nr].special_graphic[special] = graphic;
474 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
479 /* correct special font/graphic mapping for cloned fonts for downwards
480 compatibility of PREVIEW fonts -- this is only needed for implicit
481 redefinition of special font by redefined base font, and only if other
482 fonts are cloned from this special font (like in the "Zelda" level set) */
483 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
485 int font_nr = font_to_graphic[i].font_nr;
486 int special = font_to_graphic[i].special;
487 int graphic = font_to_graphic[i].graphic;
489 if (IS_SPECIAL_GFX_ARG(special))
491 boolean special_redefined =
492 getImageListEntryFromImageID(graphic)->redefined;
493 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
495 if (special_cloned && !special_redefined)
499 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
501 int font_nr2 = font_to_graphic[j].font_nr;
502 int special2 = font_to_graphic[j].special;
503 int graphic2 = font_to_graphic[j].graphic;
505 if (IS_SPECIAL_GFX_ARG(special2) &&
506 graphic2 == graphic_info[graphic].clone_from)
508 font_info[font_nr].special_graphic[special] =
509 font_info[font_nr2].special_graphic[special2];
510 font_info[font_nr].special_bitmap_id[special] =
511 font_info[font_nr2].special_bitmap_id[special2];
518 // reset non-redefined ".active" font graphics if normal font is redefined
519 // (this different treatment is needed because normal and active fonts are
520 // independently defined ("active" is not a property of font definitions!)
521 for (i = 0; i < NUM_FONTS; i++)
523 int font_nr_base = i;
524 int font_nr_active = FONT_ACTIVE(font_nr_base);
526 // check only those fonts with exist as normal and ".active" variant
527 if (font_nr_base != font_nr_active)
529 int base_graphic = font_info[font_nr_base].graphic;
530 int active_graphic = font_info[font_nr_active].graphic;
531 boolean base_redefined =
532 getImageListEntryFromImageID(base_graphic)->redefined;
533 boolean active_redefined =
534 getImageListEntryFromImageID(active_graphic)->redefined;
536 /* if the base font ("font.menu_1", for example) has been redefined,
537 but not the active font ("font.menu_1.active", for example), do not
538 use an existing (in this case considered obsolete) active font
539 anymore, but use the automatically determined default font */
540 if (base_redefined && !active_redefined)
541 font_info[font_nr_active].graphic = base_graphic;
543 // now also check each "special" font (which may be the same as above)
544 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
546 int base_graphic = font_info[font_nr_base].special_graphic[j];
547 int active_graphic = font_info[font_nr_active].special_graphic[j];
548 boolean base_redefined =
549 getImageListEntryFromImageID(base_graphic)->redefined;
550 boolean active_redefined =
551 getImageListEntryFromImageID(active_graphic)->redefined;
553 // same as above, but check special graphic definitions, for example:
554 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
555 if (base_redefined && !active_redefined)
557 font_info[font_nr_active].special_graphic[j] =
558 font_info[font_nr_base].special_graphic[j];
559 font_info[font_nr_active].special_bitmap_id[j] =
560 font_info[font_nr_base].special_bitmap_id[j];
566 // ---------- initialize font bitmap array ----------
568 if (font_bitmap_info != NULL)
569 FreeFontInfo(font_bitmap_info);
572 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
574 // ---------- initialize font bitmap definitions ----------
576 for (i = 0; i < NUM_FONTS; i++)
578 if (i < NUM_INITIAL_FONTS)
580 font_bitmap_info[i] = font_initial[i];
584 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
586 int font_bitmap_id = font_info[i].special_bitmap_id[j];
587 int graphic = font_info[i].special_graphic[j];
589 // set 'graphic_info' for font entries, if uninitialized (guessed)
590 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
592 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
593 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
596 // copy font relevant information from graphics information
597 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
598 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
599 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
600 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
601 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
603 font_bitmap_info[font_bitmap_id].offset_x =
604 graphic_info[graphic].offset_x;
605 font_bitmap_info[font_bitmap_id].offset_y =
606 graphic_info[graphic].offset_y;
608 font_bitmap_info[font_bitmap_id].draw_xoffset =
609 graphic_info[graphic].draw_xoffset;
610 font_bitmap_info[font_bitmap_id].draw_yoffset =
611 graphic_info[graphic].draw_yoffset;
613 font_bitmap_info[font_bitmap_id].num_chars =
614 graphic_info[graphic].anim_frames;
615 font_bitmap_info[font_bitmap_id].num_chars_per_line =
616 graphic_info[graphic].anim_frames_per_line;
620 InitFontInfo(font_bitmap_info, num_font_bitmaps,
621 getFontBitmapID, getFontFromToken);
624 static void InitGlobalAnimGraphicInfo(void)
626 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
627 int num_property_mappings = getImageListPropertyMappingSize();
630 if (graphic_info == NULL) // still at startup phase
633 // always start with reliable default values (no global animations)
634 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
635 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
636 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
637 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
639 // initialize global animation definitions from static configuration
640 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
642 int j = GLOBAL_ANIM_ID_PART_BASE;
643 int k = GFX_SPECIAL_ARG_DEFAULT;
645 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
648 // initialize global animation definitions from dynamic configuration
649 for (i = 0; i < num_property_mappings; i++)
651 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
652 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
653 int special = property_mapping[i].ext3_index;
654 int graphic = property_mapping[i].artwork_index;
656 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
659 // set animation part to base part, if not specified
660 if (!IS_GLOBAL_ANIM_PART(part_nr))
661 part_nr = GLOBAL_ANIM_ID_PART_BASE;
663 // set animation screen to default, if not specified
664 if (!IS_SPECIAL_GFX_ARG(special))
665 special = GFX_SPECIAL_ARG_DEFAULT;
667 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
669 // fix default value for ".draw_masked" (for backward compatibility)
670 struct GraphicInfo *g = &graphic_info[graphic];
671 struct FileInfo *image = getImageListEntryFromImageID(graphic);
672 char **parameter_raw = image->parameter;
673 int p = GFX_ARG_DRAW_MASKED;
674 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
675 image_config_suffix[p].token,
676 image_config_suffix[p].type);
678 // if ".draw_masked" parameter is undefined, use default value "TRUE"
679 if (draw_masked == ARG_UNDEFINED_VALUE)
680 g->draw_masked = TRUE;
684 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
685 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
686 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
687 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
688 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
689 Debug("init:InitGlobalAnimGraphicInfo",
690 "anim %d, part %d, mode %d => %d",
691 i, j, k, global_anim_info[i].graphic[j][k]);
695 static void InitGlobalAnimSoundInfo(void)
697 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
698 int num_property_mappings = getSoundListPropertyMappingSize();
701 // always start with reliable default values (no global animation sounds)
702 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
703 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
704 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
705 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
707 // initialize global animation sound definitions from dynamic configuration
708 for (i = 0; i < num_property_mappings; i++)
710 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
711 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
712 int special = property_mapping[i].ext3_index;
713 int sound = property_mapping[i].artwork_index;
715 // sound uses control definition; map it to position of graphic (artwork)
716 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
718 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
721 // set animation part to base part, if not specified
722 if (!IS_GLOBAL_ANIM_PART(part_nr))
723 part_nr = GLOBAL_ANIM_ID_PART_BASE;
725 // set animation screen to default, if not specified
726 if (!IS_SPECIAL_GFX_ARG(special))
727 special = GFX_SPECIAL_ARG_DEFAULT;
729 global_anim_info[anim_nr].sound[part_nr][special] = sound;
733 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
734 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
735 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
736 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
737 Debug("init:InitGlobalAnimSoundInfo",
738 "anim %d, part %d, mode %d => %d",
739 i, j, k, global_anim_info[i].sound[j][k]);
743 static void InitGlobalAnimMusicInfo(void)
745 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
746 int num_property_mappings = getMusicListPropertyMappingSize();
749 // always start with reliable default values (no global animation music)
750 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
755 // initialize global animation music definitions from dynamic configuration
756 for (i = 0; i < num_property_mappings; i++)
758 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
759 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
760 int special = property_mapping[i].ext2_index;
761 int music = property_mapping[i].artwork_index;
763 // music uses control definition; map it to position of graphic (artwork)
764 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
766 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
769 // set animation part to base part, if not specified
770 if (!IS_GLOBAL_ANIM_PART(part_nr))
771 part_nr = GLOBAL_ANIM_ID_PART_BASE;
773 // set animation screen to default, if not specified
774 if (!IS_SPECIAL_GFX_ARG(special))
775 special = GFX_SPECIAL_ARG_DEFAULT;
777 global_anim_info[anim_nr].music[part_nr][special] = music;
781 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
782 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
783 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
784 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
785 Debug("init:InitGlobalAnimMusicInfo",
786 "anim %d, part %d, mode %d => %d",
787 i, j, k, global_anim_info[i].music[j][k]);
791 static void InitElementGraphicInfo(void)
793 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
794 int num_property_mappings = getImageListPropertyMappingSize();
797 if (graphic_info == NULL) // still at startup phase
800 // set values to -1 to identify later as "uninitialized" values
801 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
803 for (act = 0; act < NUM_ACTIONS; act++)
805 element_info[i].graphic[act] = -1;
806 element_info[i].crumbled[act] = -1;
808 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
810 element_info[i].direction_graphic[act][dir] = -1;
811 element_info[i].direction_crumbled[act][dir] = -1;
818 // initialize normal element/graphic mapping from static configuration
819 for (i = 0; element_to_graphic[i].element > -1; i++)
821 int element = element_to_graphic[i].element;
822 int action = element_to_graphic[i].action;
823 int direction = element_to_graphic[i].direction;
824 boolean crumbled = element_to_graphic[i].crumbled;
825 int graphic = element_to_graphic[i].graphic;
826 int base_graphic = el2baseimg(element);
828 if (graphic_info[graphic].bitmap == NULL)
831 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
834 boolean base_redefined =
835 getImageListEntryFromImageID(base_graphic)->redefined;
836 boolean act_dir_redefined =
837 getImageListEntryFromImageID(graphic)->redefined;
839 /* if the base graphic ("emerald", for example) has been redefined,
840 but not the action graphic ("emerald.falling", for example), do not
841 use an existing (in this case considered obsolete) action graphic
842 anymore, but use the automatically determined default graphic */
843 if (base_redefined && !act_dir_redefined)
848 action = ACTION_DEFAULT;
853 element_info[element].direction_crumbled[action][direction] = graphic;
855 element_info[element].crumbled[action] = graphic;
860 element_info[element].direction_graphic[action][direction] = graphic;
862 element_info[element].graphic[action] = graphic;
866 // initialize normal element/graphic mapping from dynamic configuration
867 for (i = 0; i < num_property_mappings; i++)
869 int element = property_mapping[i].base_index;
870 int action = property_mapping[i].ext1_index;
871 int direction = property_mapping[i].ext2_index;
872 int special = property_mapping[i].ext3_index;
873 int graphic = property_mapping[i].artwork_index;
874 boolean crumbled = FALSE;
876 if (special == GFX_SPECIAL_ARG_CRUMBLED)
882 if (graphic_info[graphic].bitmap == NULL)
885 if (element >= MAX_NUM_ELEMENTS || special != -1)
889 action = ACTION_DEFAULT;
894 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
895 element_info[element].direction_crumbled[action][dir] = -1;
898 element_info[element].direction_crumbled[action][direction] = graphic;
900 element_info[element].crumbled[action] = graphic;
905 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
906 element_info[element].direction_graphic[action][dir] = -1;
909 element_info[element].direction_graphic[action][direction] = graphic;
911 element_info[element].graphic[action] = graphic;
915 // now copy all graphics that are defined to be cloned from other graphics
916 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
918 int graphic = element_info[i].graphic[ACTION_DEFAULT];
919 int crumbled_like, diggable_like;
924 crumbled_like = graphic_info[graphic].crumbled_like;
925 diggable_like = graphic_info[graphic].diggable_like;
927 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
929 for (act = 0; act < NUM_ACTIONS; act++)
930 element_info[i].crumbled[act] =
931 element_info[crumbled_like].crumbled[act];
932 for (act = 0; act < NUM_ACTIONS; act++)
933 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
934 element_info[i].direction_crumbled[act][dir] =
935 element_info[crumbled_like].direction_crumbled[act][dir];
938 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
940 element_info[i].graphic[ACTION_DIGGING] =
941 element_info[diggable_like].graphic[ACTION_DIGGING];
942 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
943 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
944 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
948 // set hardcoded definitions for some runtime elements without graphic
949 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
951 // set hardcoded definitions for some internal elements without graphic
952 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
954 if (IS_EDITOR_CASCADE_INACTIVE(i))
955 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
956 else if (IS_EDITOR_CASCADE_ACTIVE(i))
957 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
960 // now set all undefined/invalid graphics to -1 to set to default after it
961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
963 for (act = 0; act < NUM_ACTIONS; act++)
967 graphic = element_info[i].graphic[act];
968 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
969 element_info[i].graphic[act] = -1;
971 graphic = element_info[i].crumbled[act];
972 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
973 element_info[i].crumbled[act] = -1;
975 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
977 graphic = element_info[i].direction_graphic[act][dir];
978 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
979 element_info[i].direction_graphic[act][dir] = -1;
981 graphic = element_info[i].direction_crumbled[act][dir];
982 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
983 element_info[i].direction_crumbled[act][dir] = -1;
990 // adjust graphics with 2nd tile for movement according to direction
991 // (do this before correcting '-1' values to minimize calculations)
992 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
994 for (act = 0; act < NUM_ACTIONS; act++)
996 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
998 int graphic = element_info[i].direction_graphic[act][dir];
999 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1001 if (act == ACTION_FALLING) // special case
1002 graphic = element_info[i].graphic[act];
1004 if (graphic != -1 &&
1005 graphic_info[graphic].double_movement &&
1006 graphic_info[graphic].swap_double_tiles != 0)
1008 struct GraphicInfo *g = &graphic_info[graphic];
1009 int src_x_front = g->src_x;
1010 int src_y_front = g->src_y;
1011 int src_x_back = g->src_x + g->offset2_x;
1012 int src_y_back = g->src_y + g->offset2_y;
1013 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1015 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1016 src_y_front < src_y_back);
1017 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1018 boolean swap_movement_tiles_autodetected =
1019 (!frames_are_ordered_diagonally &&
1020 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1021 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1022 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1023 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1025 // swap frontside and backside graphic tile coordinates, if needed
1026 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1028 // get current (wrong) backside tile coordinates
1029 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1031 // set frontside tile coordinates to backside tile coordinates
1032 g->src_x = src_x_back;
1033 g->src_y = src_y_back;
1035 // invert tile offset to point to new backside tile coordinates
1039 // do not swap front and backside tiles again after correction
1040 g->swap_double_tiles = 0;
1047 UPDATE_BUSY_STATE();
1049 // now set all '-1' values to element specific default values
1050 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1052 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1053 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1054 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1055 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1057 if (default_graphic == -1)
1058 default_graphic = IMG_UNKNOWN;
1060 if (default_crumbled == -1)
1061 default_crumbled = default_graphic;
1063 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1065 default_direction_graphic[dir] =
1066 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1067 default_direction_crumbled[dir] =
1068 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1070 if (default_direction_graphic[dir] == -1)
1071 default_direction_graphic[dir] = default_graphic;
1073 if (default_direction_crumbled[dir] == -1)
1074 default_direction_crumbled[dir] = default_direction_graphic[dir];
1077 for (act = 0; act < NUM_ACTIONS; act++)
1079 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1080 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1081 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1082 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1083 act == ACTION_TURNING_FROM_RIGHT ||
1084 act == ACTION_TURNING_FROM_UP ||
1085 act == ACTION_TURNING_FROM_DOWN);
1087 // generic default action graphic (defined by "[default]" directive)
1088 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1089 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1090 int default_remove_graphic = IMG_EMPTY;
1092 if (act_remove && default_action_graphic != -1)
1093 default_remove_graphic = default_action_graphic;
1095 // look for special default action graphic (classic game specific)
1096 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1097 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1098 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1099 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1100 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1101 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1102 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1103 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1105 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1106 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1107 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1108 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1109 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1110 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1111 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1112 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1114 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1115 // !!! make this better !!!
1116 if (i == EL_EMPTY_SPACE)
1118 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1119 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1122 if (default_action_graphic == -1)
1123 default_action_graphic = default_graphic;
1125 if (default_action_crumbled == -1)
1126 default_action_crumbled = default_action_graphic;
1128 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1130 // use action graphic as the default direction graphic, if undefined
1131 int default_action_direction_graphic = element_info[i].graphic[act];
1132 int default_action_direction_crumbled = element_info[i].crumbled[act];
1134 // no graphic for current action -- use default direction graphic
1135 if (default_action_direction_graphic == -1)
1136 default_action_direction_graphic =
1137 (act_remove ? default_remove_graphic :
1139 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1140 default_action_graphic != default_graphic ?
1141 default_action_graphic :
1142 default_direction_graphic[dir]);
1144 if (element_info[i].direction_graphic[act][dir] == -1)
1145 element_info[i].direction_graphic[act][dir] =
1146 default_action_direction_graphic;
1148 if (default_action_direction_crumbled == -1)
1149 default_action_direction_crumbled =
1150 element_info[i].direction_graphic[act][dir];
1152 if (element_info[i].direction_crumbled[act][dir] == -1)
1153 element_info[i].direction_crumbled[act][dir] =
1154 default_action_direction_crumbled;
1157 // no graphic for this specific action -- use default action graphic
1158 if (element_info[i].graphic[act] == -1)
1159 element_info[i].graphic[act] =
1160 (act_remove ? default_remove_graphic :
1161 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1162 default_action_graphic);
1164 if (element_info[i].crumbled[act] == -1)
1165 element_info[i].crumbled[act] = element_info[i].graphic[act];
1169 UPDATE_BUSY_STATE();
1172 static void InitElementSpecialGraphicInfo(void)
1174 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1175 int num_property_mappings = getImageListPropertyMappingSize();
1178 // always start with reliable default values
1179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1180 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1181 element_info[i].special_graphic[j] =
1182 element_info[i].graphic[ACTION_DEFAULT];
1184 // initialize special element/graphic mapping from static configuration
1185 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1187 int element = element_to_special_graphic[i].element;
1188 int special = element_to_special_graphic[i].special;
1189 int graphic = element_to_special_graphic[i].graphic;
1190 int base_graphic = el2baseimg(element);
1191 boolean base_redefined =
1192 getImageListEntryFromImageID(base_graphic)->redefined;
1193 boolean special_redefined =
1194 getImageListEntryFromImageID(graphic)->redefined;
1196 /* if the base graphic ("emerald", for example) has been redefined,
1197 but not the special graphic ("emerald.EDITOR", for example), do not
1198 use an existing (in this case considered obsolete) special graphic
1199 anymore, but use the automatically created (down-scaled) graphic */
1200 if (base_redefined && !special_redefined)
1203 element_info[element].special_graphic[special] = graphic;
1206 // initialize special element/graphic mapping from dynamic configuration
1207 for (i = 0; i < num_property_mappings; i++)
1209 int element = property_mapping[i].base_index;
1210 int action = property_mapping[i].ext1_index;
1211 int direction = property_mapping[i].ext2_index;
1212 int special = property_mapping[i].ext3_index;
1213 int graphic = property_mapping[i].artwork_index;
1215 // for action ".active", replace element with active element, if exists
1216 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1218 element = ELEMENT_ACTIVE(element);
1222 if (element >= MAX_NUM_ELEMENTS)
1225 // do not change special graphic if action or direction was specified
1226 if (action != -1 || direction != -1)
1229 if (IS_SPECIAL_GFX_ARG(special))
1230 element_info[element].special_graphic[special] = graphic;
1233 // now set all undefined/invalid graphics to default
1234 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1235 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1236 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1237 element_info[i].special_graphic[j] =
1238 element_info[i].graphic[ACTION_DEFAULT];
1241 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1243 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1244 return get_parameter_value(value_raw, suffix, type);
1246 if (strEqual(value_raw, ARG_UNDEFINED))
1247 return ARG_UNDEFINED_VALUE;
1249 if (type == TYPE_ELEMENT)
1251 char *value = getHashEntry(element_token_hash, value_raw);
1256 Warn("error found in config file:");
1257 Warn("- config file: '%s'", getImageConfigFilename());
1258 Warn("error: invalid element token '%s'", value_raw);
1259 Warn("custom graphic rejected for this element/action");
1260 Warn("fallback done to undefined element for this graphic");
1264 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1266 else if (type == TYPE_GRAPHIC)
1268 char *value = getHashEntry(graphic_token_hash, value_raw);
1269 int fallback_graphic = IMG_CHAR_EXCLAM;
1274 Warn("error found in config file:");
1275 Warn("- config file: '%s'", getImageConfigFilename());
1276 Warn("error: invalid graphic token '%s'", value_raw);
1277 Warn("custom graphic rejected for this element/action");
1278 Warn("fallback done to 'char_exclam' for this graphic");
1282 return (value != NULL ? atoi(value) : fallback_graphic);
1288 static int get_scaled_graphic_width(int graphic)
1290 int original_width = getOriginalImageWidthFromImageID(graphic);
1291 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1293 return original_width * scale_up_factor;
1296 static int get_scaled_graphic_height(int graphic)
1298 int original_height = getOriginalImageHeightFromImageID(graphic);
1299 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1301 return original_height * scale_up_factor;
1304 static void set_graphic_parameters_ext(int graphic, int *parameter,
1305 Bitmap **src_bitmaps)
1307 struct GraphicInfo *g = &graphic_info[graphic];
1308 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1309 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1310 int anim_frames_per_line = 1;
1312 // always start with reliable default values
1313 g->src_image_width = 0;
1314 g->src_image_height = 0;
1317 g->width = TILEX; // default for element graphics
1318 g->height = TILEY; // default for element graphics
1319 g->offset_x = 0; // one or both of these values ...
1320 g->offset_y = 0; // ... will be corrected later
1321 g->offset2_x = 0; // one or both of these values ...
1322 g->offset2_y = 0; // ... will be corrected later
1323 g->swap_double_tiles = -1; // auto-detect tile swapping
1324 g->crumbled_like = -1; // do not use clone element
1325 g->diggable_like = -1; // do not use clone element
1326 g->border_size = TILEX / 8; // "CRUMBLED" border size
1327 g->scale_up_factor = 1; // default: no scaling up
1328 g->tile_size = TILESIZE; // default: standard tile size
1329 g->clone_from = -1; // do not use clone graphic
1330 g->init_delay_fixed = 0;
1331 g->init_delay_random = 0;
1332 g->init_delay_action = -1;
1333 g->anim_delay_fixed = 0;
1334 g->anim_delay_random = 0;
1335 g->anim_delay_action = -1;
1336 g->post_delay_fixed = 0;
1337 g->post_delay_random = 0;
1338 g->post_delay_action = -1;
1339 g->init_event = ANIM_EVENT_UNDEFINED;
1340 g->anim_event = ANIM_EVENT_UNDEFINED;
1341 g->init_event_action = -1;
1342 g->anim_event_action = -1;
1343 g->draw_masked = FALSE;
1345 g->fade_mode = FADE_MODE_DEFAULT;
1349 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1350 g->align = ALIGN_CENTER; // default for title screens
1351 g->valign = VALIGN_MIDDLE; // default for title screens
1352 g->sort_priority = 0; // default for title screens
1354 g->style = STYLE_DEFAULT;
1356 g->bitmaps = src_bitmaps;
1357 g->bitmap = src_bitmap;
1359 // optional zoom factor for scaling up the image to a larger size
1360 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1361 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1362 if (g->scale_up_factor < 1)
1363 g->scale_up_factor = 1; // no scaling
1365 // optional tile size for using non-standard image size
1366 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1368 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1371 // CHECK: should tile sizes less than standard tile size be allowed?
1372 if (g->tile_size < TILESIZE)
1373 g->tile_size = TILESIZE; // standard tile size
1376 // when setting tile size, also set width and height accordingly
1377 g->width = g->tile_size;
1378 g->height = g->tile_size;
1381 if (g->use_image_size)
1383 // set new default bitmap size (with scaling, but without small images)
1384 g->width = get_scaled_graphic_width(graphic);
1385 g->height = get_scaled_graphic_height(graphic);
1388 // optional width and height of each animation frame
1389 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1390 g->width = parameter[GFX_ARG_WIDTH];
1391 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1392 g->height = parameter[GFX_ARG_HEIGHT];
1394 // optional x and y tile position of animation frame sequence
1395 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1396 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1397 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1398 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1400 // optional x and y pixel position of animation frame sequence
1401 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1402 g->src_x = parameter[GFX_ARG_X];
1403 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1404 g->src_y = parameter[GFX_ARG_Y];
1411 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1412 g->width, getTokenFromImageID(graphic), TILEX);
1415 g->width = TILEX; // will be checked to be inside bitmap later
1421 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1422 g->height, getTokenFromImageID(graphic), TILEY);
1425 g->height = TILEY; // will be checked to be inside bitmap later
1431 // get final bitmap size (with scaling, but without small images)
1432 int src_image_width = get_scaled_graphic_width(graphic);
1433 int src_image_height = get_scaled_graphic_height(graphic);
1435 if (src_image_width == 0 || src_image_height == 0)
1437 // only happens when loaded outside artwork system (like "global.busy")
1438 src_image_width = src_bitmap->width;
1439 src_image_height = src_bitmap->height;
1442 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1444 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1445 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1449 anim_frames_per_row = MAX(1, src_image_width / g->width);
1450 anim_frames_per_col = MAX(1, src_image_height / g->height);
1453 g->src_image_width = src_image_width;
1454 g->src_image_height = src_image_height;
1457 // correct x or y offset dependent of vertical or horizontal frame order
1458 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1460 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1461 parameter[GFX_ARG_OFFSET] : g->height);
1462 anim_frames_per_line = anim_frames_per_col;
1464 else // frames are ordered horizontally
1466 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1467 parameter[GFX_ARG_OFFSET] : g->width);
1468 anim_frames_per_line = anim_frames_per_row;
1471 // optionally, the x and y offset of frames can be specified directly
1472 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1473 g->offset_x = parameter[GFX_ARG_XOFFSET];
1474 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1475 g->offset_y = parameter[GFX_ARG_YOFFSET];
1477 // optionally, moving animations may have separate start and end graphics
1478 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1480 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1481 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1483 // correct x or y offset2 dependent of vertical or horizontal frame order
1484 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1485 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1486 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1487 else // frames are ordered horizontally
1488 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1489 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1491 // optionally, the x and y offset of 2nd graphic can be specified directly
1492 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1493 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1494 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1495 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1497 // optionally, the second movement tile can be specified as start tile
1498 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1499 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1501 // automatically determine correct number of frames, if not defined
1502 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1503 g->anim_frames = parameter[GFX_ARG_FRAMES];
1504 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1505 g->anim_frames = anim_frames_per_row;
1506 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1507 g->anim_frames = anim_frames_per_col;
1511 if (g->anim_frames < 1) // frames must be at least 1
1514 g->anim_frames_per_line =
1515 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1516 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1518 g->anim_delay = parameter[GFX_ARG_DELAY];
1519 if (g->anim_delay < 1) // delay must be at least 1
1522 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1524 // automatically determine correct start frame, if not defined
1525 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1526 g->anim_start_frame = 0;
1527 else if (g->anim_mode & ANIM_REVERSE)
1528 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1530 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1532 // animation synchronized with global frame counter, not move position
1533 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1535 // optional element for cloning crumble graphics
1536 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1537 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1539 // optional element for cloning digging graphics
1540 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1541 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1543 // optional border size for "crumbling" diggable graphics
1544 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1545 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1547 // used for global animations and player "boring" and "sleeping" actions
1548 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1549 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1550 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1551 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1552 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1553 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1554 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1555 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1556 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1557 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1558 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1559 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1561 // used for global animations
1562 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1563 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1564 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1565 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1566 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1567 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1568 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1569 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1570 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1571 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1572 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1573 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1574 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1575 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1577 // used for toon animations and global animations
1578 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1579 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1580 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1581 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1582 g->direction = parameter[GFX_ARG_DIRECTION];
1583 g->position = parameter[GFX_ARG_POSITION];
1584 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1585 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1587 if (g->step_delay < 1) // delay must be at least 1
1590 // this is only used for drawing font characters
1591 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1592 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1594 // use a different default value for global animations and toons
1595 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1596 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1597 g->draw_masked = TRUE;
1599 // this is used for drawing envelopes, global animations and toons
1600 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1601 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1603 // used for toon animations and global animations
1604 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1605 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1607 // optional graphic for cloning all graphics settings
1608 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1609 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1611 // optional settings for drawing title screens and title messages
1612 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1613 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1614 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1615 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1616 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1617 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1618 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1619 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1620 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1621 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1622 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1623 g->align = parameter[GFX_ARG_ALIGN];
1624 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1625 g->valign = parameter[GFX_ARG_VALIGN];
1626 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1627 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1629 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1630 g->class = parameter[GFX_ARG_CLASS];
1631 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1632 g->style = parameter[GFX_ARG_STYLE];
1634 // this is only used for drawing menu buttons and text
1635 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1636 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1637 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1638 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1641 static void set_graphic_parameters(int graphic)
1643 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1644 char **parameter_raw = image->parameter;
1645 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1646 int parameter[NUM_GFX_ARGS];
1649 // if fallback to default artwork is done, also use the default parameters
1650 if (image->fallback_to_default)
1651 parameter_raw = image->default_parameter;
1653 // get integer values from string parameters
1654 for (i = 0; i < NUM_GFX_ARGS; i++)
1655 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1656 image_config_suffix[i].token,
1657 image_config_suffix[i].type);
1659 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1661 UPDATE_BUSY_STATE();
1664 static void set_cloned_graphic_parameters(int graphic)
1666 int fallback_graphic = IMG_CHAR_EXCLAM;
1667 int max_num_images = getImageListSize();
1668 int clone_graphic = graphic_info[graphic].clone_from;
1669 int num_references_followed = 1;
1671 while (graphic_info[clone_graphic].clone_from != -1 &&
1672 num_references_followed < max_num_images)
1674 clone_graphic = graphic_info[clone_graphic].clone_from;
1676 num_references_followed++;
1679 if (num_references_followed >= max_num_images)
1682 Warn("error found in config file:");
1683 Warn("- config file: '%s'", getImageConfigFilename());
1684 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1685 Warn("error: loop discovered when resolving cloned graphics");
1686 Warn("custom graphic rejected for this element/action");
1688 if (graphic == fallback_graphic)
1689 Fail("no fallback graphic available");
1691 Warn("fallback done to 'char_exclam' for this graphic");
1694 graphic_info[graphic] = graphic_info[fallback_graphic];
1698 graphic_info[graphic] = graphic_info[clone_graphic];
1699 graphic_info[graphic].clone_from = clone_graphic;
1703 static void InitGraphicInfo(void)
1705 int fallback_graphic = IMG_CHAR_EXCLAM;
1706 int num_images = getImageListSize();
1709 // use image size as default values for width and height for these images
1710 static int full_size_graphics[] =
1713 IMG_GLOBAL_BORDER_MAIN,
1714 IMG_GLOBAL_BORDER_SCORES,
1715 IMG_GLOBAL_BORDER_EDITOR,
1716 IMG_GLOBAL_BORDER_PLAYING,
1719 IMG_BACKGROUND_ENVELOPE_1,
1720 IMG_BACKGROUND_ENVELOPE_2,
1721 IMG_BACKGROUND_ENVELOPE_3,
1722 IMG_BACKGROUND_ENVELOPE_4,
1723 IMG_BACKGROUND_REQUEST,
1726 IMG_BACKGROUND_TITLE_INITIAL,
1727 IMG_BACKGROUND_TITLE,
1728 IMG_BACKGROUND_MAIN,
1729 IMG_BACKGROUND_NAMES,
1730 IMG_BACKGROUND_LEVELS,
1731 IMG_BACKGROUND_LEVELNR,
1732 IMG_BACKGROUND_SCORES,
1733 IMG_BACKGROUND_EDITOR,
1734 IMG_BACKGROUND_INFO,
1735 IMG_BACKGROUND_INFO_ELEMENTS,
1736 IMG_BACKGROUND_INFO_MUSIC,
1737 IMG_BACKGROUND_INFO_CREDITS,
1738 IMG_BACKGROUND_INFO_PROGRAM,
1739 IMG_BACKGROUND_INFO_VERSION,
1740 IMG_BACKGROUND_INFO_LEVELSET,
1741 IMG_BACKGROUND_SETUP,
1742 IMG_BACKGROUND_PLAYING,
1743 IMG_BACKGROUND_DOOR,
1744 IMG_BACKGROUND_TAPE,
1745 IMG_BACKGROUND_PANEL,
1746 IMG_BACKGROUND_PALETTE,
1747 IMG_BACKGROUND_TOOLBOX,
1749 IMG_TITLESCREEN_INITIAL_1,
1750 IMG_TITLESCREEN_INITIAL_2,
1751 IMG_TITLESCREEN_INITIAL_3,
1752 IMG_TITLESCREEN_INITIAL_4,
1753 IMG_TITLESCREEN_INITIAL_5,
1760 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1761 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1762 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1763 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1764 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1765 IMG_BACKGROUND_TITLEMESSAGE_1,
1766 IMG_BACKGROUND_TITLEMESSAGE_2,
1767 IMG_BACKGROUND_TITLEMESSAGE_3,
1768 IMG_BACKGROUND_TITLEMESSAGE_4,
1769 IMG_BACKGROUND_TITLEMESSAGE_5,
1774 FreeGlobalAnimEventInfo();
1776 checked_free(graphic_info);
1778 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1780 // initialize "use_image_size" flag with default value
1781 for (i = 0; i < num_images; i++)
1782 graphic_info[i].use_image_size = FALSE;
1784 // initialize "use_image_size" flag from static configuration above
1785 for (i = 0; full_size_graphics[i] != -1; i++)
1786 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1788 // first set all graphic paramaters ...
1789 for (i = 0; i < num_images; i++)
1790 set_graphic_parameters(i);
1792 // ... then copy these parameters for cloned graphics
1793 for (i = 0; i < num_images; i++)
1794 if (graphic_info[i].clone_from != -1)
1795 set_cloned_graphic_parameters(i);
1797 for (i = 0; i < num_images; i++)
1799 Bitmap *src_bitmap = graphic_info[i].bitmap;
1803 int src_bitmap_width, src_bitmap_height;
1805 // now check if no animation frames are outside of the loaded image
1807 if (graphic_info[i].bitmap == NULL)
1808 continue; // skip check for optional images that are undefined
1810 // get image size (this can differ from the standard element tile size!)
1811 width = graphic_info[i].width;
1812 height = graphic_info[i].height;
1814 // get final bitmap size (with scaling, but without small images)
1815 src_bitmap_width = graphic_info[i].src_image_width;
1816 src_bitmap_height = graphic_info[i].src_image_height;
1818 // check if first animation frame is inside specified bitmap
1820 // do not use getGraphicSourceXY() here to get position of first frame;
1821 // this avoids calculating wrong start position for out-of-bounds frame
1822 src_x = graphic_info[i].src_x;
1823 src_y = graphic_info[i].src_y;
1825 if (program.headless)
1828 if (src_x < 0 || src_y < 0 ||
1829 src_x + width > src_bitmap_width ||
1830 src_y + height > src_bitmap_height)
1833 Warn("error found in config file:");
1834 Warn("- config file: '%s'", getImageConfigFilename());
1835 Warn("- config token: '%s'", getTokenFromImageID(i));
1836 Warn("- image file: '%s'", src_bitmap->source_filename);
1837 Warn("- frame size: %d, %d", width, height);
1838 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1839 src_x, src_y, src_bitmap_width, src_bitmap_height);
1840 Warn("custom graphic rejected for this element/action");
1842 if (i == fallback_graphic)
1843 Fail("no fallback graphic available");
1845 Warn("fallback done to 'char_exclam' for this graphic");
1848 graphic_info[i] = graphic_info[fallback_graphic];
1850 // if first frame out of bounds, do not check last frame anymore
1854 // check if last animation frame is inside specified bitmap
1856 last_frame = graphic_info[i].anim_frames - 1;
1857 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1859 if (src_x < 0 || src_y < 0 ||
1860 src_x + width > src_bitmap_width ||
1861 src_y + height > src_bitmap_height)
1864 Warn("error found in config file:");
1865 Warn("- config file: '%s'", getImageConfigFilename());
1866 Warn("- config token: '%s'", getTokenFromImageID(i));
1867 Warn("- image file: '%s'", src_bitmap->source_filename);
1868 Warn("- frame size: %d, %d", width, height);
1869 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1870 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1871 Warn("custom graphic rejected for this element/action");
1873 if (i == fallback_graphic)
1874 Fail("no fallback graphic available");
1876 Warn("fallback done to 'char_exclam' for this graphic");
1879 graphic_info[i] = graphic_info[fallback_graphic];
1884 static void InitGraphicCompatibilityInfo(void)
1886 struct FileInfo *fi_global_door =
1887 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1888 int num_images = getImageListSize();
1891 /* the following compatibility handling is needed for the following case:
1892 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1893 graphics mainly used for door and panel graphics, like editor, tape and
1894 in-game buttons with hard-coded bitmap positions and button sizes; as
1895 these graphics now have individual definitions, redefining "global.door"
1896 to change all these graphics at once like before does not work anymore
1897 (because all those individual definitions still have their default values);
1898 to solve this, remap all those individual definitions that are not
1899 redefined to the new bitmap of "global.door" if it was redefined */
1901 // special compatibility handling if image "global.door" was redefined
1902 if (fi_global_door->redefined)
1904 for (i = 0; i < num_images; i++)
1906 struct FileInfo *fi = getImageListEntryFromImageID(i);
1908 // process only those images that still use the default settings
1911 // process all images which default to same image as "global.door"
1912 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1915 Debug("init:InitGraphicCompatibilityInfo",
1916 "special treatment needed for token '%s'", fi->token);
1919 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1920 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1926 InitGraphicCompatibilityInfo_Doors();
1929 static void InitElementSoundInfo(void)
1931 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1932 int num_property_mappings = getSoundListPropertyMappingSize();
1935 // set values to -1 to identify later as "uninitialized" values
1936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1937 for (act = 0; act < NUM_ACTIONS; act++)
1938 element_info[i].sound[act] = -1;
1940 // initialize element/sound mapping from static configuration
1941 for (i = 0; element_to_sound[i].element > -1; i++)
1943 int element = element_to_sound[i].element;
1944 int action = element_to_sound[i].action;
1945 int sound = element_to_sound[i].sound;
1946 boolean is_class = element_to_sound[i].is_class;
1949 action = ACTION_DEFAULT;
1952 element_info[element].sound[action] = sound;
1954 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1955 if (strEqual(element_info[j].class_name,
1956 element_info[element].class_name))
1957 element_info[j].sound[action] = sound;
1960 // initialize element class/sound mapping from dynamic configuration
1961 for (i = 0; i < num_property_mappings; i++)
1963 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1964 int action = property_mapping[i].ext1_index;
1965 int sound = property_mapping[i].artwork_index;
1967 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1971 action = ACTION_DEFAULT;
1973 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1974 if (strEqual(element_info[j].class_name,
1975 element_info[element_class].class_name))
1976 element_info[j].sound[action] = sound;
1979 // initialize element/sound mapping from dynamic configuration
1980 for (i = 0; i < num_property_mappings; i++)
1982 int element = property_mapping[i].base_index;
1983 int action = property_mapping[i].ext1_index;
1984 int sound = property_mapping[i].artwork_index;
1986 if (element >= MAX_NUM_ELEMENTS)
1990 action = ACTION_DEFAULT;
1992 element_info[element].sound[action] = sound;
1995 // now set all '-1' values to element specific default values
1996 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1998 for (act = 0; act < NUM_ACTIONS; act++)
2000 // generic default action sound (defined by "[default]" directive)
2001 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2003 // look for special default action sound (classic game specific)
2004 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2005 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2006 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2007 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2008 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2009 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2010 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2011 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2013 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2014 // !!! make this better !!!
2015 if (i == EL_EMPTY_SPACE)
2016 default_action_sound = element_info[EL_DEFAULT].sound[act];
2018 // no sound for this specific action -- use default action sound
2019 if (element_info[i].sound[act] == -1)
2020 element_info[i].sound[act] = default_action_sound;
2024 // copy sound settings to some elements that are only stored in level file
2025 // in native R'n'D levels, but are used by game engine in native EM levels
2026 for (i = 0; copy_properties[i][0] != -1; i++)
2027 for (j = 1; j <= 4; j++)
2028 for (act = 0; act < NUM_ACTIONS; act++)
2029 element_info[copy_properties[i][j]].sound[act] =
2030 element_info[copy_properties[i][0]].sound[act];
2033 static void InitGameModeSoundInfo(void)
2037 // set values to -1 to identify later as "uninitialized" values
2038 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2041 // initialize gamemode/sound mapping from static configuration
2042 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2044 int gamemode = gamemode_to_sound[i].gamemode;
2045 int sound = gamemode_to_sound[i].sound;
2048 gamemode = GAME_MODE_DEFAULT;
2050 menu.sound[gamemode] = sound;
2053 // now set all '-1' values to levelset specific default values
2054 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2055 if (menu.sound[i] == -1)
2056 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2059 static void set_sound_parameters(int sound, char **parameter_raw)
2061 int parameter[NUM_SND_ARGS];
2064 // get integer values from string parameters
2065 for (i = 0; i < NUM_SND_ARGS; i++)
2067 get_parameter_value(parameter_raw[i],
2068 sound_config_suffix[i].token,
2069 sound_config_suffix[i].type);
2071 // explicit loop mode setting in configuration overrides default value
2072 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2073 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2075 // sound volume to change the original volume when loading the sound file
2076 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2078 // sound priority to give certain sounds a higher or lower priority
2079 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2082 static void InitSoundInfo(void)
2084 int *sound_effect_properties;
2085 int num_sounds = getSoundListSize();
2088 checked_free(sound_info);
2090 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2091 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2093 // initialize sound effect for all elements to "no sound"
2094 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2095 for (j = 0; j < NUM_ACTIONS; j++)
2096 element_info[i].sound[j] = SND_UNDEFINED;
2098 for (i = 0; i < num_sounds; i++)
2100 struct FileInfo *sound = getSoundListEntry(i);
2101 int len_effect_text = strlen(sound->token);
2103 sound_effect_properties[i] = ACTION_OTHER;
2104 sound_info[i].loop = FALSE; // default: play sound only once
2106 // determine all loop sounds and identify certain sound classes
2108 for (j = 0; element_action_info[j].suffix; j++)
2110 int len_action_text = strlen(element_action_info[j].suffix);
2112 if (len_action_text < len_effect_text &&
2113 strEqual(&sound->token[len_effect_text - len_action_text],
2114 element_action_info[j].suffix))
2116 sound_effect_properties[i] = element_action_info[j].value;
2117 sound_info[i].loop = element_action_info[j].is_loop_sound;
2123 // associate elements and some selected sound actions
2125 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2127 if (element_info[j].class_name)
2129 int len_class_text = strlen(element_info[j].class_name);
2131 if (len_class_text + 1 < len_effect_text &&
2132 strncmp(sound->token,
2133 element_info[j].class_name, len_class_text) == 0 &&
2134 sound->token[len_class_text] == '.')
2136 int sound_action_value = sound_effect_properties[i];
2138 element_info[j].sound[sound_action_value] = i;
2143 set_sound_parameters(i, sound->parameter);
2146 free(sound_effect_properties);
2149 static void InitGameModeMusicInfo(void)
2151 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2152 int num_property_mappings = getMusicListPropertyMappingSize();
2153 int default_levelset_music = -1;
2156 // set values to -1 to identify later as "uninitialized" values
2157 for (i = 0; i < MAX_LEVELS; i++)
2158 levelset.music[i] = -1;
2159 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2162 // initialize gamemode/music mapping from static configuration
2163 for (i = 0; gamemode_to_music[i].music > -1; i++)
2165 int gamemode = gamemode_to_music[i].gamemode;
2166 int music = gamemode_to_music[i].music;
2169 gamemode = GAME_MODE_DEFAULT;
2171 menu.music[gamemode] = music;
2174 // initialize gamemode/music mapping from dynamic configuration
2175 for (i = 0; i < num_property_mappings; i++)
2177 int prefix = property_mapping[i].base_index;
2178 int gamemode = property_mapping[i].ext2_index;
2179 int level = property_mapping[i].ext3_index;
2180 int music = property_mapping[i].artwork_index;
2182 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2186 gamemode = GAME_MODE_DEFAULT;
2188 // level specific music only allowed for in-game music
2189 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2190 gamemode = GAME_MODE_PLAYING;
2195 default_levelset_music = music;
2198 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2199 levelset.music[level] = music;
2200 if (gamemode != GAME_MODE_PLAYING)
2201 menu.music[gamemode] = music;
2204 // now set all '-1' values to menu specific default values
2205 // (undefined values of "levelset.music[]" might stay at "-1" to
2206 // allow dynamic selection of music files from music directory!)
2207 for (i = 0; i < MAX_LEVELS; i++)
2208 if (levelset.music[i] == -1)
2209 levelset.music[i] = default_levelset_music;
2210 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2211 if (menu.music[i] == -1)
2212 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2215 static void set_music_parameters(int music, char **parameter_raw)
2217 int parameter[NUM_MUS_ARGS];
2220 // get integer values from string parameters
2221 for (i = 0; i < NUM_MUS_ARGS; i++)
2223 get_parameter_value(parameter_raw[i],
2224 music_config_suffix[i].token,
2225 music_config_suffix[i].type);
2227 // explicit loop mode setting in configuration overrides default value
2228 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2229 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2232 static void InitMusicInfo(void)
2234 int num_music = getMusicListSize();
2237 checked_free(music_info);
2239 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2241 for (i = 0; i < num_music; i++)
2243 struct FileInfo *music = getMusicListEntry(i);
2244 int len_music_text = strlen(music->token);
2246 music_info[i].loop = TRUE; // default: play music in loop mode
2248 // determine all loop music
2250 for (j = 0; music_prefix_info[j].prefix; j++)
2252 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2254 if (len_prefix_text < len_music_text &&
2255 strncmp(music->token,
2256 music_prefix_info[j].prefix, len_prefix_text) == 0)
2258 music_info[i].loop = music_prefix_info[j].is_loop_music;
2264 set_music_parameters(i, music->parameter);
2269 static void InitGameInfoFromArtworkInfo(void)
2271 // special case: store initial value of custom artwork setting
2272 game.use_masked_elements_initial = game.use_masked_elements;
2275 static void ReinitializeGraphics(void)
2277 print_timestamp_init("ReinitializeGraphics");
2279 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2281 InitGraphicInfo(); // graphic properties mapping
2282 print_timestamp_time("InitGraphicInfo");
2283 InitElementGraphicInfo(); // element game graphic mapping
2284 print_timestamp_time("InitElementGraphicInfo");
2285 InitElementSpecialGraphicInfo(); // element special graphic mapping
2286 print_timestamp_time("InitElementSpecialGraphicInfo");
2288 InitElementSmallImages(); // scale elements to all needed sizes
2289 print_timestamp_time("InitElementSmallImages");
2290 InitScaledImages(); // scale all other images, if needed
2291 print_timestamp_time("InitScaledImages");
2292 InitBitmapPointers(); // set standard size bitmap pointers
2293 print_timestamp_time("InitBitmapPointers");
2294 InitFontGraphicInfo(); // initialize text drawing functions
2295 print_timestamp_time("InitFontGraphicInfo");
2296 InitGlobalAnimGraphicInfo(); // initialize global animation config
2297 print_timestamp_time("InitGlobalAnimGraphicInfo");
2299 InitImageTextures(); // create textures for certain images
2300 print_timestamp_time("InitImageTextures");
2302 InitGraphicInfo_EM(); // graphic mapping for EM engine
2303 print_timestamp_time("InitGraphicInfo_EM");
2305 InitGraphicCompatibilityInfo();
2306 print_timestamp_time("InitGraphicCompatibilityInfo");
2309 print_timestamp_time("InitGadgets");
2311 print_timestamp_time("InitDoors");
2313 InitGameInfoFromArtworkInfo();
2315 print_timestamp_done("ReinitializeGraphics");
2318 static void ReinitializeSounds(void)
2320 InitSoundInfo(); // sound properties mapping
2321 InitElementSoundInfo(); // element game sound mapping
2322 InitGameModeSoundInfo(); // game mode sound mapping
2323 InitGlobalAnimSoundInfo(); // global animation sound settings
2325 InitPlayLevelSound(); // internal game sound settings
2328 static void ReinitializeMusic(void)
2330 InitMusicInfo(); // music properties mapping
2331 InitGameModeMusicInfo(); // game mode music mapping
2332 InitGlobalAnimMusicInfo(); // global animation music settings
2335 static int get_special_property_bit(int element, int property_bit_nr)
2337 struct PropertyBitInfo
2343 static struct PropertyBitInfo pb_can_move_into_acid[] =
2345 // the player may be able fall into acid when gravity is activated
2350 { EL_SP_MURPHY, 0 },
2351 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2353 // all elements that can move may be able to also move into acid
2356 { EL_BUG_RIGHT, 1 },
2359 { EL_SPACESHIP, 2 },
2360 { EL_SPACESHIP_LEFT, 2 },
2361 { EL_SPACESHIP_RIGHT, 2 },
2362 { EL_SPACESHIP_UP, 2 },
2363 { EL_SPACESHIP_DOWN, 2 },
2364 { EL_BD_BUTTERFLY, 3 },
2365 { EL_BD_BUTTERFLY_LEFT, 3 },
2366 { EL_BD_BUTTERFLY_RIGHT, 3 },
2367 { EL_BD_BUTTERFLY_UP, 3 },
2368 { EL_BD_BUTTERFLY_DOWN, 3 },
2369 { EL_BD_FIREFLY, 4 },
2370 { EL_BD_FIREFLY_LEFT, 4 },
2371 { EL_BD_FIREFLY_RIGHT, 4 },
2372 { EL_BD_FIREFLY_UP, 4 },
2373 { EL_BD_FIREFLY_DOWN, 4 },
2375 { EL_YAMYAM_LEFT, 5 },
2376 { EL_YAMYAM_RIGHT, 5 },
2377 { EL_YAMYAM_UP, 5 },
2378 { EL_YAMYAM_DOWN, 5 },
2379 { EL_DARK_YAMYAM, 6 },
2382 { EL_PACMAN_LEFT, 8 },
2383 { EL_PACMAN_RIGHT, 8 },
2384 { EL_PACMAN_UP, 8 },
2385 { EL_PACMAN_DOWN, 8 },
2387 { EL_MOLE_LEFT, 9 },
2388 { EL_MOLE_RIGHT, 9 },
2390 { EL_MOLE_DOWN, 9 },
2394 { EL_SATELLITE, 13 },
2395 { EL_SP_SNIKSNAK, 14 },
2396 { EL_SP_ELECTRON, 15 },
2399 { EL_SPRING_LEFT, 17 },
2400 { EL_SPRING_RIGHT, 17 },
2401 { EL_EMC_ANDROID, 18 },
2406 static struct PropertyBitInfo pb_dont_collide_with[] =
2408 { EL_SP_SNIKSNAK, 0 },
2409 { EL_SP_ELECTRON, 1 },
2417 struct PropertyBitInfo *pb_info;
2420 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2421 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2426 struct PropertyBitInfo *pb_info = NULL;
2429 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2430 if (pb_definition[i].bit_nr == property_bit_nr)
2431 pb_info = pb_definition[i].pb_info;
2433 if (pb_info == NULL)
2436 for (i = 0; pb_info[i].element != -1; i++)
2437 if (pb_info[i].element == element)
2438 return pb_info[i].bit_nr;
2443 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2444 boolean property_value)
2446 int bit_nr = get_special_property_bit(element, property_bit_nr);
2451 *bitfield |= (1 << bit_nr);
2453 *bitfield &= ~(1 << bit_nr);
2457 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2459 int bit_nr = get_special_property_bit(element, property_bit_nr);
2462 return ((*bitfield & (1 << bit_nr)) != 0);
2467 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2469 static int group_nr;
2470 static struct ElementGroupInfo *group;
2471 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2474 if (actual_group == NULL) // not yet initialized
2477 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2479 Warn("recursion too deep when resolving group element %d",
2480 group_element - EL_GROUP_START + 1);
2482 // replace element which caused too deep recursion by question mark
2483 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2488 if (recursion_depth == 0) // initialization
2490 group = actual_group;
2491 group_nr = GROUP_NR(group_element);
2493 group->num_elements_resolved = 0;
2494 group->choice_pos = 0;
2496 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2497 element_info[i].in_group[group_nr] = FALSE;
2500 for (i = 0; i < actual_group->num_elements; i++)
2502 int element = actual_group->element[i];
2504 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2507 if (IS_GROUP_ELEMENT(element))
2508 ResolveGroupElementExt(element, recursion_depth + 1);
2511 group->element_resolved[group->num_elements_resolved++] = element;
2512 element_info[element].in_group[group_nr] = TRUE;
2517 void ResolveGroupElement(int group_element)
2519 ResolveGroupElementExt(group_element, 0);
2522 void InitElementPropertiesStatic(void)
2524 static boolean clipboard_elements_initialized = FALSE;
2526 static int ep_diggable[] =
2531 EL_SP_BUGGY_BASE_ACTIVATING,
2534 EL_INVISIBLE_SAND_ACTIVE,
2537 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2538 // (if amoeba can grow into anything diggable, maybe keep these out)
2543 EL_SP_BUGGY_BASE_ACTIVE,
2550 static int ep_collectible_only[] =
2572 EL_DYNABOMB_INCREASE_NUMBER,
2573 EL_DYNABOMB_INCREASE_SIZE,
2574 EL_DYNABOMB_INCREASE_POWER,
2592 // !!! handle separately !!!
2593 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2599 static int ep_dont_run_into[] =
2601 // same elements as in 'ep_dont_touch'
2607 // same elements as in 'ep_dont_collide_with'
2619 // !!! maybe this should better be handled by 'ep_diggable' !!!
2624 EL_SP_BUGGY_BASE_ACTIVE,
2631 static int ep_dont_collide_with[] =
2633 // same elements as in 'ep_dont_touch'
2650 static int ep_dont_touch[] =
2660 static int ep_indestructible[] =
2664 EL_ACID_POOL_TOPLEFT,
2665 EL_ACID_POOL_TOPRIGHT,
2666 EL_ACID_POOL_BOTTOMLEFT,
2667 EL_ACID_POOL_BOTTOM,
2668 EL_ACID_POOL_BOTTOMRIGHT,
2669 EL_SP_HARDWARE_GRAY,
2670 EL_SP_HARDWARE_GREEN,
2671 EL_SP_HARDWARE_BLUE,
2673 EL_SP_HARDWARE_YELLOW,
2674 EL_SP_HARDWARE_BASE_1,
2675 EL_SP_HARDWARE_BASE_2,
2676 EL_SP_HARDWARE_BASE_3,
2677 EL_SP_HARDWARE_BASE_4,
2678 EL_SP_HARDWARE_BASE_5,
2679 EL_SP_HARDWARE_BASE_6,
2680 EL_INVISIBLE_STEELWALL,
2681 EL_INVISIBLE_STEELWALL_ACTIVE,
2682 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2683 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2684 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2685 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2686 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2687 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2688 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2689 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2690 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2691 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2692 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2693 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2695 EL_LIGHT_SWITCH_ACTIVE,
2696 EL_SIGN_EXCLAMATION,
2697 EL_SIGN_RADIOACTIVITY,
2704 EL_SIGN_ENTRY_FORBIDDEN,
2705 EL_SIGN_EMERGENCY_EXIT,
2713 EL_STEEL_EXIT_CLOSED,
2715 EL_STEEL_EXIT_OPENING,
2716 EL_STEEL_EXIT_CLOSING,
2717 EL_EM_STEEL_EXIT_CLOSED,
2718 EL_EM_STEEL_EXIT_OPEN,
2719 EL_EM_STEEL_EXIT_OPENING,
2720 EL_EM_STEEL_EXIT_CLOSING,
2721 EL_DC_STEELWALL_1_LEFT,
2722 EL_DC_STEELWALL_1_RIGHT,
2723 EL_DC_STEELWALL_1_TOP,
2724 EL_DC_STEELWALL_1_BOTTOM,
2725 EL_DC_STEELWALL_1_HORIZONTAL,
2726 EL_DC_STEELWALL_1_VERTICAL,
2727 EL_DC_STEELWALL_1_TOPLEFT,
2728 EL_DC_STEELWALL_1_TOPRIGHT,
2729 EL_DC_STEELWALL_1_BOTTOMLEFT,
2730 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2731 EL_DC_STEELWALL_1_TOPLEFT_2,
2732 EL_DC_STEELWALL_1_TOPRIGHT_2,
2733 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2734 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2735 EL_DC_STEELWALL_2_LEFT,
2736 EL_DC_STEELWALL_2_RIGHT,
2737 EL_DC_STEELWALL_2_TOP,
2738 EL_DC_STEELWALL_2_BOTTOM,
2739 EL_DC_STEELWALL_2_HORIZONTAL,
2740 EL_DC_STEELWALL_2_VERTICAL,
2741 EL_DC_STEELWALL_2_MIDDLE,
2742 EL_DC_STEELWALL_2_SINGLE,
2743 EL_STEELWALL_SLIPPERY,
2757 EL_GATE_1_GRAY_ACTIVE,
2758 EL_GATE_2_GRAY_ACTIVE,
2759 EL_GATE_3_GRAY_ACTIVE,
2760 EL_GATE_4_GRAY_ACTIVE,
2769 EL_EM_GATE_1_GRAY_ACTIVE,
2770 EL_EM_GATE_2_GRAY_ACTIVE,
2771 EL_EM_GATE_3_GRAY_ACTIVE,
2772 EL_EM_GATE_4_GRAY_ACTIVE,
2781 EL_EMC_GATE_5_GRAY_ACTIVE,
2782 EL_EMC_GATE_6_GRAY_ACTIVE,
2783 EL_EMC_GATE_7_GRAY_ACTIVE,
2784 EL_EMC_GATE_8_GRAY_ACTIVE,
2786 EL_DC_GATE_WHITE_GRAY,
2787 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2788 EL_DC_GATE_FAKE_GRAY,
2790 EL_SWITCHGATE_OPENING,
2791 EL_SWITCHGATE_CLOSED,
2792 EL_SWITCHGATE_CLOSING,
2793 EL_DC_SWITCHGATE_SWITCH_UP,
2794 EL_DC_SWITCHGATE_SWITCH_DOWN,
2796 EL_TIMEGATE_OPENING,
2798 EL_TIMEGATE_CLOSING,
2799 EL_DC_TIMEGATE_SWITCH,
2800 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2804 EL_TUBE_VERTICAL_LEFT,
2805 EL_TUBE_VERTICAL_RIGHT,
2806 EL_TUBE_HORIZONTAL_UP,
2807 EL_TUBE_HORIZONTAL_DOWN,
2812 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2813 EL_EXPANDABLE_STEELWALL_VERTICAL,
2814 EL_EXPANDABLE_STEELWALL_ANY,
2819 static int ep_slippery[] =
2833 EL_ROBOT_WHEEL_ACTIVE,
2839 EL_ACID_POOL_TOPLEFT,
2840 EL_ACID_POOL_TOPRIGHT,
2850 EL_STEELWALL_SLIPPERY,
2853 EL_EMC_WALL_SLIPPERY_1,
2854 EL_EMC_WALL_SLIPPERY_2,
2855 EL_EMC_WALL_SLIPPERY_3,
2856 EL_EMC_WALL_SLIPPERY_4,
2858 EL_EMC_MAGIC_BALL_ACTIVE,
2863 static int ep_can_change[] =
2868 static int ep_can_move[] =
2870 // same elements as in 'pb_can_move_into_acid'
2893 static int ep_can_fall[] =
2908 EL_QUICKSAND_FAST_FULL,
2910 EL_BD_MAGIC_WALL_FULL,
2911 EL_DC_MAGIC_WALL_FULL,
2925 static int ep_can_smash_player[] =
2951 static int ep_can_smash_enemies[] =
2960 static int ep_can_smash_everything[] =
2969 static int ep_explodes_by_fire[] =
2971 // same elements as in 'ep_explodes_impact'
2976 // same elements as in 'ep_explodes_smashed'
2986 EL_EM_DYNAMITE_ACTIVE,
2987 EL_DYNABOMB_PLAYER_1_ACTIVE,
2988 EL_DYNABOMB_PLAYER_2_ACTIVE,
2989 EL_DYNABOMB_PLAYER_3_ACTIVE,
2990 EL_DYNABOMB_PLAYER_4_ACTIVE,
2991 EL_DYNABOMB_INCREASE_NUMBER,
2992 EL_DYNABOMB_INCREASE_SIZE,
2993 EL_DYNABOMB_INCREASE_POWER,
2994 EL_SP_DISK_RED_ACTIVE,
3008 static int ep_explodes_smashed[] =
3010 // same elements as in 'ep_explodes_impact'
3024 static int ep_explodes_impact[] =
3033 static int ep_walkable_over[] =
3053 EL_SOKOBAN_FIELD_EMPTY,
3060 EL_EM_STEEL_EXIT_OPEN,
3061 EL_EM_STEEL_EXIT_OPENING,
3070 EL_GATE_1_GRAY_ACTIVE,
3071 EL_GATE_2_GRAY_ACTIVE,
3072 EL_GATE_3_GRAY_ACTIVE,
3073 EL_GATE_4_GRAY_ACTIVE,
3081 static int ep_walkable_inside[] =
3086 EL_TUBE_VERTICAL_LEFT,
3087 EL_TUBE_VERTICAL_RIGHT,
3088 EL_TUBE_HORIZONTAL_UP,
3089 EL_TUBE_HORIZONTAL_DOWN,
3098 static int ep_walkable_under[] =
3103 static int ep_passable_over[] =
3113 EL_EM_GATE_1_GRAY_ACTIVE,
3114 EL_EM_GATE_2_GRAY_ACTIVE,
3115 EL_EM_GATE_3_GRAY_ACTIVE,
3116 EL_EM_GATE_4_GRAY_ACTIVE,
3125 EL_EMC_GATE_5_GRAY_ACTIVE,
3126 EL_EMC_GATE_6_GRAY_ACTIVE,
3127 EL_EMC_GATE_7_GRAY_ACTIVE,
3128 EL_EMC_GATE_8_GRAY_ACTIVE,
3130 EL_DC_GATE_WHITE_GRAY,
3131 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3138 static int ep_passable_inside[] =
3144 EL_SP_PORT_HORIZONTAL,
3145 EL_SP_PORT_VERTICAL,
3147 EL_SP_GRAVITY_PORT_LEFT,
3148 EL_SP_GRAVITY_PORT_RIGHT,
3149 EL_SP_GRAVITY_PORT_UP,
3150 EL_SP_GRAVITY_PORT_DOWN,
3151 EL_SP_GRAVITY_ON_PORT_LEFT,
3152 EL_SP_GRAVITY_ON_PORT_RIGHT,
3153 EL_SP_GRAVITY_ON_PORT_UP,
3154 EL_SP_GRAVITY_ON_PORT_DOWN,
3155 EL_SP_GRAVITY_OFF_PORT_LEFT,
3156 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3157 EL_SP_GRAVITY_OFF_PORT_UP,
3158 EL_SP_GRAVITY_OFF_PORT_DOWN,
3163 static int ep_passable_under[] =
3168 static int ep_droppable[] =
3173 static int ep_explodes_1x1_old[] =
3178 static int ep_pushable[] =
3190 EL_SOKOBAN_FIELD_FULL,
3199 static int ep_explodes_cross_old[] =
3204 static int ep_protected[] =
3206 // same elements as in 'ep_walkable_inside'
3210 EL_TUBE_VERTICAL_LEFT,
3211 EL_TUBE_VERTICAL_RIGHT,
3212 EL_TUBE_HORIZONTAL_UP,
3213 EL_TUBE_HORIZONTAL_DOWN,
3219 // same elements as in 'ep_passable_over'
3228 EL_EM_GATE_1_GRAY_ACTIVE,
3229 EL_EM_GATE_2_GRAY_ACTIVE,
3230 EL_EM_GATE_3_GRAY_ACTIVE,
3231 EL_EM_GATE_4_GRAY_ACTIVE,
3240 EL_EMC_GATE_5_GRAY_ACTIVE,
3241 EL_EMC_GATE_6_GRAY_ACTIVE,
3242 EL_EMC_GATE_7_GRAY_ACTIVE,
3243 EL_EMC_GATE_8_GRAY_ACTIVE,
3245 EL_DC_GATE_WHITE_GRAY,
3246 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3250 // same elements as in 'ep_passable_inside'
3255 EL_SP_PORT_HORIZONTAL,
3256 EL_SP_PORT_VERTICAL,
3258 EL_SP_GRAVITY_PORT_LEFT,
3259 EL_SP_GRAVITY_PORT_RIGHT,
3260 EL_SP_GRAVITY_PORT_UP,
3261 EL_SP_GRAVITY_PORT_DOWN,
3262 EL_SP_GRAVITY_ON_PORT_LEFT,
3263 EL_SP_GRAVITY_ON_PORT_RIGHT,
3264 EL_SP_GRAVITY_ON_PORT_UP,
3265 EL_SP_GRAVITY_ON_PORT_DOWN,
3266 EL_SP_GRAVITY_OFF_PORT_LEFT,
3267 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3268 EL_SP_GRAVITY_OFF_PORT_UP,
3269 EL_SP_GRAVITY_OFF_PORT_DOWN,
3274 static int ep_throwable[] =
3279 static int ep_can_explode[] =
3281 // same elements as in 'ep_explodes_impact'
3286 // same elements as in 'ep_explodes_smashed'
3292 // elements that can explode by explosion or by dragonfire
3296 EL_EM_DYNAMITE_ACTIVE,
3297 EL_DYNABOMB_PLAYER_1_ACTIVE,
3298 EL_DYNABOMB_PLAYER_2_ACTIVE,
3299 EL_DYNABOMB_PLAYER_3_ACTIVE,
3300 EL_DYNABOMB_PLAYER_4_ACTIVE,
3301 EL_DYNABOMB_INCREASE_NUMBER,
3302 EL_DYNABOMB_INCREASE_SIZE,
3303 EL_DYNABOMB_INCREASE_POWER,
3304 EL_SP_DISK_RED_ACTIVE,
3312 // elements that can explode only by explosion
3318 static int ep_gravity_reachable[] =
3324 EL_INVISIBLE_SAND_ACTIVE,
3329 EL_SP_PORT_HORIZONTAL,
3330 EL_SP_PORT_VERTICAL,
3332 EL_SP_GRAVITY_PORT_LEFT,
3333 EL_SP_GRAVITY_PORT_RIGHT,
3334 EL_SP_GRAVITY_PORT_UP,
3335 EL_SP_GRAVITY_PORT_DOWN,
3336 EL_SP_GRAVITY_ON_PORT_LEFT,
3337 EL_SP_GRAVITY_ON_PORT_RIGHT,
3338 EL_SP_GRAVITY_ON_PORT_UP,
3339 EL_SP_GRAVITY_ON_PORT_DOWN,
3340 EL_SP_GRAVITY_OFF_PORT_LEFT,
3341 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3342 EL_SP_GRAVITY_OFF_PORT_UP,
3343 EL_SP_GRAVITY_OFF_PORT_DOWN,
3349 static int ep_empty_space[] =
3372 static int ep_player[] =
3379 EL_SOKOBAN_FIELD_PLAYER,
3385 static int ep_can_pass_magic_wall[] =
3399 static int ep_can_pass_dc_magic_wall[] =
3415 static int ep_switchable[] =
3419 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3420 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3421 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3422 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3423 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3424 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3425 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3426 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3427 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3428 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3429 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3430 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3431 EL_SWITCHGATE_SWITCH_UP,
3432 EL_SWITCHGATE_SWITCH_DOWN,
3433 EL_DC_SWITCHGATE_SWITCH_UP,
3434 EL_DC_SWITCHGATE_SWITCH_DOWN,
3436 EL_LIGHT_SWITCH_ACTIVE,
3438 EL_DC_TIMEGATE_SWITCH,
3439 EL_BALLOON_SWITCH_LEFT,
3440 EL_BALLOON_SWITCH_RIGHT,
3441 EL_BALLOON_SWITCH_UP,
3442 EL_BALLOON_SWITCH_DOWN,
3443 EL_BALLOON_SWITCH_ANY,
3444 EL_BALLOON_SWITCH_NONE,
3447 EL_EMC_MAGIC_BALL_SWITCH,
3448 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3453 static int ep_bd_element[] =
3487 static int ep_sp_element[] =
3489 // should always be valid
3492 // standard classic Supaplex elements
3499 EL_SP_HARDWARE_GRAY,
3507 EL_SP_GRAVITY_PORT_RIGHT,
3508 EL_SP_GRAVITY_PORT_DOWN,
3509 EL_SP_GRAVITY_PORT_LEFT,
3510 EL_SP_GRAVITY_PORT_UP,
3515 EL_SP_PORT_VERTICAL,
3516 EL_SP_PORT_HORIZONTAL,
3522 EL_SP_HARDWARE_BASE_1,
3523 EL_SP_HARDWARE_GREEN,
3524 EL_SP_HARDWARE_BLUE,
3526 EL_SP_HARDWARE_YELLOW,
3527 EL_SP_HARDWARE_BASE_2,
3528 EL_SP_HARDWARE_BASE_3,
3529 EL_SP_HARDWARE_BASE_4,
3530 EL_SP_HARDWARE_BASE_5,
3531 EL_SP_HARDWARE_BASE_6,
3535 // additional elements that appeared in newer Supaplex levels
3538 // additional gravity port elements (not switching, but setting gravity)
3539 EL_SP_GRAVITY_ON_PORT_LEFT,
3540 EL_SP_GRAVITY_ON_PORT_RIGHT,
3541 EL_SP_GRAVITY_ON_PORT_UP,
3542 EL_SP_GRAVITY_ON_PORT_DOWN,
3543 EL_SP_GRAVITY_OFF_PORT_LEFT,
3544 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3545 EL_SP_GRAVITY_OFF_PORT_UP,
3546 EL_SP_GRAVITY_OFF_PORT_DOWN,
3548 // more than one Murphy in a level results in an inactive clone
3551 // runtime Supaplex elements
3552 EL_SP_DISK_RED_ACTIVE,
3553 EL_SP_TERMINAL_ACTIVE,
3554 EL_SP_BUGGY_BASE_ACTIVATING,
3555 EL_SP_BUGGY_BASE_ACTIVE,
3562 static int ep_sb_element[] =
3567 EL_SOKOBAN_FIELD_EMPTY,
3568 EL_SOKOBAN_FIELD_FULL,
3569 EL_SOKOBAN_FIELD_PLAYER,
3574 EL_INVISIBLE_STEELWALL,
3579 static int ep_gem[] =
3591 static int ep_food_dark_yamyam[] =
3619 static int ep_food_penguin[] =
3633 static int ep_food_pig[] =
3645 static int ep_historic_wall[] =
3656 EL_GATE_1_GRAY_ACTIVE,
3657 EL_GATE_2_GRAY_ACTIVE,
3658 EL_GATE_3_GRAY_ACTIVE,
3659 EL_GATE_4_GRAY_ACTIVE,
3668 EL_EM_GATE_1_GRAY_ACTIVE,
3669 EL_EM_GATE_2_GRAY_ACTIVE,
3670 EL_EM_GATE_3_GRAY_ACTIVE,
3671 EL_EM_GATE_4_GRAY_ACTIVE,
3678 EL_EXPANDABLE_WALL_HORIZONTAL,
3679 EL_EXPANDABLE_WALL_VERTICAL,
3680 EL_EXPANDABLE_WALL_ANY,
3681 EL_EXPANDABLE_WALL_GROWING,
3682 EL_BD_EXPANDABLE_WALL,
3689 EL_SP_HARDWARE_GRAY,
3690 EL_SP_HARDWARE_GREEN,
3691 EL_SP_HARDWARE_BLUE,
3693 EL_SP_HARDWARE_YELLOW,
3694 EL_SP_HARDWARE_BASE_1,
3695 EL_SP_HARDWARE_BASE_2,
3696 EL_SP_HARDWARE_BASE_3,
3697 EL_SP_HARDWARE_BASE_4,
3698 EL_SP_HARDWARE_BASE_5,
3699 EL_SP_HARDWARE_BASE_6,
3701 EL_SP_TERMINAL_ACTIVE,
3704 EL_INVISIBLE_STEELWALL,
3705 EL_INVISIBLE_STEELWALL_ACTIVE,
3707 EL_INVISIBLE_WALL_ACTIVE,
3708 EL_STEELWALL_SLIPPERY,
3725 static int ep_historic_solid[] =
3729 EL_EXPANDABLE_WALL_HORIZONTAL,
3730 EL_EXPANDABLE_WALL_VERTICAL,
3731 EL_EXPANDABLE_WALL_ANY,
3732 EL_BD_EXPANDABLE_WALL,
3745 EL_QUICKSAND_FILLING,
3746 EL_QUICKSAND_EMPTYING,
3748 EL_MAGIC_WALL_ACTIVE,
3749 EL_MAGIC_WALL_EMPTYING,
3750 EL_MAGIC_WALL_FILLING,
3754 EL_BD_MAGIC_WALL_ACTIVE,
3755 EL_BD_MAGIC_WALL_EMPTYING,
3756 EL_BD_MAGIC_WALL_FULL,
3757 EL_BD_MAGIC_WALL_FILLING,
3758 EL_BD_MAGIC_WALL_DEAD,
3767 EL_SP_TERMINAL_ACTIVE,
3771 EL_INVISIBLE_WALL_ACTIVE,
3772 EL_SWITCHGATE_SWITCH_UP,
3773 EL_SWITCHGATE_SWITCH_DOWN,
3775 EL_TIMEGATE_SWITCH_ACTIVE,
3787 // the following elements are a direct copy of "indestructible" elements,
3788 // except "EL_ACID", which is "indestructible", but not "solid"!
3793 EL_ACID_POOL_TOPLEFT,
3794 EL_ACID_POOL_TOPRIGHT,
3795 EL_ACID_POOL_BOTTOMLEFT,
3796 EL_ACID_POOL_BOTTOM,
3797 EL_ACID_POOL_BOTTOMRIGHT,
3798 EL_SP_HARDWARE_GRAY,
3799 EL_SP_HARDWARE_GREEN,
3800 EL_SP_HARDWARE_BLUE,
3802 EL_SP_HARDWARE_YELLOW,
3803 EL_SP_HARDWARE_BASE_1,
3804 EL_SP_HARDWARE_BASE_2,
3805 EL_SP_HARDWARE_BASE_3,
3806 EL_SP_HARDWARE_BASE_4,
3807 EL_SP_HARDWARE_BASE_5,
3808 EL_SP_HARDWARE_BASE_6,
3809 EL_INVISIBLE_STEELWALL,
3810 EL_INVISIBLE_STEELWALL_ACTIVE,
3811 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3812 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3813 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3814 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3815 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3816 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3817 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3818 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3819 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3820 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3821 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3822 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3824 EL_LIGHT_SWITCH_ACTIVE,
3825 EL_SIGN_EXCLAMATION,
3826 EL_SIGN_RADIOACTIVITY,
3833 EL_SIGN_ENTRY_FORBIDDEN,
3834 EL_SIGN_EMERGENCY_EXIT,
3842 EL_STEEL_EXIT_CLOSED,
3844 EL_STEEL_EXIT_OPENING,
3845 EL_STEEL_EXIT_CLOSING,
3846 EL_EM_STEEL_EXIT_CLOSED,
3847 EL_EM_STEEL_EXIT_OPEN,
3848 EL_EM_STEEL_EXIT_OPENING,
3849 EL_EM_STEEL_EXIT_CLOSING,
3850 EL_DC_STEELWALL_1_LEFT,
3851 EL_DC_STEELWALL_1_RIGHT,
3852 EL_DC_STEELWALL_1_TOP,
3853 EL_DC_STEELWALL_1_BOTTOM,
3854 EL_DC_STEELWALL_1_HORIZONTAL,
3855 EL_DC_STEELWALL_1_VERTICAL,
3856 EL_DC_STEELWALL_1_TOPLEFT,
3857 EL_DC_STEELWALL_1_TOPRIGHT,
3858 EL_DC_STEELWALL_1_BOTTOMLEFT,
3859 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3860 EL_DC_STEELWALL_1_TOPLEFT_2,
3861 EL_DC_STEELWALL_1_TOPRIGHT_2,
3862 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3863 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3864 EL_DC_STEELWALL_2_LEFT,
3865 EL_DC_STEELWALL_2_RIGHT,
3866 EL_DC_STEELWALL_2_TOP,
3867 EL_DC_STEELWALL_2_BOTTOM,
3868 EL_DC_STEELWALL_2_HORIZONTAL,
3869 EL_DC_STEELWALL_2_VERTICAL,
3870 EL_DC_STEELWALL_2_MIDDLE,
3871 EL_DC_STEELWALL_2_SINGLE,
3872 EL_STEELWALL_SLIPPERY,
3886 EL_GATE_1_GRAY_ACTIVE,
3887 EL_GATE_2_GRAY_ACTIVE,
3888 EL_GATE_3_GRAY_ACTIVE,
3889 EL_GATE_4_GRAY_ACTIVE,
3898 EL_EM_GATE_1_GRAY_ACTIVE,
3899 EL_EM_GATE_2_GRAY_ACTIVE,
3900 EL_EM_GATE_3_GRAY_ACTIVE,
3901 EL_EM_GATE_4_GRAY_ACTIVE,
3910 EL_EMC_GATE_5_GRAY_ACTIVE,
3911 EL_EMC_GATE_6_GRAY_ACTIVE,
3912 EL_EMC_GATE_7_GRAY_ACTIVE,
3913 EL_EMC_GATE_8_GRAY_ACTIVE,
3915 EL_DC_GATE_WHITE_GRAY,
3916 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3917 EL_DC_GATE_FAKE_GRAY,
3919 EL_SWITCHGATE_OPENING,
3920 EL_SWITCHGATE_CLOSED,
3921 EL_SWITCHGATE_CLOSING,
3922 EL_DC_SWITCHGATE_SWITCH_UP,
3923 EL_DC_SWITCHGATE_SWITCH_DOWN,
3925 EL_TIMEGATE_OPENING,
3927 EL_TIMEGATE_CLOSING,
3928 EL_DC_TIMEGATE_SWITCH,
3929 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3933 EL_TUBE_VERTICAL_LEFT,
3934 EL_TUBE_VERTICAL_RIGHT,
3935 EL_TUBE_HORIZONTAL_UP,
3936 EL_TUBE_HORIZONTAL_DOWN,
3941 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3942 EL_EXPANDABLE_STEELWALL_VERTICAL,
3943 EL_EXPANDABLE_STEELWALL_ANY,
3948 static int ep_classic_enemy[] =
3965 static int ep_belt[] =
3967 EL_CONVEYOR_BELT_1_LEFT,
3968 EL_CONVEYOR_BELT_1_MIDDLE,
3969 EL_CONVEYOR_BELT_1_RIGHT,
3970 EL_CONVEYOR_BELT_2_LEFT,
3971 EL_CONVEYOR_BELT_2_MIDDLE,
3972 EL_CONVEYOR_BELT_2_RIGHT,
3973 EL_CONVEYOR_BELT_3_LEFT,
3974 EL_CONVEYOR_BELT_3_MIDDLE,
3975 EL_CONVEYOR_BELT_3_RIGHT,
3976 EL_CONVEYOR_BELT_4_LEFT,
3977 EL_CONVEYOR_BELT_4_MIDDLE,
3978 EL_CONVEYOR_BELT_4_RIGHT,
3983 static int ep_belt_active[] =
3985 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3986 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3987 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3988 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3989 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3990 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3991 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3992 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3993 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3994 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3995 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3996 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4001 static int ep_belt_switch[] =
4003 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4004 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4005 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4006 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4007 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4008 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4009 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4010 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4011 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4012 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4013 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4014 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4019 static int ep_tube[] =
4026 EL_TUBE_HORIZONTAL_UP,
4027 EL_TUBE_HORIZONTAL_DOWN,
4029 EL_TUBE_VERTICAL_LEFT,
4030 EL_TUBE_VERTICAL_RIGHT,
4036 static int ep_acid_pool[] =
4038 EL_ACID_POOL_TOPLEFT,
4039 EL_ACID_POOL_TOPRIGHT,
4040 EL_ACID_POOL_BOTTOMLEFT,
4041 EL_ACID_POOL_BOTTOM,
4042 EL_ACID_POOL_BOTTOMRIGHT,
4047 static int ep_keygate[] =
4057 EL_GATE_1_GRAY_ACTIVE,
4058 EL_GATE_2_GRAY_ACTIVE,
4059 EL_GATE_3_GRAY_ACTIVE,
4060 EL_GATE_4_GRAY_ACTIVE,
4069 EL_EM_GATE_1_GRAY_ACTIVE,
4070 EL_EM_GATE_2_GRAY_ACTIVE,
4071 EL_EM_GATE_3_GRAY_ACTIVE,
4072 EL_EM_GATE_4_GRAY_ACTIVE,
4081 EL_EMC_GATE_5_GRAY_ACTIVE,
4082 EL_EMC_GATE_6_GRAY_ACTIVE,
4083 EL_EMC_GATE_7_GRAY_ACTIVE,
4084 EL_EMC_GATE_8_GRAY_ACTIVE,
4086 EL_DC_GATE_WHITE_GRAY,
4087 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4092 static int ep_amoeboid[] =
4104 static int ep_amoebalive[] =
4115 static int ep_has_editor_content[] =
4121 EL_SOKOBAN_FIELD_PLAYER,
4138 static int ep_can_turn_each_move[] =
4140 // !!! do something with this one !!!
4144 static int ep_can_grow[] =
4158 static int ep_active_bomb[] =
4161 EL_EM_DYNAMITE_ACTIVE,
4162 EL_DYNABOMB_PLAYER_1_ACTIVE,
4163 EL_DYNABOMB_PLAYER_2_ACTIVE,
4164 EL_DYNABOMB_PLAYER_3_ACTIVE,
4165 EL_DYNABOMB_PLAYER_4_ACTIVE,
4166 EL_SP_DISK_RED_ACTIVE,
4171 static int ep_inactive[] =
4197 EL_QUICKSAND_FAST_EMPTY,
4220 EL_GATE_1_GRAY_ACTIVE,
4221 EL_GATE_2_GRAY_ACTIVE,
4222 EL_GATE_3_GRAY_ACTIVE,
4223 EL_GATE_4_GRAY_ACTIVE,
4232 EL_EM_GATE_1_GRAY_ACTIVE,
4233 EL_EM_GATE_2_GRAY_ACTIVE,
4234 EL_EM_GATE_3_GRAY_ACTIVE,
4235 EL_EM_GATE_4_GRAY_ACTIVE,
4244 EL_EMC_GATE_5_GRAY_ACTIVE,
4245 EL_EMC_GATE_6_GRAY_ACTIVE,
4246 EL_EMC_GATE_7_GRAY_ACTIVE,
4247 EL_EMC_GATE_8_GRAY_ACTIVE,
4249 EL_DC_GATE_WHITE_GRAY,
4250 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4251 EL_DC_GATE_FAKE_GRAY,
4254 EL_INVISIBLE_STEELWALL,
4262 EL_WALL_EMERALD_YELLOW,
4263 EL_DYNABOMB_INCREASE_NUMBER,
4264 EL_DYNABOMB_INCREASE_SIZE,
4265 EL_DYNABOMB_INCREASE_POWER,
4269 EL_SOKOBAN_FIELD_EMPTY,
4270 EL_SOKOBAN_FIELD_FULL,
4271 EL_WALL_EMERALD_RED,
4272 EL_WALL_EMERALD_PURPLE,
4273 EL_ACID_POOL_TOPLEFT,
4274 EL_ACID_POOL_TOPRIGHT,
4275 EL_ACID_POOL_BOTTOMLEFT,
4276 EL_ACID_POOL_BOTTOM,
4277 EL_ACID_POOL_BOTTOMRIGHT,
4281 EL_BD_MAGIC_WALL_DEAD,
4283 EL_DC_MAGIC_WALL_DEAD,
4284 EL_AMOEBA_TO_DIAMOND,
4292 EL_SP_GRAVITY_PORT_RIGHT,
4293 EL_SP_GRAVITY_PORT_DOWN,
4294 EL_SP_GRAVITY_PORT_LEFT,
4295 EL_SP_GRAVITY_PORT_UP,
4296 EL_SP_PORT_HORIZONTAL,
4297 EL_SP_PORT_VERTICAL,
4308 EL_SP_HARDWARE_GRAY,
4309 EL_SP_HARDWARE_GREEN,
4310 EL_SP_HARDWARE_BLUE,
4312 EL_SP_HARDWARE_YELLOW,
4313 EL_SP_HARDWARE_BASE_1,
4314 EL_SP_HARDWARE_BASE_2,
4315 EL_SP_HARDWARE_BASE_3,
4316 EL_SP_HARDWARE_BASE_4,
4317 EL_SP_HARDWARE_BASE_5,
4318 EL_SP_HARDWARE_BASE_6,
4319 EL_SP_GRAVITY_ON_PORT_LEFT,
4320 EL_SP_GRAVITY_ON_PORT_RIGHT,
4321 EL_SP_GRAVITY_ON_PORT_UP,
4322 EL_SP_GRAVITY_ON_PORT_DOWN,
4323 EL_SP_GRAVITY_OFF_PORT_LEFT,
4324 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4325 EL_SP_GRAVITY_OFF_PORT_UP,
4326 EL_SP_GRAVITY_OFF_PORT_DOWN,
4327 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4328 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4329 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4330 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4331 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4332 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4333 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4334 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4335 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4336 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4337 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4338 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4339 EL_SIGN_EXCLAMATION,
4340 EL_SIGN_RADIOACTIVITY,
4347 EL_SIGN_ENTRY_FORBIDDEN,
4348 EL_SIGN_EMERGENCY_EXIT,
4356 EL_DC_STEELWALL_1_LEFT,
4357 EL_DC_STEELWALL_1_RIGHT,
4358 EL_DC_STEELWALL_1_TOP,
4359 EL_DC_STEELWALL_1_BOTTOM,
4360 EL_DC_STEELWALL_1_HORIZONTAL,
4361 EL_DC_STEELWALL_1_VERTICAL,
4362 EL_DC_STEELWALL_1_TOPLEFT,
4363 EL_DC_STEELWALL_1_TOPRIGHT,
4364 EL_DC_STEELWALL_1_BOTTOMLEFT,
4365 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4366 EL_DC_STEELWALL_1_TOPLEFT_2,
4367 EL_DC_STEELWALL_1_TOPRIGHT_2,
4368 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4369 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4370 EL_DC_STEELWALL_2_LEFT,
4371 EL_DC_STEELWALL_2_RIGHT,
4372 EL_DC_STEELWALL_2_TOP,
4373 EL_DC_STEELWALL_2_BOTTOM,
4374 EL_DC_STEELWALL_2_HORIZONTAL,
4375 EL_DC_STEELWALL_2_VERTICAL,
4376 EL_DC_STEELWALL_2_MIDDLE,
4377 EL_DC_STEELWALL_2_SINGLE,
4378 EL_STEELWALL_SLIPPERY,
4383 EL_EMC_WALL_SLIPPERY_1,
4384 EL_EMC_WALL_SLIPPERY_2,
4385 EL_EMC_WALL_SLIPPERY_3,
4386 EL_EMC_WALL_SLIPPERY_4,
4407 static int ep_em_slippery_wall[] =
4412 static int ep_gfx_crumbled[] =
4423 static int ep_editor_cascade_active[] =
4425 EL_INTERNAL_CASCADE_BD_ACTIVE,
4426 EL_INTERNAL_CASCADE_EM_ACTIVE,
4427 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4428 EL_INTERNAL_CASCADE_RND_ACTIVE,
4429 EL_INTERNAL_CASCADE_SB_ACTIVE,
4430 EL_INTERNAL_CASCADE_SP_ACTIVE,
4431 EL_INTERNAL_CASCADE_DC_ACTIVE,
4432 EL_INTERNAL_CASCADE_DX_ACTIVE,
4433 EL_INTERNAL_CASCADE_MM_ACTIVE,
4434 EL_INTERNAL_CASCADE_DF_ACTIVE,
4435 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4436 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4437 EL_INTERNAL_CASCADE_CE_ACTIVE,
4438 EL_INTERNAL_CASCADE_GE_ACTIVE,
4439 EL_INTERNAL_CASCADE_ES_ACTIVE,
4440 EL_INTERNAL_CASCADE_REF_ACTIVE,
4441 EL_INTERNAL_CASCADE_USER_ACTIVE,
4442 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4447 static int ep_editor_cascade_inactive[] =
4449 EL_INTERNAL_CASCADE_BD,
4450 EL_INTERNAL_CASCADE_EM,
4451 EL_INTERNAL_CASCADE_EMC,
4452 EL_INTERNAL_CASCADE_RND,
4453 EL_INTERNAL_CASCADE_SB,
4454 EL_INTERNAL_CASCADE_SP,
4455 EL_INTERNAL_CASCADE_DC,
4456 EL_INTERNAL_CASCADE_DX,
4457 EL_INTERNAL_CASCADE_MM,
4458 EL_INTERNAL_CASCADE_DF,
4459 EL_INTERNAL_CASCADE_CHARS,
4460 EL_INTERNAL_CASCADE_STEEL_CHARS,
4461 EL_INTERNAL_CASCADE_CE,
4462 EL_INTERNAL_CASCADE_GE,
4463 EL_INTERNAL_CASCADE_ES,
4464 EL_INTERNAL_CASCADE_REF,
4465 EL_INTERNAL_CASCADE_USER,
4466 EL_INTERNAL_CASCADE_DYNAMIC,
4471 static int ep_obsolete[] =
4475 EL_EM_KEY_1_FILE_OBSOLETE,
4476 EL_EM_KEY_2_FILE_OBSOLETE,
4477 EL_EM_KEY_3_FILE_OBSOLETE,
4478 EL_EM_KEY_4_FILE_OBSOLETE,
4479 EL_ENVELOPE_OBSOLETE,
4488 } element_properties[] =
4490 { ep_diggable, EP_DIGGABLE },
4491 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4492 { ep_dont_run_into, EP_DONT_RUN_INTO },
4493 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4494 { ep_dont_touch, EP_DONT_TOUCH },
4495 { ep_indestructible, EP_INDESTRUCTIBLE },
4496 { ep_slippery, EP_SLIPPERY },
4497 { ep_can_change, EP_CAN_CHANGE },
4498 { ep_can_move, EP_CAN_MOVE },
4499 { ep_can_fall, EP_CAN_FALL },
4500 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4501 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4502 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4503 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4504 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4505 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4506 { ep_walkable_over, EP_WALKABLE_OVER },
4507 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4508 { ep_walkable_under, EP_WALKABLE_UNDER },
4509 { ep_passable_over, EP_PASSABLE_OVER },
4510 { ep_passable_inside, EP_PASSABLE_INSIDE },
4511 { ep_passable_under, EP_PASSABLE_UNDER },
4512 { ep_droppable, EP_DROPPABLE },
4513 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4514 { ep_pushable, EP_PUSHABLE },
4515 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4516 { ep_protected, EP_PROTECTED },
4517 { ep_throwable, EP_THROWABLE },
4518 { ep_can_explode, EP_CAN_EXPLODE },
4519 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4521 { ep_empty_space, EP_EMPTY_SPACE },
4522 { ep_player, EP_PLAYER },
4523 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4524 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4525 { ep_switchable, EP_SWITCHABLE },
4526 { ep_bd_element, EP_BD_ELEMENT },
4527 { ep_sp_element, EP_SP_ELEMENT },
4528 { ep_sb_element, EP_SB_ELEMENT },
4530 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4531 { ep_food_penguin, EP_FOOD_PENGUIN },
4532 { ep_food_pig, EP_FOOD_PIG },
4533 { ep_historic_wall, EP_HISTORIC_WALL },
4534 { ep_historic_solid, EP_HISTORIC_SOLID },
4535 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4536 { ep_belt, EP_BELT },
4537 { ep_belt_active, EP_BELT_ACTIVE },
4538 { ep_belt_switch, EP_BELT_SWITCH },
4539 { ep_tube, EP_TUBE },
4540 { ep_acid_pool, EP_ACID_POOL },
4541 { ep_keygate, EP_KEYGATE },
4542 { ep_amoeboid, EP_AMOEBOID },
4543 { ep_amoebalive, EP_AMOEBALIVE },
4544 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4545 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4546 { ep_can_grow, EP_CAN_GROW },
4547 { ep_active_bomb, EP_ACTIVE_BOMB },
4548 { ep_inactive, EP_INACTIVE },
4550 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4552 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4554 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4555 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4557 { ep_obsolete, EP_OBSOLETE },
4564 // always start with reliable default values (element has no properties)
4565 // (but never initialize clipboard elements after the very first time)
4566 // (to be able to use clipboard elements between several levels)
4567 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4568 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4569 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4570 SET_PROPERTY(i, j, FALSE);
4572 // set all base element properties from above array definitions
4573 for (i = 0; element_properties[i].elements != NULL; i++)
4574 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4575 SET_PROPERTY((element_properties[i].elements)[j],
4576 element_properties[i].property, TRUE);
4578 // copy properties to some elements that are only stored in level file
4579 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4580 for (j = 0; copy_properties[j][0] != -1; j++)
4581 if (HAS_PROPERTY(copy_properties[j][0], i))
4582 for (k = 1; k <= 4; k++)
4583 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4585 // set static element properties that are not listed in array definitions
4586 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4587 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4589 clipboard_elements_initialized = TRUE;
4592 void InitElementPropertiesEngine(int engine_version)
4594 static int no_wall_properties[] =
4597 EP_COLLECTIBLE_ONLY,
4599 EP_DONT_COLLIDE_WITH,
4602 EP_CAN_SMASH_PLAYER,
4603 EP_CAN_SMASH_ENEMIES,
4604 EP_CAN_SMASH_EVERYTHING,
4609 EP_FOOD_DARK_YAMYAM,
4625 /* important: after initialization in InitElementPropertiesStatic(), the
4626 elements are not again initialized to a default value; therefore all
4627 changes have to make sure that they leave the element with a defined
4628 property (which means that conditional property changes must be set to
4629 a reliable default value before) */
4631 // resolve group elements
4632 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4633 ResolveGroupElement(EL_GROUP_START + i);
4635 // set all special, combined or engine dependent element properties
4636 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4638 // do not change (already initialized) clipboard elements here
4639 if (IS_CLIPBOARD_ELEMENT(i))
4642 // ---------- INACTIVE ----------------------------------------------------
4643 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4644 i <= EL_CHAR_END) ||
4645 (i >= EL_STEEL_CHAR_START &&
4646 i <= EL_STEEL_CHAR_END)));
4648 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4649 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4650 IS_WALKABLE_INSIDE(i) ||
4651 IS_WALKABLE_UNDER(i)));
4653 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4654 IS_PASSABLE_INSIDE(i) ||
4655 IS_PASSABLE_UNDER(i)));
4657 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4658 IS_PASSABLE_OVER(i)));
4660 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4661 IS_PASSABLE_INSIDE(i)));
4663 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4664 IS_PASSABLE_UNDER(i)));
4666 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4669 // ---------- COLLECTIBLE -------------------------------------------------
4670 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4674 // ---------- SNAPPABLE ---------------------------------------------------
4675 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4676 IS_COLLECTIBLE(i) ||
4680 // ---------- WALL --------------------------------------------------------
4681 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4683 for (j = 0; no_wall_properties[j] != -1; j++)
4684 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4685 i >= EL_FIRST_RUNTIME_UNREAL)
4686 SET_PROPERTY(i, EP_WALL, FALSE);
4688 if (IS_HISTORIC_WALL(i))
4689 SET_PROPERTY(i, EP_WALL, TRUE);
4691 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4692 if (engine_version < VERSION_IDENT(2,2,0,0))
4693 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4695 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4697 !IS_COLLECTIBLE(i)));
4699 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4700 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4701 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4703 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4706 // ---------- EXPLOSION_PROOF ---------------------------------------------
4708 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4709 else if (engine_version < VERSION_IDENT(2,2,0,0))
4710 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4712 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4716 if (IS_CUSTOM_ELEMENT(i))
4718 // these are additional properties which are initially false when set
4720 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4722 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4723 if (DONT_COLLIDE_WITH(i))
4724 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4726 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4727 if (CAN_SMASH_EVERYTHING(i))
4728 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4729 if (CAN_SMASH_ENEMIES(i))
4730 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4733 // ---------- CAN_SMASH ---------------------------------------------------
4734 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4735 CAN_SMASH_ENEMIES(i) ||
4736 CAN_SMASH_EVERYTHING(i)));
4738 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4739 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4740 EXPLODES_BY_FIRE(i)));
4742 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4743 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4744 EXPLODES_SMASHED(i)));
4746 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4747 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4748 EXPLODES_IMPACT(i)));
4750 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4751 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4753 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4754 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4755 i == EL_BLACK_ORB));
4757 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4758 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4760 IS_CUSTOM_ELEMENT(i)));
4762 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4763 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4764 i == EL_SP_ELECTRON));
4766 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4767 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4768 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4769 getMoveIntoAcidProperty(&level, i));
4771 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4772 if (MAYBE_DONT_COLLIDE_WITH(i))
4773 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4774 getDontCollideWithProperty(&level, i));
4776 // ---------- SP_PORT -----------------------------------------------------
4777 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4778 IS_PASSABLE_INSIDE(i)));
4780 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4781 for (j = 0; j < level.num_android_clone_elements; j++)
4782 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4784 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4786 // ---------- CAN_CHANGE --------------------------------------------------
4787 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4788 for (j = 0; j < element_info[i].num_change_pages; j++)
4789 if (element_info[i].change_page[j].can_change)
4790 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4792 // ---------- HAS_ACTION --------------------------------------------------
4793 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4794 for (j = 0; j < element_info[i].num_change_pages; j++)
4795 if (element_info[i].change_page[j].has_action)
4796 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4798 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4799 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4802 // ---------- GFX_CRUMBLED ------------------------------------------------
4803 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4804 element_info[i].crumbled[ACTION_DEFAULT] !=
4805 element_info[i].graphic[ACTION_DEFAULT]);
4807 // ---------- EDITOR_CASCADE ----------------------------------------------
4808 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4809 IS_EDITOR_CASCADE_INACTIVE(i)));
4812 // dynamically adjust element properties according to game engine version
4814 static int ep_em_slippery_wall[] =
4819 EL_EXPANDABLE_WALL_HORIZONTAL,
4820 EL_EXPANDABLE_WALL_VERTICAL,
4821 EL_EXPANDABLE_WALL_ANY,
4822 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4823 EL_EXPANDABLE_STEELWALL_VERTICAL,
4824 EL_EXPANDABLE_STEELWALL_ANY,
4825 EL_EXPANDABLE_STEELWALL_GROWING,
4829 static int ep_em_explodes_by_fire[] =
4832 EL_EM_DYNAMITE_ACTIVE,
4837 // special EM style gems behaviour
4838 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4839 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4840 level.em_slippery_gems);
4842 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4843 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4844 (level.em_slippery_gems &&
4845 engine_version > VERSION_IDENT(2,0,1,0)));
4847 // special EM style explosion behaviour regarding chain reactions
4848 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4849 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4850 level.em_explodes_by_fire);
4853 // this is needed because some graphics depend on element properties
4854 if (game_status == GAME_MODE_PLAYING)
4855 InitElementGraphicInfo();
4858 void InitElementPropertiesGfxElement(void)
4862 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4864 struct ElementInfo *ei = &element_info[i];
4866 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4870 static void InitGlobal(void)
4875 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4877 // check if element_name_info entry defined for each element in "main.h"
4878 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4879 Fail("undefined 'element_name_info' entry for element %d", i);
4881 element_info[i].token_name = element_name_info[i].token_name;
4882 element_info[i].class_name = element_name_info[i].class_name;
4883 element_info[i].editor_description= element_name_info[i].editor_description;
4886 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4888 // check if global_anim_name_info defined for each entry in "main.h"
4889 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4890 global_anim_name_info[i].token_name == NULL)
4891 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4893 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4896 // create hash from image config list
4897 image_config_hash = newSetupFileHash();
4898 for (i = 0; image_config[i].token != NULL; i++)
4899 setHashEntry(image_config_hash,
4900 image_config[i].token,
4901 image_config[i].value);
4903 // create hash from element token list
4904 element_token_hash = newSetupFileHash();
4905 for (i = 0; element_name_info[i].token_name != NULL; i++)
4906 setHashEntry(element_token_hash,
4907 element_name_info[i].token_name,
4910 // create hash from graphic token list
4911 graphic_token_hash = newSetupFileHash();
4912 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4913 if (strSuffix(image_config[i].value, ".png") ||
4914 strSuffix(image_config[i].value, ".pcx") ||
4915 strSuffix(image_config[i].value, ".wav") ||
4916 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4917 setHashEntry(graphic_token_hash,
4918 image_config[i].token,
4919 int2str(graphic++, 0));
4921 // create hash from font token list
4922 font_token_hash = newSetupFileHash();
4923 for (i = 0; font_info[i].token_name != NULL; i++)
4924 setHashEntry(font_token_hash,
4925 font_info[i].token_name,
4928 // set default filenames for all cloned graphics in static configuration
4929 for (i = 0; image_config[i].token != NULL; i++)
4931 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4933 char *token = image_config[i].token;
4934 char *token_clone_from = getStringCat2(token, ".clone_from");
4935 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4937 if (token_cloned != NULL)
4939 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4941 if (value_cloned != NULL)
4943 // set default filename in static configuration
4944 image_config[i].value = value_cloned;
4946 // set default filename in image config hash
4947 setHashEntry(image_config_hash, token, value_cloned);
4951 free(token_clone_from);
4955 // always start with reliable default values (all elements)
4956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4957 ActiveElement[i] = i;
4959 // now add all entries that have an active state (active elements)
4960 for (i = 0; element_with_active_state[i].element != -1; i++)
4962 int element = element_with_active_state[i].element;
4963 int element_active = element_with_active_state[i].element_active;
4965 ActiveElement[element] = element_active;
4968 // always start with reliable default values (all buttons)
4969 for (i = 0; i < NUM_IMAGE_FILES; i++)
4970 ActiveButton[i] = i;
4972 // now add all entries that have an active state (active buttons)
4973 for (i = 0; button_with_active_state[i].button != -1; i++)
4975 int button = button_with_active_state[i].button;
4976 int button_active = button_with_active_state[i].button_active;
4978 ActiveButton[button] = button_active;
4981 // always start with reliable default values (all fonts)
4982 for (i = 0; i < NUM_FONTS; i++)
4985 // now add all entries that have an active state (active fonts)
4986 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4988 int font = font_with_active_state[i].font_nr;
4989 int font_active = font_with_active_state[i].font_nr_active;
4991 ActiveFont[font] = font_active;
4994 global.autoplay_leveldir = NULL;
4995 global.patchtapes_leveldir = NULL;
4996 global.convert_leveldir = NULL;
4997 global.dumplevel_leveldir = NULL;
4998 global.dumptape_leveldir = NULL;
4999 global.create_sketch_images_dir = NULL;
5000 global.create_collect_images_dir = NULL;
5002 global.frames_per_second = 0;
5003 global.show_frames_per_second = FALSE;
5005 global.border_status = GAME_MODE_LOADING;
5006 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5008 global.use_envelope_request = FALSE;
5010 global.user_names = NULL;
5013 static void Execute_Command(char *command)
5017 if (strEqual(command, "print graphicsinfo.conf"))
5019 Print("# You can configure additional/alternative image files here.\n");
5020 Print("# (The entries below are default and therefore commented out.)\n");
5022 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5024 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5027 for (i = 0; image_config[i].token != NULL; i++)
5028 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5029 image_config[i].value));
5033 else if (strEqual(command, "print soundsinfo.conf"))
5035 Print("# You can configure additional/alternative sound files here.\n");
5036 Print("# (The entries below are default and therefore commented out.)\n");
5038 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5040 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5043 for (i = 0; sound_config[i].token != NULL; i++)
5044 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5045 sound_config[i].value));
5049 else if (strEqual(command, "print musicinfo.conf"))
5051 Print("# You can configure additional/alternative music files here.\n");
5052 Print("# (The entries below are default and therefore commented out.)\n");
5054 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5056 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5059 for (i = 0; music_config[i].token != NULL; i++)
5060 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5061 music_config[i].value));
5065 else if (strEqual(command, "print editorsetup.conf"))
5067 Print("# You can configure your personal editor element list here.\n");
5068 Print("# (The entries below are default and therefore commented out.)\n");
5071 // this is needed to be able to check element list for cascade elements
5072 InitElementPropertiesStatic();
5073 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5075 PrintEditorElementList();
5079 else if (strEqual(command, "print helpanim.conf"))
5081 Print("# You can configure different element help animations here.\n");
5082 Print("# (The entries below are default and therefore commented out.)\n");
5085 for (i = 0; helpanim_config[i].token != NULL; i++)
5087 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5088 helpanim_config[i].value));
5090 if (strEqual(helpanim_config[i].token, "end"))
5096 else if (strEqual(command, "print helptext.conf"))
5098 Print("# You can configure different element help text here.\n");
5099 Print("# (The entries below are default and therefore commented out.)\n");
5102 for (i = 0; helptext_config[i].token != NULL; i++)
5103 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5104 helptext_config[i].value));
5108 else if (strPrefix(command, "dump level "))
5110 char *filename = &command[11];
5112 if (fileExists(filename))
5114 LoadLevelFromFilename(&level, filename);
5120 char *leveldir = getStringCopy(filename); // read command parameters
5121 char *level_nr = strchr(leveldir, ' ');
5123 if (level_nr == NULL)
5124 Fail("cannot open file '%s'", filename);
5128 global.dumplevel_leveldir = leveldir;
5129 global.dumplevel_level_nr = atoi(level_nr);
5131 program.headless = TRUE;
5133 else if (strPrefix(command, "dump tape "))
5135 char *filename = &command[10];
5137 if (fileExists(filename))
5139 LoadTapeFromFilename(filename);
5145 char *leveldir = getStringCopy(filename); // read command parameters
5146 char *level_nr = strchr(leveldir, ' ');
5148 if (level_nr == NULL)
5149 Fail("cannot open file '%s'", filename);
5153 global.dumptape_leveldir = leveldir;
5154 global.dumptape_level_nr = atoi(level_nr);
5156 program.headless = TRUE;
5158 else if (strPrefix(command, "autoplay ") ||
5159 strPrefix(command, "autoffwd ") ||
5160 strPrefix(command, "autowarp ") ||
5161 strPrefix(command, "autotest ") ||
5162 strPrefix(command, "autosave ") ||
5163 strPrefix(command, "autoupload ") ||
5164 strPrefix(command, "autofix "))
5166 char *arg_ptr = strchr(command, ' ');
5167 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5169 global.autoplay_mode =
5170 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5171 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5172 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5173 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5174 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5175 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5176 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5177 AUTOPLAY_MODE_NONE);
5179 while (*str_ptr != '\0') // continue parsing string
5181 // cut leading whitespace from string, replace it by string terminator
5182 while (*str_ptr == ' ' || *str_ptr == '\t')
5185 if (*str_ptr == '\0') // end of string reached
5188 if (global.autoplay_leveldir == NULL) // read level set string
5190 global.autoplay_leveldir = str_ptr;
5191 global.autoplay_all = TRUE; // default: play all tapes
5193 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5194 global.autoplay_level[i] = FALSE;
5196 else // read level number string
5198 int level_nr = atoi(str_ptr); // get level_nr value
5200 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5201 global.autoplay_level[level_nr] = TRUE;
5203 global.autoplay_all = FALSE;
5206 // advance string pointer to the next whitespace (or end of string)
5207 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5211 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5212 program.headless = TRUE;
5214 else if (strPrefix(command, "patch tapes "))
5216 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5218 // skip leading whitespace
5219 while (*str_ptr == ' ' || *str_ptr == '\t')
5222 if (*str_ptr == '\0')
5223 Fail("cannot find MODE in command '%s'", command);
5225 global.patchtapes_mode = str_ptr; // store patch mode
5227 // advance to next whitespace (or end of string)
5228 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5231 while (*str_ptr != '\0') // continue parsing string
5233 // cut leading whitespace from string, replace it by string terminator
5234 while (*str_ptr == ' ' || *str_ptr == '\t')
5237 if (*str_ptr == '\0') // end of string reached
5240 if (global.patchtapes_leveldir == NULL) // read level set string
5242 global.patchtapes_leveldir = str_ptr;
5243 global.patchtapes_all = TRUE; // default: patch all tapes
5245 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5246 global.patchtapes_level[i] = FALSE;
5248 else // read level number string
5250 int level_nr = atoi(str_ptr); // get level_nr value
5252 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5253 global.patchtapes_level[level_nr] = TRUE;
5255 global.patchtapes_all = FALSE;
5258 // advance string pointer to the next whitespace (or end of string)
5259 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5263 if (global.patchtapes_leveldir == NULL)
5265 if (strEqual(global.patchtapes_mode, "help"))
5266 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5268 Fail("cannot find LEVELDIR in command '%s'", command);
5271 program.headless = TRUE;
5273 else if (strPrefix(command, "convert "))
5275 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5276 char *str_ptr = strchr(str_copy, ' ');
5278 global.convert_leveldir = str_copy;
5279 global.convert_level_nr = -1;
5281 if (str_ptr != NULL) // level number follows
5283 *str_ptr++ = '\0'; // terminate leveldir string
5284 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5287 program.headless = TRUE;
5289 else if (strPrefix(command, "create sketch images "))
5291 global.create_sketch_images_dir = getStringCopy(&command[21]);
5293 if (access(global.create_sketch_images_dir, W_OK) != 0)
5294 Fail("image target directory '%s' not found or not writable",
5295 global.create_sketch_images_dir);
5297 else if (strPrefix(command, "create collect image "))
5299 global.create_collect_images_dir = getStringCopy(&command[21]);
5301 if (access(global.create_collect_images_dir, W_OK) != 0)
5302 Fail("image target directory '%s' not found or not writable",
5303 global.create_collect_images_dir);
5305 else if (strPrefix(command, "create CE image "))
5307 CreateCustomElementImages(&command[16]);
5313 FailWithHelp("unrecognized command '%s'", command);
5316 // disable networking if any valid command was recognized
5317 options.network = setup.network_mode = FALSE;
5320 static void InitSetup(void)
5322 LoadUserNames(); // global user names
5323 LoadUserSetup(); // global user number
5325 LoadSetup(); // global setup info
5327 // set some options from setup file
5329 if (setup.options.verbose)
5330 options.verbose = TRUE;
5332 if (setup.debug.show_frames_per_second)
5333 global.show_frames_per_second = TRUE;
5336 static void InitGameInfo(void)
5338 game.restart_level = FALSE;
5339 game.restart_game_message = NULL;
5341 game.request_active = FALSE;
5342 game.request_active_or_moving = FALSE;
5344 game.use_masked_elements_initial = FALSE;
5347 static void InitPlayerInfo(void)
5351 // choose default local player
5352 local_player = &stored_player[0];
5354 for (i = 0; i < MAX_PLAYERS; i++)
5356 stored_player[i].connected_locally = FALSE;
5357 stored_player[i].connected_network = FALSE;
5360 local_player->connected_locally = TRUE;
5363 static void InitArtworkInfo(void)
5368 static char *get_string_in_brackets(char *string)
5370 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5372 sprintf(string_in_brackets, "[%s]", string);
5374 return string_in_brackets;
5377 static char *get_level_id_suffix(int id_nr)
5379 char *id_suffix = checked_malloc(1 + 3 + 1);
5381 if (id_nr < 0 || id_nr > 999)
5384 sprintf(id_suffix, ".%03d", id_nr);
5389 static void InitArtworkConfig(void)
5391 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5393 NUM_GLOBAL_ANIM_TOKENS + 1];
5394 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5395 NUM_GLOBAL_ANIM_TOKENS + 1];
5396 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5397 NUM_GLOBAL_ANIM_TOKENS + 1];
5398 static char *action_id_suffix[NUM_ACTIONS + 1];
5399 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5400 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5401 static char *level_id_suffix[MAX_LEVELS + 1];
5402 static char *dummy[1] = { NULL };
5403 static char *ignore_generic_tokens[] =
5408 "program_copyright",
5413 static char **ignore_image_tokens;
5414 static char **ignore_sound_tokens;
5415 static char **ignore_music_tokens;
5416 int num_ignore_generic_tokens;
5417 int num_ignore_image_tokens;
5418 int num_ignore_sound_tokens;
5419 int num_ignore_music_tokens;
5422 // dynamically determine list of generic tokens to be ignored
5423 num_ignore_generic_tokens = 0;
5424 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5425 num_ignore_generic_tokens++;
5427 // dynamically determine list of image tokens to be ignored
5428 num_ignore_image_tokens = num_ignore_generic_tokens;
5429 for (i = 0; image_config_vars[i].token != NULL; i++)
5430 num_ignore_image_tokens++;
5431 ignore_image_tokens =
5432 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5433 for (i = 0; i < num_ignore_generic_tokens; i++)
5434 ignore_image_tokens[i] = ignore_generic_tokens[i];
5435 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5436 ignore_image_tokens[num_ignore_generic_tokens + i] =
5437 image_config_vars[i].token;
5438 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5440 // dynamically determine list of sound tokens to be ignored
5441 num_ignore_sound_tokens = num_ignore_generic_tokens;
5442 ignore_sound_tokens =
5443 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5444 for (i = 0; i < num_ignore_generic_tokens; i++)
5445 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5446 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5448 // dynamically determine list of music tokens to be ignored
5449 num_ignore_music_tokens = num_ignore_generic_tokens;
5450 ignore_music_tokens =
5451 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5452 for (i = 0; i < num_ignore_generic_tokens; i++)
5453 ignore_music_tokens[i] = ignore_generic_tokens[i];
5454 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5456 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5457 image_id_prefix[i] = element_info[i].token_name;
5458 for (i = 0; i < NUM_FONTS; i++)
5459 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5460 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5461 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5462 global_anim_info[i].token_name;
5463 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5465 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5466 sound_id_prefix[i] = element_info[i].token_name;
5467 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5468 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5469 get_string_in_brackets(element_info[i].class_name);
5470 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5471 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5472 global_anim_info[i].token_name;
5473 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5475 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5476 music_id_prefix[i] = music_prefix_info[i].prefix;
5477 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5478 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5479 global_anim_info[i].token_name;
5480 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5482 for (i = 0; i < NUM_ACTIONS; i++)
5483 action_id_suffix[i] = element_action_info[i].suffix;
5484 action_id_suffix[NUM_ACTIONS] = NULL;
5486 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5487 direction_id_suffix[i] = element_direction_info[i].suffix;
5488 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5490 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5491 special_id_suffix[i] = special_suffix_info[i].suffix;
5492 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5494 for (i = 0; i < MAX_LEVELS; i++)
5495 level_id_suffix[i] = get_level_id_suffix(i);
5496 level_id_suffix[MAX_LEVELS] = NULL;
5498 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5499 image_id_prefix, action_id_suffix, direction_id_suffix,
5500 special_id_suffix, ignore_image_tokens);
5501 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5502 sound_id_prefix, action_id_suffix, dummy,
5503 special_id_suffix, ignore_sound_tokens);
5504 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5505 music_id_prefix, action_id_suffix, special_id_suffix,
5506 level_id_suffix, ignore_music_tokens);
5509 static void InitMixer(void)
5516 static void InitVideoOverlay(void)
5518 // if virtual buttons are not loaded from setup file, repeat initializing
5519 // virtual buttons grid with default values now that video is initialized
5520 if (!setup.touch.grid_initialized)
5523 InitTileCursorInfo();
5527 void InitGfxBuffers(void)
5529 static int win_xsize_last = -1;
5530 static int win_ysize_last = -1;
5532 // create additional image buffers for double-buffering and cross-fading
5534 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5536 // used to temporarily store the backbuffer -- only re-create if changed
5537 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5538 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5540 win_xsize_last = WIN_XSIZE;
5541 win_ysize_last = WIN_YSIZE;
5544 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5545 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5546 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5547 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5549 // initialize screen properties
5550 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5551 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5553 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5554 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5555 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5556 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5557 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5558 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5560 // required if door size definitions have changed
5561 InitGraphicCompatibilityInfo_Doors();
5563 InitGfxBuffers_EM();
5564 InitGfxBuffers_SP();
5567 static void InitGfx(void)
5569 struct GraphicInfo *graphic_info_last = graphic_info;
5570 char *filename_font_initial = NULL;
5571 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5572 char *image_token[NUM_INITIAL_IMAGES] =
5574 CONFIG_TOKEN_GLOBAL_BUSY,
5575 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5576 CONFIG_TOKEN_BACKGROUND_LOADING
5578 Bitmap *bitmap_font_initial = NULL;
5579 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5582 // determine settings for initial font (for displaying startup messages)
5583 for (i = 0; image_config[i].token != NULL; i++)
5585 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5587 char font_token[128];
5590 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5591 len_font_token = strlen(font_token);
5593 if (strEqual(image_config[i].token, font_token))
5595 filename_font_initial = image_config[i].value;
5597 else if (strlen(image_config[i].token) > len_font_token &&
5598 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5600 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5601 font_initial[j].src_x = atoi(image_config[i].value);
5602 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5603 font_initial[j].src_y = atoi(image_config[i].value);
5604 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5605 font_initial[j].width = atoi(image_config[i].value);
5606 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5607 font_initial[j].height = atoi(image_config[i].value);
5612 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5614 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5615 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5618 if (filename_font_initial == NULL) // should not happen
5619 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5622 InitGfxCustomArtworkInfo();
5623 InitGfxOtherSettings();
5625 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5627 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5629 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5630 font_initial[j].bitmap = bitmap_font_initial;
5632 InitFontGraphicInfo();
5636 DrawInitTextHead("Loading graphics");
5638 InitMenuDesignSettings_Static();
5640 // initialize settings for initial images with default values
5641 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5642 for (j = 0; j < NUM_GFX_ARGS; j++)
5644 get_graphic_parameter_value(image_config_suffix[j].value,
5645 image_config_suffix[j].token,
5646 image_config_suffix[j].type);
5648 // read settings for initial images from default custom artwork config
5649 char *gfx_config_filename = getPath3(options.graphics_directory,
5651 GRAPHICSINFO_FILENAME);
5653 if (fileExists(gfx_config_filename))
5655 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5657 if (setup_file_hash)
5659 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5661 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5665 filename_image_initial[i] = getStringCopy(filename);
5667 for (j = 0; image_config_suffix[j].token != NULL; j++)
5669 int type = image_config_suffix[j].type;
5670 char *suffix = image_config_suffix[j].token;
5671 char *token = getStringCat2(image_token[i], suffix);
5672 char *value = getHashEntry(setup_file_hash, token);
5674 checked_free(token);
5678 get_graphic_parameter_value(value, suffix, type);
5683 // read values from custom graphics config file
5684 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5686 freeSetupFileHash(setup_file_hash);
5690 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5692 if (filename_image_initial[i] == NULL)
5694 int len_token = strlen(image_token[i]);
5696 // read settings for initial images from static default artwork config
5697 for (j = 0; image_config[j].token != NULL; j++)
5699 if (strEqual(image_config[j].token, image_token[i]))
5701 filename_image_initial[i] = getStringCopy(image_config[j].value);
5703 else if (strlen(image_config[j].token) > len_token &&
5704 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5706 for (k = 0; image_config_suffix[k].token != NULL; k++)
5708 if (strEqual(&image_config[j].token[len_token],
5709 image_config_suffix[k].token))
5711 get_graphic_parameter_value(image_config[j].value,
5712 image_config_suffix[k].token,
5713 image_config_suffix[k].type);
5720 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5722 if (filename_image_initial[i] == NULL) // should not happen
5723 Fail("cannot get filename for '%s'", image_token[i]);
5725 image_initial[i].bitmaps =
5726 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5728 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5729 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5730 LoadCustomImage(filename_image_initial[i]);
5732 checked_free(filename_image_initial[i]);
5735 graphic_info = image_initial; // graphic == 0 => image_initial
5737 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5738 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5740 graphic_info = graphic_info_last;
5742 SetLoadingBackgroundImage();
5744 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5746 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5747 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5748 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5749 InitGfxDrawTileCursorFunction(DrawTileCursor);
5751 gfx.fade_border_source_status = global.border_status;
5752 gfx.fade_border_target_status = global.border_status;
5753 gfx.masked_border_bitmap_ptr = backbuffer;
5755 // use copy of busy animation to prevent change while reloading artwork
5759 static void InitGfxBackground(void)
5761 fieldbuffer = bitmap_db_field;
5762 SetDrawtoField(DRAW_TO_BACKBUFFER);
5764 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5766 redraw_mask = REDRAW_ALL;
5769 static void InitLevelInfo(void)
5771 LoadLevelInfo(); // global level info
5772 LoadLevelSetup_LastSeries(); // last played series info
5773 LoadLevelSetup_SeriesInfo(); // last played level info
5775 if (global.autoplay_leveldir &&
5776 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5778 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5779 global.autoplay_leveldir);
5780 if (leveldir_current == NULL)
5781 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5784 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5787 static void InitLevelArtworkInfo(void)
5789 LoadLevelArtworkInfo();
5792 static void InitImages(void)
5794 print_timestamp_init("InitImages");
5797 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5798 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5799 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5800 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5801 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5802 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5803 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5804 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5807 setLevelArtworkDir(artwork.gfx_first);
5810 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5811 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5812 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5813 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5814 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5815 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5816 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5817 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5821 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5822 leveldir_current->identifier,
5823 artwork.gfx_current_identifier,
5824 artwork.gfx_current->identifier,
5825 leveldir_current->graphics_set,
5826 leveldir_current->graphics_path);
5829 UPDATE_BUSY_STATE();
5831 ReloadCustomImages();
5832 print_timestamp_time("ReloadCustomImages");
5834 UPDATE_BUSY_STATE();
5836 LoadCustomElementDescriptions();
5837 print_timestamp_time("LoadCustomElementDescriptions");
5839 UPDATE_BUSY_STATE();
5841 LoadMenuDesignSettings();
5842 print_timestamp_time("LoadMenuDesignSettings");
5844 UPDATE_BUSY_STATE();
5846 ReinitializeGraphics();
5847 print_timestamp_time("ReinitializeGraphics");
5849 LoadMenuDesignSettings_AfterGraphics();
5850 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5852 UPDATE_BUSY_STATE();
5854 print_timestamp_done("InitImages");
5857 static void InitSound(char *identifier)
5859 print_timestamp_init("InitSound");
5861 if (identifier == NULL)
5862 identifier = artwork.snd_current->identifier;
5864 // set artwork path to send it to the sound server process
5865 setLevelArtworkDir(artwork.snd_first);
5867 InitReloadCustomSounds(identifier);
5868 print_timestamp_time("InitReloadCustomSounds");
5870 ReinitializeSounds();
5871 print_timestamp_time("ReinitializeSounds");
5873 print_timestamp_done("InitSound");
5876 static void InitMusic(char *identifier)
5878 print_timestamp_init("InitMusic");
5880 if (identifier == NULL)
5881 identifier = artwork.mus_current->identifier;
5883 // set artwork path to send it to the sound server process
5884 setLevelArtworkDir(artwork.mus_first);
5886 InitReloadCustomMusic(identifier);
5887 print_timestamp_time("InitReloadCustomMusic");
5889 ReinitializeMusic();
5890 print_timestamp_time("ReinitializeMusic");
5892 print_timestamp_done("InitMusic");
5895 static void InitArtworkDone(void)
5897 if (program.headless)
5900 InitGlobalAnimations();
5903 static void InitNetworkSettings(void)
5905 boolean network_enabled = (options.network || setup.network_mode);
5906 char *network_server = (options.server_host != NULL ? options.server_host :
5907 setup.network_server_hostname);
5909 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5910 network_server = NULL;
5912 InitNetworkInfo(network_enabled,
5916 options.server_port);
5919 void InitNetworkServer(void)
5921 if (!network.enabled || network.connected)
5924 LimitScreenUpdates(FALSE);
5926 if (game_status == GAME_MODE_LOADING)
5929 if (!ConnectToServer(network.server_host, network.server_port))
5931 network.enabled = FALSE;
5933 setup.network_mode = FALSE;
5937 SendToServer_ProtocolVersion();
5938 SendToServer_PlayerName(setup.player_name);
5939 SendToServer_NrWanted(setup.network_player_nr + 1);
5941 network.connected = TRUE;
5944 // short time to recognize result of network initialization
5945 if (game_status == GAME_MODE_LOADING)
5946 Delay_WithScreenUpdates(1000);
5949 static boolean CheckArtworkConfigForCustomElements(char *filename)
5951 SetupFileHash *setup_file_hash;
5952 boolean redefined_ce_found = FALSE;
5954 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5956 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5958 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5960 char *token = HASH_ITERATION_TOKEN(itr);
5962 if (strPrefix(token, "custom_"))
5964 redefined_ce_found = TRUE;
5969 END_HASH_ITERATION(setup_file_hash, itr)
5971 freeSetupFileHash(setup_file_hash);
5974 return redefined_ce_found;
5977 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5979 char *filename_base, *filename_local;
5980 boolean redefined_ce_found = FALSE;
5982 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5985 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5986 "leveldir_current->identifier == '%s'",
5987 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5988 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5989 "leveldir_current->graphics_path == '%s'",
5990 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5991 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5992 "leveldir_current->graphics_set == '%s'",
5993 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5994 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5995 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5996 leveldir_current == NULL ? "[NULL]" :
5997 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6000 // first look for special artwork configured in level series config
6001 filename_base = getCustomArtworkLevelConfigFilename(type);
6004 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6005 "filename_base == '%s'", filename_base);
6008 if (fileExists(filename_base))
6009 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6011 filename_local = getCustomArtworkConfigFilename(type);
6014 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6015 "filename_local == '%s'", filename_local);
6018 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6019 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6022 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6023 "redefined_ce_found == %d", redefined_ce_found);
6026 return redefined_ce_found;
6029 static void InitOverrideArtwork(void)
6031 boolean redefined_ce_found = FALSE;
6033 // to check if this level set redefines any CEs, do not use overriding
6034 gfx.override_level_graphics = FALSE;
6035 gfx.override_level_sounds = FALSE;
6036 gfx.override_level_music = FALSE;
6038 // now check if this level set has definitions for custom elements
6039 if (setup.override_level_graphics == AUTO ||
6040 setup.override_level_sounds == AUTO ||
6041 setup.override_level_music == AUTO)
6042 redefined_ce_found =
6043 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6044 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6045 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6048 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6049 redefined_ce_found);
6052 if (redefined_ce_found)
6054 // this level set has CE definitions: change "AUTO" to "FALSE"
6055 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6056 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6057 gfx.override_level_music = (setup.override_level_music == TRUE);
6061 // this level set has no CE definitions: change "AUTO" to "TRUE"
6062 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6063 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6064 gfx.override_level_music = (setup.override_level_music != FALSE);
6068 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6069 gfx.override_level_graphics,
6070 gfx.override_level_sounds,
6071 gfx.override_level_music);
6075 static char *getNewArtworkIdentifier(int type)
6077 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6078 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6079 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6080 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6081 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6082 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6083 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6084 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6085 char *leveldir_identifier = leveldir_current->identifier;
6086 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6087 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6088 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6089 TreeInfo *custom_artwork_set =
6090 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6091 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6092 char *artwork_current_identifier;
6093 char *artwork_new_identifier = NULL; // default: nothing has changed
6095 // leveldir_current may be invalid (level group, parent link)
6096 if (!validLevelSeries(leveldir_current))
6099 /* 1st step: determine artwork set to be activated in descending order:
6100 --------------------------------------------------------------------
6101 1. setup artwork (when configured to override everything else)
6102 2. artwork set configured in "levelinfo.conf" of current level set
6103 (artwork in level directory will have priority when loading later)
6104 3. artwork in level directory (stored in artwork sub-directory)
6105 4. setup artwork (currently configured in setup menu) */
6107 if (setup_override_artwork)
6108 artwork_current_identifier = setup_artwork_set;
6109 else if (has_level_artwork_set)
6110 artwork_current_identifier = leveldir_artwork_set;
6111 else if (has_custom_artwork_set)
6112 artwork_current_identifier = leveldir_identifier;
6114 artwork_current_identifier = setup_artwork_set;
6116 /* 2nd step: check if it is really needed to reload artwork set
6117 ------------------------------------------------------------ */
6119 // ---------- reload if level set and also artwork set has changed ----------
6120 if (last_leveldir_identifier[type] != leveldir_identifier &&
6121 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6122 artwork_new_identifier = artwork_current_identifier;
6124 last_leveldir_identifier[type] = leveldir_identifier;
6125 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6127 // ---------- reload if "override artwork" setting has changed --------------
6128 if (last_override_level_artwork[type] != setup_override_artwork)
6129 artwork_new_identifier = artwork_current_identifier;
6131 last_override_level_artwork[type] = setup_override_artwork;
6133 // ---------- reload if current artwork identifier has changed --------------
6134 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6135 artwork_new_identifier = artwork_current_identifier;
6137 // (we cannot compare string pointers here, so copy string content itself)
6138 setString(&last_artwork_identifier[type], artwork_current_identifier);
6140 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6142 // ---------- do not reload directly after starting -------------------------
6143 if (!initialized[type])
6144 artwork_new_identifier = NULL;
6146 initialized[type] = TRUE;
6148 return artwork_new_identifier;
6151 void ReloadCustomArtwork(int force_reload)
6153 int last_game_status = game_status; // save current game status
6154 char *gfx_new_identifier;
6155 char *snd_new_identifier;
6156 char *mus_new_identifier;
6157 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6158 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6159 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6160 boolean reload_needed;
6162 InitOverrideArtwork();
6164 AdjustGraphicsForEMC();
6165 AdjustSoundsForEMC();
6167 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6168 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6169 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6171 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6172 snd_new_identifier != NULL || force_reload_snd ||
6173 mus_new_identifier != NULL || force_reload_mus);
6178 print_timestamp_init("ReloadCustomArtwork");
6180 SetGameStatus(GAME_MODE_LOADING);
6182 FadeOut(REDRAW_ALL);
6184 SetLoadingBackgroundImage();
6186 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6187 print_timestamp_time("ClearRectangleOnBackground");
6191 UPDATE_BUSY_STATE();
6193 if (gfx_new_identifier != NULL || force_reload_gfx)
6196 Debug("init:ReloadCustomArtwork",
6197 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6198 artwork.gfx_current_identifier,
6200 artwork.gfx_current->identifier,
6201 leveldir_current->graphics_set);
6205 print_timestamp_time("InitImages");
6208 if (snd_new_identifier != NULL || force_reload_snd)
6210 InitSound(snd_new_identifier);
6211 print_timestamp_time("InitSound");
6214 if (mus_new_identifier != NULL || force_reload_mus)
6216 InitMusic(mus_new_identifier);
6217 print_timestamp_time("InitMusic");
6222 SetGameStatus(last_game_status); // restore current game status
6224 FadeOut(REDRAW_ALL);
6226 RedrawGlobalBorder();
6228 // force redraw of (open or closed) door graphics
6229 SetDoorState(DOOR_OPEN_ALL);
6230 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6232 FadeSetEnterScreen();
6233 FadeSkipNextFadeOut();
6235 print_timestamp_done("ReloadCustomArtwork");
6237 LimitScreenUpdates(FALSE);
6240 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6242 if (global.autoplay_leveldir == NULL)
6243 KeyboardAutoRepeatOff();
6246 void DisplayExitMessage(char *format, va_list ap)
6248 // also check for initialized video (headless flag may be temporarily unset)
6249 if (program.headless || !video.initialized)
6252 // check if draw buffer and fonts for exit message are already available
6253 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6256 int font_1 = FC_RED;
6257 int font_2 = FC_YELLOW;
6258 int font_3 = FC_BLUE;
6259 int font_width = getFontWidth(font_2);
6260 int font_height = getFontHeight(font_2);
6263 int sxsize = WIN_XSIZE - 2 * sx;
6264 int sysize = WIN_YSIZE - 2 * sy;
6265 int line_length = sxsize / font_width;
6266 int max_lines = sysize / font_height;
6267 int num_lines_printed;
6271 gfx.sxsize = sxsize;
6272 gfx.sysize = sysize;
6276 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6278 DrawTextSCentered(sy, font_1, "Fatal error:");
6279 sy += 3 * font_height;;
6282 DrawTextBufferVA(sx, sy, format, ap, font_2,
6283 line_length, line_length, max_lines,
6284 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6285 sy += (num_lines_printed + 3) * font_height;
6287 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6288 sy += 3 * font_height;
6291 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6292 line_length, line_length, max_lines,
6293 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6295 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6297 redraw_mask = REDRAW_ALL;
6299 // force drawing exit message even if screen updates are currently limited
6300 LimitScreenUpdates(FALSE);
6304 // deactivate toons on error message screen
6305 setup.toons = FALSE;
6307 WaitForEventToContinue();
6311 // ============================================================================
6313 // ============================================================================
6317 print_timestamp_init("OpenAll");
6319 SetGameStatus(GAME_MODE_LOADING);
6323 InitGlobal(); // initialize some global variables
6325 InitRND(NEW_RANDOMIZE);
6326 InitSimpleRandom(NEW_RANDOMIZE);
6327 InitBetterRandom(NEW_RANDOMIZE);
6329 print_timestamp_time("[init global stuff]");
6333 print_timestamp_time("[init setup/config stuff (1)]");
6335 if (options.execute_command)
6336 Execute_Command(options.execute_command);
6338 InitNetworkSettings();
6342 if (network.serveronly)
6344 #if defined(PLATFORM_UNIX)
6345 NetworkServer(network.server_port, TRUE);
6347 Warn("networking only supported in Unix version");
6350 exit(0); // never reached, server loops forever
6354 print_timestamp_time("[init setup/config stuff (2)]");
6356 print_timestamp_time("[init setup/config stuff (3)]");
6357 InitArtworkInfo(); // needed before loading gfx, sound & music
6358 print_timestamp_time("[init setup/config stuff (4)]");
6359 InitArtworkConfig(); // needed before forking sound child process
6360 print_timestamp_time("[init setup/config stuff (5)]");
6362 print_timestamp_time("[init setup/config stuff (6)]");
6366 print_timestamp_time("[init setup/config stuff]");
6368 InitVideoDefaults();
6370 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6373 InitEventFilter(FilterMouseMotionEvents);
6375 print_timestamp_time("[init video stuff]");
6377 InitElementPropertiesStatic();
6378 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6379 InitElementPropertiesGfxElement();
6381 print_timestamp_time("[init element properties stuff]");
6385 print_timestamp_time("InitGfx");
6388 print_timestamp_time("InitLevelInfo");
6390 InitLevelArtworkInfo();
6391 print_timestamp_time("InitLevelArtworkInfo");
6393 InitOverrideArtwork(); // needs to know current level directory
6394 print_timestamp_time("InitOverrideArtwork");
6396 InitImages(); // needs to know current level directory
6397 print_timestamp_time("InitImages");
6399 InitSound(NULL); // needs to know current level directory
6400 print_timestamp_time("InitSound");
6402 InitMusic(NULL); // needs to know current level directory
6403 print_timestamp_time("InitMusic");
6407 InitGfxBackground();
6413 if (global.autoplay_leveldir)
6418 else if (global.patchtapes_leveldir)
6423 else if (global.convert_leveldir)
6428 else if (global.dumplevel_leveldir)
6433 else if (global.dumptape_leveldir)
6438 else if (global.create_sketch_images_dir)
6440 CreateLevelSketchImages();
6443 else if (global.create_collect_images_dir)
6445 CreateCollectElementImages();
6449 InitNetworkServer();
6451 SetGameStatus(GAME_MODE_MAIN);
6453 FadeSetEnterScreen();
6454 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6455 FadeSkipNextFadeOut();
6457 print_timestamp_time("[post-artwork]");
6459 print_timestamp_done("OpenAll");
6461 if (setup.ask_for_remaining_tapes)
6462 setup.ask_for_uploading_tapes = TRUE;
6467 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6469 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6470 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6471 #if defined(PLATFORM_ANDROID)
6472 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6473 SDL_AndroidGetInternalStoragePath());
6474 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6475 SDL_AndroidGetExternalStoragePath());
6476 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6477 (SDL_AndroidGetExternalStorageState() &
6478 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6479 SDL_AndroidGetExternalStorageState() &
6480 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6485 static boolean WaitForApiThreads(void)
6487 unsigned int thread_delay = 0;
6488 unsigned int thread_delay_value = 10000;
6490 if (program.api_thread_count == 0)
6493 // deactivate global animations (not accessible in game state "loading")
6494 setup.toons = FALSE;
6496 // set game state to "loading" to be able to show busy animation
6497 SetGameStatus(GAME_MODE_LOADING);
6499 ResetDelayCounter(&thread_delay);
6501 // wait for threads to finish (and fail on timeout)
6502 while (program.api_thread_count > 0)
6504 if (DelayReached(&thread_delay, thread_delay_value))
6506 Error("failed waiting for threads - TIMEOUT");
6511 UPDATE_BUSY_STATE();
6519 void CloseAllAndExit(int exit_value)
6521 WaitForApiThreads();
6526 CloseAudio(); // called after freeing sounds (needed for SDL)
6534 // set a flag to tell the network server thread to quit and wait for it
6535 // using SDL_WaitThread()
6537 // Code used with SDL 1.2:
6538 // if (network.server_thread) // terminate network server
6539 // SDL_KillThread(network.server_thread);
6541 CloseVideoDisplay();
6542 ClosePlatformDependentStuff();
6544 if (exit_value != 0 && !options.execute_command)
6546 // fall back to default level set (current set may have caused an error)
6547 SaveLevelSetup_LastSeries_Deactivate();
6549 // tell user where to find error log file which may contain more details
6550 // (error notification now directly displayed on screen inside R'n'D
6551 // NotifyUserAboutErrorFile(); // currently only works for Windows