1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY_INITIAL "global.busy_initial"
38 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
39 #define CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD "global.busy_playfield"
40 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
43 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
44 #define INITIAL_IMG_GLOBAL_BUSY 1
45 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD 2
47 #define NUM_INITIAL_IMAGES_BUSY 3
49 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 3
50 #define INITIAL_IMG_BACKGROUND_LOADING 4
52 #define NUM_INITIAL_IMAGES 5
55 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
56 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
58 static int copy_properties[][5] =
62 EL_BUG_LEFT, EL_BUG_RIGHT,
63 EL_BUG_UP, EL_BUG_DOWN
67 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
68 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
72 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
73 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
77 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
78 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
82 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
83 EL_PACMAN_UP, EL_PACMAN_DOWN
87 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
88 EL_YAMYAM_UP, EL_YAMYAM_DOWN
92 EL_MOLE_LEFT, EL_MOLE_RIGHT,
93 EL_MOLE_UP, EL_MOLE_DOWN
97 EL_SPRING_LEFT, EL_SPRING_RIGHT,
98 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
107 // forward declaration for internal use
108 static int get_graphic_parameter_value(char *, char *, int);
111 static void SetLoadingBackgroundImage(void)
113 struct GraphicInfo *graphic_info_last = graphic_info;
114 int background_image = (game_status_last_screen == -1 ?
115 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
116 INITIAL_IMG_BACKGROUND_LOADING);
118 graphic_info = image_initial;
120 SetDrawDeactivationMask(REDRAW_NONE);
121 SetDrawBackgroundMask(REDRAW_ALL);
123 SetWindowBackgroundImage(background_image);
125 graphic_info = graphic_info_last;
128 static void DrawInitAnim(boolean only_when_loading)
130 struct GraphicInfo *graphic_info_last = graphic_info;
131 int graphic = (game_status_last_screen == -1 ?
132 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
133 game_status == GAME_MODE_LOADING ?
134 INITIAL_IMG_GLOBAL_BUSY :
135 INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
136 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
137 &init_last.busy_initial :
138 game_status == GAME_MODE_LOADING ?
140 &init_last.busy_playfield);
141 static unsigned int action_delay = 0;
142 unsigned int action_delay_value = GameFrameDelay;
143 int sync_frame = FrameCounter;
146 // prevent OS (Windows) from complaining about program not responding
149 if (game_status != GAME_MODE_LOADING && only_when_loading)
152 if (image_initial[graphic].bitmap == NULL || window == NULL)
155 if (!DelayReached(&action_delay, action_delay_value))
159 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
161 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
163 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
164 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
166 graphic_info = image_initial;
168 if (sync_frame % image_initial[graphic].anim_delay == 0)
172 int width = graphic_info[graphic].width;
173 int height = graphic_info[graphic].height;
174 int frame = getGraphicAnimationFrame(graphic, sync_frame);
176 ClearRectangleOnBackground(drawto, x, y, width, height);
178 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
179 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
181 BlitBitmap(drawto, window, x, y, width, height, x, y);
184 graphic_info = graphic_info_last;
189 static void DrawProgramInfo(void)
191 int font1_nr = FC_YELLOW;
192 int font2_nr = FC_RED;
193 int font2_height = getFontHeight(font2_nr);
196 int ypos3 = WIN_YSIZE - 20 - font2_height;
198 DrawInitText(getProgramInitString(), ypos1, font1_nr);
199 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
200 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
203 static void FreeGadgets(void)
205 FreeLevelEditorGadgets();
212 void InitGadgets(void)
214 static boolean gadgets_initialized = FALSE;
216 if (gadgets_initialized)
219 CreateLevelEditorGadgets();
223 CreateScreenGadgets();
225 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
227 gadgets_initialized = TRUE;
230 static void InitElementSmallImagesScaledUp(int graphic)
232 struct GraphicInfo *g = &graphic_info[graphic];
234 // create small and game tile sized bitmaps (and scale up, if needed)
235 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
238 static void InitElementSmallImages(void)
240 print_timestamp_init("InitElementSmallImages");
242 static int special_graphics[] =
256 IMG_EDITOR_ELEMENT_BORDER,
257 IMG_EDITOR_ELEMENT_BORDER_INPUT,
258 IMG_EDITOR_CASCADE_LIST,
259 IMG_EDITOR_CASCADE_LIST_ACTIVE,
262 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
263 int num_property_mappings = getImageListPropertyMappingSize();
266 print_timestamp_time("getImageListPropertyMapping/Size");
268 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
269 // initialize normal element images from static configuration
270 for (i = 0; element_to_graphic[i].element > -1; i++)
271 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
272 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
274 // initialize special element images from static configuration
275 for (i = 0; element_to_special_graphic[i].element > -1; i++)
276 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
277 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
279 // initialize element images from dynamic configuration
280 for (i = 0; i < num_property_mappings; i++)
281 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
282 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
283 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
285 // initialize special non-element images from above list
286 for (i = 0; special_graphics[i] > -1; i++)
287 InitElementSmallImagesScaledUp(special_graphics[i]);
288 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
290 print_timestamp_done("InitElementSmallImages");
293 static void InitScaledImagesScaledUp(int graphic)
295 struct GraphicInfo *g = &graphic_info[graphic];
297 ScaleImage(graphic, g->scale_up_factor);
300 static void InitScaledImages(void)
302 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303 int num_property_mappings = getImageListPropertyMappingSize();
306 // scale normal images from static configuration, if not already scaled
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 InitScaledImagesScaledUp(i);
310 // scale images from dynamic configuration, if not already scaled
311 for (i = 0; i < num_property_mappings; i++)
312 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
315 static void InitBitmapPointers(void)
317 int num_images = getImageListSize();
320 // standard size bitmap may have changed -- update default bitmap pointer
321 for (i = 0; i < num_images; i++)
322 if (graphic_info[i].bitmaps)
323 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
326 void InitImageTextures(void)
328 static int texture_graphics[] =
330 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
331 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
332 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
333 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
334 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
335 IMG_MENU_BUTTON_TOUCH_BACK,
336 IMG_MENU_BUTTON_TOUCH_NEXT,
337 IMG_MENU_BUTTON_TOUCH_BACK2,
338 IMG_MENU_BUTTON_TOUCH_NEXT2,
343 FreeAllImageTextures();
345 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
346 CreateImageTextures(i);
348 for (i = 0; i < MAX_NUM_TOONS; i++)
349 CreateImageTextures(IMG_TOON_1 + i);
351 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
353 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
355 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
357 int graphic = global_anim_info[i].graphic[j][k];
359 if (graphic == IMG_UNDEFINED)
362 CreateImageTextures(graphic);
367 for (i = 0; texture_graphics[i] > -1; i++)
368 CreateImageTextures(texture_graphics[i]);
371 static int getFontBitmapID(int font_nr)
375 // (special case: do not use special font for GAME_MODE_LOADING)
376 if (game_status >= GAME_MODE_TITLE_INITIAL &&
377 game_status <= GAME_MODE_PSEUDO_PREVIEW)
378 special = game_status;
379 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
380 special = GFX_SPECIAL_ARG_MAIN;
381 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
382 special = GFX_SPECIAL_ARG_NAMES;
385 return font_info[font_nr].special_bitmap_id[special];
390 static int getFontFromToken(char *token)
392 char *value = getHashEntry(font_token_hash, token);
397 // if font not found, use reliable default value
398 return FONT_INITIAL_1;
401 static void InitFontGraphicInfo(void)
403 static struct FontBitmapInfo *font_bitmap_info = NULL;
404 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
405 int num_property_mappings = getImageListPropertyMappingSize();
406 int num_font_bitmaps = NUM_FONTS;
409 if (graphic_info == NULL) // still at startup phase
411 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
412 getFontBitmapID, getFontFromToken);
417 // ---------- initialize font graphic definitions ----------
419 // always start with reliable default values (normal font graphics)
420 for (i = 0; i < NUM_FONTS; i++)
421 font_info[i].graphic = IMG_FONT_INITIAL_1;
423 // initialize normal font/graphic mapping from static configuration
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
433 font_info[font_nr].graphic = graphic;
436 // always start with reliable default values (special font graphics)
437 for (i = 0; i < NUM_FONTS; i++)
439 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
441 font_info[i].special_graphic[j] = font_info[i].graphic;
442 font_info[i].special_bitmap_id[j] = i;
446 // initialize special font/graphic mapping from static configuration
447 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
449 int font_nr = font_to_graphic[i].font_nr;
450 int special = font_to_graphic[i].special;
451 int graphic = font_to_graphic[i].graphic;
452 int base_graphic = font2baseimg(font_nr);
454 if (IS_SPECIAL_GFX_ARG(special))
456 boolean base_redefined =
457 getImageListEntryFromImageID(base_graphic)->redefined;
458 boolean special_redefined =
459 getImageListEntryFromImageID(graphic)->redefined;
460 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
462 /* if the base font ("font.title_1", for example) has been redefined,
463 but not the special font ("font.title_1.LEVELS", for example), do not
464 use an existing (in this case considered obsolete) special font
465 anymore, but use the automatically determined default font */
466 /* special case: cloned special fonts must be explicitly redefined,
467 but are not automatically redefined by redefining base font */
468 if (base_redefined && !special_redefined && !special_cloned)
471 font_info[font_nr].special_graphic[special] = graphic;
472 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
477 // initialize special font/graphic mapping from dynamic configuration
478 for (i = 0; i < num_property_mappings; i++)
480 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
481 int special = property_mapping[i].ext3_index;
482 int graphic = property_mapping[i].artwork_index;
484 if (font_nr < 0 || font_nr >= NUM_FONTS)
487 if (IS_SPECIAL_GFX_ARG(special))
489 font_info[font_nr].special_graphic[special] = graphic;
490 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
495 /* correct special font/graphic mapping for cloned fonts for downwards
496 compatibility of PREVIEW fonts -- this is only needed for implicit
497 redefinition of special font by redefined base font, and only if other
498 fonts are cloned from this special font (like in the "Zelda" level set) */
499 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
501 int font_nr = font_to_graphic[i].font_nr;
502 int special = font_to_graphic[i].special;
503 int graphic = font_to_graphic[i].graphic;
505 if (IS_SPECIAL_GFX_ARG(special))
507 boolean special_redefined =
508 getImageListEntryFromImageID(graphic)->redefined;
509 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
511 if (special_cloned && !special_redefined)
515 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
517 int font_nr2 = font_to_graphic[j].font_nr;
518 int special2 = font_to_graphic[j].special;
519 int graphic2 = font_to_graphic[j].graphic;
521 if (IS_SPECIAL_GFX_ARG(special2) &&
522 graphic2 == graphic_info[graphic].clone_from)
524 font_info[font_nr].special_graphic[special] =
525 font_info[font_nr2].special_graphic[special2];
526 font_info[font_nr].special_bitmap_id[special] =
527 font_info[font_nr2].special_bitmap_id[special2];
534 // reset non-redefined ".active" font graphics if normal font is redefined
535 // (this different treatment is needed because normal and active fonts are
536 // independently defined ("active" is not a property of font definitions!)
537 for (i = 0; i < NUM_FONTS; i++)
539 int font_nr_base = i;
540 int font_nr_active = FONT_ACTIVE(font_nr_base);
542 // check only those fonts with exist as normal and ".active" variant
543 if (font_nr_base != font_nr_active)
545 int base_graphic = font_info[font_nr_base].graphic;
546 int active_graphic = font_info[font_nr_active].graphic;
547 boolean base_redefined =
548 getImageListEntryFromImageID(base_graphic)->redefined;
549 boolean active_redefined =
550 getImageListEntryFromImageID(active_graphic)->redefined;
552 /* if the base font ("font.menu_1", for example) has been redefined,
553 but not the active font ("font.menu_1.active", for example), do not
554 use an existing (in this case considered obsolete) active font
555 anymore, but use the automatically determined default font */
556 if (base_redefined && !active_redefined)
557 font_info[font_nr_active].graphic = base_graphic;
559 // now also check each "special" font (which may be the same as above)
560 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
562 int base_graphic = font_info[font_nr_base].special_graphic[j];
563 int active_graphic = font_info[font_nr_active].special_graphic[j];
564 boolean base_redefined =
565 getImageListEntryFromImageID(base_graphic)->redefined;
566 boolean active_redefined =
567 getImageListEntryFromImageID(active_graphic)->redefined;
569 // same as above, but check special graphic definitions, for example:
570 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
571 if (base_redefined && !active_redefined)
573 font_info[font_nr_active].special_graphic[j] =
574 font_info[font_nr_base].special_graphic[j];
575 font_info[font_nr_active].special_bitmap_id[j] =
576 font_info[font_nr_base].special_bitmap_id[j];
582 // ---------- initialize font bitmap array ----------
584 if (font_bitmap_info != NULL)
585 FreeFontInfo(font_bitmap_info);
588 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
590 // ---------- initialize font bitmap definitions ----------
592 for (i = 0; i < NUM_FONTS; i++)
594 if (i < NUM_INITIAL_FONTS)
596 font_bitmap_info[i] = font_initial[i];
600 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
602 int font_bitmap_id = font_info[i].special_bitmap_id[j];
603 int graphic = font_info[i].special_graphic[j];
605 // set 'graphic_info' for font entries, if uninitialized (guessed)
606 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
608 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
609 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
612 // copy font relevant information from graphics information
613 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
614 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
615 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
616 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
617 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
619 font_bitmap_info[font_bitmap_id].offset_x =
620 graphic_info[graphic].offset_x;
621 font_bitmap_info[font_bitmap_id].offset_y =
622 graphic_info[graphic].offset_y;
624 font_bitmap_info[font_bitmap_id].draw_xoffset =
625 graphic_info[graphic].draw_xoffset;
626 font_bitmap_info[font_bitmap_id].draw_yoffset =
627 graphic_info[graphic].draw_yoffset;
629 font_bitmap_info[font_bitmap_id].num_chars =
630 graphic_info[graphic].anim_frames;
631 font_bitmap_info[font_bitmap_id].num_chars_per_line =
632 graphic_info[graphic].anim_frames_per_line;
636 InitFontInfo(font_bitmap_info, num_font_bitmaps,
637 getFontBitmapID, getFontFromToken);
640 static void InitGlobalAnimGraphicInfo(void)
642 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
643 int num_property_mappings = getImageListPropertyMappingSize();
646 if (graphic_info == NULL) // still at startup phase
649 // always start with reliable default values (no global animations)
650 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
651 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
652 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
653 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
655 // initialize global animation definitions from static configuration
656 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
658 int j = GLOBAL_ANIM_ID_PART_BASE;
659 int k = GFX_SPECIAL_ARG_DEFAULT;
661 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
664 // initialize global animation definitions from dynamic configuration
665 for (i = 0; i < num_property_mappings; i++)
667 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
668 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
669 int special = property_mapping[i].ext3_index;
670 int graphic = property_mapping[i].artwork_index;
672 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
675 // set animation part to base part, if not specified
676 if (!IS_GLOBAL_ANIM_PART(part_nr))
677 part_nr = GLOBAL_ANIM_ID_PART_BASE;
679 // set animation screen to default, if not specified
680 if (!IS_SPECIAL_GFX_ARG(special))
681 special = GFX_SPECIAL_ARG_DEFAULT;
683 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
685 // fix default value for ".draw_masked" (for backward compatibility)
686 struct GraphicInfo *g = &graphic_info[graphic];
687 struct FileInfo *image = getImageListEntryFromImageID(graphic);
688 char **parameter_raw = image->parameter;
689 int p = GFX_ARG_DRAW_MASKED;
690 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
691 image_config_suffix[p].token,
692 image_config_suffix[p].type);
694 // if ".draw_masked" parameter is undefined, use default value "TRUE"
695 if (draw_masked == ARG_UNDEFINED_VALUE)
696 g->draw_masked = TRUE;
700 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
701 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
702 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
703 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
704 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
705 Debug("init:InitGlobalAnimGraphicInfo",
706 "anim %d, part %d, mode %d => %d",
707 i, j, k, global_anim_info[i].graphic[j][k]);
711 static void InitGlobalAnimSoundInfo(void)
713 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
714 int num_property_mappings = getSoundListPropertyMappingSize();
717 // always start with reliable default values (no global animation sounds)
718 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
719 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
720 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
721 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
723 // initialize global animation sound definitions from dynamic configuration
724 for (i = 0; i < num_property_mappings; i++)
726 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
727 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
728 int special = property_mapping[i].ext3_index;
729 int sound = property_mapping[i].artwork_index;
731 // sound uses control definition; map it to position of graphic (artwork)
732 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
734 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
737 // set animation part to base part, if not specified
738 if (!IS_GLOBAL_ANIM_PART(part_nr))
739 part_nr = GLOBAL_ANIM_ID_PART_BASE;
741 // set animation screen to default, if not specified
742 if (!IS_SPECIAL_GFX_ARG(special))
743 special = GFX_SPECIAL_ARG_DEFAULT;
745 global_anim_info[anim_nr].sound[part_nr][special] = sound;
749 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
750 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
751 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
752 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
753 Debug("init:InitGlobalAnimSoundInfo",
754 "anim %d, part %d, mode %d => %d",
755 i, j, k, global_anim_info[i].sound[j][k]);
759 static void InitGlobalAnimMusicInfo(void)
761 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
762 int num_property_mappings = getMusicListPropertyMappingSize();
765 // always start with reliable default values (no global animation music)
766 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
767 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
768 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
769 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
771 // initialize global animation music definitions from dynamic configuration
772 for (i = 0; i < num_property_mappings; i++)
774 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
775 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
776 int special = property_mapping[i].ext2_index;
777 int music = property_mapping[i].artwork_index;
779 // music uses control definition; map it to position of graphic (artwork)
780 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
782 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
785 // set animation part to base part, if not specified
786 if (!IS_GLOBAL_ANIM_PART(part_nr))
787 part_nr = GLOBAL_ANIM_ID_PART_BASE;
789 // set animation screen to default, if not specified
790 if (!IS_SPECIAL_GFX_ARG(special))
791 special = GFX_SPECIAL_ARG_DEFAULT;
793 global_anim_info[anim_nr].music[part_nr][special] = music;
797 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
798 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
799 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
800 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
801 Debug("init:InitGlobalAnimMusicInfo",
802 "anim %d, part %d, mode %d => %d",
803 i, j, k, global_anim_info[i].music[j][k]);
807 static void InitElementGraphicInfo(void)
809 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
810 int num_property_mappings = getImageListPropertyMappingSize();
813 if (graphic_info == NULL) // still at startup phase
816 // set values to -1 to identify later as "uninitialized" values
817 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
819 for (act = 0; act < NUM_ACTIONS; act++)
821 element_info[i].graphic[act] = -1;
822 element_info[i].crumbled[act] = -1;
824 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
826 element_info[i].direction_graphic[act][dir] = -1;
827 element_info[i].direction_crumbled[act][dir] = -1;
834 // initialize normal element/graphic mapping from static configuration
835 for (i = 0; element_to_graphic[i].element > -1; i++)
837 int element = element_to_graphic[i].element;
838 int action = element_to_graphic[i].action;
839 int direction = element_to_graphic[i].direction;
840 boolean crumbled = element_to_graphic[i].crumbled;
841 int graphic = element_to_graphic[i].graphic;
842 int base_graphic = el2baseimg(element);
844 if (graphic_info[graphic].bitmap == NULL)
847 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
850 boolean base_redefined =
851 getImageListEntryFromImageID(base_graphic)->redefined;
852 boolean act_dir_redefined =
853 getImageListEntryFromImageID(graphic)->redefined;
855 /* if the base graphic ("emerald", for example) has been redefined,
856 but not the action graphic ("emerald.falling", for example), do not
857 use an existing (in this case considered obsolete) action graphic
858 anymore, but use the automatically determined default graphic */
859 if (base_redefined && !act_dir_redefined)
864 action = ACTION_DEFAULT;
869 element_info[element].direction_crumbled[action][direction] = graphic;
871 element_info[element].crumbled[action] = graphic;
876 element_info[element].direction_graphic[action][direction] = graphic;
878 element_info[element].graphic[action] = graphic;
882 // initialize normal element/graphic mapping from dynamic configuration
883 for (i = 0; i < num_property_mappings; i++)
885 int element = property_mapping[i].base_index;
886 int action = property_mapping[i].ext1_index;
887 int direction = property_mapping[i].ext2_index;
888 int special = property_mapping[i].ext3_index;
889 int graphic = property_mapping[i].artwork_index;
890 boolean crumbled = FALSE;
892 if (special == GFX_SPECIAL_ARG_CRUMBLED)
898 if (graphic_info[graphic].bitmap == NULL)
901 if (element >= MAX_NUM_ELEMENTS || special != -1)
905 action = ACTION_DEFAULT;
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 element_info[element].direction_crumbled[action][dir] = -1;
914 element_info[element].direction_crumbled[action][direction] = graphic;
916 element_info[element].crumbled[action] = graphic;
921 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 element_info[element].direction_graphic[action][dir] = -1;
925 element_info[element].direction_graphic[action][direction] = graphic;
927 element_info[element].graphic[action] = graphic;
931 // now copy all graphics that are defined to be cloned from other graphics
932 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
934 int graphic = element_info[i].graphic[ACTION_DEFAULT];
935 int crumbled_like, diggable_like;
940 crumbled_like = graphic_info[graphic].crumbled_like;
941 diggable_like = graphic_info[graphic].diggable_like;
943 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
945 for (act = 0; act < NUM_ACTIONS; act++)
946 element_info[i].crumbled[act] =
947 element_info[crumbled_like].crumbled[act];
948 for (act = 0; act < NUM_ACTIONS; act++)
949 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
950 element_info[i].direction_crumbled[act][dir] =
951 element_info[crumbled_like].direction_crumbled[act][dir];
954 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
956 element_info[i].graphic[ACTION_DIGGING] =
957 element_info[diggable_like].graphic[ACTION_DIGGING];
958 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
959 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
960 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
964 // set hardcoded definitions for some runtime elements without graphic
965 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
967 // set hardcoded definitions for some internal elements without graphic
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 if (IS_EDITOR_CASCADE_INACTIVE(i))
971 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
972 else if (IS_EDITOR_CASCADE_ACTIVE(i))
973 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
976 // now set all undefined/invalid graphics to -1 to set to default after it
977 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
979 for (act = 0; act < NUM_ACTIONS; act++)
983 graphic = element_info[i].graphic[act];
984 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
985 element_info[i].graphic[act] = -1;
987 graphic = element_info[i].crumbled[act];
988 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
989 element_info[i].crumbled[act] = -1;
991 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
993 graphic = element_info[i].direction_graphic[act][dir];
994 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
995 element_info[i].direction_graphic[act][dir] = -1;
997 graphic = element_info[i].direction_crumbled[act][dir];
998 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
999 element_info[i].direction_crumbled[act][dir] = -1;
1004 UPDATE_BUSY_STATE();
1006 // adjust graphics with 2nd tile for movement according to direction
1007 // (do this before correcting '-1' values to minimize calculations)
1008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1010 for (act = 0; act < NUM_ACTIONS; act++)
1012 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1014 int graphic = element_info[i].direction_graphic[act][dir];
1015 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1017 if (act == ACTION_FALLING) // special case
1018 graphic = element_info[i].graphic[act];
1020 if (graphic != -1 &&
1021 graphic_info[graphic].double_movement &&
1022 graphic_info[graphic].swap_double_tiles != 0)
1024 struct GraphicInfo *g = &graphic_info[graphic];
1025 int src_x_front = g->src_x;
1026 int src_y_front = g->src_y;
1027 int src_x_back = g->src_x + g->offset2_x;
1028 int src_y_back = g->src_y + g->offset2_y;
1029 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1031 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1032 src_y_front < src_y_back);
1033 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1034 boolean swap_movement_tiles_autodetected =
1035 (!frames_are_ordered_diagonally &&
1036 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1037 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1038 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1039 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1041 // swap frontside and backside graphic tile coordinates, if needed
1042 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1044 // get current (wrong) backside tile coordinates
1045 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1047 // set frontside tile coordinates to backside tile coordinates
1048 g->src_x = src_x_back;
1049 g->src_y = src_y_back;
1051 // invert tile offset to point to new backside tile coordinates
1055 // do not swap front and backside tiles again after correction
1056 g->swap_double_tiles = 0;
1063 UPDATE_BUSY_STATE();
1065 // now set all '-1' values to element specific default values
1066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1069 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1070 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1071 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1073 if (default_graphic == -1)
1074 default_graphic = IMG_UNKNOWN;
1076 if (default_crumbled == -1)
1077 default_crumbled = default_graphic;
1079 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1081 default_direction_graphic[dir] =
1082 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1083 default_direction_crumbled[dir] =
1084 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1086 if (default_direction_graphic[dir] == -1)
1087 default_direction_graphic[dir] = default_graphic;
1089 if (default_direction_crumbled[dir] == -1)
1090 default_direction_crumbled[dir] = default_direction_graphic[dir];
1093 for (act = 0; act < NUM_ACTIONS; act++)
1095 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1096 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1097 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1098 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1099 act == ACTION_TURNING_FROM_RIGHT ||
1100 act == ACTION_TURNING_FROM_UP ||
1101 act == ACTION_TURNING_FROM_DOWN);
1103 // generic default action graphic (defined by "[default]" directive)
1104 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1105 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1106 int default_remove_graphic = IMG_EMPTY;
1108 if (act_remove && default_action_graphic != -1)
1109 default_remove_graphic = default_action_graphic;
1111 // look for special default action graphic (classic game specific)
1112 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1113 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1114 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1115 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1116 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1117 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1118 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1119 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1121 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1122 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1123 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1124 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1125 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1126 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1127 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1128 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1130 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1131 // !!! make this better !!!
1132 if (i == EL_EMPTY_SPACE)
1134 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1135 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1138 if (default_action_graphic == -1)
1139 default_action_graphic = default_graphic;
1141 if (default_action_crumbled == -1)
1142 default_action_crumbled = default_action_graphic;
1144 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1146 // use action graphic as the default direction graphic, if undefined
1147 int default_action_direction_graphic = element_info[i].graphic[act];
1148 int default_action_direction_crumbled = element_info[i].crumbled[act];
1150 // no graphic for current action -- use default direction graphic
1151 if (default_action_direction_graphic == -1)
1152 default_action_direction_graphic =
1153 (act_remove ? default_remove_graphic :
1155 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1156 default_action_graphic != default_graphic ?
1157 default_action_graphic :
1158 default_direction_graphic[dir]);
1160 if (element_info[i].direction_graphic[act][dir] == -1)
1161 element_info[i].direction_graphic[act][dir] =
1162 default_action_direction_graphic;
1164 if (default_action_direction_crumbled == -1)
1165 default_action_direction_crumbled =
1166 element_info[i].direction_graphic[act][dir];
1168 if (element_info[i].direction_crumbled[act][dir] == -1)
1169 element_info[i].direction_crumbled[act][dir] =
1170 default_action_direction_crumbled;
1173 // no graphic for this specific action -- use default action graphic
1174 if (element_info[i].graphic[act] == -1)
1175 element_info[i].graphic[act] =
1176 (act_remove ? default_remove_graphic :
1177 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1178 default_action_graphic);
1180 if (element_info[i].crumbled[act] == -1)
1181 element_info[i].crumbled[act] = element_info[i].graphic[act];
1185 UPDATE_BUSY_STATE();
1188 static void InitElementSpecialGraphicInfo(void)
1190 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1191 int num_property_mappings = getImageListPropertyMappingSize();
1194 // always start with reliable default values
1195 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1196 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1197 element_info[i].special_graphic[j] =
1198 element_info[i].graphic[ACTION_DEFAULT];
1200 // initialize special element/graphic mapping from static configuration
1201 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1203 int element = element_to_special_graphic[i].element;
1204 int special = element_to_special_graphic[i].special;
1205 int graphic = element_to_special_graphic[i].graphic;
1206 int base_graphic = el2baseimg(element);
1207 boolean base_redefined =
1208 getImageListEntryFromImageID(base_graphic)->redefined;
1209 boolean special_redefined =
1210 getImageListEntryFromImageID(graphic)->redefined;
1212 /* if the base graphic ("emerald", for example) has been redefined,
1213 but not the special graphic ("emerald.EDITOR", for example), do not
1214 use an existing (in this case considered obsolete) special graphic
1215 anymore, but use the automatically created (down-scaled) graphic */
1216 if (base_redefined && !special_redefined)
1219 element_info[element].special_graphic[special] = graphic;
1222 // initialize special element/graphic mapping from dynamic configuration
1223 for (i = 0; i < num_property_mappings; i++)
1225 int element = property_mapping[i].base_index;
1226 int action = property_mapping[i].ext1_index;
1227 int direction = property_mapping[i].ext2_index;
1228 int special = property_mapping[i].ext3_index;
1229 int graphic = property_mapping[i].artwork_index;
1231 // for action ".active", replace element with active element, if exists
1232 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1234 element = ELEMENT_ACTIVE(element);
1238 if (element >= MAX_NUM_ELEMENTS)
1241 // do not change special graphic if action or direction was specified
1242 if (action != -1 || direction != -1)
1245 if (IS_SPECIAL_GFX_ARG(special))
1246 element_info[element].special_graphic[special] = graphic;
1249 // now set all undefined/invalid graphics to default
1250 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1251 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1252 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1253 element_info[i].special_graphic[j] =
1254 element_info[i].graphic[ACTION_DEFAULT];
1257 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1259 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1260 return get_parameter_value(value_raw, suffix, type);
1262 if (strEqual(value_raw, ARG_UNDEFINED))
1263 return ARG_UNDEFINED_VALUE;
1265 if (type == TYPE_ELEMENT)
1267 char *value = getHashEntry(element_token_hash, value_raw);
1272 Warn("error found in config file:");
1273 Warn("- config file: '%s'", getImageConfigFilename());
1274 Warn("error: invalid element token '%s'", value_raw);
1275 Warn("custom graphic rejected for this element/action");
1276 Warn("fallback done to undefined element for this graphic");
1280 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1282 else if (type == TYPE_GRAPHIC)
1284 char *value = getHashEntry(graphic_token_hash, value_raw);
1285 int fallback_graphic = IMG_CHAR_EXCLAM;
1290 Warn("error found in config file:");
1291 Warn("- config file: '%s'", getImageConfigFilename());
1292 Warn("error: invalid graphic token '%s'", value_raw);
1293 Warn("custom graphic rejected for this element/action");
1294 Warn("fallback done to 'char_exclam' for this graphic");
1298 return (value != NULL ? atoi(value) : fallback_graphic);
1304 static int get_scaled_graphic_width(int graphic)
1306 int original_width = getOriginalImageWidthFromImageID(graphic);
1307 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1309 return original_width * scale_up_factor;
1312 static int get_scaled_graphic_height(int graphic)
1314 int original_height = getOriginalImageHeightFromImageID(graphic);
1315 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1317 return original_height * scale_up_factor;
1320 static void set_graphic_parameters_ext(int graphic, int *parameter,
1321 Bitmap **src_bitmaps)
1323 struct GraphicInfo *g = &graphic_info[graphic];
1324 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1325 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1326 int anim_frames_per_line = 1;
1328 // always start with reliable default values
1329 g->src_image_width = 0;
1330 g->src_image_height = 0;
1333 g->width = TILEX; // default for element graphics
1334 g->height = TILEY; // default for element graphics
1335 g->offset_x = 0; // one or both of these values ...
1336 g->offset_y = 0; // ... will be corrected later
1337 g->offset2_x = 0; // one or both of these values ...
1338 g->offset2_y = 0; // ... will be corrected later
1339 g->swap_double_tiles = -1; // auto-detect tile swapping
1340 g->crumbled_like = -1; // do not use clone element
1341 g->diggable_like = -1; // do not use clone element
1342 g->border_size = TILEX / 8; // "CRUMBLED" border size
1343 g->scale_up_factor = 1; // default: no scaling up
1344 g->tile_size = TILESIZE; // default: standard tile size
1345 g->clone_from = -1; // do not use clone graphic
1346 g->init_delay_fixed = 0;
1347 g->init_delay_random = 0;
1348 g->init_delay_action = -1;
1349 g->anim_delay_fixed = 0;
1350 g->anim_delay_random = 0;
1351 g->anim_delay_action = -1;
1352 g->post_delay_fixed = 0;
1353 g->post_delay_random = 0;
1354 g->post_delay_action = -1;
1355 g->init_event = ANIM_EVENT_UNDEFINED;
1356 g->anim_event = ANIM_EVENT_UNDEFINED;
1357 g->init_event_action = -1;
1358 g->anim_event_action = -1;
1359 g->draw_masked = FALSE;
1361 g->fade_mode = FADE_MODE_DEFAULT;
1365 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1366 g->align = ALIGN_CENTER; // default for title screens
1367 g->valign = VALIGN_MIDDLE; // default for title screens
1368 g->sort_priority = 0; // default for title screens
1370 g->style = STYLE_DEFAULT;
1372 g->bitmaps = src_bitmaps;
1373 g->bitmap = src_bitmap;
1375 // optional zoom factor for scaling up the image to a larger size
1376 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1377 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1378 if (g->scale_up_factor < 1)
1379 g->scale_up_factor = 1; // no scaling
1381 // optional tile size for using non-standard image size
1382 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1384 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1387 // CHECK: should tile sizes less than standard tile size be allowed?
1388 if (g->tile_size < TILESIZE)
1389 g->tile_size = TILESIZE; // standard tile size
1392 // when setting tile size, also set width and height accordingly
1393 g->width = g->tile_size;
1394 g->height = g->tile_size;
1397 if (g->use_image_size)
1399 // set new default bitmap size (with scaling, but without small images)
1400 g->width = get_scaled_graphic_width(graphic);
1401 g->height = get_scaled_graphic_height(graphic);
1404 // optional width and height of each animation frame
1405 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1406 g->width = parameter[GFX_ARG_WIDTH];
1407 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1408 g->height = parameter[GFX_ARG_HEIGHT];
1410 // optional x and y tile position of animation frame sequence
1411 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1412 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1413 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1414 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1416 // optional x and y pixel position of animation frame sequence
1417 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1418 g->src_x = parameter[GFX_ARG_X];
1419 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1420 g->src_y = parameter[GFX_ARG_Y];
1427 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1428 g->width, getTokenFromImageID(graphic), TILEX);
1431 g->width = TILEX; // will be checked to be inside bitmap later
1437 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1438 g->height, getTokenFromImageID(graphic), TILEY);
1441 g->height = TILEY; // will be checked to be inside bitmap later
1447 // get final bitmap size (with scaling, but without small images)
1448 int src_image_width = get_scaled_graphic_width(graphic);
1449 int src_image_height = get_scaled_graphic_height(graphic);
1451 if (src_image_width == 0 || src_image_height == 0)
1453 // only happens when loaded outside artwork system (like "global.busy")
1454 src_image_width = src_bitmap->width;
1455 src_image_height = src_bitmap->height;
1458 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1460 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1461 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1465 anim_frames_per_row = MAX(1, src_image_width / g->width);
1466 anim_frames_per_col = MAX(1, src_image_height / g->height);
1469 g->src_image_width = src_image_width;
1470 g->src_image_height = src_image_height;
1473 // correct x or y offset dependent of vertical or horizontal frame order
1474 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1476 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1477 parameter[GFX_ARG_OFFSET] : g->height);
1478 anim_frames_per_line = anim_frames_per_col;
1480 else // frames are ordered horizontally
1482 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1483 parameter[GFX_ARG_OFFSET] : g->width);
1484 anim_frames_per_line = anim_frames_per_row;
1487 // optionally, the x and y offset of frames can be specified directly
1488 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1489 g->offset_x = parameter[GFX_ARG_XOFFSET];
1490 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1491 g->offset_y = parameter[GFX_ARG_YOFFSET];
1493 // optionally, moving animations may have separate start and end graphics
1494 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1496 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1497 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1499 // correct x or y offset2 dependent of vertical or horizontal frame order
1500 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1501 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1502 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1503 else // frames are ordered horizontally
1504 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1505 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1507 // optionally, the x and y offset of 2nd graphic can be specified directly
1508 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1509 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1510 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1511 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1513 // optionally, the second movement tile can be specified as start tile
1514 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1515 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1517 // automatically determine correct number of frames, if not defined
1518 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1519 g->anim_frames = parameter[GFX_ARG_FRAMES];
1520 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1521 g->anim_frames = anim_frames_per_row;
1522 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1523 g->anim_frames = anim_frames_per_col;
1527 if (g->anim_frames < 1) // frames must be at least 1
1530 g->anim_frames_per_line =
1531 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1532 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1534 g->anim_delay = parameter[GFX_ARG_DELAY];
1535 if (g->anim_delay < 1) // delay must be at least 1
1538 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1540 // automatically determine correct start frame, if not defined
1541 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1542 g->anim_start_frame = 0;
1543 else if (g->anim_mode & ANIM_REVERSE)
1544 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1546 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1548 // animation synchronized with global frame counter, not move position
1549 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1551 // optional element for cloning crumble graphics
1552 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1553 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1555 // optional element for cloning digging graphics
1556 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1557 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1559 // optional border size for "crumbling" diggable graphics
1560 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1561 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1563 // used for global animations and player "boring" and "sleeping" actions
1564 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1565 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1566 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1567 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1568 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1569 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1570 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1571 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1572 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1573 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1574 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1575 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1577 // used for global animations
1578 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1579 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1580 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1581 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1582 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1583 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1584 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1585 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1586 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1587 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1588 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1589 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1590 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1591 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1593 // used for toon animations and global animations
1594 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1595 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1596 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1597 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1598 g->direction = parameter[GFX_ARG_DIRECTION];
1599 g->position = parameter[GFX_ARG_POSITION];
1600 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1601 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1603 if (g->step_delay < 1) // delay must be at least 1
1606 // this is only used for drawing font characters
1607 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1608 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1610 // use a different default value for global animations and toons
1611 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1612 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1613 g->draw_masked = TRUE;
1615 // this is used for drawing envelopes, global animations and toons
1616 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1617 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1619 // used for toon animations and global animations
1620 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1621 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1623 // optional graphic for cloning all graphics settings
1624 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1625 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1627 // optional settings for drawing title screens and title messages
1628 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1629 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1630 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1631 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1632 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1633 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1634 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1635 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1636 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1637 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1638 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1639 g->align = parameter[GFX_ARG_ALIGN];
1640 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1641 g->valign = parameter[GFX_ARG_VALIGN];
1642 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1643 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1645 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1646 g->class = parameter[GFX_ARG_CLASS];
1647 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1648 g->style = parameter[GFX_ARG_STYLE];
1650 // this is only used for drawing menu buttons and text
1651 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1652 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1653 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1654 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1657 static void set_graphic_parameters(int graphic)
1659 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1660 char **parameter_raw = image->parameter;
1661 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1662 int parameter[NUM_GFX_ARGS];
1665 // if fallback to default artwork is done, also use the default parameters
1666 if (image->fallback_to_default)
1667 parameter_raw = image->default_parameter;
1669 // get integer values from string parameters
1670 for (i = 0; i < NUM_GFX_ARGS; i++)
1671 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1672 image_config_suffix[i].token,
1673 image_config_suffix[i].type);
1675 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1677 UPDATE_BUSY_STATE();
1680 static void set_cloned_graphic_parameters(int graphic)
1682 int fallback_graphic = IMG_CHAR_EXCLAM;
1683 int max_num_images = getImageListSize();
1684 int clone_graphic = graphic_info[graphic].clone_from;
1685 int num_references_followed = 1;
1687 while (graphic_info[clone_graphic].clone_from != -1 &&
1688 num_references_followed < max_num_images)
1690 clone_graphic = graphic_info[clone_graphic].clone_from;
1692 num_references_followed++;
1695 if (num_references_followed >= max_num_images)
1698 Warn("error found in config file:");
1699 Warn("- config file: '%s'", getImageConfigFilename());
1700 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1701 Warn("error: loop discovered when resolving cloned graphics");
1702 Warn("custom graphic rejected for this element/action");
1704 if (graphic == fallback_graphic)
1705 Fail("no fallback graphic available");
1707 Warn("fallback done to 'char_exclam' for this graphic");
1710 graphic_info[graphic] = graphic_info[fallback_graphic];
1714 graphic_info[graphic] = graphic_info[clone_graphic];
1715 graphic_info[graphic].clone_from = clone_graphic;
1719 static void InitGraphicInfo(void)
1721 int fallback_graphic = IMG_CHAR_EXCLAM;
1722 int num_images = getImageListSize();
1725 // use image size as default values for width and height for these images
1726 static int full_size_graphics[] =
1729 IMG_GLOBAL_BORDER_MAIN,
1730 IMG_GLOBAL_BORDER_SCORES,
1731 IMG_GLOBAL_BORDER_EDITOR,
1732 IMG_GLOBAL_BORDER_PLAYING,
1735 IMG_BACKGROUND_ENVELOPE_1,
1736 IMG_BACKGROUND_ENVELOPE_2,
1737 IMG_BACKGROUND_ENVELOPE_3,
1738 IMG_BACKGROUND_ENVELOPE_4,
1739 IMG_BACKGROUND_REQUEST,
1742 IMG_BACKGROUND_LOADING_INITIAL,
1743 IMG_BACKGROUND_LOADING,
1744 IMG_BACKGROUND_TITLE_INITIAL,
1745 IMG_BACKGROUND_TITLE,
1746 IMG_BACKGROUND_MAIN,
1747 IMG_BACKGROUND_NAMES,
1748 IMG_BACKGROUND_LEVELS,
1749 IMG_BACKGROUND_LEVELNR,
1750 IMG_BACKGROUND_SCORES,
1751 IMG_BACKGROUND_SCOREINFO,
1752 IMG_BACKGROUND_EDITOR,
1753 IMG_BACKGROUND_INFO,
1754 IMG_BACKGROUND_INFO_ELEMENTS,
1755 IMG_BACKGROUND_INFO_MUSIC,
1756 IMG_BACKGROUND_INFO_CREDITS,
1757 IMG_BACKGROUND_INFO_PROGRAM,
1758 IMG_BACKGROUND_INFO_VERSION,
1759 IMG_BACKGROUND_INFO_LEVELSET,
1760 IMG_BACKGROUND_SETUP,
1761 IMG_BACKGROUND_PLAYING,
1762 IMG_BACKGROUND_DOOR,
1763 IMG_BACKGROUND_TAPE,
1764 IMG_BACKGROUND_PANEL,
1765 IMG_BACKGROUND_PALETTE,
1766 IMG_BACKGROUND_TOOLBOX,
1768 IMG_TITLESCREEN_INITIAL_1,
1769 IMG_TITLESCREEN_INITIAL_2,
1770 IMG_TITLESCREEN_INITIAL_3,
1771 IMG_TITLESCREEN_INITIAL_4,
1772 IMG_TITLESCREEN_INITIAL_5,
1779 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1780 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1781 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1782 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1783 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1784 IMG_BACKGROUND_TITLEMESSAGE_1,
1785 IMG_BACKGROUND_TITLEMESSAGE_2,
1786 IMG_BACKGROUND_TITLEMESSAGE_3,
1787 IMG_BACKGROUND_TITLEMESSAGE_4,
1788 IMG_BACKGROUND_TITLEMESSAGE_5,
1793 FreeGlobalAnimEventInfo();
1795 checked_free(graphic_info);
1797 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1799 // initialize "use_image_size" flag with default value
1800 for (i = 0; i < num_images; i++)
1801 graphic_info[i].use_image_size = FALSE;
1803 // initialize "use_image_size" flag from static configuration above
1804 for (i = 0; full_size_graphics[i] != -1; i++)
1805 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1807 // first set all graphic paramaters ...
1808 for (i = 0; i < num_images; i++)
1809 set_graphic_parameters(i);
1811 // ... then copy these parameters for cloned graphics
1812 for (i = 0; i < num_images; i++)
1813 if (graphic_info[i].clone_from != -1)
1814 set_cloned_graphic_parameters(i);
1816 for (i = 0; i < num_images; i++)
1818 Bitmap *src_bitmap = graphic_info[i].bitmap;
1822 int src_bitmap_width, src_bitmap_height;
1824 // now check if no animation frames are outside of the loaded image
1826 if (graphic_info[i].bitmap == NULL)
1827 continue; // skip check for optional images that are undefined
1829 // get image size (this can differ from the standard element tile size!)
1830 width = graphic_info[i].width;
1831 height = graphic_info[i].height;
1833 // get final bitmap size (with scaling, but without small images)
1834 src_bitmap_width = graphic_info[i].src_image_width;
1835 src_bitmap_height = graphic_info[i].src_image_height;
1837 // check if first animation frame is inside specified bitmap
1839 // do not use getGraphicSourceXY() here to get position of first frame;
1840 // this avoids calculating wrong start position for out-of-bounds frame
1841 src_x = graphic_info[i].src_x;
1842 src_y = graphic_info[i].src_y;
1844 if (program.headless)
1847 if (src_x < 0 || src_y < 0 ||
1848 src_x + width > src_bitmap_width ||
1849 src_y + height > src_bitmap_height)
1852 Warn("error found in config file:");
1853 Warn("- config file: '%s'", getImageConfigFilename());
1854 Warn("- config token: '%s'", getTokenFromImageID(i));
1855 Warn("- image file: '%s'", src_bitmap->source_filename);
1856 Warn("- frame size: %d, %d", width, height);
1857 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1858 src_x, src_y, src_bitmap_width, src_bitmap_height);
1859 Warn("custom graphic rejected for this element/action");
1861 if (i == fallback_graphic)
1862 Fail("no fallback graphic available");
1864 Warn("fallback done to 'char_exclam' for this graphic");
1867 graphic_info[i] = graphic_info[fallback_graphic];
1869 // if first frame out of bounds, do not check last frame anymore
1873 // check if last animation frame is inside specified bitmap
1875 last_frame = graphic_info[i].anim_frames - 1;
1876 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1878 if (src_x < 0 || src_y < 0 ||
1879 src_x + width > src_bitmap_width ||
1880 src_y + height > src_bitmap_height)
1883 Warn("error found in config file:");
1884 Warn("- config file: '%s'", getImageConfigFilename());
1885 Warn("- config token: '%s'", getTokenFromImageID(i));
1886 Warn("- image file: '%s'", src_bitmap->source_filename);
1887 Warn("- frame size: %d, %d", width, height);
1888 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1889 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1890 Warn("custom graphic rejected for this element/action");
1892 if (i == fallback_graphic)
1893 Fail("no fallback graphic available");
1895 Warn("fallback done to 'char_exclam' for this graphic");
1898 graphic_info[i] = graphic_info[fallback_graphic];
1903 static void InitGraphicCompatibilityInfo(void)
1905 struct FileInfo *fi_global_door =
1906 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1907 int num_images = getImageListSize();
1910 /* the following compatibility handling is needed for the following case:
1911 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1912 graphics mainly used for door and panel graphics, like editor, tape and
1913 in-game buttons with hard-coded bitmap positions and button sizes; as
1914 these graphics now have individual definitions, redefining "global.door"
1915 to change all these graphics at once like before does not work anymore
1916 (because all those individual definitions still have their default values);
1917 to solve this, remap all those individual definitions that are not
1918 redefined to the new bitmap of "global.door" if it was redefined */
1920 // special compatibility handling if image "global.door" was redefined
1921 if (fi_global_door->redefined)
1923 for (i = 0; i < num_images; i++)
1925 struct FileInfo *fi = getImageListEntryFromImageID(i);
1927 // process only those images that still use the default settings
1930 // process all images which default to same image as "global.door"
1931 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1933 // skip all images that are cloned from images that default to same
1934 // image as "global.door", but that are redefined to something else
1935 if (graphic_info[i].clone_from != -1)
1937 int cloned_graphic = graphic_info[i].clone_from;
1939 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
1944 Debug("init:InitGraphicCompatibilityInfo",
1945 "special treatment needed for token '%s'", fi->token);
1948 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1949 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1955 InitGraphicCompatibilityInfo_Doors();
1958 static void InitElementSoundInfo(void)
1960 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1961 int num_property_mappings = getSoundListPropertyMappingSize();
1964 // set values to -1 to identify later as "uninitialized" values
1965 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1966 for (act = 0; act < NUM_ACTIONS; act++)
1967 element_info[i].sound[act] = -1;
1969 // initialize element/sound mapping from static configuration
1970 for (i = 0; element_to_sound[i].element > -1; i++)
1972 int element = element_to_sound[i].element;
1973 int action = element_to_sound[i].action;
1974 int sound = element_to_sound[i].sound;
1975 boolean is_class = element_to_sound[i].is_class;
1978 action = ACTION_DEFAULT;
1981 element_info[element].sound[action] = sound;
1983 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1984 if (strEqual(element_info[j].class_name,
1985 element_info[element].class_name))
1986 element_info[j].sound[action] = sound;
1989 // initialize element class/sound mapping from dynamic configuration
1990 for (i = 0; i < num_property_mappings; i++)
1992 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1993 int action = property_mapping[i].ext1_index;
1994 int sound = property_mapping[i].artwork_index;
1996 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2000 action = ACTION_DEFAULT;
2002 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2003 if (strEqual(element_info[j].class_name,
2004 element_info[element_class].class_name))
2005 element_info[j].sound[action] = sound;
2008 // initialize element/sound mapping from dynamic configuration
2009 for (i = 0; i < num_property_mappings; i++)
2011 int element = property_mapping[i].base_index;
2012 int action = property_mapping[i].ext1_index;
2013 int sound = property_mapping[i].artwork_index;
2015 if (element >= MAX_NUM_ELEMENTS)
2019 action = ACTION_DEFAULT;
2021 element_info[element].sound[action] = sound;
2024 // now set all '-1' values to element specific default values
2025 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2027 for (act = 0; act < NUM_ACTIONS; act++)
2029 // generic default action sound (defined by "[default]" directive)
2030 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2032 // look for special default action sound (classic game specific)
2033 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2034 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2035 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2036 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2037 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2038 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2039 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2040 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2042 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2043 // !!! make this better !!!
2044 if (i == EL_EMPTY_SPACE)
2045 default_action_sound = element_info[EL_DEFAULT].sound[act];
2047 // no sound for this specific action -- use default action sound
2048 if (element_info[i].sound[act] == -1)
2049 element_info[i].sound[act] = default_action_sound;
2053 // copy sound settings to some elements that are only stored in level file
2054 // in native R'n'D levels, but are used by game engine in native EM levels
2055 for (i = 0; copy_properties[i][0] != -1; i++)
2056 for (j = 1; j <= 4; j++)
2057 for (act = 0; act < NUM_ACTIONS; act++)
2058 element_info[copy_properties[i][j]].sound[act] =
2059 element_info[copy_properties[i][0]].sound[act];
2062 static void InitGameModeSoundInfo(void)
2066 // set values to -1 to identify later as "uninitialized" values
2067 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2070 // initialize gamemode/sound mapping from static configuration
2071 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2073 int gamemode = gamemode_to_sound[i].gamemode;
2074 int sound = gamemode_to_sound[i].sound;
2077 gamemode = GAME_MODE_DEFAULT;
2079 menu.sound[gamemode] = sound;
2082 // now set all '-1' values to levelset specific default values
2083 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2084 if (menu.sound[i] == -1)
2085 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2088 static void set_sound_parameters(int sound, char **parameter_raw)
2090 int parameter[NUM_SND_ARGS];
2093 // get integer values from string parameters
2094 for (i = 0; i < NUM_SND_ARGS; i++)
2096 get_parameter_value(parameter_raw[i],
2097 sound_config_suffix[i].token,
2098 sound_config_suffix[i].type);
2100 // explicit loop mode setting in configuration overrides default value
2101 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2102 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2104 // sound volume to change the original volume when loading the sound file
2105 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2107 // sound priority to give certain sounds a higher or lower priority
2108 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2111 static void InitSoundInfo(void)
2113 int *sound_effect_properties;
2114 int num_sounds = getSoundListSize();
2117 checked_free(sound_info);
2119 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2120 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2122 // initialize sound effect for all elements to "no sound"
2123 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2124 for (j = 0; j < NUM_ACTIONS; j++)
2125 element_info[i].sound[j] = SND_UNDEFINED;
2127 for (i = 0; i < num_sounds; i++)
2129 struct FileInfo *sound = getSoundListEntry(i);
2130 int len_effect_text = strlen(sound->token);
2132 sound_effect_properties[i] = ACTION_OTHER;
2133 sound_info[i].loop = FALSE; // default: play sound only once
2135 // determine all loop sounds and identify certain sound classes
2137 for (j = 0; element_action_info[j].suffix; j++)
2139 int len_action_text = strlen(element_action_info[j].suffix);
2141 if (len_action_text < len_effect_text &&
2142 strEqual(&sound->token[len_effect_text - len_action_text],
2143 element_action_info[j].suffix))
2145 sound_effect_properties[i] = element_action_info[j].value;
2146 sound_info[i].loop = element_action_info[j].is_loop_sound;
2152 // associate elements and some selected sound actions
2154 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2156 if (element_info[j].class_name)
2158 int len_class_text = strlen(element_info[j].class_name);
2160 if (len_class_text + 1 < len_effect_text &&
2161 strncmp(sound->token,
2162 element_info[j].class_name, len_class_text) == 0 &&
2163 sound->token[len_class_text] == '.')
2165 int sound_action_value = sound_effect_properties[i];
2167 element_info[j].sound[sound_action_value] = i;
2172 set_sound_parameters(i, sound->parameter);
2175 free(sound_effect_properties);
2178 static void InitGameModeMusicInfo(void)
2180 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2181 int num_property_mappings = getMusicListPropertyMappingSize();
2182 int default_levelset_music = -1;
2185 // set values to -1 to identify later as "uninitialized" values
2186 for (i = 0; i < MAX_LEVELS; i++)
2187 levelset.music[i] = -1;
2188 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2191 // initialize gamemode/music mapping from static configuration
2192 for (i = 0; gamemode_to_music[i].music > -1; i++)
2194 int gamemode = gamemode_to_music[i].gamemode;
2195 int music = gamemode_to_music[i].music;
2198 gamemode = GAME_MODE_DEFAULT;
2200 menu.music[gamemode] = music;
2203 // initialize gamemode/music mapping from dynamic configuration
2204 for (i = 0; i < num_property_mappings; i++)
2206 int prefix = property_mapping[i].base_index;
2207 int gamemode = property_mapping[i].ext2_index;
2208 int level = property_mapping[i].ext3_index;
2209 int music = property_mapping[i].artwork_index;
2211 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2215 gamemode = GAME_MODE_DEFAULT;
2217 // level specific music only allowed for in-game music
2218 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2219 gamemode = GAME_MODE_PLAYING;
2224 default_levelset_music = music;
2227 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2228 levelset.music[level] = music;
2229 if (gamemode != GAME_MODE_PLAYING)
2230 menu.music[gamemode] = music;
2233 // now set all '-1' values to menu specific default values
2234 // (undefined values of "levelset.music[]" might stay at "-1" to
2235 // allow dynamic selection of music files from music directory!)
2236 for (i = 0; i < MAX_LEVELS; i++)
2237 if (levelset.music[i] == -1)
2238 levelset.music[i] = default_levelset_music;
2239 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2240 if (menu.music[i] == -1)
2241 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2244 static void set_music_parameters(int music, char **parameter_raw)
2246 int parameter[NUM_MUS_ARGS];
2249 // get integer values from string parameters
2250 for (i = 0; i < NUM_MUS_ARGS; i++)
2252 get_parameter_value(parameter_raw[i],
2253 music_config_suffix[i].token,
2254 music_config_suffix[i].type);
2256 // explicit loop mode setting in configuration overrides default value
2257 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2258 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2261 static void InitMusicInfo(void)
2263 int num_music = getMusicListSize();
2266 checked_free(music_info);
2268 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2270 for (i = 0; i < num_music; i++)
2272 struct FileInfo *music = getMusicListEntry(i);
2273 int len_music_text = strlen(music->token);
2275 music_info[i].loop = TRUE; // default: play music in loop mode
2277 // determine all loop music
2279 for (j = 0; music_prefix_info[j].prefix; j++)
2281 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2283 if (len_prefix_text < len_music_text &&
2284 strncmp(music->token,
2285 music_prefix_info[j].prefix, len_prefix_text) == 0)
2287 music_info[i].loop = music_prefix_info[j].is_loop_music;
2293 set_music_parameters(i, music->parameter);
2298 static void InitGameInfoFromArtworkInfo(void)
2300 // special case: store initial value of custom artwork setting
2301 game.use_masked_elements_initial = game.use_masked_elements;
2304 static void ReinitializeGraphics(void)
2306 print_timestamp_init("ReinitializeGraphics");
2308 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2310 InitGraphicInfo(); // graphic properties mapping
2311 print_timestamp_time("InitGraphicInfo");
2312 InitElementGraphicInfo(); // element game graphic mapping
2313 print_timestamp_time("InitElementGraphicInfo");
2314 InitElementSpecialGraphicInfo(); // element special graphic mapping
2315 print_timestamp_time("InitElementSpecialGraphicInfo");
2317 InitElementSmallImages(); // scale elements to all needed sizes
2318 print_timestamp_time("InitElementSmallImages");
2319 InitScaledImages(); // scale all other images, if needed
2320 print_timestamp_time("InitScaledImages");
2321 InitBitmapPointers(); // set standard size bitmap pointers
2322 print_timestamp_time("InitBitmapPointers");
2323 InitFontGraphicInfo(); // initialize text drawing functions
2324 print_timestamp_time("InitFontGraphicInfo");
2325 InitGlobalAnimGraphicInfo(); // initialize global animation config
2326 print_timestamp_time("InitGlobalAnimGraphicInfo");
2328 InitImageTextures(); // create textures for certain images
2329 print_timestamp_time("InitImageTextures");
2331 InitGraphicInfo_EM(); // graphic mapping for EM engine
2332 print_timestamp_time("InitGraphicInfo_EM");
2334 InitGraphicCompatibilityInfo();
2335 print_timestamp_time("InitGraphicCompatibilityInfo");
2338 print_timestamp_time("InitGadgets");
2340 print_timestamp_time("InitDoors");
2342 InitGameInfoFromArtworkInfo();
2344 print_timestamp_done("ReinitializeGraphics");
2347 static void ReinitializeSounds(void)
2349 InitSoundInfo(); // sound properties mapping
2350 InitElementSoundInfo(); // element game sound mapping
2351 InitGameModeSoundInfo(); // game mode sound mapping
2352 InitGlobalAnimSoundInfo(); // global animation sound settings
2354 InitPlayLevelSound(); // internal game sound settings
2357 static void ReinitializeMusic(void)
2359 InitMusicInfo(); // music properties mapping
2360 InitGameModeMusicInfo(); // game mode music mapping
2361 InitGlobalAnimMusicInfo(); // global animation music settings
2364 static int get_special_property_bit(int element, int property_bit_nr)
2366 struct PropertyBitInfo
2372 static struct PropertyBitInfo pb_can_move_into_acid[] =
2374 // the player may be able fall into acid when gravity is activated
2379 { EL_SP_MURPHY, 0 },
2380 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2382 // all elements that can move may be able to also move into acid
2385 { EL_BUG_RIGHT, 1 },
2388 { EL_SPACESHIP, 2 },
2389 { EL_SPACESHIP_LEFT, 2 },
2390 { EL_SPACESHIP_RIGHT, 2 },
2391 { EL_SPACESHIP_UP, 2 },
2392 { EL_SPACESHIP_DOWN, 2 },
2393 { EL_BD_BUTTERFLY, 3 },
2394 { EL_BD_BUTTERFLY_LEFT, 3 },
2395 { EL_BD_BUTTERFLY_RIGHT, 3 },
2396 { EL_BD_BUTTERFLY_UP, 3 },
2397 { EL_BD_BUTTERFLY_DOWN, 3 },
2398 { EL_BD_FIREFLY, 4 },
2399 { EL_BD_FIREFLY_LEFT, 4 },
2400 { EL_BD_FIREFLY_RIGHT, 4 },
2401 { EL_BD_FIREFLY_UP, 4 },
2402 { EL_BD_FIREFLY_DOWN, 4 },
2404 { EL_YAMYAM_LEFT, 5 },
2405 { EL_YAMYAM_RIGHT, 5 },
2406 { EL_YAMYAM_UP, 5 },
2407 { EL_YAMYAM_DOWN, 5 },
2408 { EL_DARK_YAMYAM, 6 },
2411 { EL_PACMAN_LEFT, 8 },
2412 { EL_PACMAN_RIGHT, 8 },
2413 { EL_PACMAN_UP, 8 },
2414 { EL_PACMAN_DOWN, 8 },
2416 { EL_MOLE_LEFT, 9 },
2417 { EL_MOLE_RIGHT, 9 },
2419 { EL_MOLE_DOWN, 9 },
2423 { EL_SATELLITE, 13 },
2424 { EL_SP_SNIKSNAK, 14 },
2425 { EL_SP_ELECTRON, 15 },
2428 { EL_SPRING_LEFT, 17 },
2429 { EL_SPRING_RIGHT, 17 },
2430 { EL_EMC_ANDROID, 18 },
2435 static struct PropertyBitInfo pb_dont_collide_with[] =
2437 { EL_SP_SNIKSNAK, 0 },
2438 { EL_SP_ELECTRON, 1 },
2446 struct PropertyBitInfo *pb_info;
2449 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2450 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2455 struct PropertyBitInfo *pb_info = NULL;
2458 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2459 if (pb_definition[i].bit_nr == property_bit_nr)
2460 pb_info = pb_definition[i].pb_info;
2462 if (pb_info == NULL)
2465 for (i = 0; pb_info[i].element != -1; i++)
2466 if (pb_info[i].element == element)
2467 return pb_info[i].bit_nr;
2472 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2473 boolean property_value)
2475 int bit_nr = get_special_property_bit(element, property_bit_nr);
2480 *bitfield |= (1 << bit_nr);
2482 *bitfield &= ~(1 << bit_nr);
2486 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2488 int bit_nr = get_special_property_bit(element, property_bit_nr);
2491 return ((*bitfield & (1 << bit_nr)) != 0);
2496 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2498 static int group_nr;
2499 static struct ElementGroupInfo *group;
2500 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2503 if (actual_group == NULL) // not yet initialized
2506 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2508 Warn("recursion too deep when resolving group element %d",
2509 group_element - EL_GROUP_START + 1);
2511 // replace element which caused too deep recursion by question mark
2512 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2517 if (recursion_depth == 0) // initialization
2519 group = actual_group;
2520 group_nr = GROUP_NR(group_element);
2522 group->num_elements_resolved = 0;
2523 group->choice_pos = 0;
2525 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2526 element_info[i].in_group[group_nr] = FALSE;
2529 for (i = 0; i < actual_group->num_elements; i++)
2531 int element = actual_group->element[i];
2533 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2536 if (IS_GROUP_ELEMENT(element))
2537 ResolveGroupElementExt(element, recursion_depth + 1);
2540 group->element_resolved[group->num_elements_resolved++] = element;
2541 element_info[element].in_group[group_nr] = TRUE;
2546 void ResolveGroupElement(int group_element)
2548 ResolveGroupElementExt(group_element, 0);
2551 void InitElementPropertiesStatic(void)
2553 static boolean clipboard_elements_initialized = FALSE;
2555 static int ep_diggable[] =
2560 EL_SP_BUGGY_BASE_ACTIVATING,
2563 EL_INVISIBLE_SAND_ACTIVE,
2566 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2567 // (if amoeba can grow into anything diggable, maybe keep these out)
2572 EL_SP_BUGGY_BASE_ACTIVE,
2579 static int ep_collectible_only[] =
2601 EL_DYNABOMB_INCREASE_NUMBER,
2602 EL_DYNABOMB_INCREASE_SIZE,
2603 EL_DYNABOMB_INCREASE_POWER,
2621 // !!! handle separately !!!
2622 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2628 static int ep_dont_run_into[] =
2630 // same elements as in 'ep_dont_touch'
2636 // same elements as in 'ep_dont_collide_with'
2648 // !!! maybe this should better be handled by 'ep_diggable' !!!
2653 EL_SP_BUGGY_BASE_ACTIVE,
2660 static int ep_dont_collide_with[] =
2662 // same elements as in 'ep_dont_touch'
2679 static int ep_dont_touch[] =
2689 static int ep_indestructible[] =
2693 EL_ACID_POOL_TOPLEFT,
2694 EL_ACID_POOL_TOPRIGHT,
2695 EL_ACID_POOL_BOTTOMLEFT,
2696 EL_ACID_POOL_BOTTOM,
2697 EL_ACID_POOL_BOTTOMRIGHT,
2698 EL_SP_HARDWARE_GRAY,
2699 EL_SP_HARDWARE_GREEN,
2700 EL_SP_HARDWARE_BLUE,
2702 EL_SP_HARDWARE_YELLOW,
2703 EL_SP_HARDWARE_BASE_1,
2704 EL_SP_HARDWARE_BASE_2,
2705 EL_SP_HARDWARE_BASE_3,
2706 EL_SP_HARDWARE_BASE_4,
2707 EL_SP_HARDWARE_BASE_5,
2708 EL_SP_HARDWARE_BASE_6,
2709 EL_INVISIBLE_STEELWALL,
2710 EL_INVISIBLE_STEELWALL_ACTIVE,
2711 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2712 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2713 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2714 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2715 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2716 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2717 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2718 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2719 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2720 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2721 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2722 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2724 EL_LIGHT_SWITCH_ACTIVE,
2725 EL_SIGN_EXCLAMATION,
2726 EL_SIGN_RADIOACTIVITY,
2733 EL_SIGN_ENTRY_FORBIDDEN,
2734 EL_SIGN_EMERGENCY_EXIT,
2742 EL_STEEL_EXIT_CLOSED,
2744 EL_STEEL_EXIT_OPENING,
2745 EL_STEEL_EXIT_CLOSING,
2746 EL_EM_STEEL_EXIT_CLOSED,
2747 EL_EM_STEEL_EXIT_OPEN,
2748 EL_EM_STEEL_EXIT_OPENING,
2749 EL_EM_STEEL_EXIT_CLOSING,
2750 EL_DC_STEELWALL_1_LEFT,
2751 EL_DC_STEELWALL_1_RIGHT,
2752 EL_DC_STEELWALL_1_TOP,
2753 EL_DC_STEELWALL_1_BOTTOM,
2754 EL_DC_STEELWALL_1_HORIZONTAL,
2755 EL_DC_STEELWALL_1_VERTICAL,
2756 EL_DC_STEELWALL_1_TOPLEFT,
2757 EL_DC_STEELWALL_1_TOPRIGHT,
2758 EL_DC_STEELWALL_1_BOTTOMLEFT,
2759 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2760 EL_DC_STEELWALL_1_TOPLEFT_2,
2761 EL_DC_STEELWALL_1_TOPRIGHT_2,
2762 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2763 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2764 EL_DC_STEELWALL_2_LEFT,
2765 EL_DC_STEELWALL_2_RIGHT,
2766 EL_DC_STEELWALL_2_TOP,
2767 EL_DC_STEELWALL_2_BOTTOM,
2768 EL_DC_STEELWALL_2_HORIZONTAL,
2769 EL_DC_STEELWALL_2_VERTICAL,
2770 EL_DC_STEELWALL_2_MIDDLE,
2771 EL_DC_STEELWALL_2_SINGLE,
2772 EL_STEELWALL_SLIPPERY,
2786 EL_GATE_1_GRAY_ACTIVE,
2787 EL_GATE_2_GRAY_ACTIVE,
2788 EL_GATE_3_GRAY_ACTIVE,
2789 EL_GATE_4_GRAY_ACTIVE,
2798 EL_EM_GATE_1_GRAY_ACTIVE,
2799 EL_EM_GATE_2_GRAY_ACTIVE,
2800 EL_EM_GATE_3_GRAY_ACTIVE,
2801 EL_EM_GATE_4_GRAY_ACTIVE,
2810 EL_EMC_GATE_5_GRAY_ACTIVE,
2811 EL_EMC_GATE_6_GRAY_ACTIVE,
2812 EL_EMC_GATE_7_GRAY_ACTIVE,
2813 EL_EMC_GATE_8_GRAY_ACTIVE,
2815 EL_DC_GATE_WHITE_GRAY,
2816 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2817 EL_DC_GATE_FAKE_GRAY,
2819 EL_SWITCHGATE_OPENING,
2820 EL_SWITCHGATE_CLOSED,
2821 EL_SWITCHGATE_CLOSING,
2822 EL_DC_SWITCHGATE_SWITCH_UP,
2823 EL_DC_SWITCHGATE_SWITCH_DOWN,
2825 EL_TIMEGATE_OPENING,
2827 EL_TIMEGATE_CLOSING,
2828 EL_DC_TIMEGATE_SWITCH,
2829 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2833 EL_TUBE_VERTICAL_LEFT,
2834 EL_TUBE_VERTICAL_RIGHT,
2835 EL_TUBE_HORIZONTAL_UP,
2836 EL_TUBE_HORIZONTAL_DOWN,
2841 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2842 EL_EXPANDABLE_STEELWALL_VERTICAL,
2843 EL_EXPANDABLE_STEELWALL_ANY,
2848 static int ep_slippery[] =
2862 EL_ROBOT_WHEEL_ACTIVE,
2868 EL_ACID_POOL_TOPLEFT,
2869 EL_ACID_POOL_TOPRIGHT,
2879 EL_STEELWALL_SLIPPERY,
2882 EL_EMC_WALL_SLIPPERY_1,
2883 EL_EMC_WALL_SLIPPERY_2,
2884 EL_EMC_WALL_SLIPPERY_3,
2885 EL_EMC_WALL_SLIPPERY_4,
2887 EL_EMC_MAGIC_BALL_ACTIVE,
2892 static int ep_can_change[] =
2897 static int ep_can_move[] =
2899 // same elements as in 'pb_can_move_into_acid'
2922 static int ep_can_fall[] =
2937 EL_QUICKSAND_FAST_FULL,
2939 EL_BD_MAGIC_WALL_FULL,
2940 EL_DC_MAGIC_WALL_FULL,
2954 static int ep_can_smash_player[] =
2980 static int ep_can_smash_enemies[] =
2989 static int ep_can_smash_everything[] =
2998 static int ep_explodes_by_fire[] =
3000 // same elements as in 'ep_explodes_impact'
3005 // same elements as in 'ep_explodes_smashed'
3015 EL_EM_DYNAMITE_ACTIVE,
3016 EL_DYNABOMB_PLAYER_1_ACTIVE,
3017 EL_DYNABOMB_PLAYER_2_ACTIVE,
3018 EL_DYNABOMB_PLAYER_3_ACTIVE,
3019 EL_DYNABOMB_PLAYER_4_ACTIVE,
3020 EL_DYNABOMB_INCREASE_NUMBER,
3021 EL_DYNABOMB_INCREASE_SIZE,
3022 EL_DYNABOMB_INCREASE_POWER,
3023 EL_SP_DISK_RED_ACTIVE,
3037 static int ep_explodes_smashed[] =
3039 // same elements as in 'ep_explodes_impact'
3053 static int ep_explodes_impact[] =
3062 static int ep_walkable_over[] =
3082 EL_SOKOBAN_FIELD_EMPTY,
3089 EL_EM_STEEL_EXIT_OPEN,
3090 EL_EM_STEEL_EXIT_OPENING,
3099 EL_GATE_1_GRAY_ACTIVE,
3100 EL_GATE_2_GRAY_ACTIVE,
3101 EL_GATE_3_GRAY_ACTIVE,
3102 EL_GATE_4_GRAY_ACTIVE,
3110 static int ep_walkable_inside[] =
3115 EL_TUBE_VERTICAL_LEFT,
3116 EL_TUBE_VERTICAL_RIGHT,
3117 EL_TUBE_HORIZONTAL_UP,
3118 EL_TUBE_HORIZONTAL_DOWN,
3127 static int ep_walkable_under[] =
3132 static int ep_passable_over[] =
3142 EL_EM_GATE_1_GRAY_ACTIVE,
3143 EL_EM_GATE_2_GRAY_ACTIVE,
3144 EL_EM_GATE_3_GRAY_ACTIVE,
3145 EL_EM_GATE_4_GRAY_ACTIVE,
3154 EL_EMC_GATE_5_GRAY_ACTIVE,
3155 EL_EMC_GATE_6_GRAY_ACTIVE,
3156 EL_EMC_GATE_7_GRAY_ACTIVE,
3157 EL_EMC_GATE_8_GRAY_ACTIVE,
3159 EL_DC_GATE_WHITE_GRAY,
3160 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3167 static int ep_passable_inside[] =
3173 EL_SP_PORT_HORIZONTAL,
3174 EL_SP_PORT_VERTICAL,
3176 EL_SP_GRAVITY_PORT_LEFT,
3177 EL_SP_GRAVITY_PORT_RIGHT,
3178 EL_SP_GRAVITY_PORT_UP,
3179 EL_SP_GRAVITY_PORT_DOWN,
3180 EL_SP_GRAVITY_ON_PORT_LEFT,
3181 EL_SP_GRAVITY_ON_PORT_RIGHT,
3182 EL_SP_GRAVITY_ON_PORT_UP,
3183 EL_SP_GRAVITY_ON_PORT_DOWN,
3184 EL_SP_GRAVITY_OFF_PORT_LEFT,
3185 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3186 EL_SP_GRAVITY_OFF_PORT_UP,
3187 EL_SP_GRAVITY_OFF_PORT_DOWN,
3192 static int ep_passable_under[] =
3197 static int ep_droppable[] =
3202 static int ep_explodes_1x1_old[] =
3207 static int ep_pushable[] =
3219 EL_SOKOBAN_FIELD_FULL,
3228 static int ep_explodes_cross_old[] =
3233 static int ep_protected[] =
3235 // same elements as in 'ep_walkable_inside'
3239 EL_TUBE_VERTICAL_LEFT,
3240 EL_TUBE_VERTICAL_RIGHT,
3241 EL_TUBE_HORIZONTAL_UP,
3242 EL_TUBE_HORIZONTAL_DOWN,
3248 // same elements as in 'ep_passable_over'
3257 EL_EM_GATE_1_GRAY_ACTIVE,
3258 EL_EM_GATE_2_GRAY_ACTIVE,
3259 EL_EM_GATE_3_GRAY_ACTIVE,
3260 EL_EM_GATE_4_GRAY_ACTIVE,
3269 EL_EMC_GATE_5_GRAY_ACTIVE,
3270 EL_EMC_GATE_6_GRAY_ACTIVE,
3271 EL_EMC_GATE_7_GRAY_ACTIVE,
3272 EL_EMC_GATE_8_GRAY_ACTIVE,
3274 EL_DC_GATE_WHITE_GRAY,
3275 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3279 // same elements as in 'ep_passable_inside'
3284 EL_SP_PORT_HORIZONTAL,
3285 EL_SP_PORT_VERTICAL,
3287 EL_SP_GRAVITY_PORT_LEFT,
3288 EL_SP_GRAVITY_PORT_RIGHT,
3289 EL_SP_GRAVITY_PORT_UP,
3290 EL_SP_GRAVITY_PORT_DOWN,
3291 EL_SP_GRAVITY_ON_PORT_LEFT,
3292 EL_SP_GRAVITY_ON_PORT_RIGHT,
3293 EL_SP_GRAVITY_ON_PORT_UP,
3294 EL_SP_GRAVITY_ON_PORT_DOWN,
3295 EL_SP_GRAVITY_OFF_PORT_LEFT,
3296 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3297 EL_SP_GRAVITY_OFF_PORT_UP,
3298 EL_SP_GRAVITY_OFF_PORT_DOWN,
3303 static int ep_throwable[] =
3308 static int ep_can_explode[] =
3310 // same elements as in 'ep_explodes_impact'
3315 // same elements as in 'ep_explodes_smashed'
3321 // elements that can explode by explosion or by dragonfire
3325 EL_EM_DYNAMITE_ACTIVE,
3326 EL_DYNABOMB_PLAYER_1_ACTIVE,
3327 EL_DYNABOMB_PLAYER_2_ACTIVE,
3328 EL_DYNABOMB_PLAYER_3_ACTIVE,
3329 EL_DYNABOMB_PLAYER_4_ACTIVE,
3330 EL_DYNABOMB_INCREASE_NUMBER,
3331 EL_DYNABOMB_INCREASE_SIZE,
3332 EL_DYNABOMB_INCREASE_POWER,
3333 EL_SP_DISK_RED_ACTIVE,
3341 // elements that can explode only by explosion
3347 static int ep_gravity_reachable[] =
3353 EL_INVISIBLE_SAND_ACTIVE,
3358 EL_SP_PORT_HORIZONTAL,
3359 EL_SP_PORT_VERTICAL,
3361 EL_SP_GRAVITY_PORT_LEFT,
3362 EL_SP_GRAVITY_PORT_RIGHT,
3363 EL_SP_GRAVITY_PORT_UP,
3364 EL_SP_GRAVITY_PORT_DOWN,
3365 EL_SP_GRAVITY_ON_PORT_LEFT,
3366 EL_SP_GRAVITY_ON_PORT_RIGHT,
3367 EL_SP_GRAVITY_ON_PORT_UP,
3368 EL_SP_GRAVITY_ON_PORT_DOWN,
3369 EL_SP_GRAVITY_OFF_PORT_LEFT,
3370 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3371 EL_SP_GRAVITY_OFF_PORT_UP,
3372 EL_SP_GRAVITY_OFF_PORT_DOWN,
3378 static int ep_empty_space[] =
3401 static int ep_player[] =
3408 EL_SOKOBAN_FIELD_PLAYER,
3414 static int ep_can_pass_magic_wall[] =
3428 static int ep_can_pass_dc_magic_wall[] =
3444 static int ep_switchable[] =
3448 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3449 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3450 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3451 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3452 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3453 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3454 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3455 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3456 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3457 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3458 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3459 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3460 EL_SWITCHGATE_SWITCH_UP,
3461 EL_SWITCHGATE_SWITCH_DOWN,
3462 EL_DC_SWITCHGATE_SWITCH_UP,
3463 EL_DC_SWITCHGATE_SWITCH_DOWN,
3465 EL_LIGHT_SWITCH_ACTIVE,
3467 EL_DC_TIMEGATE_SWITCH,
3468 EL_BALLOON_SWITCH_LEFT,
3469 EL_BALLOON_SWITCH_RIGHT,
3470 EL_BALLOON_SWITCH_UP,
3471 EL_BALLOON_SWITCH_DOWN,
3472 EL_BALLOON_SWITCH_ANY,
3473 EL_BALLOON_SWITCH_NONE,
3476 EL_EMC_MAGIC_BALL_SWITCH,
3477 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3482 static int ep_bd_element[] =
3516 static int ep_sp_element[] =
3518 // should always be valid
3521 // standard classic Supaplex elements
3528 EL_SP_HARDWARE_GRAY,
3536 EL_SP_GRAVITY_PORT_RIGHT,
3537 EL_SP_GRAVITY_PORT_DOWN,
3538 EL_SP_GRAVITY_PORT_LEFT,
3539 EL_SP_GRAVITY_PORT_UP,
3544 EL_SP_PORT_VERTICAL,
3545 EL_SP_PORT_HORIZONTAL,
3551 EL_SP_HARDWARE_BASE_1,
3552 EL_SP_HARDWARE_GREEN,
3553 EL_SP_HARDWARE_BLUE,
3555 EL_SP_HARDWARE_YELLOW,
3556 EL_SP_HARDWARE_BASE_2,
3557 EL_SP_HARDWARE_BASE_3,
3558 EL_SP_HARDWARE_BASE_4,
3559 EL_SP_HARDWARE_BASE_5,
3560 EL_SP_HARDWARE_BASE_6,
3564 // additional elements that appeared in newer Supaplex levels
3567 // additional gravity port elements (not switching, but setting gravity)
3568 EL_SP_GRAVITY_ON_PORT_LEFT,
3569 EL_SP_GRAVITY_ON_PORT_RIGHT,
3570 EL_SP_GRAVITY_ON_PORT_UP,
3571 EL_SP_GRAVITY_ON_PORT_DOWN,
3572 EL_SP_GRAVITY_OFF_PORT_LEFT,
3573 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3574 EL_SP_GRAVITY_OFF_PORT_UP,
3575 EL_SP_GRAVITY_OFF_PORT_DOWN,
3577 // more than one Murphy in a level results in an inactive clone
3580 // runtime Supaplex elements
3581 EL_SP_DISK_RED_ACTIVE,
3582 EL_SP_TERMINAL_ACTIVE,
3583 EL_SP_BUGGY_BASE_ACTIVATING,
3584 EL_SP_BUGGY_BASE_ACTIVE,
3591 static int ep_sb_element[] =
3596 EL_SOKOBAN_FIELD_EMPTY,
3597 EL_SOKOBAN_FIELD_FULL,
3598 EL_SOKOBAN_FIELD_PLAYER,
3603 EL_INVISIBLE_STEELWALL,
3608 static int ep_gem[] =
3620 static int ep_food_dark_yamyam[] =
3648 static int ep_food_penguin[] =
3662 static int ep_food_pig[] =
3674 static int ep_historic_wall[] =
3685 EL_GATE_1_GRAY_ACTIVE,
3686 EL_GATE_2_GRAY_ACTIVE,
3687 EL_GATE_3_GRAY_ACTIVE,
3688 EL_GATE_4_GRAY_ACTIVE,
3697 EL_EM_GATE_1_GRAY_ACTIVE,
3698 EL_EM_GATE_2_GRAY_ACTIVE,
3699 EL_EM_GATE_3_GRAY_ACTIVE,
3700 EL_EM_GATE_4_GRAY_ACTIVE,
3707 EL_EXPANDABLE_WALL_HORIZONTAL,
3708 EL_EXPANDABLE_WALL_VERTICAL,
3709 EL_EXPANDABLE_WALL_ANY,
3710 EL_EXPANDABLE_WALL_GROWING,
3711 EL_BD_EXPANDABLE_WALL,
3718 EL_SP_HARDWARE_GRAY,
3719 EL_SP_HARDWARE_GREEN,
3720 EL_SP_HARDWARE_BLUE,
3722 EL_SP_HARDWARE_YELLOW,
3723 EL_SP_HARDWARE_BASE_1,
3724 EL_SP_HARDWARE_BASE_2,
3725 EL_SP_HARDWARE_BASE_3,
3726 EL_SP_HARDWARE_BASE_4,
3727 EL_SP_HARDWARE_BASE_5,
3728 EL_SP_HARDWARE_BASE_6,
3730 EL_SP_TERMINAL_ACTIVE,
3733 EL_INVISIBLE_STEELWALL,
3734 EL_INVISIBLE_STEELWALL_ACTIVE,
3736 EL_INVISIBLE_WALL_ACTIVE,
3737 EL_STEELWALL_SLIPPERY,
3754 static int ep_historic_solid[] =
3758 EL_EXPANDABLE_WALL_HORIZONTAL,
3759 EL_EXPANDABLE_WALL_VERTICAL,
3760 EL_EXPANDABLE_WALL_ANY,
3761 EL_BD_EXPANDABLE_WALL,
3774 EL_QUICKSAND_FILLING,
3775 EL_QUICKSAND_EMPTYING,
3777 EL_MAGIC_WALL_ACTIVE,
3778 EL_MAGIC_WALL_EMPTYING,
3779 EL_MAGIC_WALL_FILLING,
3783 EL_BD_MAGIC_WALL_ACTIVE,
3784 EL_BD_MAGIC_WALL_EMPTYING,
3785 EL_BD_MAGIC_WALL_FULL,
3786 EL_BD_MAGIC_WALL_FILLING,
3787 EL_BD_MAGIC_WALL_DEAD,
3796 EL_SP_TERMINAL_ACTIVE,
3800 EL_INVISIBLE_WALL_ACTIVE,
3801 EL_SWITCHGATE_SWITCH_UP,
3802 EL_SWITCHGATE_SWITCH_DOWN,
3804 EL_TIMEGATE_SWITCH_ACTIVE,
3816 // the following elements are a direct copy of "indestructible" elements,
3817 // except "EL_ACID", which is "indestructible", but not "solid"!
3822 EL_ACID_POOL_TOPLEFT,
3823 EL_ACID_POOL_TOPRIGHT,
3824 EL_ACID_POOL_BOTTOMLEFT,
3825 EL_ACID_POOL_BOTTOM,
3826 EL_ACID_POOL_BOTTOMRIGHT,
3827 EL_SP_HARDWARE_GRAY,
3828 EL_SP_HARDWARE_GREEN,
3829 EL_SP_HARDWARE_BLUE,
3831 EL_SP_HARDWARE_YELLOW,
3832 EL_SP_HARDWARE_BASE_1,
3833 EL_SP_HARDWARE_BASE_2,
3834 EL_SP_HARDWARE_BASE_3,
3835 EL_SP_HARDWARE_BASE_4,
3836 EL_SP_HARDWARE_BASE_5,
3837 EL_SP_HARDWARE_BASE_6,
3838 EL_INVISIBLE_STEELWALL,
3839 EL_INVISIBLE_STEELWALL_ACTIVE,
3840 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3841 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3842 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3843 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3844 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3845 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3846 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3847 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3848 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3849 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3850 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3851 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3853 EL_LIGHT_SWITCH_ACTIVE,
3854 EL_SIGN_EXCLAMATION,
3855 EL_SIGN_RADIOACTIVITY,
3862 EL_SIGN_ENTRY_FORBIDDEN,
3863 EL_SIGN_EMERGENCY_EXIT,
3871 EL_STEEL_EXIT_CLOSED,
3873 EL_STEEL_EXIT_OPENING,
3874 EL_STEEL_EXIT_CLOSING,
3875 EL_EM_STEEL_EXIT_CLOSED,
3876 EL_EM_STEEL_EXIT_OPEN,
3877 EL_EM_STEEL_EXIT_OPENING,
3878 EL_EM_STEEL_EXIT_CLOSING,
3879 EL_DC_STEELWALL_1_LEFT,
3880 EL_DC_STEELWALL_1_RIGHT,
3881 EL_DC_STEELWALL_1_TOP,
3882 EL_DC_STEELWALL_1_BOTTOM,
3883 EL_DC_STEELWALL_1_HORIZONTAL,
3884 EL_DC_STEELWALL_1_VERTICAL,
3885 EL_DC_STEELWALL_1_TOPLEFT,
3886 EL_DC_STEELWALL_1_TOPRIGHT,
3887 EL_DC_STEELWALL_1_BOTTOMLEFT,
3888 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3889 EL_DC_STEELWALL_1_TOPLEFT_2,
3890 EL_DC_STEELWALL_1_TOPRIGHT_2,
3891 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3892 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3893 EL_DC_STEELWALL_2_LEFT,
3894 EL_DC_STEELWALL_2_RIGHT,
3895 EL_DC_STEELWALL_2_TOP,
3896 EL_DC_STEELWALL_2_BOTTOM,
3897 EL_DC_STEELWALL_2_HORIZONTAL,
3898 EL_DC_STEELWALL_2_VERTICAL,
3899 EL_DC_STEELWALL_2_MIDDLE,
3900 EL_DC_STEELWALL_2_SINGLE,
3901 EL_STEELWALL_SLIPPERY,
3915 EL_GATE_1_GRAY_ACTIVE,
3916 EL_GATE_2_GRAY_ACTIVE,
3917 EL_GATE_3_GRAY_ACTIVE,
3918 EL_GATE_4_GRAY_ACTIVE,
3927 EL_EM_GATE_1_GRAY_ACTIVE,
3928 EL_EM_GATE_2_GRAY_ACTIVE,
3929 EL_EM_GATE_3_GRAY_ACTIVE,
3930 EL_EM_GATE_4_GRAY_ACTIVE,
3939 EL_EMC_GATE_5_GRAY_ACTIVE,
3940 EL_EMC_GATE_6_GRAY_ACTIVE,
3941 EL_EMC_GATE_7_GRAY_ACTIVE,
3942 EL_EMC_GATE_8_GRAY_ACTIVE,
3944 EL_DC_GATE_WHITE_GRAY,
3945 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3946 EL_DC_GATE_FAKE_GRAY,
3948 EL_SWITCHGATE_OPENING,
3949 EL_SWITCHGATE_CLOSED,
3950 EL_SWITCHGATE_CLOSING,
3951 EL_DC_SWITCHGATE_SWITCH_UP,
3952 EL_DC_SWITCHGATE_SWITCH_DOWN,
3954 EL_TIMEGATE_OPENING,
3956 EL_TIMEGATE_CLOSING,
3957 EL_DC_TIMEGATE_SWITCH,
3958 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3962 EL_TUBE_VERTICAL_LEFT,
3963 EL_TUBE_VERTICAL_RIGHT,
3964 EL_TUBE_HORIZONTAL_UP,
3965 EL_TUBE_HORIZONTAL_DOWN,
3970 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3971 EL_EXPANDABLE_STEELWALL_VERTICAL,
3972 EL_EXPANDABLE_STEELWALL_ANY,
3977 static int ep_classic_enemy[] =
3994 static int ep_belt[] =
3996 EL_CONVEYOR_BELT_1_LEFT,
3997 EL_CONVEYOR_BELT_1_MIDDLE,
3998 EL_CONVEYOR_BELT_1_RIGHT,
3999 EL_CONVEYOR_BELT_2_LEFT,
4000 EL_CONVEYOR_BELT_2_MIDDLE,
4001 EL_CONVEYOR_BELT_2_RIGHT,
4002 EL_CONVEYOR_BELT_3_LEFT,
4003 EL_CONVEYOR_BELT_3_MIDDLE,
4004 EL_CONVEYOR_BELT_3_RIGHT,
4005 EL_CONVEYOR_BELT_4_LEFT,
4006 EL_CONVEYOR_BELT_4_MIDDLE,
4007 EL_CONVEYOR_BELT_4_RIGHT,
4012 static int ep_belt_active[] =
4014 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4015 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4016 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4017 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4018 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4019 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4020 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4021 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4022 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4023 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4024 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4025 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4030 static int ep_belt_switch[] =
4032 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4033 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4034 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4035 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4036 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4037 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4038 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4039 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4040 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4041 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4042 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4043 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4048 static int ep_tube[] =
4055 EL_TUBE_HORIZONTAL_UP,
4056 EL_TUBE_HORIZONTAL_DOWN,
4058 EL_TUBE_VERTICAL_LEFT,
4059 EL_TUBE_VERTICAL_RIGHT,
4065 static int ep_acid_pool[] =
4067 EL_ACID_POOL_TOPLEFT,
4068 EL_ACID_POOL_TOPRIGHT,
4069 EL_ACID_POOL_BOTTOMLEFT,
4070 EL_ACID_POOL_BOTTOM,
4071 EL_ACID_POOL_BOTTOMRIGHT,
4076 static int ep_keygate[] =
4086 EL_GATE_1_GRAY_ACTIVE,
4087 EL_GATE_2_GRAY_ACTIVE,
4088 EL_GATE_3_GRAY_ACTIVE,
4089 EL_GATE_4_GRAY_ACTIVE,
4098 EL_EM_GATE_1_GRAY_ACTIVE,
4099 EL_EM_GATE_2_GRAY_ACTIVE,
4100 EL_EM_GATE_3_GRAY_ACTIVE,
4101 EL_EM_GATE_4_GRAY_ACTIVE,
4110 EL_EMC_GATE_5_GRAY_ACTIVE,
4111 EL_EMC_GATE_6_GRAY_ACTIVE,
4112 EL_EMC_GATE_7_GRAY_ACTIVE,
4113 EL_EMC_GATE_8_GRAY_ACTIVE,
4115 EL_DC_GATE_WHITE_GRAY,
4116 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4121 static int ep_amoeboid[] =
4133 static int ep_amoebalive[] =
4144 static int ep_has_editor_content[] =
4150 EL_SOKOBAN_FIELD_PLAYER,
4167 static int ep_can_turn_each_move[] =
4169 // !!! do something with this one !!!
4173 static int ep_can_grow[] =
4187 static int ep_active_bomb[] =
4190 EL_EM_DYNAMITE_ACTIVE,
4191 EL_DYNABOMB_PLAYER_1_ACTIVE,
4192 EL_DYNABOMB_PLAYER_2_ACTIVE,
4193 EL_DYNABOMB_PLAYER_3_ACTIVE,
4194 EL_DYNABOMB_PLAYER_4_ACTIVE,
4195 EL_SP_DISK_RED_ACTIVE,
4200 static int ep_inactive[] =
4226 EL_QUICKSAND_FAST_EMPTY,
4249 EL_GATE_1_GRAY_ACTIVE,
4250 EL_GATE_2_GRAY_ACTIVE,
4251 EL_GATE_3_GRAY_ACTIVE,
4252 EL_GATE_4_GRAY_ACTIVE,
4261 EL_EM_GATE_1_GRAY_ACTIVE,
4262 EL_EM_GATE_2_GRAY_ACTIVE,
4263 EL_EM_GATE_3_GRAY_ACTIVE,
4264 EL_EM_GATE_4_GRAY_ACTIVE,
4273 EL_EMC_GATE_5_GRAY_ACTIVE,
4274 EL_EMC_GATE_6_GRAY_ACTIVE,
4275 EL_EMC_GATE_7_GRAY_ACTIVE,
4276 EL_EMC_GATE_8_GRAY_ACTIVE,
4278 EL_DC_GATE_WHITE_GRAY,
4279 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4280 EL_DC_GATE_FAKE_GRAY,
4283 EL_INVISIBLE_STEELWALL,
4291 EL_WALL_EMERALD_YELLOW,
4292 EL_DYNABOMB_INCREASE_NUMBER,
4293 EL_DYNABOMB_INCREASE_SIZE,
4294 EL_DYNABOMB_INCREASE_POWER,
4298 EL_SOKOBAN_FIELD_EMPTY,
4299 EL_SOKOBAN_FIELD_FULL,
4300 EL_WALL_EMERALD_RED,
4301 EL_WALL_EMERALD_PURPLE,
4302 EL_ACID_POOL_TOPLEFT,
4303 EL_ACID_POOL_TOPRIGHT,
4304 EL_ACID_POOL_BOTTOMLEFT,
4305 EL_ACID_POOL_BOTTOM,
4306 EL_ACID_POOL_BOTTOMRIGHT,
4310 EL_BD_MAGIC_WALL_DEAD,
4312 EL_DC_MAGIC_WALL_DEAD,
4313 EL_AMOEBA_TO_DIAMOND,
4321 EL_SP_GRAVITY_PORT_RIGHT,
4322 EL_SP_GRAVITY_PORT_DOWN,
4323 EL_SP_GRAVITY_PORT_LEFT,
4324 EL_SP_GRAVITY_PORT_UP,
4325 EL_SP_PORT_HORIZONTAL,
4326 EL_SP_PORT_VERTICAL,
4337 EL_SP_HARDWARE_GRAY,
4338 EL_SP_HARDWARE_GREEN,
4339 EL_SP_HARDWARE_BLUE,
4341 EL_SP_HARDWARE_YELLOW,
4342 EL_SP_HARDWARE_BASE_1,
4343 EL_SP_HARDWARE_BASE_2,
4344 EL_SP_HARDWARE_BASE_3,
4345 EL_SP_HARDWARE_BASE_4,
4346 EL_SP_HARDWARE_BASE_5,
4347 EL_SP_HARDWARE_BASE_6,
4348 EL_SP_GRAVITY_ON_PORT_LEFT,
4349 EL_SP_GRAVITY_ON_PORT_RIGHT,
4350 EL_SP_GRAVITY_ON_PORT_UP,
4351 EL_SP_GRAVITY_ON_PORT_DOWN,
4352 EL_SP_GRAVITY_OFF_PORT_LEFT,
4353 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4354 EL_SP_GRAVITY_OFF_PORT_UP,
4355 EL_SP_GRAVITY_OFF_PORT_DOWN,
4356 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4357 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4358 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4359 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4360 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4361 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4362 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4363 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4364 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4365 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4366 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4367 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4368 EL_SIGN_EXCLAMATION,
4369 EL_SIGN_RADIOACTIVITY,
4376 EL_SIGN_ENTRY_FORBIDDEN,
4377 EL_SIGN_EMERGENCY_EXIT,
4385 EL_DC_STEELWALL_1_LEFT,
4386 EL_DC_STEELWALL_1_RIGHT,
4387 EL_DC_STEELWALL_1_TOP,
4388 EL_DC_STEELWALL_1_BOTTOM,
4389 EL_DC_STEELWALL_1_HORIZONTAL,
4390 EL_DC_STEELWALL_1_VERTICAL,
4391 EL_DC_STEELWALL_1_TOPLEFT,
4392 EL_DC_STEELWALL_1_TOPRIGHT,
4393 EL_DC_STEELWALL_1_BOTTOMLEFT,
4394 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4395 EL_DC_STEELWALL_1_TOPLEFT_2,
4396 EL_DC_STEELWALL_1_TOPRIGHT_2,
4397 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4398 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4399 EL_DC_STEELWALL_2_LEFT,
4400 EL_DC_STEELWALL_2_RIGHT,
4401 EL_DC_STEELWALL_2_TOP,
4402 EL_DC_STEELWALL_2_BOTTOM,
4403 EL_DC_STEELWALL_2_HORIZONTAL,
4404 EL_DC_STEELWALL_2_VERTICAL,
4405 EL_DC_STEELWALL_2_MIDDLE,
4406 EL_DC_STEELWALL_2_SINGLE,
4407 EL_STEELWALL_SLIPPERY,
4412 EL_EMC_WALL_SLIPPERY_1,
4413 EL_EMC_WALL_SLIPPERY_2,
4414 EL_EMC_WALL_SLIPPERY_3,
4415 EL_EMC_WALL_SLIPPERY_4,
4436 static int ep_em_slippery_wall[] =
4441 static int ep_gfx_crumbled[] =
4452 static int ep_editor_cascade_active[] =
4454 EL_INTERNAL_CASCADE_BD_ACTIVE,
4455 EL_INTERNAL_CASCADE_EM_ACTIVE,
4456 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4457 EL_INTERNAL_CASCADE_RND_ACTIVE,
4458 EL_INTERNAL_CASCADE_SB_ACTIVE,
4459 EL_INTERNAL_CASCADE_SP_ACTIVE,
4460 EL_INTERNAL_CASCADE_DC_ACTIVE,
4461 EL_INTERNAL_CASCADE_DX_ACTIVE,
4462 EL_INTERNAL_CASCADE_MM_ACTIVE,
4463 EL_INTERNAL_CASCADE_DF_ACTIVE,
4464 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4465 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4466 EL_INTERNAL_CASCADE_CE_ACTIVE,
4467 EL_INTERNAL_CASCADE_GE_ACTIVE,
4468 EL_INTERNAL_CASCADE_ES_ACTIVE,
4469 EL_INTERNAL_CASCADE_REF_ACTIVE,
4470 EL_INTERNAL_CASCADE_USER_ACTIVE,
4471 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4476 static int ep_editor_cascade_inactive[] =
4478 EL_INTERNAL_CASCADE_BD,
4479 EL_INTERNAL_CASCADE_EM,
4480 EL_INTERNAL_CASCADE_EMC,
4481 EL_INTERNAL_CASCADE_RND,
4482 EL_INTERNAL_CASCADE_SB,
4483 EL_INTERNAL_CASCADE_SP,
4484 EL_INTERNAL_CASCADE_DC,
4485 EL_INTERNAL_CASCADE_DX,
4486 EL_INTERNAL_CASCADE_MM,
4487 EL_INTERNAL_CASCADE_DF,
4488 EL_INTERNAL_CASCADE_CHARS,
4489 EL_INTERNAL_CASCADE_STEEL_CHARS,
4490 EL_INTERNAL_CASCADE_CE,
4491 EL_INTERNAL_CASCADE_GE,
4492 EL_INTERNAL_CASCADE_ES,
4493 EL_INTERNAL_CASCADE_REF,
4494 EL_INTERNAL_CASCADE_USER,
4495 EL_INTERNAL_CASCADE_DYNAMIC,
4500 static int ep_obsolete[] =
4504 EL_EM_KEY_1_FILE_OBSOLETE,
4505 EL_EM_KEY_2_FILE_OBSOLETE,
4506 EL_EM_KEY_3_FILE_OBSOLETE,
4507 EL_EM_KEY_4_FILE_OBSOLETE,
4508 EL_ENVELOPE_OBSOLETE,
4517 } element_properties[] =
4519 { ep_diggable, EP_DIGGABLE },
4520 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4521 { ep_dont_run_into, EP_DONT_RUN_INTO },
4522 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4523 { ep_dont_touch, EP_DONT_TOUCH },
4524 { ep_indestructible, EP_INDESTRUCTIBLE },
4525 { ep_slippery, EP_SLIPPERY },
4526 { ep_can_change, EP_CAN_CHANGE },
4527 { ep_can_move, EP_CAN_MOVE },
4528 { ep_can_fall, EP_CAN_FALL },
4529 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4530 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4531 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4532 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4533 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4534 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4535 { ep_walkable_over, EP_WALKABLE_OVER },
4536 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4537 { ep_walkable_under, EP_WALKABLE_UNDER },
4538 { ep_passable_over, EP_PASSABLE_OVER },
4539 { ep_passable_inside, EP_PASSABLE_INSIDE },
4540 { ep_passable_under, EP_PASSABLE_UNDER },
4541 { ep_droppable, EP_DROPPABLE },
4542 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4543 { ep_pushable, EP_PUSHABLE },
4544 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4545 { ep_protected, EP_PROTECTED },
4546 { ep_throwable, EP_THROWABLE },
4547 { ep_can_explode, EP_CAN_EXPLODE },
4548 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4550 { ep_empty_space, EP_EMPTY_SPACE },
4551 { ep_player, EP_PLAYER },
4552 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4553 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4554 { ep_switchable, EP_SWITCHABLE },
4555 { ep_bd_element, EP_BD_ELEMENT },
4556 { ep_sp_element, EP_SP_ELEMENT },
4557 { ep_sb_element, EP_SB_ELEMENT },
4559 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4560 { ep_food_penguin, EP_FOOD_PENGUIN },
4561 { ep_food_pig, EP_FOOD_PIG },
4562 { ep_historic_wall, EP_HISTORIC_WALL },
4563 { ep_historic_solid, EP_HISTORIC_SOLID },
4564 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4565 { ep_belt, EP_BELT },
4566 { ep_belt_active, EP_BELT_ACTIVE },
4567 { ep_belt_switch, EP_BELT_SWITCH },
4568 { ep_tube, EP_TUBE },
4569 { ep_acid_pool, EP_ACID_POOL },
4570 { ep_keygate, EP_KEYGATE },
4571 { ep_amoeboid, EP_AMOEBOID },
4572 { ep_amoebalive, EP_AMOEBALIVE },
4573 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4574 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4575 { ep_can_grow, EP_CAN_GROW },
4576 { ep_active_bomb, EP_ACTIVE_BOMB },
4577 { ep_inactive, EP_INACTIVE },
4579 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4581 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4583 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4584 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4586 { ep_obsolete, EP_OBSOLETE },
4593 // always start with reliable default values (element has no properties)
4594 // (but never initialize clipboard elements after the very first time)
4595 // (to be able to use clipboard elements between several levels)
4596 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4597 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4598 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4599 SET_PROPERTY(i, j, FALSE);
4601 // set all base element properties from above array definitions
4602 for (i = 0; element_properties[i].elements != NULL; i++)
4603 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4604 SET_PROPERTY((element_properties[i].elements)[j],
4605 element_properties[i].property, TRUE);
4607 // copy properties to some elements that are only stored in level file
4608 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4609 for (j = 0; copy_properties[j][0] != -1; j++)
4610 if (HAS_PROPERTY(copy_properties[j][0], i))
4611 for (k = 1; k <= 4; k++)
4612 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4614 // set static element properties that are not listed in array definitions
4615 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4616 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4618 clipboard_elements_initialized = TRUE;
4621 void InitElementPropertiesEngine(int engine_version)
4623 static int no_wall_properties[] =
4626 EP_COLLECTIBLE_ONLY,
4628 EP_DONT_COLLIDE_WITH,
4631 EP_CAN_SMASH_PLAYER,
4632 EP_CAN_SMASH_ENEMIES,
4633 EP_CAN_SMASH_EVERYTHING,
4638 EP_FOOD_DARK_YAMYAM,
4654 /* important: after initialization in InitElementPropertiesStatic(), the
4655 elements are not again initialized to a default value; therefore all
4656 changes have to make sure that they leave the element with a defined
4657 property (which means that conditional property changes must be set to
4658 a reliable default value before) */
4660 // resolve group elements
4661 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4662 ResolveGroupElement(EL_GROUP_START + i);
4664 // set all special, combined or engine dependent element properties
4665 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4667 // do not change (already initialized) clipboard elements here
4668 if (IS_CLIPBOARD_ELEMENT(i))
4671 // ---------- INACTIVE ----------------------------------------------------
4672 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4673 i <= EL_CHAR_END) ||
4674 (i >= EL_STEEL_CHAR_START &&
4675 i <= EL_STEEL_CHAR_END)));
4677 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4678 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4679 IS_WALKABLE_INSIDE(i) ||
4680 IS_WALKABLE_UNDER(i)));
4682 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4683 IS_PASSABLE_INSIDE(i) ||
4684 IS_PASSABLE_UNDER(i)));
4686 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4687 IS_PASSABLE_OVER(i)));
4689 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4690 IS_PASSABLE_INSIDE(i)));
4692 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4693 IS_PASSABLE_UNDER(i)));
4695 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4698 // ---------- COLLECTIBLE -------------------------------------------------
4699 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4703 // ---------- SNAPPABLE ---------------------------------------------------
4704 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4705 IS_COLLECTIBLE(i) ||
4709 // ---------- WALL --------------------------------------------------------
4710 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4712 for (j = 0; no_wall_properties[j] != -1; j++)
4713 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4714 i >= EL_FIRST_RUNTIME_UNREAL)
4715 SET_PROPERTY(i, EP_WALL, FALSE);
4717 if (IS_HISTORIC_WALL(i))
4718 SET_PROPERTY(i, EP_WALL, TRUE);
4720 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4721 if (engine_version < VERSION_IDENT(2,2,0,0))
4722 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4724 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4726 !IS_COLLECTIBLE(i)));
4728 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4729 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4730 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4732 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4735 // ---------- EXPLOSION_PROOF ---------------------------------------------
4737 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4738 else if (engine_version < VERSION_IDENT(2,2,0,0))
4739 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4741 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4745 if (IS_CUSTOM_ELEMENT(i))
4747 // these are additional properties which are initially false when set
4749 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4751 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4752 if (DONT_COLLIDE_WITH(i))
4753 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4755 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4756 if (CAN_SMASH_EVERYTHING(i))
4757 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4758 if (CAN_SMASH_ENEMIES(i))
4759 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4762 // ---------- CAN_SMASH ---------------------------------------------------
4763 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4764 CAN_SMASH_ENEMIES(i) ||
4765 CAN_SMASH_EVERYTHING(i)));
4767 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4768 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4769 EXPLODES_BY_FIRE(i)));
4771 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4772 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4773 EXPLODES_SMASHED(i)));
4775 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4776 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4777 EXPLODES_IMPACT(i)));
4779 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4780 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4782 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4783 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4784 i == EL_BLACK_ORB));
4786 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4787 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4789 IS_CUSTOM_ELEMENT(i)));
4791 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4792 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4793 i == EL_SP_ELECTRON));
4795 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4796 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4797 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4798 getMoveIntoAcidProperty(&level, i));
4800 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4801 if (MAYBE_DONT_COLLIDE_WITH(i))
4802 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4803 getDontCollideWithProperty(&level, i));
4805 // ---------- SP_PORT -----------------------------------------------------
4806 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4807 IS_PASSABLE_INSIDE(i)));
4809 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4810 for (j = 0; j < level.num_android_clone_elements; j++)
4811 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4813 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4815 // ---------- CAN_CHANGE --------------------------------------------------
4816 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4817 for (j = 0; j < element_info[i].num_change_pages; j++)
4818 if (element_info[i].change_page[j].can_change)
4819 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4821 // ---------- HAS_ACTION --------------------------------------------------
4822 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4823 for (j = 0; j < element_info[i].num_change_pages; j++)
4824 if (element_info[i].change_page[j].has_action)
4825 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4827 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4828 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4831 // ---------- GFX_CRUMBLED ------------------------------------------------
4832 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4833 element_info[i].crumbled[ACTION_DEFAULT] !=
4834 element_info[i].graphic[ACTION_DEFAULT]);
4836 // ---------- EDITOR_CASCADE ----------------------------------------------
4837 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4838 IS_EDITOR_CASCADE_INACTIVE(i)));
4841 // dynamically adjust element properties according to game engine version
4843 static int ep_em_slippery_wall[] =
4848 EL_EXPANDABLE_WALL_HORIZONTAL,
4849 EL_EXPANDABLE_WALL_VERTICAL,
4850 EL_EXPANDABLE_WALL_ANY,
4851 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4852 EL_EXPANDABLE_STEELWALL_VERTICAL,
4853 EL_EXPANDABLE_STEELWALL_ANY,
4854 EL_EXPANDABLE_STEELWALL_GROWING,
4858 static int ep_em_explodes_by_fire[] =
4861 EL_EM_DYNAMITE_ACTIVE,
4866 // special EM style gems behaviour
4867 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4868 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4869 level.em_slippery_gems);
4871 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4872 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4873 (level.em_slippery_gems &&
4874 engine_version > VERSION_IDENT(2,0,1,0)));
4876 // special EM style explosion behaviour regarding chain reactions
4877 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4878 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4879 level.em_explodes_by_fire);
4882 // this is needed because some graphics depend on element properties
4883 if (game_status == GAME_MODE_PLAYING)
4884 InitElementGraphicInfo();
4887 void InitElementPropertiesGfxElement(void)
4891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4893 struct ElementInfo *ei = &element_info[i];
4895 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4899 static void InitGlobal(void)
4904 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4906 // check if element_name_info entry defined for each element in "main.h"
4907 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4908 Fail("undefined 'element_name_info' entry for element %d", i);
4910 element_info[i].token_name = element_name_info[i].token_name;
4911 element_info[i].class_name = element_name_info[i].class_name;
4912 element_info[i].editor_description= element_name_info[i].editor_description;
4915 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4917 // check if global_anim_name_info defined for each entry in "main.h"
4918 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4919 global_anim_name_info[i].token_name == NULL)
4920 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4922 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4925 // create hash to store URLs for global animations
4926 anim_url_hash = newSetupFileHash();
4928 // create hash from image config list
4929 image_config_hash = newSetupFileHash();
4930 for (i = 0; image_config[i].token != NULL; i++)
4931 setHashEntry(image_config_hash,
4932 image_config[i].token,
4933 image_config[i].value);
4935 // create hash from element token list
4936 element_token_hash = newSetupFileHash();
4937 for (i = 0; element_name_info[i].token_name != NULL; i++)
4938 setHashEntry(element_token_hash,
4939 element_name_info[i].token_name,
4942 // create hash from graphic token list
4943 graphic_token_hash = newSetupFileHash();
4944 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4945 if (strSuffix(image_config[i].value, ".png") ||
4946 strSuffix(image_config[i].value, ".pcx") ||
4947 strSuffix(image_config[i].value, ".wav") ||
4948 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4949 setHashEntry(graphic_token_hash,
4950 image_config[i].token,
4951 int2str(graphic++, 0));
4953 // create hash from font token list
4954 font_token_hash = newSetupFileHash();
4955 for (i = 0; font_info[i].token_name != NULL; i++)
4956 setHashEntry(font_token_hash,
4957 font_info[i].token_name,
4960 // set default filenames for all cloned graphics in static configuration
4961 for (i = 0; image_config[i].token != NULL; i++)
4963 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4965 char *token = image_config[i].token;
4966 char *token_clone_from = getStringCat2(token, ".clone_from");
4967 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4969 if (token_cloned != NULL)
4971 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4973 if (value_cloned != NULL)
4975 // set default filename in static configuration
4976 image_config[i].value = value_cloned;
4978 // set default filename in image config hash
4979 setHashEntry(image_config_hash, token, value_cloned);
4983 free(token_clone_from);
4987 // always start with reliable default values (all elements)
4988 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4989 ActiveElement[i] = i;
4991 // now add all entries that have an active state (active elements)
4992 for (i = 0; element_with_active_state[i].element != -1; i++)
4994 int element = element_with_active_state[i].element;
4995 int element_active = element_with_active_state[i].element_active;
4997 ActiveElement[element] = element_active;
5000 // always start with reliable default values (all buttons)
5001 for (i = 0; i < NUM_IMAGE_FILES; i++)
5002 ActiveButton[i] = i;
5004 // now add all entries that have an active state (active buttons)
5005 for (i = 0; button_with_active_state[i].button != -1; i++)
5007 int button = button_with_active_state[i].button;
5008 int button_active = button_with_active_state[i].button_active;
5010 ActiveButton[button] = button_active;
5013 // always start with reliable default values (all fonts)
5014 for (i = 0; i < NUM_FONTS; i++)
5017 // now add all entries that have an active state (active fonts)
5018 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5020 int font = font_with_active_state[i].font_nr;
5021 int font_active = font_with_active_state[i].font_nr_active;
5023 ActiveFont[font] = font_active;
5026 global.autoplay_leveldir = NULL;
5027 global.patchtapes_leveldir = NULL;
5028 global.convert_leveldir = NULL;
5029 global.dumplevel_leveldir = NULL;
5030 global.dumptape_leveldir = NULL;
5031 global.create_sketch_images_dir = NULL;
5032 global.create_collect_images_dir = NULL;
5034 global.frames_per_second = 0;
5035 global.show_frames_per_second = FALSE;
5037 global.border_status = GAME_MODE_LOADING;
5038 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5040 global.use_envelope_request = FALSE;
5042 global.user_names = NULL;
5045 static void Execute_Command(char *command)
5049 if (strEqual(command, "print graphicsinfo.conf"))
5051 Print("# You can configure additional/alternative image files here.\n");
5052 Print("# (The entries below are default and therefore commented out.)\n");
5054 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5056 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5059 for (i = 0; image_config[i].token != NULL; i++)
5060 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5061 image_config[i].value));
5065 else if (strEqual(command, "print soundsinfo.conf"))
5067 Print("# You can configure additional/alternative sound files here.\n");
5068 Print("# (The entries below are default and therefore commented out.)\n");
5070 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5072 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5075 for (i = 0; sound_config[i].token != NULL; i++)
5076 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5077 sound_config[i].value));
5081 else if (strEqual(command, "print musicinfo.conf"))
5083 Print("# You can configure additional/alternative music files here.\n");
5084 Print("# (The entries below are default and therefore commented out.)\n");
5086 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5088 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5091 for (i = 0; music_config[i].token != NULL; i++)
5092 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5093 music_config[i].value));
5097 else if (strEqual(command, "print editorsetup.conf"))
5099 Print("# You can configure your personal editor element list here.\n");
5100 Print("# (The entries below are default and therefore commented out.)\n");
5103 // this is needed to be able to check element list for cascade elements
5104 InitElementPropertiesStatic();
5105 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5107 PrintEditorElementList();
5111 else if (strEqual(command, "print helpanim.conf"))
5113 Print("# You can configure different element help animations here.\n");
5114 Print("# (The entries below are default and therefore commented out.)\n");
5117 for (i = 0; helpanim_config[i].token != NULL; i++)
5119 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5120 helpanim_config[i].value));
5122 if (strEqual(helpanim_config[i].token, "end"))
5128 else if (strEqual(command, "print helptext.conf"))
5130 Print("# You can configure different element help text here.\n");
5131 Print("# (The entries below are default and therefore commented out.)\n");
5134 for (i = 0; helptext_config[i].token != NULL; i++)
5135 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5136 helptext_config[i].value));
5140 else if (strPrefix(command, "dump level "))
5142 char *filename = &command[11];
5144 if (fileExists(filename))
5146 LoadLevelFromFilename(&level, filename);
5152 char *leveldir = getStringCopy(filename); // read command parameters
5153 char *level_nr = strchr(leveldir, ' ');
5155 if (level_nr == NULL)
5156 Fail("cannot open file '%s'", filename);
5160 global.dumplevel_leveldir = leveldir;
5161 global.dumplevel_level_nr = atoi(level_nr);
5163 program.headless = TRUE;
5165 else if (strPrefix(command, "dump tape "))
5167 char *filename = &command[10];
5169 if (fileExists(filename))
5171 LoadTapeFromFilename(filename);
5177 char *leveldir = getStringCopy(filename); // read command parameters
5178 char *level_nr = strchr(leveldir, ' ');
5180 if (level_nr == NULL)
5181 Fail("cannot open file '%s'", filename);
5185 global.dumptape_leveldir = leveldir;
5186 global.dumptape_level_nr = atoi(level_nr);
5188 program.headless = TRUE;
5190 else if (strPrefix(command, "autoplay ") ||
5191 strPrefix(command, "autoffwd ") ||
5192 strPrefix(command, "autowarp ") ||
5193 strPrefix(command, "autotest ") ||
5194 strPrefix(command, "autosave ") ||
5195 strPrefix(command, "autoupload ") ||
5196 strPrefix(command, "autofix "))
5198 char *arg_ptr = strchr(command, ' ');
5199 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5201 global.autoplay_mode =
5202 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5203 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5204 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5205 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5206 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5207 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5208 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5209 AUTOPLAY_MODE_NONE);
5211 while (*str_ptr != '\0') // continue parsing string
5213 // cut leading whitespace from string, replace it by string terminator
5214 while (*str_ptr == ' ' || *str_ptr == '\t')
5217 if (*str_ptr == '\0') // end of string reached
5220 if (global.autoplay_leveldir == NULL) // read level set string
5222 global.autoplay_leveldir = str_ptr;
5223 global.autoplay_all = TRUE; // default: play all tapes
5225 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5226 global.autoplay_level[i] = FALSE;
5228 else // read level number string
5230 int level_nr = atoi(str_ptr); // get level_nr value
5232 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5233 global.autoplay_level[level_nr] = TRUE;
5235 global.autoplay_all = FALSE;
5238 // advance string pointer to the next whitespace (or end of string)
5239 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5243 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5244 program.headless = TRUE;
5246 else if (strPrefix(command, "patch tapes "))
5248 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5250 // skip leading whitespace
5251 while (*str_ptr == ' ' || *str_ptr == '\t')
5254 if (*str_ptr == '\0')
5255 Fail("cannot find MODE in command '%s'", command);
5257 global.patchtapes_mode = str_ptr; // store patch mode
5259 // advance to next whitespace (or end of string)
5260 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5263 while (*str_ptr != '\0') // continue parsing string
5265 // cut leading whitespace from string, replace it by string terminator
5266 while (*str_ptr == ' ' || *str_ptr == '\t')
5269 if (*str_ptr == '\0') // end of string reached
5272 if (global.patchtapes_leveldir == NULL) // read level set string
5274 global.patchtapes_leveldir = str_ptr;
5275 global.patchtapes_all = TRUE; // default: patch all tapes
5277 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5278 global.patchtapes_level[i] = FALSE;
5280 else // read level number string
5282 int level_nr = atoi(str_ptr); // get level_nr value
5284 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5285 global.patchtapes_level[level_nr] = TRUE;
5287 global.patchtapes_all = FALSE;
5290 // advance string pointer to the next whitespace (or end of string)
5291 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5295 if (global.patchtapes_leveldir == NULL)
5297 if (strEqual(global.patchtapes_mode, "help"))
5298 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5300 Fail("cannot find LEVELDIR in command '%s'", command);
5303 program.headless = TRUE;
5305 else if (strPrefix(command, "convert "))
5307 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5308 char *str_ptr = strchr(str_copy, ' ');
5310 global.convert_leveldir = str_copy;
5311 global.convert_level_nr = -1;
5313 if (str_ptr != NULL) // level number follows
5315 *str_ptr++ = '\0'; // terminate leveldir string
5316 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5319 program.headless = TRUE;
5321 else if (strPrefix(command, "create sketch images "))
5323 global.create_sketch_images_dir = getStringCopy(&command[21]);
5325 if (access(global.create_sketch_images_dir, W_OK) != 0)
5326 Fail("image target directory '%s' not found or not writable",
5327 global.create_sketch_images_dir);
5329 else if (strPrefix(command, "create collect image "))
5331 global.create_collect_images_dir = getStringCopy(&command[21]);
5333 if (access(global.create_collect_images_dir, W_OK) != 0)
5334 Fail("image target directory '%s' not found or not writable",
5335 global.create_collect_images_dir);
5337 else if (strPrefix(command, "create CE image "))
5339 CreateCustomElementImages(&command[16]);
5345 FailWithHelp("unrecognized command '%s'", command);
5348 // disable networking if any valid command was recognized
5349 options.network = setup.network_mode = FALSE;
5352 static void InitSetup(void)
5354 LoadUserNames(); // global user names
5355 LoadUserSetup(); // global user number
5357 LoadSetup(); // global setup info
5359 // set some options from setup file
5361 if (setup.options.verbose)
5362 options.verbose = TRUE;
5364 if (setup.debug.show_frames_per_second)
5365 global.show_frames_per_second = TRUE;
5368 static void InitGameInfo(void)
5370 game.restart_level = FALSE;
5371 game.restart_game_message = NULL;
5373 game.request_active = FALSE;
5374 game.request_active_or_moving = FALSE;
5376 game.use_masked_elements_initial = FALSE;
5379 static void InitPlayerInfo(void)
5383 // choose default local player
5384 local_player = &stored_player[0];
5386 for (i = 0; i < MAX_PLAYERS; i++)
5388 stored_player[i].connected_locally = FALSE;
5389 stored_player[i].connected_network = FALSE;
5392 local_player->connected_locally = TRUE;
5395 static void InitArtworkInfo(void)
5400 static char *get_string_in_brackets(char *string)
5402 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5404 sprintf(string_in_brackets, "[%s]", string);
5406 return string_in_brackets;
5409 static char *get_level_id_suffix(int id_nr)
5411 char *id_suffix = checked_malloc(1 + 3 + 1);
5413 if (id_nr < 0 || id_nr > 999)
5416 sprintf(id_suffix, ".%03d", id_nr);
5421 static void InitArtworkConfig(void)
5423 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5425 NUM_GLOBAL_ANIM_TOKENS + 1];
5426 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5427 NUM_GLOBAL_ANIM_TOKENS + 1];
5428 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5429 NUM_GLOBAL_ANIM_TOKENS + 1];
5430 static char *action_id_suffix[NUM_ACTIONS + 1];
5431 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5432 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5433 static char *level_id_suffix[MAX_LEVELS + 1];
5434 static char *dummy[1] = { NULL };
5435 static char *ignore_generic_tokens[] =
5440 "program_copyright",
5445 static char **ignore_image_tokens;
5446 static char **ignore_sound_tokens;
5447 static char **ignore_music_tokens;
5448 int num_ignore_generic_tokens;
5449 int num_ignore_image_tokens;
5450 int num_ignore_sound_tokens;
5451 int num_ignore_music_tokens;
5454 // dynamically determine list of generic tokens to be ignored
5455 num_ignore_generic_tokens = 0;
5456 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5457 num_ignore_generic_tokens++;
5459 // dynamically determine list of image tokens to be ignored
5460 num_ignore_image_tokens = num_ignore_generic_tokens;
5461 for (i = 0; image_config_vars[i].token != NULL; i++)
5462 num_ignore_image_tokens++;
5463 ignore_image_tokens =
5464 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5465 for (i = 0; i < num_ignore_generic_tokens; i++)
5466 ignore_image_tokens[i] = ignore_generic_tokens[i];
5467 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5468 ignore_image_tokens[num_ignore_generic_tokens + i] =
5469 image_config_vars[i].token;
5470 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5472 // dynamically determine list of sound tokens to be ignored
5473 num_ignore_sound_tokens = num_ignore_generic_tokens;
5474 ignore_sound_tokens =
5475 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5476 for (i = 0; i < num_ignore_generic_tokens; i++)
5477 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5478 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5480 // dynamically determine list of music tokens to be ignored
5481 num_ignore_music_tokens = num_ignore_generic_tokens;
5482 ignore_music_tokens =
5483 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5484 for (i = 0; i < num_ignore_generic_tokens; i++)
5485 ignore_music_tokens[i] = ignore_generic_tokens[i];
5486 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5488 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5489 image_id_prefix[i] = element_info[i].token_name;
5490 for (i = 0; i < NUM_FONTS; i++)
5491 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5492 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5493 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5494 global_anim_info[i].token_name;
5495 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5497 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5498 sound_id_prefix[i] = element_info[i].token_name;
5499 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5500 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5501 get_string_in_brackets(element_info[i].class_name);
5502 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5503 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5504 global_anim_info[i].token_name;
5505 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5507 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5508 music_id_prefix[i] = music_prefix_info[i].prefix;
5509 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5510 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5511 global_anim_info[i].token_name;
5512 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5514 for (i = 0; i < NUM_ACTIONS; i++)
5515 action_id_suffix[i] = element_action_info[i].suffix;
5516 action_id_suffix[NUM_ACTIONS] = NULL;
5518 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5519 direction_id_suffix[i] = element_direction_info[i].suffix;
5520 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5522 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5523 special_id_suffix[i] = special_suffix_info[i].suffix;
5524 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5526 for (i = 0; i < MAX_LEVELS; i++)
5527 level_id_suffix[i] = get_level_id_suffix(i);
5528 level_id_suffix[MAX_LEVELS] = NULL;
5530 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5531 image_id_prefix, action_id_suffix, direction_id_suffix,
5532 special_id_suffix, ignore_image_tokens);
5533 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5534 sound_id_prefix, action_id_suffix, dummy,
5535 special_id_suffix, ignore_sound_tokens);
5536 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5537 music_id_prefix, action_id_suffix, special_id_suffix,
5538 level_id_suffix, ignore_music_tokens);
5541 static void InitMixer(void)
5548 static void InitVideoOverlay(void)
5550 // if virtual buttons are not loaded from setup file, repeat initializing
5551 // virtual buttons grid with default values now that video is initialized
5552 if (!setup.touch.grid_initialized)
5555 InitTileCursorInfo();
5559 void InitGfxBuffers(void)
5561 static int win_xsize_last = -1;
5562 static int win_ysize_last = -1;
5564 // create additional image buffers for double-buffering and cross-fading
5566 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5568 // used to temporarily store the backbuffer -- only re-create if changed
5569 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5570 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5572 win_xsize_last = WIN_XSIZE;
5573 win_ysize_last = WIN_YSIZE;
5576 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5577 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5578 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5579 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5581 // initialize screen properties
5582 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5583 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5585 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5586 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5587 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5588 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5589 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5590 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5592 // required if door size definitions have changed
5593 InitGraphicCompatibilityInfo_Doors();
5595 InitGfxBuffers_EM();
5596 InitGfxBuffers_SP();
5599 static void InitGfx(void)
5601 struct GraphicInfo *graphic_info_last = graphic_info;
5602 char *filename_font_initial = NULL;
5603 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5604 char *image_token[NUM_INITIAL_IMAGES] =
5606 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5607 CONFIG_TOKEN_GLOBAL_BUSY,
5608 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5609 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5610 CONFIG_TOKEN_BACKGROUND_LOADING
5612 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5616 &init.busy_playfield
5618 Bitmap *bitmap_font_initial = NULL;
5619 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5622 // determine settings for initial font (for displaying startup messages)
5623 for (i = 0; image_config[i].token != NULL; i++)
5625 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5627 char font_token[128];
5630 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5631 len_font_token = strlen(font_token);
5633 if (strEqual(image_config[i].token, font_token))
5635 filename_font_initial = image_config[i].value;
5637 else if (strlen(image_config[i].token) > len_font_token &&
5638 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5640 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5641 font_initial[j].src_x = atoi(image_config[i].value);
5642 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5643 font_initial[j].src_y = atoi(image_config[i].value);
5644 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5645 font_initial[j].width = atoi(image_config[i].value);
5646 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5647 font_initial[j].height = atoi(image_config[i].value);
5652 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5654 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5655 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5658 if (filename_font_initial == NULL) // should not happen
5659 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5662 InitGfxCustomArtworkInfo();
5663 InitGfxOtherSettings();
5665 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5667 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5669 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5670 font_initial[j].bitmap = bitmap_font_initial;
5672 InitFontGraphicInfo();
5676 DrawInitTextHead("Loading graphics");
5678 InitMenuDesignSettings_Static();
5680 // initialize settings for initial images with default values
5681 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5682 for (j = 0; j < NUM_GFX_ARGS; j++)
5684 get_graphic_parameter_value(image_config_suffix[j].value,
5685 image_config_suffix[j].token,
5686 image_config_suffix[j].type);
5688 // read settings for initial images from default custom artwork config
5689 char *gfx_config_filename = getPath3(options.graphics_directory,
5691 GRAPHICSINFO_FILENAME);
5693 if (fileExists(gfx_config_filename))
5695 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5697 if (setup_file_hash)
5699 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5701 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5705 filename_image_initial[i] = getStringCopy(filename);
5707 for (j = 0; image_config_suffix[j].token != NULL; j++)
5709 int type = image_config_suffix[j].type;
5710 char *suffix = image_config_suffix[j].token;
5711 char *token = getStringCat2(image_token[i], suffix);
5712 char *value = getHashEntry(setup_file_hash, token);
5714 checked_free(token);
5718 get_graphic_parameter_value(value, suffix, type);
5723 // read values from custom graphics config file
5724 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5726 freeSetupFileHash(setup_file_hash);
5730 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5732 if (filename_image_initial[i] == NULL)
5734 int len_token = strlen(image_token[i]);
5736 // read settings for initial images from static default artwork config
5737 for (j = 0; image_config[j].token != NULL; j++)
5739 if (strEqual(image_config[j].token, image_token[i]))
5741 filename_image_initial[i] = getStringCopy(image_config[j].value);
5743 else if (strlen(image_config[j].token) > len_token &&
5744 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5746 for (k = 0; image_config_suffix[k].token != NULL; k++)
5748 if (strEqual(&image_config[j].token[len_token],
5749 image_config_suffix[k].token))
5751 get_graphic_parameter_value(image_config[j].value,
5752 image_config_suffix[k].token,
5753 image_config_suffix[k].type);
5760 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5762 if (filename_image_initial[i] == NULL) // should not happen
5763 Fail("cannot get filename for '%s'", image_token[i]);
5765 image_initial[i].bitmaps =
5766 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5768 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5769 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5770 LoadCustomImage(filename_image_initial[i]);
5772 checked_free(filename_image_initial[i]);
5775 graphic_info = image_initial; // graphic == 0 => image_initial
5777 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5778 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5780 graphic_info = graphic_info_last;
5782 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5784 // set image size for busy animations
5785 init_busy[i]->width = image_initial[i].width;
5786 init_busy[i]->height = image_initial[i].height;
5789 SetLoadingBackgroundImage();
5791 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5793 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5794 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5795 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5796 InitGfxDrawTileCursorFunction(DrawTileCursor);
5798 gfx.fade_border_source_status = global.border_status;
5799 gfx.fade_border_target_status = global.border_status;
5800 gfx.masked_border_bitmap_ptr = backbuffer;
5802 // use copy of busy animation to prevent change while reloading artwork
5806 static void InitGfxBackground(void)
5808 fieldbuffer = bitmap_db_field;
5809 SetDrawtoField(DRAW_TO_BACKBUFFER);
5811 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5813 redraw_mask = REDRAW_ALL;
5816 static void InitLevelInfo(void)
5818 LoadLevelInfo(); // global level info
5819 LoadLevelSetup_LastSeries(); // last played series info
5820 LoadLevelSetup_SeriesInfo(); // last played level info
5822 if (global.autoplay_leveldir &&
5823 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5825 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5826 global.autoplay_leveldir);
5827 if (leveldir_current == NULL)
5828 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5831 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5834 static void InitLevelArtworkInfo(void)
5836 LoadLevelArtworkInfo();
5839 static void InitImages(void)
5841 print_timestamp_init("InitImages");
5844 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5845 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5846 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5847 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5848 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5849 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5850 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5851 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5854 setLevelArtworkDir(artwork.gfx_first);
5857 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5858 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5859 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5860 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5861 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5862 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5863 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5864 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5868 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5869 leveldir_current->identifier,
5870 artwork.gfx_current_identifier,
5871 artwork.gfx_current->identifier,
5872 leveldir_current->graphics_set,
5873 leveldir_current->graphics_path);
5876 UPDATE_BUSY_STATE();
5878 ReloadCustomImages();
5879 print_timestamp_time("ReloadCustomImages");
5881 UPDATE_BUSY_STATE();
5883 LoadCustomElementDescriptions();
5884 print_timestamp_time("LoadCustomElementDescriptions");
5886 UPDATE_BUSY_STATE();
5888 LoadMenuDesignSettings();
5889 print_timestamp_time("LoadMenuDesignSettings");
5891 UPDATE_BUSY_STATE();
5893 ReinitializeGraphics();
5894 print_timestamp_time("ReinitializeGraphics");
5896 LoadMenuDesignSettings_AfterGraphics();
5897 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5899 UPDATE_BUSY_STATE();
5901 print_timestamp_done("InitImages");
5904 static void InitSound(char *identifier)
5906 print_timestamp_init("InitSound");
5908 if (identifier == NULL)
5909 identifier = artwork.snd_current->identifier;
5911 // set artwork path to send it to the sound server process
5912 setLevelArtworkDir(artwork.snd_first);
5914 InitReloadCustomSounds(identifier);
5915 print_timestamp_time("InitReloadCustomSounds");
5917 ReinitializeSounds();
5918 print_timestamp_time("ReinitializeSounds");
5920 print_timestamp_done("InitSound");
5923 static void InitMusic(char *identifier)
5925 print_timestamp_init("InitMusic");
5927 if (identifier == NULL)
5928 identifier = artwork.mus_current->identifier;
5930 // set artwork path to send it to the sound server process
5931 setLevelArtworkDir(artwork.mus_first);
5933 InitReloadCustomMusic(identifier);
5934 print_timestamp_time("InitReloadCustomMusic");
5936 ReinitializeMusic();
5937 print_timestamp_time("ReinitializeMusic");
5939 print_timestamp_done("InitMusic");
5942 static void InitArtworkDone(void)
5944 if (program.headless)
5947 InitGlobalAnimations();
5950 static void InitNetworkSettings(void)
5952 boolean network_enabled = (options.network || setup.network_mode);
5953 char *network_server = (options.server_host != NULL ? options.server_host :
5954 setup.network_server_hostname);
5956 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5957 network_server = NULL;
5959 InitNetworkInfo(network_enabled,
5963 options.server_port);
5966 void InitNetworkServer(void)
5968 if (!network.enabled || network.connected)
5971 LimitScreenUpdates(FALSE);
5973 if (game_status == GAME_MODE_LOADING)
5976 if (!ConnectToServer(network.server_host, network.server_port))
5978 network.enabled = FALSE;
5980 setup.network_mode = FALSE;
5984 SendToServer_ProtocolVersion();
5985 SendToServer_PlayerName(setup.player_name);
5986 SendToServer_NrWanted(setup.network_player_nr + 1);
5988 network.connected = TRUE;
5991 // short time to recognize result of network initialization
5992 if (game_status == GAME_MODE_LOADING)
5993 Delay_WithScreenUpdates(1000);
5996 static boolean CheckArtworkConfigForCustomElements(char *filename)
5998 SetupFileHash *setup_file_hash;
5999 boolean redefined_ce_found = FALSE;
6001 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6003 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6005 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6007 char *token = HASH_ITERATION_TOKEN(itr);
6009 if (strPrefix(token, "custom_"))
6011 redefined_ce_found = TRUE;
6016 END_HASH_ITERATION(setup_file_hash, itr)
6018 freeSetupFileHash(setup_file_hash);
6021 return redefined_ce_found;
6024 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6026 char *filename_base, *filename_local;
6027 boolean redefined_ce_found = FALSE;
6029 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6032 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6033 "leveldir_current->identifier == '%s'",
6034 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6035 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6036 "leveldir_current->graphics_path == '%s'",
6037 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6038 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6039 "leveldir_current->graphics_set == '%s'",
6040 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6041 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6042 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6043 leveldir_current == NULL ? "[NULL]" :
6044 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6047 // first look for special artwork configured in level series config
6048 filename_base = getCustomArtworkLevelConfigFilename(type);
6051 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6052 "filename_base == '%s'", filename_base);
6055 if (fileExists(filename_base))
6056 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6058 filename_local = getCustomArtworkConfigFilename(type);
6061 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6062 "filename_local == '%s'", filename_local);
6065 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6066 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6069 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6070 "redefined_ce_found == %d", redefined_ce_found);
6073 return redefined_ce_found;
6076 static void InitOverrideArtwork(void)
6078 boolean redefined_ce_found = FALSE;
6080 // to check if this level set redefines any CEs, do not use overriding
6081 gfx.override_level_graphics = FALSE;
6082 gfx.override_level_sounds = FALSE;
6083 gfx.override_level_music = FALSE;
6085 // now check if this level set has definitions for custom elements
6086 if (setup.override_level_graphics == AUTO ||
6087 setup.override_level_sounds == AUTO ||
6088 setup.override_level_music == AUTO)
6089 redefined_ce_found =
6090 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6091 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6092 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6095 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6096 redefined_ce_found);
6099 if (redefined_ce_found)
6101 // this level set has CE definitions: change "AUTO" to "FALSE"
6102 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6103 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6104 gfx.override_level_music = (setup.override_level_music == TRUE);
6108 // this level set has no CE definitions: change "AUTO" to "TRUE"
6109 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6110 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6111 gfx.override_level_music = (setup.override_level_music != FALSE);
6115 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6116 gfx.override_level_graphics,
6117 gfx.override_level_sounds,
6118 gfx.override_level_music);
6122 static char *getNewArtworkIdentifier(int type)
6124 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6125 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6126 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6127 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6128 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6129 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6130 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6131 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6132 char *leveldir_identifier = leveldir_current->identifier;
6133 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6134 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6135 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6136 TreeInfo *custom_artwork_set =
6137 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6138 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6139 char *artwork_current_identifier;
6140 char *artwork_new_identifier = NULL; // default: nothing has changed
6142 // leveldir_current may be invalid (level group, parent link)
6143 if (!validLevelSeries(leveldir_current))
6146 /* 1st step: determine artwork set to be activated in descending order:
6147 --------------------------------------------------------------------
6148 1. setup artwork (when configured to override everything else)
6149 2. artwork set configured in "levelinfo.conf" of current level set
6150 (artwork in level directory will have priority when loading later)
6151 3. artwork in level directory (stored in artwork sub-directory)
6152 4. setup artwork (currently configured in setup menu) */
6154 if (setup_override_artwork)
6155 artwork_current_identifier = setup_artwork_set;
6156 else if (has_level_artwork_set)
6157 artwork_current_identifier = leveldir_artwork_set;
6158 else if (has_custom_artwork_set)
6159 artwork_current_identifier = leveldir_identifier;
6161 artwork_current_identifier = setup_artwork_set;
6163 /* 2nd step: check if it is really needed to reload artwork set
6164 ------------------------------------------------------------ */
6166 // ---------- reload if level set and also artwork set has changed ----------
6167 if (last_leveldir_identifier[type] != leveldir_identifier &&
6168 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6169 artwork_new_identifier = artwork_current_identifier;
6171 last_leveldir_identifier[type] = leveldir_identifier;
6172 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6174 // ---------- reload if "override artwork" setting has changed --------------
6175 if (last_override_level_artwork[type] != setup_override_artwork)
6176 artwork_new_identifier = artwork_current_identifier;
6178 last_override_level_artwork[type] = setup_override_artwork;
6180 // ---------- reload if current artwork identifier has changed --------------
6181 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6182 artwork_new_identifier = artwork_current_identifier;
6184 // (we cannot compare string pointers here, so copy string content itself)
6185 setString(&last_artwork_identifier[type], artwork_current_identifier);
6187 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6189 // ---------- do not reload directly after starting -------------------------
6190 if (!initialized[type])
6191 artwork_new_identifier = NULL;
6193 initialized[type] = TRUE;
6195 return artwork_new_identifier;
6198 void ReloadCustomArtwork(int force_reload)
6200 int last_game_status = game_status; // save current game status
6201 char *gfx_new_identifier;
6202 char *snd_new_identifier;
6203 char *mus_new_identifier;
6204 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6205 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6206 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6207 boolean reload_needed;
6209 InitOverrideArtwork();
6211 AdjustGraphicsForEMC();
6212 AdjustSoundsForEMC();
6214 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6215 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6216 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6218 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6219 snd_new_identifier != NULL || force_reload_snd ||
6220 mus_new_identifier != NULL || force_reload_mus);
6225 print_timestamp_init("ReloadCustomArtwork");
6227 SetGameStatus(GAME_MODE_LOADING);
6229 FadeOut(REDRAW_ALL);
6231 SetLoadingBackgroundImage();
6233 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6234 print_timestamp_time("ClearRectangleOnBackground");
6238 UPDATE_BUSY_STATE();
6240 if (gfx_new_identifier != NULL || force_reload_gfx)
6243 Debug("init:ReloadCustomArtwork",
6244 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6245 artwork.gfx_current_identifier,
6247 artwork.gfx_current->identifier,
6248 leveldir_current->graphics_set);
6252 print_timestamp_time("InitImages");
6255 if (snd_new_identifier != NULL || force_reload_snd)
6257 InitSound(snd_new_identifier);
6258 print_timestamp_time("InitSound");
6261 if (mus_new_identifier != NULL || force_reload_mus)
6263 InitMusic(mus_new_identifier);
6264 print_timestamp_time("InitMusic");
6269 SetGameStatus(last_game_status); // restore current game status
6271 FadeOut(REDRAW_ALL);
6273 RedrawGlobalBorder();
6275 // force redraw of (open or closed) door graphics
6276 SetDoorState(DOOR_OPEN_ALL);
6277 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6279 FadeSetEnterScreen();
6280 FadeSkipNextFadeOut();
6282 print_timestamp_done("ReloadCustomArtwork");
6284 LimitScreenUpdates(FALSE);
6287 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6289 if (global.autoplay_leveldir == NULL)
6290 KeyboardAutoRepeatOff();
6293 void DisplayExitMessage(char *format, va_list ap)
6295 // also check for initialized video (headless flag may be temporarily unset)
6296 if (program.headless || !video.initialized)
6299 // check if draw buffer and fonts for exit message are already available
6300 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6303 int font_1 = FC_RED;
6304 int font_2 = FC_YELLOW;
6305 int font_3 = FC_BLUE;
6306 int font_width = getFontWidth(font_2);
6307 int font_height = getFontHeight(font_2);
6310 int sxsize = WIN_XSIZE - 2 * sx;
6311 int sysize = WIN_YSIZE - 2 * sy;
6312 int line_length = sxsize / font_width;
6313 int max_lines = sysize / font_height;
6314 int num_lines_printed;
6318 gfx.sxsize = sxsize;
6319 gfx.sysize = sysize;
6323 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6325 DrawTextSCentered(sy, font_1, "Fatal error:");
6326 sy += 3 * font_height;;
6329 DrawTextBufferVA(sx, sy, format, ap, font_2,
6330 line_length, line_length, max_lines,
6331 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6332 sy += (num_lines_printed + 3) * font_height;
6334 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6335 sy += 3 * font_height;
6338 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6339 line_length, line_length, max_lines,
6340 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6342 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6344 redraw_mask = REDRAW_ALL;
6346 // force drawing exit message even if screen updates are currently limited
6347 LimitScreenUpdates(FALSE);
6351 // deactivate toons on error message screen
6352 setup.toons = FALSE;
6354 WaitForEventToContinue();
6358 // ============================================================================
6360 // ============================================================================
6364 print_timestamp_init("OpenAll");
6366 SetGameStatus(GAME_MODE_LOADING);
6370 InitGlobal(); // initialize some global variables
6372 InitRND(NEW_RANDOMIZE);
6373 InitSimpleRandom(NEW_RANDOMIZE);
6374 InitBetterRandom(NEW_RANDOMIZE);
6376 print_timestamp_time("[init global stuff]");
6380 print_timestamp_time("[init setup/config stuff (1)]");
6382 if (options.execute_command)
6383 Execute_Command(options.execute_command);
6385 InitNetworkSettings();
6389 if (network.serveronly)
6391 #if defined(PLATFORM_UNIX)
6392 NetworkServer(network.server_port, TRUE);
6394 Warn("networking only supported in Unix version");
6397 exit(0); // never reached, server loops forever
6401 print_timestamp_time("[init setup/config stuff (2)]");
6403 print_timestamp_time("[init setup/config stuff (3)]");
6404 InitArtworkInfo(); // needed before loading gfx, sound & music
6405 print_timestamp_time("[init setup/config stuff (4)]");
6406 InitArtworkConfig(); // needed before forking sound child process
6407 print_timestamp_time("[init setup/config stuff (5)]");
6409 print_timestamp_time("[init setup/config stuff (6)]");
6413 print_timestamp_time("[init setup/config stuff]");
6415 InitVideoDefaults();
6417 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6420 InitEventFilter(FilterMouseMotionEvents);
6422 print_timestamp_time("[init video stuff]");
6424 InitElementPropertiesStatic();
6425 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6426 InitElementPropertiesGfxElement();
6428 print_timestamp_time("[init element properties stuff]");
6432 print_timestamp_time("InitGfx");
6435 print_timestamp_time("InitLevelInfo");
6437 InitLevelArtworkInfo();
6438 print_timestamp_time("InitLevelArtworkInfo");
6440 InitOverrideArtwork(); // needs to know current level directory
6441 print_timestamp_time("InitOverrideArtwork");
6443 InitImages(); // needs to know current level directory
6444 print_timestamp_time("InitImages");
6446 InitSound(NULL); // needs to know current level directory
6447 print_timestamp_time("InitSound");
6449 InitMusic(NULL); // needs to know current level directory
6450 print_timestamp_time("InitMusic");
6454 InitGfxBackground();
6460 if (global.autoplay_leveldir)
6465 else if (global.patchtapes_leveldir)
6470 else if (global.convert_leveldir)
6475 else if (global.dumplevel_leveldir)
6480 else if (global.dumptape_leveldir)
6485 else if (global.create_sketch_images_dir)
6487 CreateLevelSketchImages();
6490 else if (global.create_collect_images_dir)
6492 CreateCollectElementImages();
6496 InitNetworkServer();
6498 SetGameStatus(GAME_MODE_MAIN);
6500 FadeSetEnterScreen();
6501 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6502 FadeSkipNextFadeOut();
6504 print_timestamp_time("[post-artwork]");
6506 print_timestamp_done("OpenAll");
6508 if (setup.ask_for_remaining_tapes)
6509 setup.ask_for_uploading_tapes = TRUE;
6514 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6516 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6517 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6518 #if defined(PLATFORM_ANDROID)
6519 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6520 SDL_AndroidGetInternalStoragePath());
6521 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6522 SDL_AndroidGetExternalStoragePath());
6523 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6524 (SDL_AndroidGetExternalStorageState() &
6525 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6526 SDL_AndroidGetExternalStorageState() &
6527 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6532 static boolean WaitForApiThreads(void)
6534 unsigned int thread_delay = 0;
6535 unsigned int thread_delay_value = 10000;
6537 if (program.api_thread_count == 0)
6540 // deactivate global animations (not accessible in game state "loading")
6541 setup.toons = FALSE;
6543 // set game state to "loading" to be able to show busy animation
6544 SetGameStatus(GAME_MODE_LOADING);
6546 ResetDelayCounter(&thread_delay);
6548 // wait for threads to finish (and fail on timeout)
6549 while (program.api_thread_count > 0)
6551 if (DelayReached(&thread_delay, thread_delay_value))
6553 Error("failed waiting for threads - TIMEOUT");
6558 UPDATE_BUSY_STATE();
6566 void CloseAllAndExit(int exit_value)
6568 WaitForApiThreads();
6573 CloseAudio(); // called after freeing sounds (needed for SDL)
6581 // set a flag to tell the network server thread to quit and wait for it
6582 // using SDL_WaitThread()
6584 // Code used with SDL 1.2:
6585 // if (network.server_thread) // terminate network server
6586 // SDL_KillThread(network.server_thread);
6588 CloseVideoDisplay();
6589 ClosePlatformDependentStuff();
6591 if (exit_value != 0 && !options.execute_command)
6593 // fall back to default level set (current set may have caused an error)
6594 SaveLevelSetup_LastSeries_Deactivate();
6596 // tell user where to find error log file which may contain more details
6597 // (error notification now directly displayed on screen inside R'n'D
6598 // NotifyUserAboutErrorFile(); // currently only works for Windows