1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY_INITIAL "global.busy_initial"
38 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
39 #define CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD "global.busy_playfield"
40 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
43 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
44 #define INITIAL_IMG_GLOBAL_BUSY 1
45 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD 2
47 #define NUM_INITIAL_IMAGES_BUSY 3
49 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 3
50 #define INITIAL_IMG_BACKGROUND_LOADING 4
52 #define NUM_INITIAL_IMAGES 5
55 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
56 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
58 static int copy_properties[][5] =
62 EL_BUG_LEFT, EL_BUG_RIGHT,
63 EL_BUG_UP, EL_BUG_DOWN
67 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
68 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
72 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
73 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
77 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
78 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
82 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
83 EL_PACMAN_UP, EL_PACMAN_DOWN
87 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
88 EL_YAMYAM_UP, EL_YAMYAM_DOWN
92 EL_MOLE_LEFT, EL_MOLE_RIGHT,
93 EL_MOLE_UP, EL_MOLE_DOWN
97 EL_SPRING_LEFT, EL_SPRING_RIGHT,
98 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
107 // forward declaration for internal use
108 static int get_graphic_parameter_value(char *, char *, int);
111 static void SetLoadingBackgroundImage(void)
113 struct GraphicInfo *graphic_info_last = graphic_info;
114 int background_image = (game_status_last_screen == -1 ?
115 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
116 INITIAL_IMG_BACKGROUND_LOADING);
118 graphic_info = image_initial;
120 SetDrawDeactivationMask(REDRAW_NONE);
121 SetDrawBackgroundMask(REDRAW_ALL);
123 SetWindowBackgroundImage(background_image);
125 graphic_info = graphic_info_last;
128 static void DrawInitAnim(boolean only_when_loading)
130 struct GraphicInfo *graphic_info_last = graphic_info;
131 int graphic = (game_status_last_screen == -1 ?
132 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
133 game_status == GAME_MODE_LOADING ?
134 INITIAL_IMG_GLOBAL_BUSY :
135 INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
136 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
137 &init_last.busy_initial :
138 game_status == GAME_MODE_LOADING ?
140 &init_last.busy_playfield);
141 static unsigned int action_delay = 0;
142 unsigned int action_delay_value = GameFrameDelay;
143 int sync_frame = FrameCounter;
146 // prevent OS (Windows) from complaining about program not responding
149 if (game_status != GAME_MODE_LOADING && only_when_loading)
152 if (image_initial[graphic].bitmap == NULL || window == NULL)
155 if (!DelayReached(&action_delay, action_delay_value))
159 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
161 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
163 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
164 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
166 graphic_info = image_initial;
168 if (sync_frame % image_initial[graphic].anim_delay == 0)
172 int width = graphic_info[graphic].width;
173 int height = graphic_info[graphic].height;
174 int frame = getGraphicAnimationFrame(graphic, sync_frame);
176 ClearRectangleOnBackground(drawto, x, y, width, height);
178 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
179 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
181 BlitBitmap(drawto, window, x, y, width, height, x, y);
184 graphic_info = graphic_info_last;
189 static void DrawProgramInfo(void)
191 int font1_nr = FC_YELLOW;
192 int font2_nr = FC_RED;
193 int font2_height = getFontHeight(font2_nr);
196 int ypos3 = WIN_YSIZE - 20 - font2_height;
198 DrawInitText(getProgramInitString(), ypos1, font1_nr);
199 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
200 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
203 static void FreeGadgets(void)
205 FreeLevelEditorGadgets();
212 void InitGadgets(void)
214 static boolean gadgets_initialized = FALSE;
216 if (gadgets_initialized)
219 CreateLevelEditorGadgets();
223 CreateScreenGadgets();
225 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
227 gadgets_initialized = TRUE;
230 static void InitElementSmallImagesScaledUp(int graphic)
232 struct GraphicInfo *g = &graphic_info[graphic];
234 // create small and game tile sized bitmaps (and scale up, if needed)
235 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
238 static void InitElementSmallImages(void)
240 print_timestamp_init("InitElementSmallImages");
242 static int special_graphics[] =
256 IMG_EDITOR_ELEMENT_BORDER,
257 IMG_EDITOR_ELEMENT_BORDER_INPUT,
258 IMG_EDITOR_CASCADE_LIST,
259 IMG_EDITOR_CASCADE_LIST_ACTIVE,
262 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
263 int num_property_mappings = getImageListPropertyMappingSize();
266 print_timestamp_time("getImageListPropertyMapping/Size");
268 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
269 // initialize normal element images from static configuration
270 for (i = 0; element_to_graphic[i].element > -1; i++)
271 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
272 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
274 // initialize special element images from static configuration
275 for (i = 0; element_to_special_graphic[i].element > -1; i++)
276 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
277 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
279 // initialize element images from dynamic configuration
280 for (i = 0; i < num_property_mappings; i++)
281 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
282 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
283 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
285 // initialize special non-element images from above list
286 for (i = 0; special_graphics[i] > -1; i++)
287 InitElementSmallImagesScaledUp(special_graphics[i]);
288 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
290 print_timestamp_done("InitElementSmallImages");
293 static void InitScaledImagesScaledUp(int graphic)
295 struct GraphicInfo *g = &graphic_info[graphic];
297 ScaleImage(graphic, g->scale_up_factor);
300 static void InitScaledImages(void)
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
306 // scale normal images from static configuration, if not already scaled
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 InitScaledImagesScaledUp(i);
310 // scale images from dynamic configuration, if not already scaled
311 for (i = 0; i < num_property_mappings; i++)
312 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
315 static void InitBitmapPointers(void)
317 int num_images = getImageListSize();
320 // standard size bitmap may have changed -- update default bitmap pointer
321 for (i = 0; i < num_images; i++)
322 if (graphic_info[i].bitmaps)
323 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
326 void InitImageTextures(void)
328 static int texture_graphics[] =
330 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
331 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
332 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
333 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
334 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
335 IMG_MENU_BUTTON_TOUCH_BACK,
336 IMG_MENU_BUTTON_TOUCH_NEXT,
337 IMG_MENU_BUTTON_TOUCH_BACK2,
338 IMG_MENU_BUTTON_TOUCH_NEXT2,
343 FreeAllImageTextures();
345 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
346 CreateImageTextures(i);
348 for (i = 0; i < MAX_NUM_TOONS; i++)
349 CreateImageTextures(IMG_TOON_1 + i);
351 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
353 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
355 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
357 int graphic = global_anim_info[i].graphic[j][k];
359 if (graphic == IMG_UNDEFINED)
362 CreateImageTextures(graphic);
367 for (i = 0; texture_graphics[i] > -1; i++)
368 CreateImageTextures(texture_graphics[i]);
371 static int getFontBitmapID(int font_nr)
375 // (special case: do not use special font for GAME_MODE_LOADING)
376 if (game_status >= GAME_MODE_TITLE_INITIAL &&
377 game_status <= GAME_MODE_PSEUDO_PREVIEW)
378 special = game_status;
379 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
380 special = GFX_SPECIAL_ARG_MAIN;
381 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
382 special = GFX_SPECIAL_ARG_NAMES;
385 return font_info[font_nr].special_bitmap_id[special];
390 static int getFontFromToken(char *token)
392 char *value = getHashEntry(font_token_hash, token);
397 // if font not found, use reliable default value
398 return FONT_INITIAL_1;
401 static void InitFontGraphicInfo(void)
403 static struct FontBitmapInfo *font_bitmap_info = NULL;
404 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
405 int num_property_mappings = getImageListPropertyMappingSize();
406 int num_font_bitmaps = NUM_FONTS;
409 if (graphic_info == NULL) // still at startup phase
411 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
412 getFontBitmapID, getFontFromToken);
417 // ---------- initialize font graphic definitions ----------
419 // always start with reliable default values (normal font graphics)
420 for (i = 0; i < NUM_FONTS; i++)
421 font_info[i].graphic = IMG_FONT_INITIAL_1;
423 // initialize normal font/graphic mapping from static configuration
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
433 font_info[font_nr].graphic = graphic;
436 // always start with reliable default values (special font graphics)
437 for (i = 0; i < NUM_FONTS; i++)
439 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
441 font_info[i].special_graphic[j] = font_info[i].graphic;
442 font_info[i].special_bitmap_id[j] = i;
446 // initialize special font/graphic mapping from static configuration
447 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
449 int font_nr = font_to_graphic[i].font_nr;
450 int special = font_to_graphic[i].special;
451 int graphic = font_to_graphic[i].graphic;
452 int base_graphic = font2baseimg(font_nr);
454 if (IS_SPECIAL_GFX_ARG(special))
456 boolean base_redefined =
457 getImageListEntryFromImageID(base_graphic)->redefined;
458 boolean special_redefined =
459 getImageListEntryFromImageID(graphic)->redefined;
460 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
462 /* if the base font ("font.title_1", for example) has been redefined,
463 but not the special font ("font.title_1.LEVELS", for example), do not
464 use an existing (in this case considered obsolete) special font
465 anymore, but use the automatically determined default font */
466 /* special case: cloned special fonts must be explicitly redefined,
467 but are not automatically redefined by redefining base font */
468 if (base_redefined && !special_redefined && !special_cloned)
471 font_info[font_nr].special_graphic[special] = graphic;
472 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
477 // initialize special font/graphic mapping from dynamic configuration
478 for (i = 0; i < num_property_mappings; i++)
480 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
481 int special = property_mapping[i].ext3_index;
482 int graphic = property_mapping[i].artwork_index;
484 if (font_nr < 0 || font_nr >= NUM_FONTS)
487 if (IS_SPECIAL_GFX_ARG(special))
489 font_info[font_nr].special_graphic[special] = graphic;
490 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
495 /* correct special font/graphic mapping for cloned fonts for downwards
496 compatibility of PREVIEW fonts -- this is only needed for implicit
497 redefinition of special font by redefined base font, and only if other
498 fonts are cloned from this special font (like in the "Zelda" level set) */
499 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
501 int font_nr = font_to_graphic[i].font_nr;
502 int special = font_to_graphic[i].special;
503 int graphic = font_to_graphic[i].graphic;
505 if (IS_SPECIAL_GFX_ARG(special))
507 boolean special_redefined =
508 getImageListEntryFromImageID(graphic)->redefined;
509 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
511 if (special_cloned && !special_redefined)
515 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
517 int font_nr2 = font_to_graphic[j].font_nr;
518 int special2 = font_to_graphic[j].special;
519 int graphic2 = font_to_graphic[j].graphic;
521 if (IS_SPECIAL_GFX_ARG(special2) &&
522 graphic2 == graphic_info[graphic].clone_from)
524 font_info[font_nr].special_graphic[special] =
525 font_info[font_nr2].special_graphic[special2];
526 font_info[font_nr].special_bitmap_id[special] =
527 font_info[font_nr2].special_bitmap_id[special2];
534 // reset non-redefined ".active" font graphics if normal font is redefined
535 // (this different treatment is needed because normal and active fonts are
536 // independently defined ("active" is not a property of font definitions!)
537 for (i = 0; i < NUM_FONTS; i++)
539 int font_nr_base = i;
540 int font_nr_active = FONT_ACTIVE(font_nr_base);
542 // check only those fonts with exist as normal and ".active" variant
543 if (font_nr_base != font_nr_active)
545 int base_graphic = font_info[font_nr_base].graphic;
546 int active_graphic = font_info[font_nr_active].graphic;
547 boolean base_redefined =
548 getImageListEntryFromImageID(base_graphic)->redefined;
549 boolean active_redefined =
550 getImageListEntryFromImageID(active_graphic)->redefined;
552 /* if the base font ("font.menu_1", for example) has been redefined,
553 but not the active font ("font.menu_1.active", for example), do not
554 use an existing (in this case considered obsolete) active font
555 anymore, but use the automatically determined default font */
556 if (base_redefined && !active_redefined)
557 font_info[font_nr_active].graphic = base_graphic;
559 // now also check each "special" font (which may be the same as above)
560 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
562 int base_graphic = font_info[font_nr_base].special_graphic[j];
563 int active_graphic = font_info[font_nr_active].special_graphic[j];
564 boolean base_redefined =
565 getImageListEntryFromImageID(base_graphic)->redefined;
566 boolean active_redefined =
567 getImageListEntryFromImageID(active_graphic)->redefined;
569 // same as above, but check special graphic definitions, for example:
570 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
571 if (base_redefined && !active_redefined)
573 font_info[font_nr_active].special_graphic[j] =
574 font_info[font_nr_base].special_graphic[j];
575 font_info[font_nr_active].special_bitmap_id[j] =
576 font_info[font_nr_base].special_bitmap_id[j];
582 // ---------- initialize font bitmap array ----------
584 if (font_bitmap_info != NULL)
585 FreeFontInfo(font_bitmap_info);
588 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
590 // ---------- initialize font bitmap definitions ----------
592 for (i = 0; i < NUM_FONTS; i++)
594 if (i < NUM_INITIAL_FONTS)
596 font_bitmap_info[i] = font_initial[i];
600 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
602 int font_bitmap_id = font_info[i].special_bitmap_id[j];
603 int graphic = font_info[i].special_graphic[j];
605 // set 'graphic_info' for font entries, if uninitialized (guessed)
606 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
608 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
609 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
612 // copy font relevant information from graphics information
613 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
614 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
615 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
616 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
617 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
619 font_bitmap_info[font_bitmap_id].offset_x =
620 graphic_info[graphic].offset_x;
621 font_bitmap_info[font_bitmap_id].offset_y =
622 graphic_info[graphic].offset_y;
624 font_bitmap_info[font_bitmap_id].draw_xoffset =
625 graphic_info[graphic].draw_xoffset;
626 font_bitmap_info[font_bitmap_id].draw_yoffset =
627 graphic_info[graphic].draw_yoffset;
629 font_bitmap_info[font_bitmap_id].num_chars =
630 graphic_info[graphic].anim_frames;
631 font_bitmap_info[font_bitmap_id].num_chars_per_line =
632 graphic_info[graphic].anim_frames_per_line;
636 InitFontInfo(font_bitmap_info, num_font_bitmaps,
637 getFontBitmapID, getFontFromToken);
640 static void InitGlobalAnimGraphicInfo(void)
642 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
643 int num_property_mappings = getImageListPropertyMappingSize();
646 if (graphic_info == NULL) // still at startup phase
649 // always start with reliable default values (no global animations)
650 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
651 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
652 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
653 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
655 // initialize global animation definitions from static configuration
656 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
658 int j = GLOBAL_ANIM_ID_PART_BASE;
659 int k = GFX_SPECIAL_ARG_DEFAULT;
661 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
664 // initialize global animation definitions from dynamic configuration
665 for (i = 0; i < num_property_mappings; i++)
667 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
668 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
669 int special = property_mapping[i].ext3_index;
670 int graphic = property_mapping[i].artwork_index;
672 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
675 // set animation part to base part, if not specified
676 if (!IS_GLOBAL_ANIM_PART(part_nr))
677 part_nr = GLOBAL_ANIM_ID_PART_BASE;
679 // set animation screen to default, if not specified
680 if (!IS_SPECIAL_GFX_ARG(special))
681 special = GFX_SPECIAL_ARG_DEFAULT;
683 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
685 // fix default value for ".draw_masked" (for backward compatibility)
686 struct GraphicInfo *g = &graphic_info[graphic];
687 struct FileInfo *image = getImageListEntryFromImageID(graphic);
688 char **parameter_raw = image->parameter;
689 int p = GFX_ARG_DRAW_MASKED;
690 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
691 image_config_suffix[p].token,
692 image_config_suffix[p].type);
694 // if ".draw_masked" parameter is undefined, use default value "TRUE"
695 if (draw_masked == ARG_UNDEFINED_VALUE)
696 g->draw_masked = TRUE;
700 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
701 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
702 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
703 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
704 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
705 Debug("init:InitGlobalAnimGraphicInfo",
706 "anim %d, part %d, mode %d => %d",
707 i, j, k, global_anim_info[i].graphic[j][k]);
711 static void InitGlobalAnimSoundInfo(void)
713 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
714 int num_property_mappings = getSoundListPropertyMappingSize();
717 // always start with reliable default values (no global animation sounds)
718 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
719 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
720 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
721 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
723 // initialize global animation sound definitions from dynamic configuration
724 for (i = 0; i < num_property_mappings; i++)
726 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
727 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
728 int special = property_mapping[i].ext3_index;
729 int sound = property_mapping[i].artwork_index;
731 // sound uses control definition; map it to position of graphic (artwork)
732 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
734 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
737 // set animation part to base part, if not specified
738 if (!IS_GLOBAL_ANIM_PART(part_nr))
739 part_nr = GLOBAL_ANIM_ID_PART_BASE;
741 // set animation screen to default, if not specified
742 if (!IS_SPECIAL_GFX_ARG(special))
743 special = GFX_SPECIAL_ARG_DEFAULT;
745 global_anim_info[anim_nr].sound[part_nr][special] = sound;
749 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
750 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
751 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
752 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
753 Debug("init:InitGlobalAnimSoundInfo",
754 "anim %d, part %d, mode %d => %d",
755 i, j, k, global_anim_info[i].sound[j][k]);
759 static void InitGlobalAnimMusicInfo(void)
761 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
762 int num_property_mappings = getMusicListPropertyMappingSize();
765 // always start with reliable default values (no global animation music)
766 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
767 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
768 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
769 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
771 // initialize global animation music definitions from dynamic configuration
772 for (i = 0; i < num_property_mappings; i++)
774 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
775 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
776 int special = property_mapping[i].ext2_index;
777 int music = property_mapping[i].artwork_index;
779 // music uses control definition; map it to position of graphic (artwork)
780 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
782 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
785 // set animation part to base part, if not specified
786 if (!IS_GLOBAL_ANIM_PART(part_nr))
787 part_nr = GLOBAL_ANIM_ID_PART_BASE;
789 // set animation screen to default, if not specified
790 if (!IS_SPECIAL_GFX_ARG(special))
791 special = GFX_SPECIAL_ARG_DEFAULT;
793 global_anim_info[anim_nr].music[part_nr][special] = music;
797 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
798 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
799 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
800 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
801 Debug("init:InitGlobalAnimMusicInfo",
802 "anim %d, part %d, mode %d => %d",
803 i, j, k, global_anim_info[i].music[j][k]);
807 static void InitElementGraphicInfo(void)
809 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
810 int num_property_mappings = getImageListPropertyMappingSize();
813 if (graphic_info == NULL) // still at startup phase
816 // set values to -1 to identify later as "uninitialized" values
817 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
819 for (act = 0; act < NUM_ACTIONS; act++)
821 element_info[i].graphic[act] = -1;
822 element_info[i].crumbled[act] = -1;
824 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
826 element_info[i].direction_graphic[act][dir] = -1;
827 element_info[i].direction_crumbled[act][dir] = -1;
834 // initialize normal element/graphic mapping from static configuration
835 for (i = 0; element_to_graphic[i].element > -1; i++)
837 int element = element_to_graphic[i].element;
838 int action = element_to_graphic[i].action;
839 int direction = element_to_graphic[i].direction;
840 boolean crumbled = element_to_graphic[i].crumbled;
841 int graphic = element_to_graphic[i].graphic;
842 int base_graphic = el2baseimg(element);
844 if (graphic_info[graphic].bitmap == NULL)
847 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
850 boolean base_redefined =
851 getImageListEntryFromImageID(base_graphic)->redefined;
852 boolean act_dir_redefined =
853 getImageListEntryFromImageID(graphic)->redefined;
855 /* if the base graphic ("emerald", for example) has been redefined,
856 but not the action graphic ("emerald.falling", for example), do not
857 use an existing (in this case considered obsolete) action graphic
858 anymore, but use the automatically determined default graphic */
859 if (base_redefined && !act_dir_redefined)
864 action = ACTION_DEFAULT;
869 element_info[element].direction_crumbled[action][direction] = graphic;
871 element_info[element].crumbled[action] = graphic;
876 element_info[element].direction_graphic[action][direction] = graphic;
878 element_info[element].graphic[action] = graphic;
882 // initialize normal element/graphic mapping from dynamic configuration
883 for (i = 0; i < num_property_mappings; i++)
885 int element = property_mapping[i].base_index;
886 int action = property_mapping[i].ext1_index;
887 int direction = property_mapping[i].ext2_index;
888 int special = property_mapping[i].ext3_index;
889 int graphic = property_mapping[i].artwork_index;
890 boolean crumbled = FALSE;
892 if (special == GFX_SPECIAL_ARG_CRUMBLED)
898 if (graphic_info[graphic].bitmap == NULL)
901 if (element >= MAX_NUM_ELEMENTS || special != -1)
905 action = ACTION_DEFAULT;
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 element_info[element].direction_crumbled[action][dir] = -1;
914 element_info[element].direction_crumbled[action][direction] = graphic;
916 element_info[element].crumbled[action] = graphic;
921 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 element_info[element].direction_graphic[action][dir] = -1;
925 element_info[element].direction_graphic[action][direction] = graphic;
927 element_info[element].graphic[action] = graphic;
931 // now copy all graphics that are defined to be cloned from other graphics
932 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
934 int graphic = element_info[i].graphic[ACTION_DEFAULT];
935 int crumbled_like, diggable_like;
940 crumbled_like = graphic_info[graphic].crumbled_like;
941 diggable_like = graphic_info[graphic].diggable_like;
943 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
945 for (act = 0; act < NUM_ACTIONS; act++)
946 element_info[i].crumbled[act] =
947 element_info[crumbled_like].crumbled[act];
948 for (act = 0; act < NUM_ACTIONS; act++)
949 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
950 element_info[i].direction_crumbled[act][dir] =
951 element_info[crumbled_like].direction_crumbled[act][dir];
954 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
956 element_info[i].graphic[ACTION_DIGGING] =
957 element_info[diggable_like].graphic[ACTION_DIGGING];
958 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
959 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
960 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
964 // set hardcoded definitions for some runtime elements without graphic
965 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
967 // set hardcoded definitions for some internal elements without graphic
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 if (IS_EDITOR_CASCADE_INACTIVE(i))
971 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
972 else if (IS_EDITOR_CASCADE_ACTIVE(i))
973 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
976 // now set all undefined/invalid graphics to -1 to set to default after it
977 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
979 for (act = 0; act < NUM_ACTIONS; act++)
983 graphic = element_info[i].graphic[act];
984 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
985 element_info[i].graphic[act] = -1;
987 graphic = element_info[i].crumbled[act];
988 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
989 element_info[i].crumbled[act] = -1;
991 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
993 graphic = element_info[i].direction_graphic[act][dir];
994 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
995 element_info[i].direction_graphic[act][dir] = -1;
997 graphic = element_info[i].direction_crumbled[act][dir];
998 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
999 element_info[i].direction_crumbled[act][dir] = -1;
1004 UPDATE_BUSY_STATE();
1006 // adjust graphics with 2nd tile for movement according to direction
1007 // (do this before correcting '-1' values to minimize calculations)
1008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1010 for (act = 0; act < NUM_ACTIONS; act++)
1012 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1014 int graphic = element_info[i].direction_graphic[act][dir];
1015 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1017 if (act == ACTION_FALLING) // special case
1018 graphic = element_info[i].graphic[act];
1020 if (graphic != -1 &&
1021 graphic_info[graphic].double_movement &&
1022 graphic_info[graphic].swap_double_tiles != 0)
1024 struct GraphicInfo *g = &graphic_info[graphic];
1025 int src_x_front = g->src_x;
1026 int src_y_front = g->src_y;
1027 int src_x_back = g->src_x + g->offset2_x;
1028 int src_y_back = g->src_y + g->offset2_y;
1029 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1031 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1032 src_y_front < src_y_back);
1033 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1034 boolean swap_movement_tiles_autodetected =
1035 (!frames_are_ordered_diagonally &&
1036 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1037 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1038 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1039 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1041 // swap frontside and backside graphic tile coordinates, if needed
1042 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1044 // get current (wrong) backside tile coordinates
1045 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1047 // set frontside tile coordinates to backside tile coordinates
1048 g->src_x = src_x_back;
1049 g->src_y = src_y_back;
1051 // invert tile offset to point to new backside tile coordinates
1055 // do not swap front and backside tiles again after correction
1056 g->swap_double_tiles = 0;
1063 UPDATE_BUSY_STATE();
1065 // now set all '-1' values to element specific default values
1066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1069 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1070 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1071 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1073 if (default_graphic == -1)
1074 default_graphic = IMG_UNKNOWN;
1076 if (default_crumbled == -1)
1077 default_crumbled = default_graphic;
1079 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1081 default_direction_graphic[dir] =
1082 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1083 default_direction_crumbled[dir] =
1084 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1086 if (default_direction_graphic[dir] == -1)
1087 default_direction_graphic[dir] = default_graphic;
1089 if (default_direction_crumbled[dir] == -1)
1090 default_direction_crumbled[dir] = default_direction_graphic[dir];
1093 for (act = 0; act < NUM_ACTIONS; act++)
1095 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1096 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1097 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1098 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1099 act == ACTION_TURNING_FROM_RIGHT ||
1100 act == ACTION_TURNING_FROM_UP ||
1101 act == ACTION_TURNING_FROM_DOWN);
1103 // generic default action graphic (defined by "[default]" directive)
1104 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1105 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1106 int default_remove_graphic = IMG_EMPTY;
1108 if (act_remove && default_action_graphic != -1)
1109 default_remove_graphic = default_action_graphic;
1111 // look for special default action graphic (classic game specific)
1112 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1113 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1114 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1115 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1116 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1117 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1118 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1119 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1121 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1122 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1123 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1124 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1125 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1126 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1127 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1128 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1130 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1131 // !!! make this better !!!
1132 if (i == EL_EMPTY_SPACE)
1134 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1135 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1138 if (default_action_graphic == -1)
1139 default_action_graphic = default_graphic;
1141 if (default_action_crumbled == -1)
1142 default_action_crumbled = default_action_graphic;
1144 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1146 // use action graphic as the default direction graphic, if undefined
1147 int default_action_direction_graphic = element_info[i].graphic[act];
1148 int default_action_direction_crumbled = element_info[i].crumbled[act];
1150 // no graphic for current action -- use default direction graphic
1151 if (default_action_direction_graphic == -1)
1152 default_action_direction_graphic =
1153 (act_remove ? default_remove_graphic :
1155 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1156 default_action_graphic != default_graphic ?
1157 default_action_graphic :
1158 default_direction_graphic[dir]);
1160 if (element_info[i].direction_graphic[act][dir] == -1)
1161 element_info[i].direction_graphic[act][dir] =
1162 default_action_direction_graphic;
1164 if (default_action_direction_crumbled == -1)
1165 default_action_direction_crumbled =
1166 element_info[i].direction_graphic[act][dir];
1168 if (element_info[i].direction_crumbled[act][dir] == -1)
1169 element_info[i].direction_crumbled[act][dir] =
1170 default_action_direction_crumbled;
1173 // no graphic for this specific action -- use default action graphic
1174 if (element_info[i].graphic[act] == -1)
1175 element_info[i].graphic[act] =
1176 (act_remove ? default_remove_graphic :
1177 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1178 default_action_graphic);
1180 if (element_info[i].crumbled[act] == -1)
1181 element_info[i].crumbled[act] = element_info[i].graphic[act];
1185 UPDATE_BUSY_STATE();
1188 static void InitElementSpecialGraphicInfo(void)
1190 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1191 int num_property_mappings = getImageListPropertyMappingSize();
1194 // always start with reliable default values
1195 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1196 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1197 element_info[i].special_graphic[j] =
1198 element_info[i].graphic[ACTION_DEFAULT];
1200 // initialize special element/graphic mapping from static configuration
1201 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1203 int element = element_to_special_graphic[i].element;
1204 int special = element_to_special_graphic[i].special;
1205 int graphic = element_to_special_graphic[i].graphic;
1206 int base_graphic = el2baseimg(element);
1207 boolean base_redefined =
1208 getImageListEntryFromImageID(base_graphic)->redefined;
1209 boolean special_redefined =
1210 getImageListEntryFromImageID(graphic)->redefined;
1212 /* if the base graphic ("emerald", for example) has been redefined,
1213 but not the special graphic ("emerald.EDITOR", for example), do not
1214 use an existing (in this case considered obsolete) special graphic
1215 anymore, but use the automatically created (down-scaled) graphic */
1216 if (base_redefined && !special_redefined)
1219 element_info[element].special_graphic[special] = graphic;
1222 // initialize special element/graphic mapping from dynamic configuration
1223 for (i = 0; i < num_property_mappings; i++)
1225 int element = property_mapping[i].base_index;
1226 int action = property_mapping[i].ext1_index;
1227 int direction = property_mapping[i].ext2_index;
1228 int special = property_mapping[i].ext3_index;
1229 int graphic = property_mapping[i].artwork_index;
1231 // for action ".active", replace element with active element, if exists
1232 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1234 element = ELEMENT_ACTIVE(element);
1238 if (element >= MAX_NUM_ELEMENTS)
1241 // do not change special graphic if action or direction was specified
1242 if (action != -1 || direction != -1)
1245 if (IS_SPECIAL_GFX_ARG(special))
1246 element_info[element].special_graphic[special] = graphic;
1249 // now set all undefined/invalid graphics to default
1250 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1251 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1252 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1253 element_info[i].special_graphic[j] =
1254 element_info[i].graphic[ACTION_DEFAULT];
1257 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1259 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1260 return get_parameter_value(value_raw, suffix, type);
1262 if (strEqual(value_raw, ARG_UNDEFINED))
1263 return ARG_UNDEFINED_VALUE;
1265 if (type == TYPE_ELEMENT)
1267 char *value = getHashEntry(element_token_hash, value_raw);
1272 Warn("error found in config file:");
1273 Warn("- config file: '%s'", getImageConfigFilename());
1274 Warn("error: invalid element token '%s'", value_raw);
1275 Warn("custom graphic rejected for this element/action");
1276 Warn("fallback done to undefined element for this graphic");
1280 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1282 else if (type == TYPE_GRAPHIC)
1284 char *value = getHashEntry(graphic_token_hash, value_raw);
1285 int fallback_graphic = IMG_CHAR_EXCLAM;
1290 Warn("error found in config file:");
1291 Warn("- config file: '%s'", getImageConfigFilename());
1292 Warn("error: invalid graphic token '%s'", value_raw);
1293 Warn("custom graphic rejected for this element/action");
1294 Warn("fallback done to 'char_exclam' for this graphic");
1298 return (value != NULL ? atoi(value) : fallback_graphic);
1304 static int get_scaled_graphic_width(int graphic)
1306 int original_width = getOriginalImageWidthFromImageID(graphic);
1307 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1309 return original_width * scale_up_factor;
1312 static int get_scaled_graphic_height(int graphic)
1314 int original_height = getOriginalImageHeightFromImageID(graphic);
1315 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1317 return original_height * scale_up_factor;
1320 static void set_graphic_parameters_ext(int graphic, int *parameter,
1321 Bitmap **src_bitmaps)
1323 struct GraphicInfo *g = &graphic_info[graphic];
1324 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1325 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1326 int anim_frames_per_line = 1;
1328 // always start with reliable default values
1329 g->src_image_width = 0;
1330 g->src_image_height = 0;
1333 g->width = TILEX; // default for element graphics
1334 g->height = TILEY; // default for element graphics
1335 g->offset_x = 0; // one or both of these values ...
1336 g->offset_y = 0; // ... will be corrected later
1337 g->offset2_x = 0; // one or both of these values ...
1338 g->offset2_y = 0; // ... will be corrected later
1339 g->swap_double_tiles = -1; // auto-detect tile swapping
1340 g->crumbled_like = -1; // do not use clone element
1341 g->diggable_like = -1; // do not use clone element
1342 g->border_size = TILEX / 8; // "CRUMBLED" border size
1343 g->scale_up_factor = 1; // default: no scaling up
1344 g->tile_size = TILESIZE; // default: standard tile size
1345 g->clone_from = -1; // do not use clone graphic
1346 g->init_delay_fixed = 0;
1347 g->init_delay_random = 0;
1348 g->init_delay_action = -1;
1349 g->anim_delay_fixed = 0;
1350 g->anim_delay_random = 0;
1351 g->anim_delay_action = -1;
1352 g->post_delay_fixed = 0;
1353 g->post_delay_random = 0;
1354 g->post_delay_action = -1;
1355 g->init_event = ANIM_EVENT_UNDEFINED;
1356 g->anim_event = ANIM_EVENT_UNDEFINED;
1357 g->init_event_action = -1;
1358 g->anim_event_action = -1;
1359 g->draw_masked = FALSE;
1361 g->fade_mode = FADE_MODE_DEFAULT;
1365 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1366 g->align = ALIGN_CENTER; // default for title screens
1367 g->valign = VALIGN_MIDDLE; // default for title screens
1368 g->sort_priority = 0; // default for title screens
1370 g->style = STYLE_DEFAULT;
1372 g->bitmaps = src_bitmaps;
1373 g->bitmap = src_bitmap;
1375 // optional zoom factor for scaling up the image to a larger size
1376 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1377 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1378 if (g->scale_up_factor < 1)
1379 g->scale_up_factor = 1; // no scaling
1381 // optional tile size for using non-standard image size
1382 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1384 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1387 // CHECK: should tile sizes less than standard tile size be allowed?
1388 if (g->tile_size < TILESIZE)
1389 g->tile_size = TILESIZE; // standard tile size
1392 // when setting tile size, also set width and height accordingly
1393 g->width = g->tile_size;
1394 g->height = g->tile_size;
1397 if (g->use_image_size)
1399 // set new default bitmap size (with scaling, but without small images)
1400 g->width = get_scaled_graphic_width(graphic);
1401 g->height = get_scaled_graphic_height(graphic);
1404 // optional width and height of each animation frame
1405 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1406 g->width = parameter[GFX_ARG_WIDTH];
1407 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1408 g->height = parameter[GFX_ARG_HEIGHT];
1410 // optional x and y tile position of animation frame sequence
1411 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1412 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1413 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1414 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1416 // optional x and y pixel position of animation frame sequence
1417 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1418 g->src_x = parameter[GFX_ARG_X];
1419 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1420 g->src_y = parameter[GFX_ARG_Y];
1427 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1428 g->width, getTokenFromImageID(graphic), TILEX);
1431 g->width = TILEX; // will be checked to be inside bitmap later
1437 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1438 g->height, getTokenFromImageID(graphic), TILEY);
1441 g->height = TILEY; // will be checked to be inside bitmap later
1447 // get final bitmap size (with scaling, but without small images)
1448 int src_image_width = get_scaled_graphic_width(graphic);
1449 int src_image_height = get_scaled_graphic_height(graphic);
1451 if (src_image_width == 0 || src_image_height == 0)
1453 // only happens when loaded outside artwork system (like "global.busy")
1454 src_image_width = src_bitmap->width;
1455 src_image_height = src_bitmap->height;
1458 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1460 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1461 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1465 anim_frames_per_row = MAX(1, src_image_width / g->width);
1466 anim_frames_per_col = MAX(1, src_image_height / g->height);
1469 g->src_image_width = src_image_width;
1470 g->src_image_height = src_image_height;
1473 // correct x or y offset dependent of vertical or horizontal frame order
1474 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1476 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1477 parameter[GFX_ARG_OFFSET] : g->height);
1478 anim_frames_per_line = anim_frames_per_col;
1480 else // frames are ordered horizontally
1482 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1483 parameter[GFX_ARG_OFFSET] : g->width);
1484 anim_frames_per_line = anim_frames_per_row;
1487 // optionally, the x and y offset of frames can be specified directly
1488 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1489 g->offset_x = parameter[GFX_ARG_XOFFSET];
1490 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1491 g->offset_y = parameter[GFX_ARG_YOFFSET];
1493 // optionally, moving animations may have separate start and end graphics
1494 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1496 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1497 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1499 // correct x or y offset2 dependent of vertical or horizontal frame order
1500 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1501 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1502 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1503 else // frames are ordered horizontally
1504 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1505 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1507 // optionally, the x and y offset of 2nd graphic can be specified directly
1508 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1509 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1510 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1511 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1513 // optionally, the second movement tile can be specified as start tile
1514 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1515 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1517 // automatically determine correct number of frames, if not defined
1518 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1519 g->anim_frames = parameter[GFX_ARG_FRAMES];
1520 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1521 g->anim_frames = anim_frames_per_row;
1522 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1523 g->anim_frames = anim_frames_per_col;
1527 if (g->anim_frames < 1) // frames must be at least 1
1530 g->anim_frames_per_line =
1531 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1532 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1534 g->anim_delay = parameter[GFX_ARG_DELAY];
1535 if (g->anim_delay < 1) // delay must be at least 1
1538 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1540 // automatically determine correct start frame, if not defined
1541 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1542 g->anim_start_frame = 0;
1543 else if (g->anim_mode & ANIM_REVERSE)
1544 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1546 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1548 // animation synchronized with global frame counter, not move position
1549 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1551 // optional element for cloning crumble graphics
1552 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1553 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1555 // optional element for cloning digging graphics
1556 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1557 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1559 // optional border size for "crumbling" diggable graphics
1560 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1561 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1563 // used for global animations and player "boring" and "sleeping" actions
1564 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1565 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1566 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1567 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1568 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1569 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1570 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1571 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1572 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1573 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1574 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1575 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1577 // used for global animations
1578 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1579 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1580 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1581 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1582 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1583 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1584 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1585 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1586 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1587 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1588 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1589 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1590 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1591 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1593 // used for toon animations and global animations
1594 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1595 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1596 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1597 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1598 g->direction = parameter[GFX_ARG_DIRECTION];
1599 g->position = parameter[GFX_ARG_POSITION];
1600 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1601 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1603 if (g->step_delay < 1) // delay must be at least 1
1606 // this is only used for drawing font characters
1607 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1608 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1610 // use a different default value for global animations and toons
1611 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1612 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1613 g->draw_masked = TRUE;
1615 // this is used for drawing envelopes, global animations and toons
1616 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1617 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1619 // used for toon animations and global animations
1620 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1621 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1623 // optional graphic for cloning all graphics settings
1624 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1625 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1627 // optional settings for drawing title screens and title messages
1628 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1629 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1630 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1631 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1632 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1633 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1634 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1635 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1636 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1637 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1638 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1639 g->align = parameter[GFX_ARG_ALIGN];
1640 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1641 g->valign = parameter[GFX_ARG_VALIGN];
1642 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1643 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1645 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1646 g->class = parameter[GFX_ARG_CLASS];
1647 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1648 g->style = parameter[GFX_ARG_STYLE];
1650 // this is only used for drawing menu buttons and text
1651 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1652 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1653 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1654 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1657 static void set_graphic_parameters(int graphic)
1659 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1660 char **parameter_raw = image->parameter;
1661 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1662 int parameter[NUM_GFX_ARGS];
1665 // if fallback to default artwork is done, also use the default parameters
1666 if (image->fallback_to_default)
1667 parameter_raw = image->default_parameter;
1669 // get integer values from string parameters
1670 for (i = 0; i < NUM_GFX_ARGS; i++)
1671 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1672 image_config_suffix[i].token,
1673 image_config_suffix[i].type);
1675 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1677 UPDATE_BUSY_STATE();
1680 static void set_cloned_graphic_parameters(int graphic)
1682 int fallback_graphic = IMG_CHAR_EXCLAM;
1683 int max_num_images = getImageListSize();
1684 int clone_graphic = graphic_info[graphic].clone_from;
1685 int num_references_followed = 1;
1687 while (graphic_info[clone_graphic].clone_from != -1 &&
1688 num_references_followed < max_num_images)
1690 clone_graphic = graphic_info[clone_graphic].clone_from;
1692 num_references_followed++;
1695 if (num_references_followed >= max_num_images)
1698 Warn("error found in config file:");
1699 Warn("- config file: '%s'", getImageConfigFilename());
1700 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1701 Warn("error: loop discovered when resolving cloned graphics");
1702 Warn("custom graphic rejected for this element/action");
1704 if (graphic == fallback_graphic)
1705 Fail("no fallback graphic available");
1707 Warn("fallback done to 'char_exclam' for this graphic");
1710 graphic_info[graphic] = graphic_info[fallback_graphic];
1714 graphic_info[graphic] = graphic_info[clone_graphic];
1715 graphic_info[graphic].clone_from = clone_graphic;
1719 static void InitGraphicInfo(void)
1721 int fallback_graphic = IMG_CHAR_EXCLAM;
1722 int num_images = getImageListSize();
1725 // use image size as default values for width and height for these images
1726 static int full_size_graphics[] =
1729 IMG_GLOBAL_BORDER_MAIN,
1730 IMG_GLOBAL_BORDER_SCORES,
1731 IMG_GLOBAL_BORDER_EDITOR,
1732 IMG_GLOBAL_BORDER_PLAYING,
1735 IMG_BACKGROUND_ENVELOPE_1,
1736 IMG_BACKGROUND_ENVELOPE_2,
1737 IMG_BACKGROUND_ENVELOPE_3,
1738 IMG_BACKGROUND_ENVELOPE_4,
1739 IMG_BACKGROUND_REQUEST,
1742 IMG_BACKGROUND_LOADING_INITIAL,
1743 IMG_BACKGROUND_LOADING,
1744 IMG_BACKGROUND_TITLE_INITIAL,
1745 IMG_BACKGROUND_TITLE,
1746 IMG_BACKGROUND_MAIN,
1747 IMG_BACKGROUND_NAMES,
1748 IMG_BACKGROUND_LEVELS,
1749 IMG_BACKGROUND_LEVELNR,
1750 IMG_BACKGROUND_SCORES,
1751 IMG_BACKGROUND_SCOREINFO,
1752 IMG_BACKGROUND_EDITOR,
1753 IMG_BACKGROUND_INFO,
1754 IMG_BACKGROUND_INFO_ELEMENTS,
1755 IMG_BACKGROUND_INFO_MUSIC,
1756 IMG_BACKGROUND_INFO_CREDITS,
1757 IMG_BACKGROUND_INFO_PROGRAM,
1758 IMG_BACKGROUND_INFO_VERSION,
1759 IMG_BACKGROUND_INFO_LEVELSET,
1760 IMG_BACKGROUND_SETUP,
1761 IMG_BACKGROUND_PLAYING,
1762 IMG_BACKGROUND_DOOR,
1763 IMG_BACKGROUND_TAPE,
1764 IMG_BACKGROUND_PANEL,
1765 IMG_BACKGROUND_PALETTE,
1766 IMG_BACKGROUND_TOOLBOX,
1768 IMG_TITLESCREEN_INITIAL_1,
1769 IMG_TITLESCREEN_INITIAL_2,
1770 IMG_TITLESCREEN_INITIAL_3,
1771 IMG_TITLESCREEN_INITIAL_4,
1772 IMG_TITLESCREEN_INITIAL_5,
1779 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1780 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1781 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1782 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1783 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1784 IMG_BACKGROUND_TITLEMESSAGE_1,
1785 IMG_BACKGROUND_TITLEMESSAGE_2,
1786 IMG_BACKGROUND_TITLEMESSAGE_3,
1787 IMG_BACKGROUND_TITLEMESSAGE_4,
1788 IMG_BACKGROUND_TITLEMESSAGE_5,
1793 FreeGlobalAnimEventInfo();
1795 checked_free(graphic_info);
1797 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1799 // initialize "use_image_size" flag with default value
1800 for (i = 0; i < num_images; i++)
1801 graphic_info[i].use_image_size = FALSE;
1803 // initialize "use_image_size" flag from static configuration above
1804 for (i = 0; full_size_graphics[i] != -1; i++)
1805 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1807 // first set all graphic paramaters ...
1808 for (i = 0; i < num_images; i++)
1809 set_graphic_parameters(i);
1811 // ... then copy these parameters for cloned graphics
1812 for (i = 0; i < num_images; i++)
1813 if (graphic_info[i].clone_from != -1)
1814 set_cloned_graphic_parameters(i);
1816 for (i = 0; i < num_images; i++)
1818 Bitmap *src_bitmap = graphic_info[i].bitmap;
1822 int src_bitmap_width, src_bitmap_height;
1824 // now check if no animation frames are outside of the loaded image
1826 if (graphic_info[i].bitmap == NULL)
1827 continue; // skip check for optional images that are undefined
1829 // get image size (this can differ from the standard element tile size!)
1830 width = graphic_info[i].width;
1831 height = graphic_info[i].height;
1833 // get final bitmap size (with scaling, but without small images)
1834 src_bitmap_width = graphic_info[i].src_image_width;
1835 src_bitmap_height = graphic_info[i].src_image_height;
1837 // check if first animation frame is inside specified bitmap
1839 // do not use getGraphicSourceXY() here to get position of first frame;
1840 // this avoids calculating wrong start position for out-of-bounds frame
1841 src_x = graphic_info[i].src_x;
1842 src_y = graphic_info[i].src_y;
1844 if (program.headless)
1847 if (src_x < 0 || src_y < 0 ||
1848 src_x + width > src_bitmap_width ||
1849 src_y + height > src_bitmap_height)
1852 Warn("error found in config file:");
1853 Warn("- config file: '%s'", getImageConfigFilename());
1854 Warn("- config token: '%s'", getTokenFromImageID(i));
1855 Warn("- image file: '%s'", src_bitmap->source_filename);
1856 Warn("- frame size: %d, %d", width, height);
1857 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1858 src_x, src_y, src_bitmap_width, src_bitmap_height);
1859 Warn("custom graphic rejected for this element/action");
1861 if (i == fallback_graphic)
1862 Fail("no fallback graphic available");
1864 Warn("fallback done to 'char_exclam' for this graphic");
1867 graphic_info[i] = graphic_info[fallback_graphic];
1869 // if first frame out of bounds, do not check last frame anymore
1873 // check if last animation frame is inside specified bitmap
1875 last_frame = graphic_info[i].anim_frames - 1;
1876 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1878 if (src_x < 0 || src_y < 0 ||
1879 src_x + width > src_bitmap_width ||
1880 src_y + height > src_bitmap_height)
1883 Warn("error found in config file:");
1884 Warn("- config file: '%s'", getImageConfigFilename());
1885 Warn("- config token: '%s'", getTokenFromImageID(i));
1886 Warn("- image file: '%s'", src_bitmap->source_filename);
1887 Warn("- frame size: %d, %d", width, height);
1888 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1889 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1890 Warn("custom graphic rejected for this element/action");
1892 if (i == fallback_graphic)
1893 Fail("no fallback graphic available");
1895 Warn("fallback done to 'char_exclam' for this graphic");
1898 graphic_info[i] = graphic_info[fallback_graphic];
1903 static void InitGraphicCompatibilityInfo(void)
1905 struct FileInfo *fi_global_door =
1906 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1907 int num_images = getImageListSize();
1910 /* the following compatibility handling is needed for the following case:
1911 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1912 graphics mainly used for door and panel graphics, like editor, tape and
1913 in-game buttons with hard-coded bitmap positions and button sizes; as
1914 these graphics now have individual definitions, redefining "global.door"
1915 to change all these graphics at once like before does not work anymore
1916 (because all those individual definitions still have their default values);
1917 to solve this, remap all those individual definitions that are not
1918 redefined to the new bitmap of "global.door" if it was redefined */
1920 // special compatibility handling if image "global.door" was redefined
1921 if (fi_global_door->redefined)
1923 for (i = 0; i < num_images; i++)
1925 struct FileInfo *fi = getImageListEntryFromImageID(i);
1927 // process only those images that still use the default settings
1930 // process all images which default to same image as "global.door"
1931 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1934 Debug("init:InitGraphicCompatibilityInfo",
1935 "special treatment needed for token '%s'", fi->token);
1938 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1939 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1945 InitGraphicCompatibilityInfo_Doors();
1948 static void InitElementSoundInfo(void)
1950 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1951 int num_property_mappings = getSoundListPropertyMappingSize();
1954 // set values to -1 to identify later as "uninitialized" values
1955 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1956 for (act = 0; act < NUM_ACTIONS; act++)
1957 element_info[i].sound[act] = -1;
1959 // initialize element/sound mapping from static configuration
1960 for (i = 0; element_to_sound[i].element > -1; i++)
1962 int element = element_to_sound[i].element;
1963 int action = element_to_sound[i].action;
1964 int sound = element_to_sound[i].sound;
1965 boolean is_class = element_to_sound[i].is_class;
1968 action = ACTION_DEFAULT;
1971 element_info[element].sound[action] = sound;
1973 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1974 if (strEqual(element_info[j].class_name,
1975 element_info[element].class_name))
1976 element_info[j].sound[action] = sound;
1979 // initialize element class/sound mapping from dynamic configuration
1980 for (i = 0; i < num_property_mappings; i++)
1982 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1983 int action = property_mapping[i].ext1_index;
1984 int sound = property_mapping[i].artwork_index;
1986 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1990 action = ACTION_DEFAULT;
1992 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1993 if (strEqual(element_info[j].class_name,
1994 element_info[element_class].class_name))
1995 element_info[j].sound[action] = sound;
1998 // initialize element/sound mapping from dynamic configuration
1999 for (i = 0; i < num_property_mappings; i++)
2001 int element = property_mapping[i].base_index;
2002 int action = property_mapping[i].ext1_index;
2003 int sound = property_mapping[i].artwork_index;
2005 if (element >= MAX_NUM_ELEMENTS)
2009 action = ACTION_DEFAULT;
2011 element_info[element].sound[action] = sound;
2014 // now set all '-1' values to element specific default values
2015 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2017 for (act = 0; act < NUM_ACTIONS; act++)
2019 // generic default action sound (defined by "[default]" directive)
2020 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2022 // look for special default action sound (classic game specific)
2023 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2024 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2025 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2026 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2027 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2028 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2029 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2030 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2032 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2033 // !!! make this better !!!
2034 if (i == EL_EMPTY_SPACE)
2035 default_action_sound = element_info[EL_DEFAULT].sound[act];
2037 // no sound for this specific action -- use default action sound
2038 if (element_info[i].sound[act] == -1)
2039 element_info[i].sound[act] = default_action_sound;
2043 // copy sound settings to some elements that are only stored in level file
2044 // in native R'n'D levels, but are used by game engine in native EM levels
2045 for (i = 0; copy_properties[i][0] != -1; i++)
2046 for (j = 1; j <= 4; j++)
2047 for (act = 0; act < NUM_ACTIONS; act++)
2048 element_info[copy_properties[i][j]].sound[act] =
2049 element_info[copy_properties[i][0]].sound[act];
2052 static void InitGameModeSoundInfo(void)
2056 // set values to -1 to identify later as "uninitialized" values
2057 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2060 // initialize gamemode/sound mapping from static configuration
2061 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2063 int gamemode = gamemode_to_sound[i].gamemode;
2064 int sound = gamemode_to_sound[i].sound;
2067 gamemode = GAME_MODE_DEFAULT;
2069 menu.sound[gamemode] = sound;
2072 // now set all '-1' values to levelset specific default values
2073 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2074 if (menu.sound[i] == -1)
2075 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2078 static void set_sound_parameters(int sound, char **parameter_raw)
2080 int parameter[NUM_SND_ARGS];
2083 // get integer values from string parameters
2084 for (i = 0; i < NUM_SND_ARGS; i++)
2086 get_parameter_value(parameter_raw[i],
2087 sound_config_suffix[i].token,
2088 sound_config_suffix[i].type);
2090 // explicit loop mode setting in configuration overrides default value
2091 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2092 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2094 // sound volume to change the original volume when loading the sound file
2095 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2097 // sound priority to give certain sounds a higher or lower priority
2098 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2101 static void InitSoundInfo(void)
2103 int *sound_effect_properties;
2104 int num_sounds = getSoundListSize();
2107 checked_free(sound_info);
2109 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2110 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2112 // initialize sound effect for all elements to "no sound"
2113 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2114 for (j = 0; j < NUM_ACTIONS; j++)
2115 element_info[i].sound[j] = SND_UNDEFINED;
2117 for (i = 0; i < num_sounds; i++)
2119 struct FileInfo *sound = getSoundListEntry(i);
2120 int len_effect_text = strlen(sound->token);
2122 sound_effect_properties[i] = ACTION_OTHER;
2123 sound_info[i].loop = FALSE; // default: play sound only once
2125 // determine all loop sounds and identify certain sound classes
2127 for (j = 0; element_action_info[j].suffix; j++)
2129 int len_action_text = strlen(element_action_info[j].suffix);
2131 if (len_action_text < len_effect_text &&
2132 strEqual(&sound->token[len_effect_text - len_action_text],
2133 element_action_info[j].suffix))
2135 sound_effect_properties[i] = element_action_info[j].value;
2136 sound_info[i].loop = element_action_info[j].is_loop_sound;
2142 // associate elements and some selected sound actions
2144 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2146 if (element_info[j].class_name)
2148 int len_class_text = strlen(element_info[j].class_name);
2150 if (len_class_text + 1 < len_effect_text &&
2151 strncmp(sound->token,
2152 element_info[j].class_name, len_class_text) == 0 &&
2153 sound->token[len_class_text] == '.')
2155 int sound_action_value = sound_effect_properties[i];
2157 element_info[j].sound[sound_action_value] = i;
2162 set_sound_parameters(i, sound->parameter);
2165 free(sound_effect_properties);
2168 static void InitGameModeMusicInfo(void)
2170 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2171 int num_property_mappings = getMusicListPropertyMappingSize();
2172 int default_levelset_music = -1;
2175 // set values to -1 to identify later as "uninitialized" values
2176 for (i = 0; i < MAX_LEVELS; i++)
2177 levelset.music[i] = -1;
2178 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2181 // initialize gamemode/music mapping from static configuration
2182 for (i = 0; gamemode_to_music[i].music > -1; i++)
2184 int gamemode = gamemode_to_music[i].gamemode;
2185 int music = gamemode_to_music[i].music;
2188 gamemode = GAME_MODE_DEFAULT;
2190 menu.music[gamemode] = music;
2193 // initialize gamemode/music mapping from dynamic configuration
2194 for (i = 0; i < num_property_mappings; i++)
2196 int prefix = property_mapping[i].base_index;
2197 int gamemode = property_mapping[i].ext2_index;
2198 int level = property_mapping[i].ext3_index;
2199 int music = property_mapping[i].artwork_index;
2201 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2205 gamemode = GAME_MODE_DEFAULT;
2207 // level specific music only allowed for in-game music
2208 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2209 gamemode = GAME_MODE_PLAYING;
2214 default_levelset_music = music;
2217 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2218 levelset.music[level] = music;
2219 if (gamemode != GAME_MODE_PLAYING)
2220 menu.music[gamemode] = music;
2223 // now set all '-1' values to menu specific default values
2224 // (undefined values of "levelset.music[]" might stay at "-1" to
2225 // allow dynamic selection of music files from music directory!)
2226 for (i = 0; i < MAX_LEVELS; i++)
2227 if (levelset.music[i] == -1)
2228 levelset.music[i] = default_levelset_music;
2229 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2230 if (menu.music[i] == -1)
2231 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2234 static void set_music_parameters(int music, char **parameter_raw)
2236 int parameter[NUM_MUS_ARGS];
2239 // get integer values from string parameters
2240 for (i = 0; i < NUM_MUS_ARGS; i++)
2242 get_parameter_value(parameter_raw[i],
2243 music_config_suffix[i].token,
2244 music_config_suffix[i].type);
2246 // explicit loop mode setting in configuration overrides default value
2247 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2248 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2251 static void InitMusicInfo(void)
2253 int num_music = getMusicListSize();
2256 checked_free(music_info);
2258 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2260 for (i = 0; i < num_music; i++)
2262 struct FileInfo *music = getMusicListEntry(i);
2263 int len_music_text = strlen(music->token);
2265 music_info[i].loop = TRUE; // default: play music in loop mode
2267 // determine all loop music
2269 for (j = 0; music_prefix_info[j].prefix; j++)
2271 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2273 if (len_prefix_text < len_music_text &&
2274 strncmp(music->token,
2275 music_prefix_info[j].prefix, len_prefix_text) == 0)
2277 music_info[i].loop = music_prefix_info[j].is_loop_music;
2283 set_music_parameters(i, music->parameter);
2288 static void InitGameInfoFromArtworkInfo(void)
2290 // special case: store initial value of custom artwork setting
2291 game.use_masked_elements_initial = game.use_masked_elements;
2294 static void ReinitializeGraphics(void)
2296 print_timestamp_init("ReinitializeGraphics");
2298 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2300 InitGraphicInfo(); // graphic properties mapping
2301 print_timestamp_time("InitGraphicInfo");
2302 InitElementGraphicInfo(); // element game graphic mapping
2303 print_timestamp_time("InitElementGraphicInfo");
2304 InitElementSpecialGraphicInfo(); // element special graphic mapping
2305 print_timestamp_time("InitElementSpecialGraphicInfo");
2307 InitElementSmallImages(); // scale elements to all needed sizes
2308 print_timestamp_time("InitElementSmallImages");
2309 InitScaledImages(); // scale all other images, if needed
2310 print_timestamp_time("InitScaledImages");
2311 InitBitmapPointers(); // set standard size bitmap pointers
2312 print_timestamp_time("InitBitmapPointers");
2313 InitFontGraphicInfo(); // initialize text drawing functions
2314 print_timestamp_time("InitFontGraphicInfo");
2315 InitGlobalAnimGraphicInfo(); // initialize global animation config
2316 print_timestamp_time("InitGlobalAnimGraphicInfo");
2318 InitImageTextures(); // create textures for certain images
2319 print_timestamp_time("InitImageTextures");
2321 InitGraphicInfo_EM(); // graphic mapping for EM engine
2322 print_timestamp_time("InitGraphicInfo_EM");
2324 InitGraphicCompatibilityInfo();
2325 print_timestamp_time("InitGraphicCompatibilityInfo");
2328 print_timestamp_time("InitGadgets");
2330 print_timestamp_time("InitDoors");
2332 InitGameInfoFromArtworkInfo();
2334 print_timestamp_done("ReinitializeGraphics");
2337 static void ReinitializeSounds(void)
2339 InitSoundInfo(); // sound properties mapping
2340 InitElementSoundInfo(); // element game sound mapping
2341 InitGameModeSoundInfo(); // game mode sound mapping
2342 InitGlobalAnimSoundInfo(); // global animation sound settings
2344 InitPlayLevelSound(); // internal game sound settings
2347 static void ReinitializeMusic(void)
2349 InitMusicInfo(); // music properties mapping
2350 InitGameModeMusicInfo(); // game mode music mapping
2351 InitGlobalAnimMusicInfo(); // global animation music settings
2354 static int get_special_property_bit(int element, int property_bit_nr)
2356 struct PropertyBitInfo
2362 static struct PropertyBitInfo pb_can_move_into_acid[] =
2364 // the player may be able fall into acid when gravity is activated
2369 { EL_SP_MURPHY, 0 },
2370 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2372 // all elements that can move may be able to also move into acid
2375 { EL_BUG_RIGHT, 1 },
2378 { EL_SPACESHIP, 2 },
2379 { EL_SPACESHIP_LEFT, 2 },
2380 { EL_SPACESHIP_RIGHT, 2 },
2381 { EL_SPACESHIP_UP, 2 },
2382 { EL_SPACESHIP_DOWN, 2 },
2383 { EL_BD_BUTTERFLY, 3 },
2384 { EL_BD_BUTTERFLY_LEFT, 3 },
2385 { EL_BD_BUTTERFLY_RIGHT, 3 },
2386 { EL_BD_BUTTERFLY_UP, 3 },
2387 { EL_BD_BUTTERFLY_DOWN, 3 },
2388 { EL_BD_FIREFLY, 4 },
2389 { EL_BD_FIREFLY_LEFT, 4 },
2390 { EL_BD_FIREFLY_RIGHT, 4 },
2391 { EL_BD_FIREFLY_UP, 4 },
2392 { EL_BD_FIREFLY_DOWN, 4 },
2394 { EL_YAMYAM_LEFT, 5 },
2395 { EL_YAMYAM_RIGHT, 5 },
2396 { EL_YAMYAM_UP, 5 },
2397 { EL_YAMYAM_DOWN, 5 },
2398 { EL_DARK_YAMYAM, 6 },
2401 { EL_PACMAN_LEFT, 8 },
2402 { EL_PACMAN_RIGHT, 8 },
2403 { EL_PACMAN_UP, 8 },
2404 { EL_PACMAN_DOWN, 8 },
2406 { EL_MOLE_LEFT, 9 },
2407 { EL_MOLE_RIGHT, 9 },
2409 { EL_MOLE_DOWN, 9 },
2413 { EL_SATELLITE, 13 },
2414 { EL_SP_SNIKSNAK, 14 },
2415 { EL_SP_ELECTRON, 15 },
2418 { EL_SPRING_LEFT, 17 },
2419 { EL_SPRING_RIGHT, 17 },
2420 { EL_EMC_ANDROID, 18 },
2425 static struct PropertyBitInfo pb_dont_collide_with[] =
2427 { EL_SP_SNIKSNAK, 0 },
2428 { EL_SP_ELECTRON, 1 },
2436 struct PropertyBitInfo *pb_info;
2439 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2440 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2445 struct PropertyBitInfo *pb_info = NULL;
2448 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2449 if (pb_definition[i].bit_nr == property_bit_nr)
2450 pb_info = pb_definition[i].pb_info;
2452 if (pb_info == NULL)
2455 for (i = 0; pb_info[i].element != -1; i++)
2456 if (pb_info[i].element == element)
2457 return pb_info[i].bit_nr;
2462 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2463 boolean property_value)
2465 int bit_nr = get_special_property_bit(element, property_bit_nr);
2470 *bitfield |= (1 << bit_nr);
2472 *bitfield &= ~(1 << bit_nr);
2476 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2478 int bit_nr = get_special_property_bit(element, property_bit_nr);
2481 return ((*bitfield & (1 << bit_nr)) != 0);
2486 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2488 static int group_nr;
2489 static struct ElementGroupInfo *group;
2490 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2493 if (actual_group == NULL) // not yet initialized
2496 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2498 Warn("recursion too deep when resolving group element %d",
2499 group_element - EL_GROUP_START + 1);
2501 // replace element which caused too deep recursion by question mark
2502 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2507 if (recursion_depth == 0) // initialization
2509 group = actual_group;
2510 group_nr = GROUP_NR(group_element);
2512 group->num_elements_resolved = 0;
2513 group->choice_pos = 0;
2515 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2516 element_info[i].in_group[group_nr] = FALSE;
2519 for (i = 0; i < actual_group->num_elements; i++)
2521 int element = actual_group->element[i];
2523 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2526 if (IS_GROUP_ELEMENT(element))
2527 ResolveGroupElementExt(element, recursion_depth + 1);
2530 group->element_resolved[group->num_elements_resolved++] = element;
2531 element_info[element].in_group[group_nr] = TRUE;
2536 void ResolveGroupElement(int group_element)
2538 ResolveGroupElementExt(group_element, 0);
2541 void InitElementPropertiesStatic(void)
2543 static boolean clipboard_elements_initialized = FALSE;
2545 static int ep_diggable[] =
2550 EL_SP_BUGGY_BASE_ACTIVATING,
2553 EL_INVISIBLE_SAND_ACTIVE,
2556 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2557 // (if amoeba can grow into anything diggable, maybe keep these out)
2562 EL_SP_BUGGY_BASE_ACTIVE,
2569 static int ep_collectible_only[] =
2591 EL_DYNABOMB_INCREASE_NUMBER,
2592 EL_DYNABOMB_INCREASE_SIZE,
2593 EL_DYNABOMB_INCREASE_POWER,
2611 // !!! handle separately !!!
2612 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2618 static int ep_dont_run_into[] =
2620 // same elements as in 'ep_dont_touch'
2626 // same elements as in 'ep_dont_collide_with'
2638 // !!! maybe this should better be handled by 'ep_diggable' !!!
2643 EL_SP_BUGGY_BASE_ACTIVE,
2650 static int ep_dont_collide_with[] =
2652 // same elements as in 'ep_dont_touch'
2669 static int ep_dont_touch[] =
2679 static int ep_indestructible[] =
2683 EL_ACID_POOL_TOPLEFT,
2684 EL_ACID_POOL_TOPRIGHT,
2685 EL_ACID_POOL_BOTTOMLEFT,
2686 EL_ACID_POOL_BOTTOM,
2687 EL_ACID_POOL_BOTTOMRIGHT,
2688 EL_SP_HARDWARE_GRAY,
2689 EL_SP_HARDWARE_GREEN,
2690 EL_SP_HARDWARE_BLUE,
2692 EL_SP_HARDWARE_YELLOW,
2693 EL_SP_HARDWARE_BASE_1,
2694 EL_SP_HARDWARE_BASE_2,
2695 EL_SP_HARDWARE_BASE_3,
2696 EL_SP_HARDWARE_BASE_4,
2697 EL_SP_HARDWARE_BASE_5,
2698 EL_SP_HARDWARE_BASE_6,
2699 EL_INVISIBLE_STEELWALL,
2700 EL_INVISIBLE_STEELWALL_ACTIVE,
2701 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2702 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2703 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2704 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2705 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2706 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2707 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2708 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2709 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2710 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2711 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2712 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2714 EL_LIGHT_SWITCH_ACTIVE,
2715 EL_SIGN_EXCLAMATION,
2716 EL_SIGN_RADIOACTIVITY,
2723 EL_SIGN_ENTRY_FORBIDDEN,
2724 EL_SIGN_EMERGENCY_EXIT,
2732 EL_STEEL_EXIT_CLOSED,
2734 EL_STEEL_EXIT_OPENING,
2735 EL_STEEL_EXIT_CLOSING,
2736 EL_EM_STEEL_EXIT_CLOSED,
2737 EL_EM_STEEL_EXIT_OPEN,
2738 EL_EM_STEEL_EXIT_OPENING,
2739 EL_EM_STEEL_EXIT_CLOSING,
2740 EL_DC_STEELWALL_1_LEFT,
2741 EL_DC_STEELWALL_1_RIGHT,
2742 EL_DC_STEELWALL_1_TOP,
2743 EL_DC_STEELWALL_1_BOTTOM,
2744 EL_DC_STEELWALL_1_HORIZONTAL,
2745 EL_DC_STEELWALL_1_VERTICAL,
2746 EL_DC_STEELWALL_1_TOPLEFT,
2747 EL_DC_STEELWALL_1_TOPRIGHT,
2748 EL_DC_STEELWALL_1_BOTTOMLEFT,
2749 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2750 EL_DC_STEELWALL_1_TOPLEFT_2,
2751 EL_DC_STEELWALL_1_TOPRIGHT_2,
2752 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2753 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2754 EL_DC_STEELWALL_2_LEFT,
2755 EL_DC_STEELWALL_2_RIGHT,
2756 EL_DC_STEELWALL_2_TOP,
2757 EL_DC_STEELWALL_2_BOTTOM,
2758 EL_DC_STEELWALL_2_HORIZONTAL,
2759 EL_DC_STEELWALL_2_VERTICAL,
2760 EL_DC_STEELWALL_2_MIDDLE,
2761 EL_DC_STEELWALL_2_SINGLE,
2762 EL_STEELWALL_SLIPPERY,
2776 EL_GATE_1_GRAY_ACTIVE,
2777 EL_GATE_2_GRAY_ACTIVE,
2778 EL_GATE_3_GRAY_ACTIVE,
2779 EL_GATE_4_GRAY_ACTIVE,
2788 EL_EM_GATE_1_GRAY_ACTIVE,
2789 EL_EM_GATE_2_GRAY_ACTIVE,
2790 EL_EM_GATE_3_GRAY_ACTIVE,
2791 EL_EM_GATE_4_GRAY_ACTIVE,
2800 EL_EMC_GATE_5_GRAY_ACTIVE,
2801 EL_EMC_GATE_6_GRAY_ACTIVE,
2802 EL_EMC_GATE_7_GRAY_ACTIVE,
2803 EL_EMC_GATE_8_GRAY_ACTIVE,
2805 EL_DC_GATE_WHITE_GRAY,
2806 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2807 EL_DC_GATE_FAKE_GRAY,
2809 EL_SWITCHGATE_OPENING,
2810 EL_SWITCHGATE_CLOSED,
2811 EL_SWITCHGATE_CLOSING,
2812 EL_DC_SWITCHGATE_SWITCH_UP,
2813 EL_DC_SWITCHGATE_SWITCH_DOWN,
2815 EL_TIMEGATE_OPENING,
2817 EL_TIMEGATE_CLOSING,
2818 EL_DC_TIMEGATE_SWITCH,
2819 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2823 EL_TUBE_VERTICAL_LEFT,
2824 EL_TUBE_VERTICAL_RIGHT,
2825 EL_TUBE_HORIZONTAL_UP,
2826 EL_TUBE_HORIZONTAL_DOWN,
2831 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2832 EL_EXPANDABLE_STEELWALL_VERTICAL,
2833 EL_EXPANDABLE_STEELWALL_ANY,
2838 static int ep_slippery[] =
2852 EL_ROBOT_WHEEL_ACTIVE,
2858 EL_ACID_POOL_TOPLEFT,
2859 EL_ACID_POOL_TOPRIGHT,
2869 EL_STEELWALL_SLIPPERY,
2872 EL_EMC_WALL_SLIPPERY_1,
2873 EL_EMC_WALL_SLIPPERY_2,
2874 EL_EMC_WALL_SLIPPERY_3,
2875 EL_EMC_WALL_SLIPPERY_4,
2877 EL_EMC_MAGIC_BALL_ACTIVE,
2882 static int ep_can_change[] =
2887 static int ep_can_move[] =
2889 // same elements as in 'pb_can_move_into_acid'
2912 static int ep_can_fall[] =
2927 EL_QUICKSAND_FAST_FULL,
2929 EL_BD_MAGIC_WALL_FULL,
2930 EL_DC_MAGIC_WALL_FULL,
2944 static int ep_can_smash_player[] =
2970 static int ep_can_smash_enemies[] =
2979 static int ep_can_smash_everything[] =
2988 static int ep_explodes_by_fire[] =
2990 // same elements as in 'ep_explodes_impact'
2995 // same elements as in 'ep_explodes_smashed'
3005 EL_EM_DYNAMITE_ACTIVE,
3006 EL_DYNABOMB_PLAYER_1_ACTIVE,
3007 EL_DYNABOMB_PLAYER_2_ACTIVE,
3008 EL_DYNABOMB_PLAYER_3_ACTIVE,
3009 EL_DYNABOMB_PLAYER_4_ACTIVE,
3010 EL_DYNABOMB_INCREASE_NUMBER,
3011 EL_DYNABOMB_INCREASE_SIZE,
3012 EL_DYNABOMB_INCREASE_POWER,
3013 EL_SP_DISK_RED_ACTIVE,
3027 static int ep_explodes_smashed[] =
3029 // same elements as in 'ep_explodes_impact'
3043 static int ep_explodes_impact[] =
3052 static int ep_walkable_over[] =
3072 EL_SOKOBAN_FIELD_EMPTY,
3079 EL_EM_STEEL_EXIT_OPEN,
3080 EL_EM_STEEL_EXIT_OPENING,
3089 EL_GATE_1_GRAY_ACTIVE,
3090 EL_GATE_2_GRAY_ACTIVE,
3091 EL_GATE_3_GRAY_ACTIVE,
3092 EL_GATE_4_GRAY_ACTIVE,
3100 static int ep_walkable_inside[] =
3105 EL_TUBE_VERTICAL_LEFT,
3106 EL_TUBE_VERTICAL_RIGHT,
3107 EL_TUBE_HORIZONTAL_UP,
3108 EL_TUBE_HORIZONTAL_DOWN,
3117 static int ep_walkable_under[] =
3122 static int ep_passable_over[] =
3132 EL_EM_GATE_1_GRAY_ACTIVE,
3133 EL_EM_GATE_2_GRAY_ACTIVE,
3134 EL_EM_GATE_3_GRAY_ACTIVE,
3135 EL_EM_GATE_4_GRAY_ACTIVE,
3144 EL_EMC_GATE_5_GRAY_ACTIVE,
3145 EL_EMC_GATE_6_GRAY_ACTIVE,
3146 EL_EMC_GATE_7_GRAY_ACTIVE,
3147 EL_EMC_GATE_8_GRAY_ACTIVE,
3149 EL_DC_GATE_WHITE_GRAY,
3150 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3157 static int ep_passable_inside[] =
3163 EL_SP_PORT_HORIZONTAL,
3164 EL_SP_PORT_VERTICAL,
3166 EL_SP_GRAVITY_PORT_LEFT,
3167 EL_SP_GRAVITY_PORT_RIGHT,
3168 EL_SP_GRAVITY_PORT_UP,
3169 EL_SP_GRAVITY_PORT_DOWN,
3170 EL_SP_GRAVITY_ON_PORT_LEFT,
3171 EL_SP_GRAVITY_ON_PORT_RIGHT,
3172 EL_SP_GRAVITY_ON_PORT_UP,
3173 EL_SP_GRAVITY_ON_PORT_DOWN,
3174 EL_SP_GRAVITY_OFF_PORT_LEFT,
3175 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3176 EL_SP_GRAVITY_OFF_PORT_UP,
3177 EL_SP_GRAVITY_OFF_PORT_DOWN,
3182 static int ep_passable_under[] =
3187 static int ep_droppable[] =
3192 static int ep_explodes_1x1_old[] =
3197 static int ep_pushable[] =
3209 EL_SOKOBAN_FIELD_FULL,
3218 static int ep_explodes_cross_old[] =
3223 static int ep_protected[] =
3225 // same elements as in 'ep_walkable_inside'
3229 EL_TUBE_VERTICAL_LEFT,
3230 EL_TUBE_VERTICAL_RIGHT,
3231 EL_TUBE_HORIZONTAL_UP,
3232 EL_TUBE_HORIZONTAL_DOWN,
3238 // same elements as in 'ep_passable_over'
3247 EL_EM_GATE_1_GRAY_ACTIVE,
3248 EL_EM_GATE_2_GRAY_ACTIVE,
3249 EL_EM_GATE_3_GRAY_ACTIVE,
3250 EL_EM_GATE_4_GRAY_ACTIVE,
3259 EL_EMC_GATE_5_GRAY_ACTIVE,
3260 EL_EMC_GATE_6_GRAY_ACTIVE,
3261 EL_EMC_GATE_7_GRAY_ACTIVE,
3262 EL_EMC_GATE_8_GRAY_ACTIVE,
3264 EL_DC_GATE_WHITE_GRAY,
3265 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3269 // same elements as in 'ep_passable_inside'
3274 EL_SP_PORT_HORIZONTAL,
3275 EL_SP_PORT_VERTICAL,
3277 EL_SP_GRAVITY_PORT_LEFT,
3278 EL_SP_GRAVITY_PORT_RIGHT,
3279 EL_SP_GRAVITY_PORT_UP,
3280 EL_SP_GRAVITY_PORT_DOWN,
3281 EL_SP_GRAVITY_ON_PORT_LEFT,
3282 EL_SP_GRAVITY_ON_PORT_RIGHT,
3283 EL_SP_GRAVITY_ON_PORT_UP,
3284 EL_SP_GRAVITY_ON_PORT_DOWN,
3285 EL_SP_GRAVITY_OFF_PORT_LEFT,
3286 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3287 EL_SP_GRAVITY_OFF_PORT_UP,
3288 EL_SP_GRAVITY_OFF_PORT_DOWN,
3293 static int ep_throwable[] =
3298 static int ep_can_explode[] =
3300 // same elements as in 'ep_explodes_impact'
3305 // same elements as in 'ep_explodes_smashed'
3311 // elements that can explode by explosion or by dragonfire
3315 EL_EM_DYNAMITE_ACTIVE,
3316 EL_DYNABOMB_PLAYER_1_ACTIVE,
3317 EL_DYNABOMB_PLAYER_2_ACTIVE,
3318 EL_DYNABOMB_PLAYER_3_ACTIVE,
3319 EL_DYNABOMB_PLAYER_4_ACTIVE,
3320 EL_DYNABOMB_INCREASE_NUMBER,
3321 EL_DYNABOMB_INCREASE_SIZE,
3322 EL_DYNABOMB_INCREASE_POWER,
3323 EL_SP_DISK_RED_ACTIVE,
3331 // elements that can explode only by explosion
3337 static int ep_gravity_reachable[] =
3343 EL_INVISIBLE_SAND_ACTIVE,
3348 EL_SP_PORT_HORIZONTAL,
3349 EL_SP_PORT_VERTICAL,
3351 EL_SP_GRAVITY_PORT_LEFT,
3352 EL_SP_GRAVITY_PORT_RIGHT,
3353 EL_SP_GRAVITY_PORT_UP,
3354 EL_SP_GRAVITY_PORT_DOWN,
3355 EL_SP_GRAVITY_ON_PORT_LEFT,
3356 EL_SP_GRAVITY_ON_PORT_RIGHT,
3357 EL_SP_GRAVITY_ON_PORT_UP,
3358 EL_SP_GRAVITY_ON_PORT_DOWN,
3359 EL_SP_GRAVITY_OFF_PORT_LEFT,
3360 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3361 EL_SP_GRAVITY_OFF_PORT_UP,
3362 EL_SP_GRAVITY_OFF_PORT_DOWN,
3368 static int ep_empty_space[] =
3391 static int ep_player[] =
3398 EL_SOKOBAN_FIELD_PLAYER,
3404 static int ep_can_pass_magic_wall[] =
3418 static int ep_can_pass_dc_magic_wall[] =
3434 static int ep_switchable[] =
3438 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3439 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3440 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3441 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3442 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3443 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3444 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3445 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3446 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3447 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3448 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3449 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3450 EL_SWITCHGATE_SWITCH_UP,
3451 EL_SWITCHGATE_SWITCH_DOWN,
3452 EL_DC_SWITCHGATE_SWITCH_UP,
3453 EL_DC_SWITCHGATE_SWITCH_DOWN,
3455 EL_LIGHT_SWITCH_ACTIVE,
3457 EL_DC_TIMEGATE_SWITCH,
3458 EL_BALLOON_SWITCH_LEFT,
3459 EL_BALLOON_SWITCH_RIGHT,
3460 EL_BALLOON_SWITCH_UP,
3461 EL_BALLOON_SWITCH_DOWN,
3462 EL_BALLOON_SWITCH_ANY,
3463 EL_BALLOON_SWITCH_NONE,
3466 EL_EMC_MAGIC_BALL_SWITCH,
3467 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3472 static int ep_bd_element[] =
3506 static int ep_sp_element[] =
3508 // should always be valid
3511 // standard classic Supaplex elements
3518 EL_SP_HARDWARE_GRAY,
3526 EL_SP_GRAVITY_PORT_RIGHT,
3527 EL_SP_GRAVITY_PORT_DOWN,
3528 EL_SP_GRAVITY_PORT_LEFT,
3529 EL_SP_GRAVITY_PORT_UP,
3534 EL_SP_PORT_VERTICAL,
3535 EL_SP_PORT_HORIZONTAL,
3541 EL_SP_HARDWARE_BASE_1,
3542 EL_SP_HARDWARE_GREEN,
3543 EL_SP_HARDWARE_BLUE,
3545 EL_SP_HARDWARE_YELLOW,
3546 EL_SP_HARDWARE_BASE_2,
3547 EL_SP_HARDWARE_BASE_3,
3548 EL_SP_HARDWARE_BASE_4,
3549 EL_SP_HARDWARE_BASE_5,
3550 EL_SP_HARDWARE_BASE_6,
3554 // additional elements that appeared in newer Supaplex levels
3557 // additional gravity port elements (not switching, but setting gravity)
3558 EL_SP_GRAVITY_ON_PORT_LEFT,
3559 EL_SP_GRAVITY_ON_PORT_RIGHT,
3560 EL_SP_GRAVITY_ON_PORT_UP,
3561 EL_SP_GRAVITY_ON_PORT_DOWN,
3562 EL_SP_GRAVITY_OFF_PORT_LEFT,
3563 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3564 EL_SP_GRAVITY_OFF_PORT_UP,
3565 EL_SP_GRAVITY_OFF_PORT_DOWN,
3567 // more than one Murphy in a level results in an inactive clone
3570 // runtime Supaplex elements
3571 EL_SP_DISK_RED_ACTIVE,
3572 EL_SP_TERMINAL_ACTIVE,
3573 EL_SP_BUGGY_BASE_ACTIVATING,
3574 EL_SP_BUGGY_BASE_ACTIVE,
3581 static int ep_sb_element[] =
3586 EL_SOKOBAN_FIELD_EMPTY,
3587 EL_SOKOBAN_FIELD_FULL,
3588 EL_SOKOBAN_FIELD_PLAYER,
3593 EL_INVISIBLE_STEELWALL,
3598 static int ep_gem[] =
3610 static int ep_food_dark_yamyam[] =
3638 static int ep_food_penguin[] =
3652 static int ep_food_pig[] =
3664 static int ep_historic_wall[] =
3675 EL_GATE_1_GRAY_ACTIVE,
3676 EL_GATE_2_GRAY_ACTIVE,
3677 EL_GATE_3_GRAY_ACTIVE,
3678 EL_GATE_4_GRAY_ACTIVE,
3687 EL_EM_GATE_1_GRAY_ACTIVE,
3688 EL_EM_GATE_2_GRAY_ACTIVE,
3689 EL_EM_GATE_3_GRAY_ACTIVE,
3690 EL_EM_GATE_4_GRAY_ACTIVE,
3697 EL_EXPANDABLE_WALL_HORIZONTAL,
3698 EL_EXPANDABLE_WALL_VERTICAL,
3699 EL_EXPANDABLE_WALL_ANY,
3700 EL_EXPANDABLE_WALL_GROWING,
3701 EL_BD_EXPANDABLE_WALL,
3708 EL_SP_HARDWARE_GRAY,
3709 EL_SP_HARDWARE_GREEN,
3710 EL_SP_HARDWARE_BLUE,
3712 EL_SP_HARDWARE_YELLOW,
3713 EL_SP_HARDWARE_BASE_1,
3714 EL_SP_HARDWARE_BASE_2,
3715 EL_SP_HARDWARE_BASE_3,
3716 EL_SP_HARDWARE_BASE_4,
3717 EL_SP_HARDWARE_BASE_5,
3718 EL_SP_HARDWARE_BASE_6,
3720 EL_SP_TERMINAL_ACTIVE,
3723 EL_INVISIBLE_STEELWALL,
3724 EL_INVISIBLE_STEELWALL_ACTIVE,
3726 EL_INVISIBLE_WALL_ACTIVE,
3727 EL_STEELWALL_SLIPPERY,
3744 static int ep_historic_solid[] =
3748 EL_EXPANDABLE_WALL_HORIZONTAL,
3749 EL_EXPANDABLE_WALL_VERTICAL,
3750 EL_EXPANDABLE_WALL_ANY,
3751 EL_BD_EXPANDABLE_WALL,
3764 EL_QUICKSAND_FILLING,
3765 EL_QUICKSAND_EMPTYING,
3767 EL_MAGIC_WALL_ACTIVE,
3768 EL_MAGIC_WALL_EMPTYING,
3769 EL_MAGIC_WALL_FILLING,
3773 EL_BD_MAGIC_WALL_ACTIVE,
3774 EL_BD_MAGIC_WALL_EMPTYING,
3775 EL_BD_MAGIC_WALL_FULL,
3776 EL_BD_MAGIC_WALL_FILLING,
3777 EL_BD_MAGIC_WALL_DEAD,
3786 EL_SP_TERMINAL_ACTIVE,
3790 EL_INVISIBLE_WALL_ACTIVE,
3791 EL_SWITCHGATE_SWITCH_UP,
3792 EL_SWITCHGATE_SWITCH_DOWN,
3794 EL_TIMEGATE_SWITCH_ACTIVE,
3806 // the following elements are a direct copy of "indestructible" elements,
3807 // except "EL_ACID", which is "indestructible", but not "solid"!
3812 EL_ACID_POOL_TOPLEFT,
3813 EL_ACID_POOL_TOPRIGHT,
3814 EL_ACID_POOL_BOTTOMLEFT,
3815 EL_ACID_POOL_BOTTOM,
3816 EL_ACID_POOL_BOTTOMRIGHT,
3817 EL_SP_HARDWARE_GRAY,
3818 EL_SP_HARDWARE_GREEN,
3819 EL_SP_HARDWARE_BLUE,
3821 EL_SP_HARDWARE_YELLOW,
3822 EL_SP_HARDWARE_BASE_1,
3823 EL_SP_HARDWARE_BASE_2,
3824 EL_SP_HARDWARE_BASE_3,
3825 EL_SP_HARDWARE_BASE_4,
3826 EL_SP_HARDWARE_BASE_5,
3827 EL_SP_HARDWARE_BASE_6,
3828 EL_INVISIBLE_STEELWALL,
3829 EL_INVISIBLE_STEELWALL_ACTIVE,
3830 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3831 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3832 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3833 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3834 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3835 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3836 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3837 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3838 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3839 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3840 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3841 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3843 EL_LIGHT_SWITCH_ACTIVE,
3844 EL_SIGN_EXCLAMATION,
3845 EL_SIGN_RADIOACTIVITY,
3852 EL_SIGN_ENTRY_FORBIDDEN,
3853 EL_SIGN_EMERGENCY_EXIT,
3861 EL_STEEL_EXIT_CLOSED,
3863 EL_STEEL_EXIT_OPENING,
3864 EL_STEEL_EXIT_CLOSING,
3865 EL_EM_STEEL_EXIT_CLOSED,
3866 EL_EM_STEEL_EXIT_OPEN,
3867 EL_EM_STEEL_EXIT_OPENING,
3868 EL_EM_STEEL_EXIT_CLOSING,
3869 EL_DC_STEELWALL_1_LEFT,
3870 EL_DC_STEELWALL_1_RIGHT,
3871 EL_DC_STEELWALL_1_TOP,
3872 EL_DC_STEELWALL_1_BOTTOM,
3873 EL_DC_STEELWALL_1_HORIZONTAL,
3874 EL_DC_STEELWALL_1_VERTICAL,
3875 EL_DC_STEELWALL_1_TOPLEFT,
3876 EL_DC_STEELWALL_1_TOPRIGHT,
3877 EL_DC_STEELWALL_1_BOTTOMLEFT,
3878 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3879 EL_DC_STEELWALL_1_TOPLEFT_2,
3880 EL_DC_STEELWALL_1_TOPRIGHT_2,
3881 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3882 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3883 EL_DC_STEELWALL_2_LEFT,
3884 EL_DC_STEELWALL_2_RIGHT,
3885 EL_DC_STEELWALL_2_TOP,
3886 EL_DC_STEELWALL_2_BOTTOM,
3887 EL_DC_STEELWALL_2_HORIZONTAL,
3888 EL_DC_STEELWALL_2_VERTICAL,
3889 EL_DC_STEELWALL_2_MIDDLE,
3890 EL_DC_STEELWALL_2_SINGLE,
3891 EL_STEELWALL_SLIPPERY,
3905 EL_GATE_1_GRAY_ACTIVE,
3906 EL_GATE_2_GRAY_ACTIVE,
3907 EL_GATE_3_GRAY_ACTIVE,
3908 EL_GATE_4_GRAY_ACTIVE,
3917 EL_EM_GATE_1_GRAY_ACTIVE,
3918 EL_EM_GATE_2_GRAY_ACTIVE,
3919 EL_EM_GATE_3_GRAY_ACTIVE,
3920 EL_EM_GATE_4_GRAY_ACTIVE,
3929 EL_EMC_GATE_5_GRAY_ACTIVE,
3930 EL_EMC_GATE_6_GRAY_ACTIVE,
3931 EL_EMC_GATE_7_GRAY_ACTIVE,
3932 EL_EMC_GATE_8_GRAY_ACTIVE,
3934 EL_DC_GATE_WHITE_GRAY,
3935 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3936 EL_DC_GATE_FAKE_GRAY,
3938 EL_SWITCHGATE_OPENING,
3939 EL_SWITCHGATE_CLOSED,
3940 EL_SWITCHGATE_CLOSING,
3941 EL_DC_SWITCHGATE_SWITCH_UP,
3942 EL_DC_SWITCHGATE_SWITCH_DOWN,
3944 EL_TIMEGATE_OPENING,
3946 EL_TIMEGATE_CLOSING,
3947 EL_DC_TIMEGATE_SWITCH,
3948 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3952 EL_TUBE_VERTICAL_LEFT,
3953 EL_TUBE_VERTICAL_RIGHT,
3954 EL_TUBE_HORIZONTAL_UP,
3955 EL_TUBE_HORIZONTAL_DOWN,
3960 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3961 EL_EXPANDABLE_STEELWALL_VERTICAL,
3962 EL_EXPANDABLE_STEELWALL_ANY,
3967 static int ep_classic_enemy[] =
3984 static int ep_belt[] =
3986 EL_CONVEYOR_BELT_1_LEFT,
3987 EL_CONVEYOR_BELT_1_MIDDLE,
3988 EL_CONVEYOR_BELT_1_RIGHT,
3989 EL_CONVEYOR_BELT_2_LEFT,
3990 EL_CONVEYOR_BELT_2_MIDDLE,
3991 EL_CONVEYOR_BELT_2_RIGHT,
3992 EL_CONVEYOR_BELT_3_LEFT,
3993 EL_CONVEYOR_BELT_3_MIDDLE,
3994 EL_CONVEYOR_BELT_3_RIGHT,
3995 EL_CONVEYOR_BELT_4_LEFT,
3996 EL_CONVEYOR_BELT_4_MIDDLE,
3997 EL_CONVEYOR_BELT_4_RIGHT,
4002 static int ep_belt_active[] =
4004 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4005 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4006 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4007 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4008 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4009 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4010 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4011 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4012 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4013 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4014 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4015 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4020 static int ep_belt_switch[] =
4022 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4023 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4024 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4025 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4026 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4027 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4028 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4029 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4030 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4031 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4032 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4033 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4038 static int ep_tube[] =
4045 EL_TUBE_HORIZONTAL_UP,
4046 EL_TUBE_HORIZONTAL_DOWN,
4048 EL_TUBE_VERTICAL_LEFT,
4049 EL_TUBE_VERTICAL_RIGHT,
4055 static int ep_acid_pool[] =
4057 EL_ACID_POOL_TOPLEFT,
4058 EL_ACID_POOL_TOPRIGHT,
4059 EL_ACID_POOL_BOTTOMLEFT,
4060 EL_ACID_POOL_BOTTOM,
4061 EL_ACID_POOL_BOTTOMRIGHT,
4066 static int ep_keygate[] =
4076 EL_GATE_1_GRAY_ACTIVE,
4077 EL_GATE_2_GRAY_ACTIVE,
4078 EL_GATE_3_GRAY_ACTIVE,
4079 EL_GATE_4_GRAY_ACTIVE,
4088 EL_EM_GATE_1_GRAY_ACTIVE,
4089 EL_EM_GATE_2_GRAY_ACTIVE,
4090 EL_EM_GATE_3_GRAY_ACTIVE,
4091 EL_EM_GATE_4_GRAY_ACTIVE,
4100 EL_EMC_GATE_5_GRAY_ACTIVE,
4101 EL_EMC_GATE_6_GRAY_ACTIVE,
4102 EL_EMC_GATE_7_GRAY_ACTIVE,
4103 EL_EMC_GATE_8_GRAY_ACTIVE,
4105 EL_DC_GATE_WHITE_GRAY,
4106 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4111 static int ep_amoeboid[] =
4123 static int ep_amoebalive[] =
4134 static int ep_has_editor_content[] =
4140 EL_SOKOBAN_FIELD_PLAYER,
4157 static int ep_can_turn_each_move[] =
4159 // !!! do something with this one !!!
4163 static int ep_can_grow[] =
4177 static int ep_active_bomb[] =
4180 EL_EM_DYNAMITE_ACTIVE,
4181 EL_DYNABOMB_PLAYER_1_ACTIVE,
4182 EL_DYNABOMB_PLAYER_2_ACTIVE,
4183 EL_DYNABOMB_PLAYER_3_ACTIVE,
4184 EL_DYNABOMB_PLAYER_4_ACTIVE,
4185 EL_SP_DISK_RED_ACTIVE,
4190 static int ep_inactive[] =
4216 EL_QUICKSAND_FAST_EMPTY,
4239 EL_GATE_1_GRAY_ACTIVE,
4240 EL_GATE_2_GRAY_ACTIVE,
4241 EL_GATE_3_GRAY_ACTIVE,
4242 EL_GATE_4_GRAY_ACTIVE,
4251 EL_EM_GATE_1_GRAY_ACTIVE,
4252 EL_EM_GATE_2_GRAY_ACTIVE,
4253 EL_EM_GATE_3_GRAY_ACTIVE,
4254 EL_EM_GATE_4_GRAY_ACTIVE,
4263 EL_EMC_GATE_5_GRAY_ACTIVE,
4264 EL_EMC_GATE_6_GRAY_ACTIVE,
4265 EL_EMC_GATE_7_GRAY_ACTIVE,
4266 EL_EMC_GATE_8_GRAY_ACTIVE,
4268 EL_DC_GATE_WHITE_GRAY,
4269 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4270 EL_DC_GATE_FAKE_GRAY,
4273 EL_INVISIBLE_STEELWALL,
4281 EL_WALL_EMERALD_YELLOW,
4282 EL_DYNABOMB_INCREASE_NUMBER,
4283 EL_DYNABOMB_INCREASE_SIZE,
4284 EL_DYNABOMB_INCREASE_POWER,
4288 EL_SOKOBAN_FIELD_EMPTY,
4289 EL_SOKOBAN_FIELD_FULL,
4290 EL_WALL_EMERALD_RED,
4291 EL_WALL_EMERALD_PURPLE,
4292 EL_ACID_POOL_TOPLEFT,
4293 EL_ACID_POOL_TOPRIGHT,
4294 EL_ACID_POOL_BOTTOMLEFT,
4295 EL_ACID_POOL_BOTTOM,
4296 EL_ACID_POOL_BOTTOMRIGHT,
4300 EL_BD_MAGIC_WALL_DEAD,
4302 EL_DC_MAGIC_WALL_DEAD,
4303 EL_AMOEBA_TO_DIAMOND,
4311 EL_SP_GRAVITY_PORT_RIGHT,
4312 EL_SP_GRAVITY_PORT_DOWN,
4313 EL_SP_GRAVITY_PORT_LEFT,
4314 EL_SP_GRAVITY_PORT_UP,
4315 EL_SP_PORT_HORIZONTAL,
4316 EL_SP_PORT_VERTICAL,
4327 EL_SP_HARDWARE_GRAY,
4328 EL_SP_HARDWARE_GREEN,
4329 EL_SP_HARDWARE_BLUE,
4331 EL_SP_HARDWARE_YELLOW,
4332 EL_SP_HARDWARE_BASE_1,
4333 EL_SP_HARDWARE_BASE_2,
4334 EL_SP_HARDWARE_BASE_3,
4335 EL_SP_HARDWARE_BASE_4,
4336 EL_SP_HARDWARE_BASE_5,
4337 EL_SP_HARDWARE_BASE_6,
4338 EL_SP_GRAVITY_ON_PORT_LEFT,
4339 EL_SP_GRAVITY_ON_PORT_RIGHT,
4340 EL_SP_GRAVITY_ON_PORT_UP,
4341 EL_SP_GRAVITY_ON_PORT_DOWN,
4342 EL_SP_GRAVITY_OFF_PORT_LEFT,
4343 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4344 EL_SP_GRAVITY_OFF_PORT_UP,
4345 EL_SP_GRAVITY_OFF_PORT_DOWN,
4346 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4347 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4348 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4349 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4350 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4351 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4352 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4353 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4354 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4355 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4356 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4357 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4358 EL_SIGN_EXCLAMATION,
4359 EL_SIGN_RADIOACTIVITY,
4366 EL_SIGN_ENTRY_FORBIDDEN,
4367 EL_SIGN_EMERGENCY_EXIT,
4375 EL_DC_STEELWALL_1_LEFT,
4376 EL_DC_STEELWALL_1_RIGHT,
4377 EL_DC_STEELWALL_1_TOP,
4378 EL_DC_STEELWALL_1_BOTTOM,
4379 EL_DC_STEELWALL_1_HORIZONTAL,
4380 EL_DC_STEELWALL_1_VERTICAL,
4381 EL_DC_STEELWALL_1_TOPLEFT,
4382 EL_DC_STEELWALL_1_TOPRIGHT,
4383 EL_DC_STEELWALL_1_BOTTOMLEFT,
4384 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4385 EL_DC_STEELWALL_1_TOPLEFT_2,
4386 EL_DC_STEELWALL_1_TOPRIGHT_2,
4387 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4388 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4389 EL_DC_STEELWALL_2_LEFT,
4390 EL_DC_STEELWALL_2_RIGHT,
4391 EL_DC_STEELWALL_2_TOP,
4392 EL_DC_STEELWALL_2_BOTTOM,
4393 EL_DC_STEELWALL_2_HORIZONTAL,
4394 EL_DC_STEELWALL_2_VERTICAL,
4395 EL_DC_STEELWALL_2_MIDDLE,
4396 EL_DC_STEELWALL_2_SINGLE,
4397 EL_STEELWALL_SLIPPERY,
4402 EL_EMC_WALL_SLIPPERY_1,
4403 EL_EMC_WALL_SLIPPERY_2,
4404 EL_EMC_WALL_SLIPPERY_3,
4405 EL_EMC_WALL_SLIPPERY_4,
4426 static int ep_em_slippery_wall[] =
4431 static int ep_gfx_crumbled[] =
4442 static int ep_editor_cascade_active[] =
4444 EL_INTERNAL_CASCADE_BD_ACTIVE,
4445 EL_INTERNAL_CASCADE_EM_ACTIVE,
4446 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4447 EL_INTERNAL_CASCADE_RND_ACTIVE,
4448 EL_INTERNAL_CASCADE_SB_ACTIVE,
4449 EL_INTERNAL_CASCADE_SP_ACTIVE,
4450 EL_INTERNAL_CASCADE_DC_ACTIVE,
4451 EL_INTERNAL_CASCADE_DX_ACTIVE,
4452 EL_INTERNAL_CASCADE_MM_ACTIVE,
4453 EL_INTERNAL_CASCADE_DF_ACTIVE,
4454 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4455 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4456 EL_INTERNAL_CASCADE_CE_ACTIVE,
4457 EL_INTERNAL_CASCADE_GE_ACTIVE,
4458 EL_INTERNAL_CASCADE_ES_ACTIVE,
4459 EL_INTERNAL_CASCADE_REF_ACTIVE,
4460 EL_INTERNAL_CASCADE_USER_ACTIVE,
4461 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4466 static int ep_editor_cascade_inactive[] =
4468 EL_INTERNAL_CASCADE_BD,
4469 EL_INTERNAL_CASCADE_EM,
4470 EL_INTERNAL_CASCADE_EMC,
4471 EL_INTERNAL_CASCADE_RND,
4472 EL_INTERNAL_CASCADE_SB,
4473 EL_INTERNAL_CASCADE_SP,
4474 EL_INTERNAL_CASCADE_DC,
4475 EL_INTERNAL_CASCADE_DX,
4476 EL_INTERNAL_CASCADE_MM,
4477 EL_INTERNAL_CASCADE_DF,
4478 EL_INTERNAL_CASCADE_CHARS,
4479 EL_INTERNAL_CASCADE_STEEL_CHARS,
4480 EL_INTERNAL_CASCADE_CE,
4481 EL_INTERNAL_CASCADE_GE,
4482 EL_INTERNAL_CASCADE_ES,
4483 EL_INTERNAL_CASCADE_REF,
4484 EL_INTERNAL_CASCADE_USER,
4485 EL_INTERNAL_CASCADE_DYNAMIC,
4490 static int ep_obsolete[] =
4494 EL_EM_KEY_1_FILE_OBSOLETE,
4495 EL_EM_KEY_2_FILE_OBSOLETE,
4496 EL_EM_KEY_3_FILE_OBSOLETE,
4497 EL_EM_KEY_4_FILE_OBSOLETE,
4498 EL_ENVELOPE_OBSOLETE,
4507 } element_properties[] =
4509 { ep_diggable, EP_DIGGABLE },
4510 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4511 { ep_dont_run_into, EP_DONT_RUN_INTO },
4512 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4513 { ep_dont_touch, EP_DONT_TOUCH },
4514 { ep_indestructible, EP_INDESTRUCTIBLE },
4515 { ep_slippery, EP_SLIPPERY },
4516 { ep_can_change, EP_CAN_CHANGE },
4517 { ep_can_move, EP_CAN_MOVE },
4518 { ep_can_fall, EP_CAN_FALL },
4519 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4520 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4521 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4522 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4523 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4524 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4525 { ep_walkable_over, EP_WALKABLE_OVER },
4526 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4527 { ep_walkable_under, EP_WALKABLE_UNDER },
4528 { ep_passable_over, EP_PASSABLE_OVER },
4529 { ep_passable_inside, EP_PASSABLE_INSIDE },
4530 { ep_passable_under, EP_PASSABLE_UNDER },
4531 { ep_droppable, EP_DROPPABLE },
4532 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4533 { ep_pushable, EP_PUSHABLE },
4534 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4535 { ep_protected, EP_PROTECTED },
4536 { ep_throwable, EP_THROWABLE },
4537 { ep_can_explode, EP_CAN_EXPLODE },
4538 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4540 { ep_empty_space, EP_EMPTY_SPACE },
4541 { ep_player, EP_PLAYER },
4542 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4543 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4544 { ep_switchable, EP_SWITCHABLE },
4545 { ep_bd_element, EP_BD_ELEMENT },
4546 { ep_sp_element, EP_SP_ELEMENT },
4547 { ep_sb_element, EP_SB_ELEMENT },
4549 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4550 { ep_food_penguin, EP_FOOD_PENGUIN },
4551 { ep_food_pig, EP_FOOD_PIG },
4552 { ep_historic_wall, EP_HISTORIC_WALL },
4553 { ep_historic_solid, EP_HISTORIC_SOLID },
4554 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4555 { ep_belt, EP_BELT },
4556 { ep_belt_active, EP_BELT_ACTIVE },
4557 { ep_belt_switch, EP_BELT_SWITCH },
4558 { ep_tube, EP_TUBE },
4559 { ep_acid_pool, EP_ACID_POOL },
4560 { ep_keygate, EP_KEYGATE },
4561 { ep_amoeboid, EP_AMOEBOID },
4562 { ep_amoebalive, EP_AMOEBALIVE },
4563 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4564 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4565 { ep_can_grow, EP_CAN_GROW },
4566 { ep_active_bomb, EP_ACTIVE_BOMB },
4567 { ep_inactive, EP_INACTIVE },
4569 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4571 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4573 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4574 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4576 { ep_obsolete, EP_OBSOLETE },
4583 // always start with reliable default values (element has no properties)
4584 // (but never initialize clipboard elements after the very first time)
4585 // (to be able to use clipboard elements between several levels)
4586 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4587 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4588 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4589 SET_PROPERTY(i, j, FALSE);
4591 // set all base element properties from above array definitions
4592 for (i = 0; element_properties[i].elements != NULL; i++)
4593 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4594 SET_PROPERTY((element_properties[i].elements)[j],
4595 element_properties[i].property, TRUE);
4597 // copy properties to some elements that are only stored in level file
4598 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4599 for (j = 0; copy_properties[j][0] != -1; j++)
4600 if (HAS_PROPERTY(copy_properties[j][0], i))
4601 for (k = 1; k <= 4; k++)
4602 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4604 // set static element properties that are not listed in array definitions
4605 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4606 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4608 clipboard_elements_initialized = TRUE;
4611 void InitElementPropertiesEngine(int engine_version)
4613 static int no_wall_properties[] =
4616 EP_COLLECTIBLE_ONLY,
4618 EP_DONT_COLLIDE_WITH,
4621 EP_CAN_SMASH_PLAYER,
4622 EP_CAN_SMASH_ENEMIES,
4623 EP_CAN_SMASH_EVERYTHING,
4628 EP_FOOD_DARK_YAMYAM,
4644 /* important: after initialization in InitElementPropertiesStatic(), the
4645 elements are not again initialized to a default value; therefore all
4646 changes have to make sure that they leave the element with a defined
4647 property (which means that conditional property changes must be set to
4648 a reliable default value before) */
4650 // resolve group elements
4651 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4652 ResolveGroupElement(EL_GROUP_START + i);
4654 // set all special, combined or engine dependent element properties
4655 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4657 // do not change (already initialized) clipboard elements here
4658 if (IS_CLIPBOARD_ELEMENT(i))
4661 // ---------- INACTIVE ----------------------------------------------------
4662 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4663 i <= EL_CHAR_END) ||
4664 (i >= EL_STEEL_CHAR_START &&
4665 i <= EL_STEEL_CHAR_END)));
4667 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4668 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4669 IS_WALKABLE_INSIDE(i) ||
4670 IS_WALKABLE_UNDER(i)));
4672 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4673 IS_PASSABLE_INSIDE(i) ||
4674 IS_PASSABLE_UNDER(i)));
4676 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4677 IS_PASSABLE_OVER(i)));
4679 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4680 IS_PASSABLE_INSIDE(i)));
4682 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4683 IS_PASSABLE_UNDER(i)));
4685 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4688 // ---------- COLLECTIBLE -------------------------------------------------
4689 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4693 // ---------- SNAPPABLE ---------------------------------------------------
4694 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4695 IS_COLLECTIBLE(i) ||
4699 // ---------- WALL --------------------------------------------------------
4700 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4702 for (j = 0; no_wall_properties[j] != -1; j++)
4703 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4704 i >= EL_FIRST_RUNTIME_UNREAL)
4705 SET_PROPERTY(i, EP_WALL, FALSE);
4707 if (IS_HISTORIC_WALL(i))
4708 SET_PROPERTY(i, EP_WALL, TRUE);
4710 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4711 if (engine_version < VERSION_IDENT(2,2,0,0))
4712 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4714 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4716 !IS_COLLECTIBLE(i)));
4718 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4719 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4720 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4722 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4725 // ---------- EXPLOSION_PROOF ---------------------------------------------
4727 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4728 else if (engine_version < VERSION_IDENT(2,2,0,0))
4729 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4731 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4735 if (IS_CUSTOM_ELEMENT(i))
4737 // these are additional properties which are initially false when set
4739 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4741 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4742 if (DONT_COLLIDE_WITH(i))
4743 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4745 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4746 if (CAN_SMASH_EVERYTHING(i))
4747 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4748 if (CAN_SMASH_ENEMIES(i))
4749 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4752 // ---------- CAN_SMASH ---------------------------------------------------
4753 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4754 CAN_SMASH_ENEMIES(i) ||
4755 CAN_SMASH_EVERYTHING(i)));
4757 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4758 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4759 EXPLODES_BY_FIRE(i)));
4761 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4762 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4763 EXPLODES_SMASHED(i)));
4765 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4766 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4767 EXPLODES_IMPACT(i)));
4769 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4770 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4772 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4773 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4774 i == EL_BLACK_ORB));
4776 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4777 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4779 IS_CUSTOM_ELEMENT(i)));
4781 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4782 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4783 i == EL_SP_ELECTRON));
4785 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4786 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4787 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4788 getMoveIntoAcidProperty(&level, i));
4790 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4791 if (MAYBE_DONT_COLLIDE_WITH(i))
4792 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4793 getDontCollideWithProperty(&level, i));
4795 // ---------- SP_PORT -----------------------------------------------------
4796 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4797 IS_PASSABLE_INSIDE(i)));
4799 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4800 for (j = 0; j < level.num_android_clone_elements; j++)
4801 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4803 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4805 // ---------- CAN_CHANGE --------------------------------------------------
4806 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4807 for (j = 0; j < element_info[i].num_change_pages; j++)
4808 if (element_info[i].change_page[j].can_change)
4809 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4811 // ---------- HAS_ACTION --------------------------------------------------
4812 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4813 for (j = 0; j < element_info[i].num_change_pages; j++)
4814 if (element_info[i].change_page[j].has_action)
4815 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4817 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4818 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4821 // ---------- GFX_CRUMBLED ------------------------------------------------
4822 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4823 element_info[i].crumbled[ACTION_DEFAULT] !=
4824 element_info[i].graphic[ACTION_DEFAULT]);
4826 // ---------- EDITOR_CASCADE ----------------------------------------------
4827 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4828 IS_EDITOR_CASCADE_INACTIVE(i)));
4831 // dynamically adjust element properties according to game engine version
4833 static int ep_em_slippery_wall[] =
4838 EL_EXPANDABLE_WALL_HORIZONTAL,
4839 EL_EXPANDABLE_WALL_VERTICAL,
4840 EL_EXPANDABLE_WALL_ANY,
4841 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4842 EL_EXPANDABLE_STEELWALL_VERTICAL,
4843 EL_EXPANDABLE_STEELWALL_ANY,
4844 EL_EXPANDABLE_STEELWALL_GROWING,
4848 static int ep_em_explodes_by_fire[] =
4851 EL_EM_DYNAMITE_ACTIVE,
4856 // special EM style gems behaviour
4857 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4858 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4859 level.em_slippery_gems);
4861 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4862 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4863 (level.em_slippery_gems &&
4864 engine_version > VERSION_IDENT(2,0,1,0)));
4866 // special EM style explosion behaviour regarding chain reactions
4867 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4868 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4869 level.em_explodes_by_fire);
4872 // this is needed because some graphics depend on element properties
4873 if (game_status == GAME_MODE_PLAYING)
4874 InitElementGraphicInfo();
4877 void InitElementPropertiesGfxElement(void)
4881 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4883 struct ElementInfo *ei = &element_info[i];
4885 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4889 static void InitGlobal(void)
4894 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4896 // check if element_name_info entry defined for each element in "main.h"
4897 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4898 Fail("undefined 'element_name_info' entry for element %d", i);
4900 element_info[i].token_name = element_name_info[i].token_name;
4901 element_info[i].class_name = element_name_info[i].class_name;
4902 element_info[i].editor_description= element_name_info[i].editor_description;
4905 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4907 // check if global_anim_name_info defined for each entry in "main.h"
4908 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4909 global_anim_name_info[i].token_name == NULL)
4910 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4912 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4915 // create hash to store URLs for global animations
4916 anim_url_hash = newSetupFileHash();
4918 // create hash from image config list
4919 image_config_hash = newSetupFileHash();
4920 for (i = 0; image_config[i].token != NULL; i++)
4921 setHashEntry(image_config_hash,
4922 image_config[i].token,
4923 image_config[i].value);
4925 // create hash from element token list
4926 element_token_hash = newSetupFileHash();
4927 for (i = 0; element_name_info[i].token_name != NULL; i++)
4928 setHashEntry(element_token_hash,
4929 element_name_info[i].token_name,
4932 // create hash from graphic token list
4933 graphic_token_hash = newSetupFileHash();
4934 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4935 if (strSuffix(image_config[i].value, ".png") ||
4936 strSuffix(image_config[i].value, ".pcx") ||
4937 strSuffix(image_config[i].value, ".wav") ||
4938 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4939 setHashEntry(graphic_token_hash,
4940 image_config[i].token,
4941 int2str(graphic++, 0));
4943 // create hash from font token list
4944 font_token_hash = newSetupFileHash();
4945 for (i = 0; font_info[i].token_name != NULL; i++)
4946 setHashEntry(font_token_hash,
4947 font_info[i].token_name,
4950 // set default filenames for all cloned graphics in static configuration
4951 for (i = 0; image_config[i].token != NULL; i++)
4953 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4955 char *token = image_config[i].token;
4956 char *token_clone_from = getStringCat2(token, ".clone_from");
4957 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4959 if (token_cloned != NULL)
4961 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4963 if (value_cloned != NULL)
4965 // set default filename in static configuration
4966 image_config[i].value = value_cloned;
4968 // set default filename in image config hash
4969 setHashEntry(image_config_hash, token, value_cloned);
4973 free(token_clone_from);
4977 // always start with reliable default values (all elements)
4978 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4979 ActiveElement[i] = i;
4981 // now add all entries that have an active state (active elements)
4982 for (i = 0; element_with_active_state[i].element != -1; i++)
4984 int element = element_with_active_state[i].element;
4985 int element_active = element_with_active_state[i].element_active;
4987 ActiveElement[element] = element_active;
4990 // always start with reliable default values (all buttons)
4991 for (i = 0; i < NUM_IMAGE_FILES; i++)
4992 ActiveButton[i] = i;
4994 // now add all entries that have an active state (active buttons)
4995 for (i = 0; button_with_active_state[i].button != -1; i++)
4997 int button = button_with_active_state[i].button;
4998 int button_active = button_with_active_state[i].button_active;
5000 ActiveButton[button] = button_active;
5003 // always start with reliable default values (all fonts)
5004 for (i = 0; i < NUM_FONTS; i++)
5007 // now add all entries that have an active state (active fonts)
5008 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5010 int font = font_with_active_state[i].font_nr;
5011 int font_active = font_with_active_state[i].font_nr_active;
5013 ActiveFont[font] = font_active;
5016 global.autoplay_leveldir = NULL;
5017 global.patchtapes_leveldir = NULL;
5018 global.convert_leveldir = NULL;
5019 global.dumplevel_leveldir = NULL;
5020 global.dumptape_leveldir = NULL;
5021 global.create_sketch_images_dir = NULL;
5022 global.create_collect_images_dir = NULL;
5024 global.frames_per_second = 0;
5025 global.show_frames_per_second = FALSE;
5027 global.border_status = GAME_MODE_LOADING;
5028 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5030 global.use_envelope_request = FALSE;
5032 global.user_names = NULL;
5035 static void Execute_Command(char *command)
5039 if (strEqual(command, "print graphicsinfo.conf"))
5041 Print("# You can configure additional/alternative image files here.\n");
5042 Print("# (The entries below are default and therefore commented out.)\n");
5044 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5046 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5049 for (i = 0; image_config[i].token != NULL; i++)
5050 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5051 image_config[i].value));
5055 else if (strEqual(command, "print soundsinfo.conf"))
5057 Print("# You can configure additional/alternative sound files here.\n");
5058 Print("# (The entries below are default and therefore commented out.)\n");
5060 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5062 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5065 for (i = 0; sound_config[i].token != NULL; i++)
5066 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5067 sound_config[i].value));
5071 else if (strEqual(command, "print musicinfo.conf"))
5073 Print("# You can configure additional/alternative music files here.\n");
5074 Print("# (The entries below are default and therefore commented out.)\n");
5076 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5078 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5081 for (i = 0; music_config[i].token != NULL; i++)
5082 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5083 music_config[i].value));
5087 else if (strEqual(command, "print editorsetup.conf"))
5089 Print("# You can configure your personal editor element list here.\n");
5090 Print("# (The entries below are default and therefore commented out.)\n");
5093 // this is needed to be able to check element list for cascade elements
5094 InitElementPropertiesStatic();
5095 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5097 PrintEditorElementList();
5101 else if (strEqual(command, "print helpanim.conf"))
5103 Print("# You can configure different element help animations here.\n");
5104 Print("# (The entries below are default and therefore commented out.)\n");
5107 for (i = 0; helpanim_config[i].token != NULL; i++)
5109 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5110 helpanim_config[i].value));
5112 if (strEqual(helpanim_config[i].token, "end"))
5118 else if (strEqual(command, "print helptext.conf"))
5120 Print("# You can configure different element help text here.\n");
5121 Print("# (The entries below are default and therefore commented out.)\n");
5124 for (i = 0; helptext_config[i].token != NULL; i++)
5125 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5126 helptext_config[i].value));
5130 else if (strPrefix(command, "dump level "))
5132 char *filename = &command[11];
5134 if (fileExists(filename))
5136 LoadLevelFromFilename(&level, filename);
5142 char *leveldir = getStringCopy(filename); // read command parameters
5143 char *level_nr = strchr(leveldir, ' ');
5145 if (level_nr == NULL)
5146 Fail("cannot open file '%s'", filename);
5150 global.dumplevel_leveldir = leveldir;
5151 global.dumplevel_level_nr = atoi(level_nr);
5153 program.headless = TRUE;
5155 else if (strPrefix(command, "dump tape "))
5157 char *filename = &command[10];
5159 if (fileExists(filename))
5161 LoadTapeFromFilename(filename);
5167 char *leveldir = getStringCopy(filename); // read command parameters
5168 char *level_nr = strchr(leveldir, ' ');
5170 if (level_nr == NULL)
5171 Fail("cannot open file '%s'", filename);
5175 global.dumptape_leveldir = leveldir;
5176 global.dumptape_level_nr = atoi(level_nr);
5178 program.headless = TRUE;
5180 else if (strPrefix(command, "autoplay ") ||
5181 strPrefix(command, "autoffwd ") ||
5182 strPrefix(command, "autowarp ") ||
5183 strPrefix(command, "autotest ") ||
5184 strPrefix(command, "autosave ") ||
5185 strPrefix(command, "autoupload ") ||
5186 strPrefix(command, "autofix "))
5188 char *arg_ptr = strchr(command, ' ');
5189 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5191 global.autoplay_mode =
5192 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5193 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5194 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5195 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5196 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5197 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5198 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5199 AUTOPLAY_MODE_NONE);
5201 while (*str_ptr != '\0') // continue parsing string
5203 // cut leading whitespace from string, replace it by string terminator
5204 while (*str_ptr == ' ' || *str_ptr == '\t')
5207 if (*str_ptr == '\0') // end of string reached
5210 if (global.autoplay_leveldir == NULL) // read level set string
5212 global.autoplay_leveldir = str_ptr;
5213 global.autoplay_all = TRUE; // default: play all tapes
5215 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5216 global.autoplay_level[i] = FALSE;
5218 else // read level number string
5220 int level_nr = atoi(str_ptr); // get level_nr value
5222 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5223 global.autoplay_level[level_nr] = TRUE;
5225 global.autoplay_all = FALSE;
5228 // advance string pointer to the next whitespace (or end of string)
5229 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5233 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5234 program.headless = TRUE;
5236 else if (strPrefix(command, "patch tapes "))
5238 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5240 // skip leading whitespace
5241 while (*str_ptr == ' ' || *str_ptr == '\t')
5244 if (*str_ptr == '\0')
5245 Fail("cannot find MODE in command '%s'", command);
5247 global.patchtapes_mode = str_ptr; // store patch mode
5249 // advance to next whitespace (or end of string)
5250 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5253 while (*str_ptr != '\0') // continue parsing string
5255 // cut leading whitespace from string, replace it by string terminator
5256 while (*str_ptr == ' ' || *str_ptr == '\t')
5259 if (*str_ptr == '\0') // end of string reached
5262 if (global.patchtapes_leveldir == NULL) // read level set string
5264 global.patchtapes_leveldir = str_ptr;
5265 global.patchtapes_all = TRUE; // default: patch all tapes
5267 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5268 global.patchtapes_level[i] = FALSE;
5270 else // read level number string
5272 int level_nr = atoi(str_ptr); // get level_nr value
5274 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5275 global.patchtapes_level[level_nr] = TRUE;
5277 global.patchtapes_all = FALSE;
5280 // advance string pointer to the next whitespace (or end of string)
5281 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5285 if (global.patchtapes_leveldir == NULL)
5287 if (strEqual(global.patchtapes_mode, "help"))
5288 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5290 Fail("cannot find LEVELDIR in command '%s'", command);
5293 program.headless = TRUE;
5295 else if (strPrefix(command, "convert "))
5297 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5298 char *str_ptr = strchr(str_copy, ' ');
5300 global.convert_leveldir = str_copy;
5301 global.convert_level_nr = -1;
5303 if (str_ptr != NULL) // level number follows
5305 *str_ptr++ = '\0'; // terminate leveldir string
5306 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5309 program.headless = TRUE;
5311 else if (strPrefix(command, "create sketch images "))
5313 global.create_sketch_images_dir = getStringCopy(&command[21]);
5315 if (access(global.create_sketch_images_dir, W_OK) != 0)
5316 Fail("image target directory '%s' not found or not writable",
5317 global.create_sketch_images_dir);
5319 else if (strPrefix(command, "create collect image "))
5321 global.create_collect_images_dir = getStringCopy(&command[21]);
5323 if (access(global.create_collect_images_dir, W_OK) != 0)
5324 Fail("image target directory '%s' not found or not writable",
5325 global.create_collect_images_dir);
5327 else if (strPrefix(command, "create CE image "))
5329 CreateCustomElementImages(&command[16]);
5335 FailWithHelp("unrecognized command '%s'", command);
5338 // disable networking if any valid command was recognized
5339 options.network = setup.network_mode = FALSE;
5342 static void InitSetup(void)
5344 LoadUserNames(); // global user names
5345 LoadUserSetup(); // global user number
5347 LoadSetup(); // global setup info
5349 // set some options from setup file
5351 if (setup.options.verbose)
5352 options.verbose = TRUE;
5354 if (setup.debug.show_frames_per_second)
5355 global.show_frames_per_second = TRUE;
5358 static void InitGameInfo(void)
5360 game.restart_level = FALSE;
5361 game.restart_game_message = NULL;
5363 game.request_active = FALSE;
5364 game.request_active_or_moving = FALSE;
5366 game.use_masked_elements_initial = FALSE;
5369 static void InitPlayerInfo(void)
5373 // choose default local player
5374 local_player = &stored_player[0];
5376 for (i = 0; i < MAX_PLAYERS; i++)
5378 stored_player[i].connected_locally = FALSE;
5379 stored_player[i].connected_network = FALSE;
5382 local_player->connected_locally = TRUE;
5385 static void InitArtworkInfo(void)
5390 static char *get_string_in_brackets(char *string)
5392 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5394 sprintf(string_in_brackets, "[%s]", string);
5396 return string_in_brackets;
5399 static char *get_level_id_suffix(int id_nr)
5401 char *id_suffix = checked_malloc(1 + 3 + 1);
5403 if (id_nr < 0 || id_nr > 999)
5406 sprintf(id_suffix, ".%03d", id_nr);
5411 static void InitArtworkConfig(void)
5413 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5415 NUM_GLOBAL_ANIM_TOKENS + 1];
5416 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5417 NUM_GLOBAL_ANIM_TOKENS + 1];
5418 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5419 NUM_GLOBAL_ANIM_TOKENS + 1];
5420 static char *action_id_suffix[NUM_ACTIONS + 1];
5421 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5422 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5423 static char *level_id_suffix[MAX_LEVELS + 1];
5424 static char *dummy[1] = { NULL };
5425 static char *ignore_generic_tokens[] =
5430 "program_copyright",
5435 static char **ignore_image_tokens;
5436 static char **ignore_sound_tokens;
5437 static char **ignore_music_tokens;
5438 int num_ignore_generic_tokens;
5439 int num_ignore_image_tokens;
5440 int num_ignore_sound_tokens;
5441 int num_ignore_music_tokens;
5444 // dynamically determine list of generic tokens to be ignored
5445 num_ignore_generic_tokens = 0;
5446 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5447 num_ignore_generic_tokens++;
5449 // dynamically determine list of image tokens to be ignored
5450 num_ignore_image_tokens = num_ignore_generic_tokens;
5451 for (i = 0; image_config_vars[i].token != NULL; i++)
5452 num_ignore_image_tokens++;
5453 ignore_image_tokens =
5454 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5455 for (i = 0; i < num_ignore_generic_tokens; i++)
5456 ignore_image_tokens[i] = ignore_generic_tokens[i];
5457 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5458 ignore_image_tokens[num_ignore_generic_tokens + i] =
5459 image_config_vars[i].token;
5460 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5462 // dynamically determine list of sound tokens to be ignored
5463 num_ignore_sound_tokens = num_ignore_generic_tokens;
5464 ignore_sound_tokens =
5465 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5466 for (i = 0; i < num_ignore_generic_tokens; i++)
5467 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5468 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5470 // dynamically determine list of music tokens to be ignored
5471 num_ignore_music_tokens = num_ignore_generic_tokens;
5472 ignore_music_tokens =
5473 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5474 for (i = 0; i < num_ignore_generic_tokens; i++)
5475 ignore_music_tokens[i] = ignore_generic_tokens[i];
5476 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5479 image_id_prefix[i] = element_info[i].token_name;
5480 for (i = 0; i < NUM_FONTS; i++)
5481 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5482 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5483 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5484 global_anim_info[i].token_name;
5485 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5487 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5488 sound_id_prefix[i] = element_info[i].token_name;
5489 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5490 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5491 get_string_in_brackets(element_info[i].class_name);
5492 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5493 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5494 global_anim_info[i].token_name;
5495 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5497 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5498 music_id_prefix[i] = music_prefix_info[i].prefix;
5499 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5500 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5501 global_anim_info[i].token_name;
5502 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5504 for (i = 0; i < NUM_ACTIONS; i++)
5505 action_id_suffix[i] = element_action_info[i].suffix;
5506 action_id_suffix[NUM_ACTIONS] = NULL;
5508 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5509 direction_id_suffix[i] = element_direction_info[i].suffix;
5510 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5512 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5513 special_id_suffix[i] = special_suffix_info[i].suffix;
5514 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5516 for (i = 0; i < MAX_LEVELS; i++)
5517 level_id_suffix[i] = get_level_id_suffix(i);
5518 level_id_suffix[MAX_LEVELS] = NULL;
5520 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5521 image_id_prefix, action_id_suffix, direction_id_suffix,
5522 special_id_suffix, ignore_image_tokens);
5523 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5524 sound_id_prefix, action_id_suffix, dummy,
5525 special_id_suffix, ignore_sound_tokens);
5526 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5527 music_id_prefix, action_id_suffix, special_id_suffix,
5528 level_id_suffix, ignore_music_tokens);
5531 static void InitMixer(void)
5538 static void InitVideoOverlay(void)
5540 // if virtual buttons are not loaded from setup file, repeat initializing
5541 // virtual buttons grid with default values now that video is initialized
5542 if (!setup.touch.grid_initialized)
5545 InitTileCursorInfo();
5549 void InitGfxBuffers(void)
5551 static int win_xsize_last = -1;
5552 static int win_ysize_last = -1;
5554 // create additional image buffers for double-buffering and cross-fading
5556 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5558 // used to temporarily store the backbuffer -- only re-create if changed
5559 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5560 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5562 win_xsize_last = WIN_XSIZE;
5563 win_ysize_last = WIN_YSIZE;
5566 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5567 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5568 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5569 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5571 // initialize screen properties
5572 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5573 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5575 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5576 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5577 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5578 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5579 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5580 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5582 // required if door size definitions have changed
5583 InitGraphicCompatibilityInfo_Doors();
5585 InitGfxBuffers_EM();
5586 InitGfxBuffers_SP();
5589 static void InitGfx(void)
5591 struct GraphicInfo *graphic_info_last = graphic_info;
5592 char *filename_font_initial = NULL;
5593 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5594 char *image_token[NUM_INITIAL_IMAGES] =
5596 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5597 CONFIG_TOKEN_GLOBAL_BUSY,
5598 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5599 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5600 CONFIG_TOKEN_BACKGROUND_LOADING
5602 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5606 &init.busy_playfield
5608 Bitmap *bitmap_font_initial = NULL;
5609 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5612 // determine settings for initial font (for displaying startup messages)
5613 for (i = 0; image_config[i].token != NULL; i++)
5615 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5617 char font_token[128];
5620 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5621 len_font_token = strlen(font_token);
5623 if (strEqual(image_config[i].token, font_token))
5625 filename_font_initial = image_config[i].value;
5627 else if (strlen(image_config[i].token) > len_font_token &&
5628 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5630 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5631 font_initial[j].src_x = atoi(image_config[i].value);
5632 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5633 font_initial[j].src_y = atoi(image_config[i].value);
5634 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5635 font_initial[j].width = atoi(image_config[i].value);
5636 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5637 font_initial[j].height = atoi(image_config[i].value);
5642 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5644 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5645 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5648 if (filename_font_initial == NULL) // should not happen
5649 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5652 InitGfxCustomArtworkInfo();
5653 InitGfxOtherSettings();
5655 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5657 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5659 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5660 font_initial[j].bitmap = bitmap_font_initial;
5662 InitFontGraphicInfo();
5666 DrawInitTextHead("Loading graphics");
5668 InitMenuDesignSettings_Static();
5670 // initialize settings for initial images with default values
5671 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5672 for (j = 0; j < NUM_GFX_ARGS; j++)
5674 get_graphic_parameter_value(image_config_suffix[j].value,
5675 image_config_suffix[j].token,
5676 image_config_suffix[j].type);
5678 // read settings for initial images from default custom artwork config
5679 char *gfx_config_filename = getPath3(options.graphics_directory,
5681 GRAPHICSINFO_FILENAME);
5683 if (fileExists(gfx_config_filename))
5685 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5687 if (setup_file_hash)
5689 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5691 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5695 filename_image_initial[i] = getStringCopy(filename);
5697 for (j = 0; image_config_suffix[j].token != NULL; j++)
5699 int type = image_config_suffix[j].type;
5700 char *suffix = image_config_suffix[j].token;
5701 char *token = getStringCat2(image_token[i], suffix);
5702 char *value = getHashEntry(setup_file_hash, token);
5704 checked_free(token);
5708 get_graphic_parameter_value(value, suffix, type);
5713 // read values from custom graphics config file
5714 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5716 freeSetupFileHash(setup_file_hash);
5720 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5722 if (filename_image_initial[i] == NULL)
5724 int len_token = strlen(image_token[i]);
5726 // read settings for initial images from static default artwork config
5727 for (j = 0; image_config[j].token != NULL; j++)
5729 if (strEqual(image_config[j].token, image_token[i]))
5731 filename_image_initial[i] = getStringCopy(image_config[j].value);
5733 else if (strlen(image_config[j].token) > len_token &&
5734 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5736 for (k = 0; image_config_suffix[k].token != NULL; k++)
5738 if (strEqual(&image_config[j].token[len_token],
5739 image_config_suffix[k].token))
5741 get_graphic_parameter_value(image_config[j].value,
5742 image_config_suffix[k].token,
5743 image_config_suffix[k].type);
5750 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5752 if (filename_image_initial[i] == NULL) // should not happen
5753 Fail("cannot get filename for '%s'", image_token[i]);
5755 image_initial[i].bitmaps =
5756 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5758 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5759 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5760 LoadCustomImage(filename_image_initial[i]);
5762 checked_free(filename_image_initial[i]);
5765 graphic_info = image_initial; // graphic == 0 => image_initial
5767 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5768 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5770 graphic_info = graphic_info_last;
5772 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5774 // set image size for busy animations
5775 init_busy[i]->width = image_initial[i].width;
5776 init_busy[i]->height = image_initial[i].height;
5779 SetLoadingBackgroundImage();
5781 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5783 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5784 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5785 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5786 InitGfxDrawTileCursorFunction(DrawTileCursor);
5788 gfx.fade_border_source_status = global.border_status;
5789 gfx.fade_border_target_status = global.border_status;
5790 gfx.masked_border_bitmap_ptr = backbuffer;
5792 // use copy of busy animation to prevent change while reloading artwork
5796 static void InitGfxBackground(void)
5798 fieldbuffer = bitmap_db_field;
5799 SetDrawtoField(DRAW_TO_BACKBUFFER);
5801 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5803 redraw_mask = REDRAW_ALL;
5806 static void InitLevelInfo(void)
5808 LoadLevelInfo(); // global level info
5809 LoadLevelSetup_LastSeries(); // last played series info
5810 LoadLevelSetup_SeriesInfo(); // last played level info
5812 if (global.autoplay_leveldir &&
5813 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5815 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5816 global.autoplay_leveldir);
5817 if (leveldir_current == NULL)
5818 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5821 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5824 static void InitLevelArtworkInfo(void)
5826 LoadLevelArtworkInfo();
5829 static void InitImages(void)
5831 print_timestamp_init("InitImages");
5834 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5835 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5836 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5837 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5838 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5839 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5840 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5841 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5844 setLevelArtworkDir(artwork.gfx_first);
5847 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5848 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5849 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5850 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5851 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5852 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5853 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5854 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5858 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5859 leveldir_current->identifier,
5860 artwork.gfx_current_identifier,
5861 artwork.gfx_current->identifier,
5862 leveldir_current->graphics_set,
5863 leveldir_current->graphics_path);
5866 UPDATE_BUSY_STATE();
5868 ReloadCustomImages();
5869 print_timestamp_time("ReloadCustomImages");
5871 UPDATE_BUSY_STATE();
5873 LoadCustomElementDescriptions();
5874 print_timestamp_time("LoadCustomElementDescriptions");
5876 UPDATE_BUSY_STATE();
5878 LoadMenuDesignSettings();
5879 print_timestamp_time("LoadMenuDesignSettings");
5881 UPDATE_BUSY_STATE();
5883 ReinitializeGraphics();
5884 print_timestamp_time("ReinitializeGraphics");
5886 LoadMenuDesignSettings_AfterGraphics();
5887 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5889 UPDATE_BUSY_STATE();
5891 print_timestamp_done("InitImages");
5894 static void InitSound(char *identifier)
5896 print_timestamp_init("InitSound");
5898 if (identifier == NULL)
5899 identifier = artwork.snd_current->identifier;
5901 // set artwork path to send it to the sound server process
5902 setLevelArtworkDir(artwork.snd_first);
5904 InitReloadCustomSounds(identifier);
5905 print_timestamp_time("InitReloadCustomSounds");
5907 ReinitializeSounds();
5908 print_timestamp_time("ReinitializeSounds");
5910 print_timestamp_done("InitSound");
5913 static void InitMusic(char *identifier)
5915 print_timestamp_init("InitMusic");
5917 if (identifier == NULL)
5918 identifier = artwork.mus_current->identifier;
5920 // set artwork path to send it to the sound server process
5921 setLevelArtworkDir(artwork.mus_first);
5923 InitReloadCustomMusic(identifier);
5924 print_timestamp_time("InitReloadCustomMusic");
5926 ReinitializeMusic();
5927 print_timestamp_time("ReinitializeMusic");
5929 print_timestamp_done("InitMusic");
5932 static void InitArtworkDone(void)
5934 if (program.headless)
5937 InitGlobalAnimations();
5940 static void InitNetworkSettings(void)
5942 boolean network_enabled = (options.network || setup.network_mode);
5943 char *network_server = (options.server_host != NULL ? options.server_host :
5944 setup.network_server_hostname);
5946 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5947 network_server = NULL;
5949 InitNetworkInfo(network_enabled,
5953 options.server_port);
5956 void InitNetworkServer(void)
5958 if (!network.enabled || network.connected)
5961 LimitScreenUpdates(FALSE);
5963 if (game_status == GAME_MODE_LOADING)
5966 if (!ConnectToServer(network.server_host, network.server_port))
5968 network.enabled = FALSE;
5970 setup.network_mode = FALSE;
5974 SendToServer_ProtocolVersion();
5975 SendToServer_PlayerName(setup.player_name);
5976 SendToServer_NrWanted(setup.network_player_nr + 1);
5978 network.connected = TRUE;
5981 // short time to recognize result of network initialization
5982 if (game_status == GAME_MODE_LOADING)
5983 Delay_WithScreenUpdates(1000);
5986 static boolean CheckArtworkConfigForCustomElements(char *filename)
5988 SetupFileHash *setup_file_hash;
5989 boolean redefined_ce_found = FALSE;
5991 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5993 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5995 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5997 char *token = HASH_ITERATION_TOKEN(itr);
5999 if (strPrefix(token, "custom_"))
6001 redefined_ce_found = TRUE;
6006 END_HASH_ITERATION(setup_file_hash, itr)
6008 freeSetupFileHash(setup_file_hash);
6011 return redefined_ce_found;
6014 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6016 char *filename_base, *filename_local;
6017 boolean redefined_ce_found = FALSE;
6019 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6022 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6023 "leveldir_current->identifier == '%s'",
6024 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6025 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6026 "leveldir_current->graphics_path == '%s'",
6027 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6028 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6029 "leveldir_current->graphics_set == '%s'",
6030 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6031 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6032 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6033 leveldir_current == NULL ? "[NULL]" :
6034 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6037 // first look for special artwork configured in level series config
6038 filename_base = getCustomArtworkLevelConfigFilename(type);
6041 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6042 "filename_base == '%s'", filename_base);
6045 if (fileExists(filename_base))
6046 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6048 filename_local = getCustomArtworkConfigFilename(type);
6051 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6052 "filename_local == '%s'", filename_local);
6055 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6056 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6059 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6060 "redefined_ce_found == %d", redefined_ce_found);
6063 return redefined_ce_found;
6066 static void InitOverrideArtwork(void)
6068 boolean redefined_ce_found = FALSE;
6070 // to check if this level set redefines any CEs, do not use overriding
6071 gfx.override_level_graphics = FALSE;
6072 gfx.override_level_sounds = FALSE;
6073 gfx.override_level_music = FALSE;
6075 // now check if this level set has definitions for custom elements
6076 if (setup.override_level_graphics == AUTO ||
6077 setup.override_level_sounds == AUTO ||
6078 setup.override_level_music == AUTO)
6079 redefined_ce_found =
6080 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6081 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6082 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6085 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6086 redefined_ce_found);
6089 if (redefined_ce_found)
6091 // this level set has CE definitions: change "AUTO" to "FALSE"
6092 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6093 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6094 gfx.override_level_music = (setup.override_level_music == TRUE);
6098 // this level set has no CE definitions: change "AUTO" to "TRUE"
6099 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6100 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6101 gfx.override_level_music = (setup.override_level_music != FALSE);
6105 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6106 gfx.override_level_graphics,
6107 gfx.override_level_sounds,
6108 gfx.override_level_music);
6112 static char *getNewArtworkIdentifier(int type)
6114 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6115 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6116 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6117 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6118 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6119 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6120 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6121 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6122 char *leveldir_identifier = leveldir_current->identifier;
6123 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6124 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6125 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6126 TreeInfo *custom_artwork_set =
6127 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6128 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6129 char *artwork_current_identifier;
6130 char *artwork_new_identifier = NULL; // default: nothing has changed
6132 // leveldir_current may be invalid (level group, parent link)
6133 if (!validLevelSeries(leveldir_current))
6136 /* 1st step: determine artwork set to be activated in descending order:
6137 --------------------------------------------------------------------
6138 1. setup artwork (when configured to override everything else)
6139 2. artwork set configured in "levelinfo.conf" of current level set
6140 (artwork in level directory will have priority when loading later)
6141 3. artwork in level directory (stored in artwork sub-directory)
6142 4. setup artwork (currently configured in setup menu) */
6144 if (setup_override_artwork)
6145 artwork_current_identifier = setup_artwork_set;
6146 else if (has_level_artwork_set)
6147 artwork_current_identifier = leveldir_artwork_set;
6148 else if (has_custom_artwork_set)
6149 artwork_current_identifier = leveldir_identifier;
6151 artwork_current_identifier = setup_artwork_set;
6153 /* 2nd step: check if it is really needed to reload artwork set
6154 ------------------------------------------------------------ */
6156 // ---------- reload if level set and also artwork set has changed ----------
6157 if (last_leveldir_identifier[type] != leveldir_identifier &&
6158 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6159 artwork_new_identifier = artwork_current_identifier;
6161 last_leveldir_identifier[type] = leveldir_identifier;
6162 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6164 // ---------- reload if "override artwork" setting has changed --------------
6165 if (last_override_level_artwork[type] != setup_override_artwork)
6166 artwork_new_identifier = artwork_current_identifier;
6168 last_override_level_artwork[type] = setup_override_artwork;
6170 // ---------- reload if current artwork identifier has changed --------------
6171 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6172 artwork_new_identifier = artwork_current_identifier;
6174 // (we cannot compare string pointers here, so copy string content itself)
6175 setString(&last_artwork_identifier[type], artwork_current_identifier);
6177 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6179 // ---------- do not reload directly after starting -------------------------
6180 if (!initialized[type])
6181 artwork_new_identifier = NULL;
6183 initialized[type] = TRUE;
6185 return artwork_new_identifier;
6188 void ReloadCustomArtwork(int force_reload)
6190 int last_game_status = game_status; // save current game status
6191 char *gfx_new_identifier;
6192 char *snd_new_identifier;
6193 char *mus_new_identifier;
6194 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6195 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6196 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6197 boolean reload_needed;
6199 InitOverrideArtwork();
6201 AdjustGraphicsForEMC();
6202 AdjustSoundsForEMC();
6204 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6205 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6206 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6208 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6209 snd_new_identifier != NULL || force_reload_snd ||
6210 mus_new_identifier != NULL || force_reload_mus);
6215 print_timestamp_init("ReloadCustomArtwork");
6217 SetGameStatus(GAME_MODE_LOADING);
6219 FadeOut(REDRAW_ALL);
6221 SetLoadingBackgroundImage();
6223 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6224 print_timestamp_time("ClearRectangleOnBackground");
6228 UPDATE_BUSY_STATE();
6230 if (gfx_new_identifier != NULL || force_reload_gfx)
6233 Debug("init:ReloadCustomArtwork",
6234 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6235 artwork.gfx_current_identifier,
6237 artwork.gfx_current->identifier,
6238 leveldir_current->graphics_set);
6242 print_timestamp_time("InitImages");
6245 if (snd_new_identifier != NULL || force_reload_snd)
6247 InitSound(snd_new_identifier);
6248 print_timestamp_time("InitSound");
6251 if (mus_new_identifier != NULL || force_reload_mus)
6253 InitMusic(mus_new_identifier);
6254 print_timestamp_time("InitMusic");
6259 SetGameStatus(last_game_status); // restore current game status
6261 FadeOut(REDRAW_ALL);
6263 RedrawGlobalBorder();
6265 // force redraw of (open or closed) door graphics
6266 SetDoorState(DOOR_OPEN_ALL);
6267 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6269 FadeSetEnterScreen();
6270 FadeSkipNextFadeOut();
6272 print_timestamp_done("ReloadCustomArtwork");
6274 LimitScreenUpdates(FALSE);
6277 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6279 if (global.autoplay_leveldir == NULL)
6280 KeyboardAutoRepeatOff();
6283 void DisplayExitMessage(char *format, va_list ap)
6285 // also check for initialized video (headless flag may be temporarily unset)
6286 if (program.headless || !video.initialized)
6289 // check if draw buffer and fonts for exit message are already available
6290 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6293 int font_1 = FC_RED;
6294 int font_2 = FC_YELLOW;
6295 int font_3 = FC_BLUE;
6296 int font_width = getFontWidth(font_2);
6297 int font_height = getFontHeight(font_2);
6300 int sxsize = WIN_XSIZE - 2 * sx;
6301 int sysize = WIN_YSIZE - 2 * sy;
6302 int line_length = sxsize / font_width;
6303 int max_lines = sysize / font_height;
6304 int num_lines_printed;
6308 gfx.sxsize = sxsize;
6309 gfx.sysize = sysize;
6313 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6315 DrawTextSCentered(sy, font_1, "Fatal error:");
6316 sy += 3 * font_height;;
6319 DrawTextBufferVA(sx, sy, format, ap, font_2,
6320 line_length, line_length, max_lines,
6321 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6322 sy += (num_lines_printed + 3) * font_height;
6324 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6325 sy += 3 * font_height;
6328 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6329 line_length, line_length, max_lines,
6330 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6332 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6334 redraw_mask = REDRAW_ALL;
6336 // force drawing exit message even if screen updates are currently limited
6337 LimitScreenUpdates(FALSE);
6341 // deactivate toons on error message screen
6342 setup.toons = FALSE;
6344 WaitForEventToContinue();
6348 // ============================================================================
6350 // ============================================================================
6354 print_timestamp_init("OpenAll");
6356 SetGameStatus(GAME_MODE_LOADING);
6360 InitGlobal(); // initialize some global variables
6362 InitRND(NEW_RANDOMIZE);
6363 InitSimpleRandom(NEW_RANDOMIZE);
6364 InitBetterRandom(NEW_RANDOMIZE);
6366 print_timestamp_time("[init global stuff]");
6370 print_timestamp_time("[init setup/config stuff (1)]");
6372 if (options.execute_command)
6373 Execute_Command(options.execute_command);
6375 InitNetworkSettings();
6379 if (network.serveronly)
6381 #if defined(PLATFORM_UNIX)
6382 NetworkServer(network.server_port, TRUE);
6384 Warn("networking only supported in Unix version");
6387 exit(0); // never reached, server loops forever
6391 print_timestamp_time("[init setup/config stuff (2)]");
6393 print_timestamp_time("[init setup/config stuff (3)]");
6394 InitArtworkInfo(); // needed before loading gfx, sound & music
6395 print_timestamp_time("[init setup/config stuff (4)]");
6396 InitArtworkConfig(); // needed before forking sound child process
6397 print_timestamp_time("[init setup/config stuff (5)]");
6399 print_timestamp_time("[init setup/config stuff (6)]");
6403 print_timestamp_time("[init setup/config stuff]");
6405 InitVideoDefaults();
6407 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6410 InitEventFilter(FilterMouseMotionEvents);
6412 print_timestamp_time("[init video stuff]");
6414 InitElementPropertiesStatic();
6415 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6416 InitElementPropertiesGfxElement();
6418 print_timestamp_time("[init element properties stuff]");
6422 print_timestamp_time("InitGfx");
6425 print_timestamp_time("InitLevelInfo");
6427 InitLevelArtworkInfo();
6428 print_timestamp_time("InitLevelArtworkInfo");
6430 InitOverrideArtwork(); // needs to know current level directory
6431 print_timestamp_time("InitOverrideArtwork");
6433 InitImages(); // needs to know current level directory
6434 print_timestamp_time("InitImages");
6436 InitSound(NULL); // needs to know current level directory
6437 print_timestamp_time("InitSound");
6439 InitMusic(NULL); // needs to know current level directory
6440 print_timestamp_time("InitMusic");
6444 InitGfxBackground();
6450 if (global.autoplay_leveldir)
6455 else if (global.patchtapes_leveldir)
6460 else if (global.convert_leveldir)
6465 else if (global.dumplevel_leveldir)
6470 else if (global.dumptape_leveldir)
6475 else if (global.create_sketch_images_dir)
6477 CreateLevelSketchImages();
6480 else if (global.create_collect_images_dir)
6482 CreateCollectElementImages();
6486 InitNetworkServer();
6488 SetGameStatus(GAME_MODE_MAIN);
6490 FadeSetEnterScreen();
6491 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6492 FadeSkipNextFadeOut();
6494 print_timestamp_time("[post-artwork]");
6496 print_timestamp_done("OpenAll");
6498 if (setup.ask_for_remaining_tapes)
6499 setup.ask_for_uploading_tapes = TRUE;
6504 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6506 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6507 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6508 #if defined(PLATFORM_ANDROID)
6509 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6510 SDL_AndroidGetInternalStoragePath());
6511 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6512 SDL_AndroidGetExternalStoragePath());
6513 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6514 (SDL_AndroidGetExternalStorageState() &
6515 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6516 SDL_AndroidGetExternalStorageState() &
6517 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6522 static boolean WaitForApiThreads(void)
6524 unsigned int thread_delay = 0;
6525 unsigned int thread_delay_value = 10000;
6527 if (program.api_thread_count == 0)
6530 // deactivate global animations (not accessible in game state "loading")
6531 setup.toons = FALSE;
6533 // set game state to "loading" to be able to show busy animation
6534 SetGameStatus(GAME_MODE_LOADING);
6536 ResetDelayCounter(&thread_delay);
6538 // wait for threads to finish (and fail on timeout)
6539 while (program.api_thread_count > 0)
6541 if (DelayReached(&thread_delay, thread_delay_value))
6543 Error("failed waiting for threads - TIMEOUT");
6548 UPDATE_BUSY_STATE();
6556 void CloseAllAndExit(int exit_value)
6558 WaitForApiThreads();
6563 CloseAudio(); // called after freeing sounds (needed for SDL)
6571 // set a flag to tell the network server thread to quit and wait for it
6572 // using SDL_WaitThread()
6574 // Code used with SDL 1.2:
6575 // if (network.server_thread) // terminate network server
6576 // SDL_KillThread(network.server_thread);
6578 CloseVideoDisplay();
6579 ClosePlatformDependentStuff();
6581 if (exit_value != 0 && !options.execute_command)
6583 // fall back to default level set (current set may have caused an error)
6584 SaveLevelSetup_LastSeries_Deactivate();
6586 // tell user where to find error log file which may contain more details
6587 // (error notification now directly displayed on screen inside R'n'D
6588 // NotifyUserAboutErrorFile(); // currently only works for Windows