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 "background"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
42 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
44 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
45 #define INITIAL_IMG_GLOBAL_BUSY 1
46 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD 2
48 #define NUM_INITIAL_IMAGES_BUSY 3
50 #define INITIAL_IMG_BACKGROUND 3
51 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 4
52 #define INITIAL_IMG_BACKGROUND_LOADING 5
54 #define NUM_INITIAL_IMAGES 6
57 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
58 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
60 static int copy_properties[][5] =
64 EL_BUG_LEFT, EL_BUG_RIGHT,
65 EL_BUG_UP, EL_BUG_DOWN
69 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
70 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
74 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
75 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
79 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
80 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
84 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
85 EL_PACMAN_UP, EL_PACMAN_DOWN
89 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
90 EL_YAMYAM_UP, EL_YAMYAM_DOWN
94 EL_MOLE_LEFT, EL_MOLE_RIGHT,
95 EL_MOLE_UP, EL_MOLE_DOWN
99 EL_SPRING_LEFT, EL_SPRING_RIGHT,
100 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
109 // forward declaration for internal use
110 static int get_graphic_parameter_value(char *, char *, int);
113 static Bitmap *getLoadingBackgroundBitmap(int graphic)
115 return getBitmapFromGraphicOrDefault(graphic, INITIAL_IMG_BACKGROUND);
118 static void SetLoadingWindowBackgroundImage(int graphic)
120 SetWindowBackgroundBitmap(getLoadingBackgroundBitmap(graphic));
123 static void SetLoadingBackgroundImage(void)
125 struct GraphicInfo *graphic_info_last = graphic_info;
126 int background_image = (game_status_last_screen == -1 ?
127 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
128 INITIAL_IMG_BACKGROUND_LOADING);
130 graphic_info = image_initial;
132 SetDrawDeactivationMask(REDRAW_NONE);
133 SetDrawBackgroundMask(REDRAW_ALL);
135 SetLoadingWindowBackgroundImage(background_image);
137 graphic_info = graphic_info_last;
140 static void DrawInitAnim(boolean only_when_loading)
142 struct GraphicInfo *graphic_info_last = graphic_info;
143 int graphic = (game_status_last_screen == -1 ?
144 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
145 game_status == GAME_MODE_LOADING ?
146 INITIAL_IMG_GLOBAL_BUSY :
147 INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
148 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
149 &init_last.busy_initial :
150 game_status == GAME_MODE_LOADING ?
152 &init_last.busy_playfield);
153 static DelayCounter action_delay = { 0 };
154 int sync_frame = FrameCounter;
157 action_delay.value = GameFrameDelay;
159 // prevent OS (Windows) from complaining about program not responding
162 if (game_status != GAME_MODE_LOADING && only_when_loading)
165 if (image_initial[graphic].bitmap == NULL || window == NULL)
168 if (!DelayReached(&action_delay))
172 busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
174 busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
176 x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
177 y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
179 graphic_info = image_initial;
181 if (sync_frame % image_initial[graphic].anim_delay == 0)
185 int width = graphic_info[graphic].width;
186 int height = graphic_info[graphic].height;
187 int frame = getGraphicAnimationFrame(graphic, sync_frame);
189 ClearRectangleOnBackground(drawto, x, y, width, height);
191 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
192 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 graphic_info = graphic_info_last;
202 static void DrawProgramInfo(void)
204 int font1_nr = FC_YELLOW;
205 int font2_nr = FC_RED;
206 int font2_height = getFontHeight(font2_nr);
209 int ypos3 = WIN_YSIZE - 20 - font2_height;
211 DrawInitText(getProgramInitString(), ypos1, font1_nr);
212 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
213 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
216 static void FreeGadgets(void)
218 FreeLevelEditorGadgets();
225 void InitGadgets(void)
227 static boolean gadgets_initialized = FALSE;
229 if (gadgets_initialized)
232 CreateLevelEditorGadgets();
236 CreateScreenGadgets();
238 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
240 gadgets_initialized = TRUE;
243 static void InitElementSmallImagesScaledUp(int graphic)
245 struct GraphicInfo *g = &graphic_info[graphic];
247 // create small and game tile sized bitmaps (and scale up, if needed)
248 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
251 static void InitElementSmallImages(void)
253 print_timestamp_init("InitElementSmallImages");
255 static int special_graphics[] =
269 IMG_EDITOR_ELEMENT_BORDER,
270 IMG_EDITOR_ELEMENT_BORDER_INPUT,
271 IMG_EDITOR_CASCADE_LIST,
272 IMG_EDITOR_CASCADE_LIST_ACTIVE,
275 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
276 int num_property_mappings = getImageListPropertyMappingSize();
279 print_timestamp_time("getImageListPropertyMapping/Size");
281 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
282 // initialize normal element images from static configuration
283 for (i = 0; element_to_graphic[i].element > -1; i++)
284 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
285 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
287 // initialize special element images from static configuration
288 for (i = 0; element_to_special_graphic[i].element > -1; i++)
289 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
290 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
292 // initialize element images from dynamic configuration
293 for (i = 0; i < num_property_mappings; i++)
294 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
295 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
296 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
298 // initialize special non-element images from above list
299 for (i = 0; special_graphics[i] > -1; i++)
300 InitElementSmallImagesScaledUp(special_graphics[i]);
301 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
303 print_timestamp_done("InitElementSmallImages");
306 static void InitScaledImagesScaledUp(int graphic)
308 struct GraphicInfo *g = &graphic_info[graphic];
310 ScaleImage(graphic, g->scale_up_factor);
313 static void InitScaledImages(void)
315 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
316 int num_property_mappings = getImageListPropertyMappingSize();
319 // scale normal images from static configuration, if not already scaled
320 for (i = 0; i < NUM_IMAGE_FILES; i++)
321 InitScaledImagesScaledUp(i);
323 // scale images from dynamic configuration, if not already scaled
324 for (i = 0; i < num_property_mappings; i++)
325 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
328 static void InitBitmapPointers(void)
330 int num_images = getImageListSize();
333 // standard size bitmap may have changed -- update default bitmap pointer
334 for (i = 0; i < num_images; i++)
335 if (graphic_info[i].bitmaps)
336 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
339 void InitImageTextures(void)
341 static int texture_graphics[] =
343 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
344 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
345 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
346 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
347 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
348 IMG_MENU_BUTTON_TOUCH_BACK,
349 IMG_MENU_BUTTON_TOUCH_NEXT,
350 IMG_MENU_BUTTON_TOUCH_BACK2,
351 IMG_MENU_BUTTON_TOUCH_NEXT2,
356 FreeAllImageTextures();
358 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
359 CreateImageTextures(i);
361 for (i = 0; i < MAX_NUM_TOONS; i++)
362 CreateImageTextures(IMG_TOON_1 + i);
364 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
366 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
368 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
370 int graphic = global_anim_info[i].graphic[j][k];
372 if (graphic == IMG_UNDEFINED)
375 CreateImageTextures(graphic);
380 for (i = 0; texture_graphics[i] > -1; i++)
381 CreateImageTextures(texture_graphics[i]);
384 static int getFontBitmapID(int font_nr)
388 // (special case: do not use special font for GAME_MODE_LOADING)
389 if (game_status >= GAME_MODE_TITLE_INITIAL &&
390 game_status <= GAME_MODE_PSEUDO_PREVIEW)
391 special = game_status;
392 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
393 special = GFX_SPECIAL_ARG_MAIN;
394 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
395 special = GFX_SPECIAL_ARG_NAMES;
398 return font_info[font_nr].special_bitmap_id[special];
403 static int getFontFromToken(char *token)
405 char *value = getHashEntry(font_token_hash, token);
410 // if font not found, use reliable default value
411 return FONT_INITIAL_1;
414 static void InitFontGraphicInfo(void)
416 static struct FontBitmapInfo *font_bitmap_info = NULL;
417 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
418 int num_property_mappings = getImageListPropertyMappingSize();
419 int num_font_bitmaps = NUM_FONTS;
422 if (graphic_info == NULL) // still at startup phase
424 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
425 getFontBitmapID, getFontFromToken);
430 // ---------- initialize font graphic definitions ----------
432 // always start with reliable default values (normal font graphics)
433 for (i = 0; i < NUM_FONTS; i++)
434 font_info[i].graphic = IMG_FONT_INITIAL_1;
436 // initialize normal font/graphic mapping from static configuration
437 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
439 int font_nr = font_to_graphic[i].font_nr;
440 int special = font_to_graphic[i].special;
441 int graphic = font_to_graphic[i].graphic;
446 font_info[font_nr].graphic = graphic;
449 // always start with reliable default values (special font graphics)
450 for (i = 0; i < NUM_FONTS; i++)
452 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
454 font_info[i].special_graphic[j] = font_info[i].graphic;
455 font_info[i].special_bitmap_id[j] = i;
459 // initialize special font/graphic mapping from static configuration
460 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
462 int font_nr = font_to_graphic[i].font_nr;
463 int special = font_to_graphic[i].special;
464 int graphic = font_to_graphic[i].graphic;
465 int base_graphic = font2baseimg(font_nr);
467 if (IS_SPECIAL_GFX_ARG(special))
469 boolean base_redefined =
470 getImageListEntryFromImageID(base_graphic)->redefined;
471 boolean special_redefined =
472 getImageListEntryFromImageID(graphic)->redefined;
473 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
475 /* if the base font ("font.title_1", for example) has been redefined,
476 but not the special font ("font.title_1.LEVELS", for example), do not
477 use an existing (in this case considered obsolete) special font
478 anymore, but use the automatically determined default font */
479 /* special case: cloned special fonts must be explicitly redefined,
480 but are not automatically redefined by redefining base font */
481 if (base_redefined && !special_redefined && !special_cloned)
484 font_info[font_nr].special_graphic[special] = graphic;
485 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
490 // initialize special font/graphic mapping from dynamic configuration
491 for (i = 0; i < num_property_mappings; i++)
493 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
494 int special = property_mapping[i].ext3_index;
495 int graphic = property_mapping[i].artwork_index;
497 if (font_nr < 0 || font_nr >= NUM_FONTS)
500 if (IS_SPECIAL_GFX_ARG(special))
502 font_info[font_nr].special_graphic[special] = graphic;
503 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
508 /* correct special font/graphic mapping for cloned fonts for downwards
509 compatibility of PREVIEW fonts -- this is only needed for implicit
510 redefinition of special font by redefined base font, and only if other
511 fonts are cloned from this special font (like in the "Zelda" level set) */
512 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
514 int font_nr = font_to_graphic[i].font_nr;
515 int special = font_to_graphic[i].special;
516 int graphic = font_to_graphic[i].graphic;
518 if (IS_SPECIAL_GFX_ARG(special))
520 boolean special_redefined =
521 getImageListEntryFromImageID(graphic)->redefined;
522 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
524 if (special_cloned && !special_redefined)
528 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
530 int font_nr2 = font_to_graphic[j].font_nr;
531 int special2 = font_to_graphic[j].special;
532 int graphic2 = font_to_graphic[j].graphic;
534 if (IS_SPECIAL_GFX_ARG(special2) &&
535 graphic2 == graphic_info[graphic].clone_from)
537 font_info[font_nr].special_graphic[special] =
538 font_info[font_nr2].special_graphic[special2];
539 font_info[font_nr].special_bitmap_id[special] =
540 font_info[font_nr2].special_bitmap_id[special2];
547 // reset non-redefined ".active" font graphics if normal font is redefined
548 // (this different treatment is needed because normal and active fonts are
549 // independently defined ("active" is not a property of font definitions!)
550 for (i = 0; i < NUM_FONTS; i++)
552 int font_nr_base = i;
553 int font_nr_active = FONT_ACTIVE(font_nr_base);
555 // check only those fonts with exist as normal and ".active" variant
556 if (font_nr_base != font_nr_active)
558 int base_graphic = font_info[font_nr_base].graphic;
559 int active_graphic = font_info[font_nr_active].graphic;
560 boolean base_redefined =
561 getImageListEntryFromImageID(base_graphic)->redefined;
562 boolean active_redefined =
563 getImageListEntryFromImageID(active_graphic)->redefined;
565 /* if the base font ("font.menu_1", for example) has been redefined,
566 but not the active font ("font.menu_1.active", for example), do not
567 use an existing (in this case considered obsolete) active font
568 anymore, but use the automatically determined default font */
569 if (base_redefined && !active_redefined)
570 font_info[font_nr_active].graphic = base_graphic;
572 // now also check each "special" font (which may be the same as above)
573 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
575 int base_graphic = font_info[font_nr_base].special_graphic[j];
576 int active_graphic = font_info[font_nr_active].special_graphic[j];
577 boolean base_redefined =
578 getImageListEntryFromImageID(base_graphic)->redefined;
579 boolean active_redefined =
580 getImageListEntryFromImageID(active_graphic)->redefined;
582 // same as above, but check special graphic definitions, for example:
583 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
584 if (base_redefined && !active_redefined)
586 font_info[font_nr_active].special_graphic[j] =
587 font_info[font_nr_base].special_graphic[j];
588 font_info[font_nr_active].special_bitmap_id[j] =
589 font_info[font_nr_base].special_bitmap_id[j];
595 // ---------- initialize font bitmap array ----------
597 if (font_bitmap_info != NULL)
598 FreeFontInfo(font_bitmap_info);
601 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
603 // ---------- initialize font bitmap definitions ----------
605 for (i = 0; i < NUM_FONTS; i++)
607 if (i < NUM_INITIAL_FONTS)
609 font_bitmap_info[i] = font_initial[i];
613 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
615 int font_bitmap_id = font_info[i].special_bitmap_id[j];
616 int graphic = font_info[i].special_graphic[j];
618 // set 'graphic_info' for font entries, if uninitialized (guessed)
619 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
621 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
622 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
625 // copy font relevant information from graphics information
626 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
627 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
628 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
629 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
630 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
632 font_bitmap_info[font_bitmap_id].offset_x =
633 graphic_info[graphic].offset_x;
634 font_bitmap_info[font_bitmap_id].offset_y =
635 graphic_info[graphic].offset_y;
637 font_bitmap_info[font_bitmap_id].draw_xoffset =
638 graphic_info[graphic].draw_xoffset;
639 font_bitmap_info[font_bitmap_id].draw_yoffset =
640 graphic_info[graphic].draw_yoffset;
642 font_bitmap_info[font_bitmap_id].num_chars =
643 graphic_info[graphic].anim_frames;
644 font_bitmap_info[font_bitmap_id].num_chars_per_line =
645 graphic_info[graphic].anim_frames_per_line;
649 InitFontInfo(font_bitmap_info, num_font_bitmaps,
650 getFontBitmapID, getFontFromToken);
653 static void InitGlobalAnimGraphicInfo(void)
655 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
656 int num_property_mappings = getImageListPropertyMappingSize();
659 if (graphic_info == NULL) // still at startup phase
662 // always start with reliable default values (no global animations)
663 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
664 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
665 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
666 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
668 // initialize global animation definitions from static configuration
669 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
671 int j = GLOBAL_ANIM_ID_PART_BASE;
672 int k = GFX_SPECIAL_ARG_DEFAULT;
674 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
677 // initialize global animation definitions from dynamic configuration
678 for (i = 0; i < num_property_mappings; i++)
680 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
681 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
682 int special = property_mapping[i].ext3_index;
683 int graphic = property_mapping[i].artwork_index;
685 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
688 // set animation part to base part, if not specified
689 if (!IS_GLOBAL_ANIM_PART(part_nr))
690 part_nr = GLOBAL_ANIM_ID_PART_BASE;
692 // set animation screen to default, if not specified
693 if (!IS_SPECIAL_GFX_ARG(special))
694 special = GFX_SPECIAL_ARG_DEFAULT;
696 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
698 // fix default value for ".draw_masked" (for backward compatibility)
699 struct GraphicInfo *g = &graphic_info[graphic];
700 struct FileInfo *image = getImageListEntryFromImageID(graphic);
701 char **parameter_raw = image->parameter;
702 int p = GFX_ARG_DRAW_MASKED;
703 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
704 image_config_suffix[p].token,
705 image_config_suffix[p].type);
707 // if ".draw_masked" parameter is undefined, use default value "TRUE"
708 if (draw_masked == ARG_UNDEFINED_VALUE)
709 g->draw_masked = TRUE;
713 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
714 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
715 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
716 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
717 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
718 Debug("init:InitGlobalAnimGraphicInfo",
719 "anim %d, part %d, mode %d => %d",
720 i, j, k, global_anim_info[i].graphic[j][k]);
724 static void InitGlobalAnimSoundInfo(void)
726 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
727 int num_property_mappings = getSoundListPropertyMappingSize();
730 // always start with reliable default values (no global animation sounds)
731 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
732 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
733 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
734 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
736 // initialize global animation sound definitions from dynamic configuration
737 for (i = 0; i < num_property_mappings; i++)
739 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
740 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
741 int special = property_mapping[i].ext3_index;
742 int sound = property_mapping[i].artwork_index;
744 // sound uses control definition; map it to position of graphic (artwork)
745 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
747 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
750 // set animation part to base part, if not specified
751 if (!IS_GLOBAL_ANIM_PART(part_nr))
752 part_nr = GLOBAL_ANIM_ID_PART_BASE;
754 // set animation screen to default, if not specified
755 if (!IS_SPECIAL_GFX_ARG(special))
756 special = GFX_SPECIAL_ARG_DEFAULT;
758 global_anim_info[anim_nr].sound[part_nr][special] = sound;
762 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
763 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
764 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
765 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
766 Debug("init:InitGlobalAnimSoundInfo",
767 "anim %d, part %d, mode %d => %d",
768 i, j, k, global_anim_info[i].sound[j][k]);
772 static void InitGlobalAnimMusicInfo(void)
774 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
775 int num_property_mappings = getMusicListPropertyMappingSize();
778 // always start with reliable default values (no global animation music)
779 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
780 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
781 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
782 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
784 // initialize global animation music definitions from dynamic configuration
785 for (i = 0; i < num_property_mappings; i++)
787 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
788 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
789 int special = property_mapping[i].ext2_index;
790 int music = property_mapping[i].artwork_index;
792 // music uses control definition; map it to position of graphic (artwork)
793 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
795 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
798 // set animation part to base part, if not specified
799 if (!IS_GLOBAL_ANIM_PART(part_nr))
800 part_nr = GLOBAL_ANIM_ID_PART_BASE;
802 // set animation screen to default, if not specified
803 if (!IS_SPECIAL_GFX_ARG(special))
804 special = GFX_SPECIAL_ARG_DEFAULT;
806 global_anim_info[anim_nr].music[part_nr][special] = music;
810 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
811 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
812 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
813 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
814 Debug("init:InitGlobalAnimMusicInfo",
815 "anim %d, part %d, mode %d => %d",
816 i, j, k, global_anim_info[i].music[j][k]);
820 static void InitElementGraphicInfo(void)
822 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
823 int num_property_mappings = getImageListPropertyMappingSize();
826 if (graphic_info == NULL) // still at startup phase
829 // set values to -1 to identify later as "uninitialized" values
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832 for (act = 0; act < NUM_ACTIONS; act++)
834 element_info[i].graphic[act] = -1;
835 element_info[i].crumbled[act] = -1;
837 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
839 element_info[i].direction_graphic[act][dir] = -1;
840 element_info[i].direction_crumbled[act][dir] = -1;
847 // initialize normal element/graphic mapping from static configuration
848 for (i = 0; element_to_graphic[i].element > -1; i++)
850 int element = element_to_graphic[i].element;
851 int action = element_to_graphic[i].action;
852 int direction = element_to_graphic[i].direction;
853 boolean crumbled = element_to_graphic[i].crumbled;
854 int graphic = element_to_graphic[i].graphic;
855 int base_graphic = el2baseimg(element);
857 if (graphic_info[graphic].bitmap == NULL)
860 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
863 boolean base_redefined =
864 getImageListEntryFromImageID(base_graphic)->redefined;
865 boolean act_dir_redefined =
866 getImageListEntryFromImageID(graphic)->redefined;
868 /* if the base graphic ("emerald", for example) has been redefined,
869 but not the action graphic ("emerald.falling", for example), do not
870 use an existing (in this case considered obsolete) action graphic
871 anymore, but use the automatically determined default graphic */
872 if (base_redefined && !act_dir_redefined)
877 action = ACTION_DEFAULT;
882 element_info[element].direction_crumbled[action][direction] = graphic;
884 element_info[element].crumbled[action] = graphic;
889 element_info[element].direction_graphic[action][direction] = graphic;
891 element_info[element].graphic[action] = graphic;
895 // initialize normal element/graphic mapping from dynamic configuration
896 for (i = 0; i < num_property_mappings; i++)
898 int element = property_mapping[i].base_index;
899 int action = property_mapping[i].ext1_index;
900 int direction = property_mapping[i].ext2_index;
901 int special = property_mapping[i].ext3_index;
902 int graphic = property_mapping[i].artwork_index;
903 boolean crumbled = FALSE;
905 if (special == GFX_SPECIAL_ARG_CRUMBLED)
911 if (graphic_info[graphic].bitmap == NULL)
914 if (element >= MAX_NUM_ELEMENTS || special != -1)
918 action = ACTION_DEFAULT;
923 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
924 element_info[element].direction_crumbled[action][dir] = -1;
927 element_info[element].direction_crumbled[action][direction] = graphic;
929 element_info[element].crumbled[action] = graphic;
934 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
935 element_info[element].direction_graphic[action][dir] = -1;
938 element_info[element].direction_graphic[action][direction] = graphic;
940 element_info[element].graphic[action] = graphic;
944 // now copy all graphics that are defined to be cloned from other graphics
945 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
947 int graphic = element_info[i].graphic[ACTION_DEFAULT];
948 int crumbled_like, diggable_like;
953 crumbled_like = graphic_info[graphic].crumbled_like;
954 diggable_like = graphic_info[graphic].diggable_like;
956 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
958 for (act = 0; act < NUM_ACTIONS; act++)
959 element_info[i].crumbled[act] =
960 element_info[crumbled_like].crumbled[act];
961 for (act = 0; act < NUM_ACTIONS; act++)
962 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
963 element_info[i].direction_crumbled[act][dir] =
964 element_info[crumbled_like].direction_crumbled[act][dir];
967 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
969 element_info[i].graphic[ACTION_DIGGING] =
970 element_info[diggable_like].graphic[ACTION_DIGGING];
971 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
972 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
973 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
977 // set hardcoded definitions for some runtime elements without graphic
978 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
980 // set hardcoded definitions for some internal elements without graphic
981 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
983 if (IS_EDITOR_CASCADE_INACTIVE(i))
984 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
985 else if (IS_EDITOR_CASCADE_ACTIVE(i))
986 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
989 // now set all undefined/invalid graphics to -1 to set to default after it
990 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
992 for (act = 0; act < NUM_ACTIONS; act++)
996 graphic = element_info[i].graphic[act];
997 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
998 element_info[i].graphic[act] = -1;
1000 graphic = element_info[i].crumbled[act];
1001 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1002 element_info[i].crumbled[act] = -1;
1004 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1006 graphic = element_info[i].direction_graphic[act][dir];
1007 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1008 element_info[i].direction_graphic[act][dir] = -1;
1010 graphic = element_info[i].direction_crumbled[act][dir];
1011 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1012 element_info[i].direction_crumbled[act][dir] = -1;
1017 UPDATE_BUSY_STATE();
1019 // adjust graphics with 2nd tile for movement according to direction
1020 // (do this before correcting '-1' values to minimize calculations)
1021 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1023 for (act = 0; act < NUM_ACTIONS; act++)
1025 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1027 int graphic = element_info[i].direction_graphic[act][dir];
1028 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1030 if (act == ACTION_FALLING) // special case
1031 graphic = element_info[i].graphic[act];
1033 if (graphic != -1 &&
1034 graphic_info[graphic].double_movement &&
1035 graphic_info[graphic].swap_double_tiles != 0)
1037 struct GraphicInfo *g = &graphic_info[graphic];
1038 int src_x_front = g->src_x;
1039 int src_y_front = g->src_y;
1040 int src_x_back = g->src_x + g->offset2_x;
1041 int src_y_back = g->src_y + g->offset2_y;
1042 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1044 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1045 src_y_front < src_y_back);
1046 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1047 boolean swap_movement_tiles_autodetected =
1048 (!frames_are_ordered_diagonally &&
1049 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1050 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1051 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1052 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1054 // swap frontside and backside graphic tile coordinates, if needed
1055 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1057 // get current (wrong) backside tile coordinates
1058 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1060 // set frontside tile coordinates to backside tile coordinates
1061 g->src_x = src_x_back;
1062 g->src_y = src_y_back;
1064 // invert tile offset to point to new backside tile coordinates
1068 // do not swap front and backside tiles again after correction
1069 g->swap_double_tiles = 0;
1076 UPDATE_BUSY_STATE();
1078 // now set all '-1' values to element specific default values
1079 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1081 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1082 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1083 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1084 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1086 if (default_graphic == -1)
1087 default_graphic = IMG_UNKNOWN;
1089 if (default_crumbled == -1)
1090 default_crumbled = default_graphic;
1092 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1094 default_direction_graphic[dir] =
1095 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1096 default_direction_crumbled[dir] =
1097 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1099 if (default_direction_graphic[dir] == -1)
1100 default_direction_graphic[dir] = default_graphic;
1102 if (default_direction_crumbled[dir] == -1)
1103 default_direction_crumbled[dir] = default_direction_graphic[dir];
1106 for (act = 0; act < NUM_ACTIONS; act++)
1108 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1109 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1110 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1111 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1112 act == ACTION_TURNING_FROM_RIGHT ||
1113 act == ACTION_TURNING_FROM_UP ||
1114 act == ACTION_TURNING_FROM_DOWN);
1116 // generic default action graphic (defined by "[default]" directive)
1117 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1118 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1119 int default_remove_graphic = IMG_EMPTY;
1121 if (act_remove && default_action_graphic != -1)
1122 default_remove_graphic = default_action_graphic;
1124 // look for special default action graphic (classic game specific)
1125 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1126 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1127 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1128 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1129 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1130 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1131 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1132 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1134 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1135 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1136 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1137 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1138 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1139 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1140 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1141 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1143 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1144 // !!! make this better !!!
1145 if (i == EL_EMPTY_SPACE)
1147 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1148 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1151 if (default_action_graphic == -1)
1152 default_action_graphic = default_graphic;
1154 if (default_action_crumbled == -1)
1155 default_action_crumbled = default_action_graphic;
1157 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1159 // use action graphic as the default direction graphic, if undefined
1160 int default_action_direction_graphic = element_info[i].graphic[act];
1161 int default_action_direction_crumbled = element_info[i].crumbled[act];
1163 // no graphic for current action -- use default direction graphic
1164 if (default_action_direction_graphic == -1)
1165 default_action_direction_graphic =
1166 (act_remove ? default_remove_graphic :
1168 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1169 default_action_graphic != default_graphic ?
1170 default_action_graphic :
1171 default_direction_graphic[dir]);
1173 if (element_info[i].direction_graphic[act][dir] == -1)
1174 element_info[i].direction_graphic[act][dir] =
1175 default_action_direction_graphic;
1177 if (default_action_direction_crumbled == -1)
1178 default_action_direction_crumbled =
1179 element_info[i].direction_graphic[act][dir];
1181 if (element_info[i].direction_crumbled[act][dir] == -1)
1182 element_info[i].direction_crumbled[act][dir] =
1183 default_action_direction_crumbled;
1186 // no graphic for this specific action -- use default action graphic
1187 if (element_info[i].graphic[act] == -1)
1188 element_info[i].graphic[act] =
1189 (act_remove ? default_remove_graphic :
1190 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1191 default_action_graphic);
1193 if (element_info[i].crumbled[act] == -1)
1194 element_info[i].crumbled[act] = element_info[i].graphic[act];
1198 UPDATE_BUSY_STATE();
1201 static void InitElementSpecialGraphicInfo(void)
1203 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1204 int num_property_mappings = getImageListPropertyMappingSize();
1207 // always start with reliable default values
1208 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1209 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1210 element_info[i].special_graphic[j] =
1211 element_info[i].graphic[ACTION_DEFAULT];
1213 // initialize special element/graphic mapping from static configuration
1214 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1216 int element = element_to_special_graphic[i].element;
1217 int special = element_to_special_graphic[i].special;
1218 int graphic = element_to_special_graphic[i].graphic;
1219 int base_graphic = el2baseimg(element);
1220 boolean base_redefined =
1221 getImageListEntryFromImageID(base_graphic)->redefined;
1222 boolean special_redefined =
1223 getImageListEntryFromImageID(graphic)->redefined;
1225 /* if the base graphic ("emerald", for example) has been redefined,
1226 but not the special graphic ("emerald.EDITOR", for example), do not
1227 use an existing (in this case considered obsolete) special graphic
1228 anymore, but use the automatically created (down-scaled) graphic */
1229 if (base_redefined && !special_redefined)
1232 element_info[element].special_graphic[special] = graphic;
1235 // initialize special element/graphic mapping from dynamic configuration
1236 for (i = 0; i < num_property_mappings; i++)
1238 int element = property_mapping[i].base_index;
1239 int action = property_mapping[i].ext1_index;
1240 int direction = property_mapping[i].ext2_index;
1241 int special = property_mapping[i].ext3_index;
1242 int graphic = property_mapping[i].artwork_index;
1244 // for action ".active", replace element with active element, if exists
1245 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1247 element = ELEMENT_ACTIVE(element);
1251 if (element >= MAX_NUM_ELEMENTS)
1254 // do not change special graphic if action or direction was specified
1255 if (action != -1 || direction != -1)
1258 if (IS_SPECIAL_GFX_ARG(special))
1259 element_info[element].special_graphic[special] = graphic;
1262 // now set all undefined/invalid graphics to default
1263 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1264 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1265 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1266 element_info[i].special_graphic[j] =
1267 element_info[i].graphic[ACTION_DEFAULT];
1270 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1272 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1273 return get_parameter_value(value_raw, suffix, type);
1275 if (strEqual(value_raw, ARG_UNDEFINED))
1276 return ARG_UNDEFINED_VALUE;
1278 if (type == TYPE_ELEMENT)
1280 char *value = getHashEntry(element_token_hash, value_raw);
1285 Warn("error found in config file:");
1286 Warn("- config file: '%s'", getImageConfigFilename());
1287 Warn("error: invalid element token '%s'", value_raw);
1288 Warn("custom graphic rejected for this element/action");
1289 Warn("fallback done to undefined element for this graphic");
1293 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1295 else if (type == TYPE_GRAPHIC)
1297 char *value = getHashEntry(graphic_token_hash, value_raw);
1298 int fallback_graphic = IMG_CHAR_EXCLAM;
1303 Warn("error found in config file:");
1304 Warn("- config file: '%s'", getImageConfigFilename());
1305 Warn("error: invalid graphic token '%s'", value_raw);
1306 Warn("custom graphic rejected for this element/action");
1307 Warn("fallback done to 'char_exclam' for this graphic");
1311 return (value != NULL ? atoi(value) : fallback_graphic);
1317 static int get_scaled_graphic_width(int graphic)
1319 int original_width = getOriginalImageWidthFromImageID(graphic);
1320 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1322 return original_width * scale_up_factor;
1325 static int get_scaled_graphic_height(int graphic)
1327 int original_height = getOriginalImageHeightFromImageID(graphic);
1328 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1330 return original_height * scale_up_factor;
1333 static void set_graphic_parameters_ext(int graphic, int *parameter,
1334 Bitmap **src_bitmaps)
1336 struct GraphicInfo *g = &graphic_info[graphic];
1337 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1338 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1339 int anim_frames_per_line = 1;
1341 // always start with reliable default values
1342 g->src_image_width = 0;
1343 g->src_image_height = 0;
1346 g->width = TILEX; // default for element graphics
1347 g->height = TILEY; // default for element graphics
1348 g->offset_x = 0; // one or both of these values ...
1349 g->offset_y = 0; // ... will be corrected later
1350 g->offset2_x = 0; // one or both of these values ...
1351 g->offset2_y = 0; // ... will be corrected later
1352 g->swap_double_tiles = -1; // auto-detect tile swapping
1353 g->crumbled_like = -1; // do not use clone element
1354 g->diggable_like = -1; // do not use clone element
1355 g->border_size = TILEX / 8; // "CRUMBLED" border size
1356 g->scale_up_factor = 1; // default: no scaling up
1357 g->tile_size = TILESIZE; // default: standard tile size
1358 g->clone_from = -1; // do not use clone graphic
1359 g->init_delay_fixed = 0;
1360 g->init_delay_random = 0;
1361 g->init_delay_action = -1;
1362 g->anim_delay_fixed = 0;
1363 g->anim_delay_random = 0;
1364 g->anim_delay_action = -1;
1365 g->post_delay_fixed = 0;
1366 g->post_delay_random = 0;
1367 g->post_delay_action = -1;
1368 g->init_event = ANIM_EVENT_UNDEFINED;
1369 g->anim_event = ANIM_EVENT_UNDEFINED;
1370 g->init_event_action = -1;
1371 g->anim_event_action = -1;
1372 g->draw_masked = FALSE;
1374 g->fade_mode = FADE_MODE_DEFAULT;
1378 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1379 g->align = ALIGN_CENTER; // default for title screens
1380 g->valign = VALIGN_MIDDLE; // default for title screens
1381 g->sort_priority = 0; // default for title screens
1383 g->style = STYLE_DEFAULT;
1385 g->bitmaps = src_bitmaps;
1386 g->bitmap = src_bitmap;
1388 // optional zoom factor for scaling up the image to a larger size
1389 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1390 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1391 if (g->scale_up_factor < 1)
1392 g->scale_up_factor = 1; // no scaling
1394 // optional tile size for using non-standard image size
1395 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1397 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1400 // CHECK: should tile sizes less than standard tile size be allowed?
1401 if (g->tile_size < TILESIZE)
1402 g->tile_size = TILESIZE; // standard tile size
1405 // when setting tile size, also set width and height accordingly
1406 g->width = g->tile_size;
1407 g->height = g->tile_size;
1410 if (g->use_image_size)
1412 // set new default bitmap size (with scaling, but without small images)
1413 g->width = get_scaled_graphic_width(graphic);
1414 g->height = get_scaled_graphic_height(graphic);
1417 // optional width and height of each animation frame
1418 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1419 g->width = parameter[GFX_ARG_WIDTH];
1420 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1421 g->height = parameter[GFX_ARG_HEIGHT];
1423 // optional x and y tile position of animation frame sequence
1424 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1425 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1426 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1427 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1429 // optional x and y pixel position of animation frame sequence
1430 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1431 g->src_x = parameter[GFX_ARG_X];
1432 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1433 g->src_y = parameter[GFX_ARG_Y];
1440 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1441 g->width, getTokenFromImageID(graphic), TILEX);
1444 g->width = TILEX; // will be checked to be inside bitmap later
1450 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1451 g->height, getTokenFromImageID(graphic), TILEY);
1454 g->height = TILEY; // will be checked to be inside bitmap later
1460 // get final bitmap size (with scaling, but without small images)
1461 int src_image_width = get_scaled_graphic_width(graphic);
1462 int src_image_height = get_scaled_graphic_height(graphic);
1464 if (src_image_width == 0 || src_image_height == 0)
1466 // only happens when loaded outside artwork system (like "global.busy")
1467 src_image_width = src_bitmap->width;
1468 src_image_height = src_bitmap->height;
1471 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1473 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1474 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1478 anim_frames_per_row = MAX(1, src_image_width / g->width);
1479 anim_frames_per_col = MAX(1, src_image_height / g->height);
1482 g->src_image_width = src_image_width;
1483 g->src_image_height = src_image_height;
1486 // correct x or y offset dependent of vertical or horizontal frame order
1487 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1489 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1490 parameter[GFX_ARG_OFFSET] : g->height);
1491 anim_frames_per_line = anim_frames_per_col;
1493 else // frames are ordered horizontally
1495 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1496 parameter[GFX_ARG_OFFSET] : g->width);
1497 anim_frames_per_line = anim_frames_per_row;
1500 // optionally, the x and y offset of frames can be specified directly
1501 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1502 g->offset_x = parameter[GFX_ARG_XOFFSET];
1503 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1504 g->offset_y = parameter[GFX_ARG_YOFFSET];
1506 // optionally, moving animations may have separate start and end graphics
1507 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1509 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1510 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1512 // correct x or y offset2 dependent of vertical or horizontal frame order
1513 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1514 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1515 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1516 else // frames are ordered horizontally
1517 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1518 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1520 // optionally, the x and y offset of 2nd graphic can be specified directly
1521 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1522 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1523 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1524 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1526 // optionally, the second movement tile can be specified as start tile
1527 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1528 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1530 // automatically determine correct number of frames, if not defined
1531 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1532 g->anim_frames = parameter[GFX_ARG_FRAMES];
1533 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1534 g->anim_frames = anim_frames_per_row;
1535 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1536 g->anim_frames = anim_frames_per_col;
1540 if (g->anim_frames < 1) // frames must be at least 1
1543 g->anim_frames_per_line =
1544 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1545 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1547 g->anim_delay = parameter[GFX_ARG_DELAY];
1548 if (g->anim_delay < 1) // delay must be at least 1
1551 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1553 // automatically determine correct start frame, if not defined
1554 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1555 g->anim_start_frame = 0;
1556 else if (g->anim_mode & ANIM_REVERSE)
1557 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1559 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1561 // animation synchronized with global frame counter, not move position
1562 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1564 // animation synchronized with global anim frame counter, not move position
1565 g->anim_global_anim_sync = parameter[GFX_ARG_GLOBAL_ANIM_SYNC];
1567 // optional element for cloning crumble graphics
1568 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1569 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1571 // optional element for cloning digging graphics
1572 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1573 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1575 // optional border size for "crumbling" diggable graphics
1576 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1577 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1579 // used for global animations and player "boring" and "sleeping" actions
1580 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1581 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1582 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1583 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1584 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1585 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1586 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1587 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1588 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1589 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1590 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1591 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1593 // used for global animations
1594 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1595 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1596 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1597 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1598 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1599 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1600 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1601 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1602 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1603 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1604 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1605 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1606 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1607 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1609 // used for toon animations and global animations
1610 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1611 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1612 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1613 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1614 g->direction = parameter[GFX_ARG_DIRECTION];
1615 g->position = parameter[GFX_ARG_POSITION];
1616 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1617 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1619 if (g->step_delay < 1) // delay must be at least 1
1622 // this is only used for drawing font characters
1623 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1624 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1626 // use a different default value for global animations and toons
1627 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1628 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1629 g->draw_masked = TRUE;
1631 // this is used for drawing envelopes, global animations and toons
1632 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1633 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1635 // used for toon animations and global animations
1636 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1637 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1639 // optional graphic for cloning all graphics settings
1640 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1641 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1643 // optional settings for drawing title screens and title messages
1644 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1645 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1646 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1647 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1648 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1649 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1650 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1651 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1652 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1653 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1654 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1655 g->align = parameter[GFX_ARG_ALIGN];
1656 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1657 g->valign = parameter[GFX_ARG_VALIGN];
1658 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1659 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1661 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1662 g->class = parameter[GFX_ARG_CLASS];
1663 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1664 g->style = parameter[GFX_ARG_STYLE];
1666 // this is only used for drawing menu buttons and text
1667 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1668 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1669 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1670 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1673 static void set_graphic_parameters(int graphic)
1675 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1676 char **parameter_raw = image->parameter;
1677 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1678 int parameter[NUM_GFX_ARGS];
1681 // if fallback to default artwork is done, also use the default parameters
1682 if (image->fallback_to_default)
1683 parameter_raw = image->default_parameter;
1685 // get integer values from string parameters
1686 for (i = 0; i < NUM_GFX_ARGS; i++)
1687 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1688 image_config_suffix[i].token,
1689 image_config_suffix[i].type);
1691 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1693 UPDATE_BUSY_STATE();
1696 static void set_cloned_graphic_parameters(int graphic)
1698 int fallback_graphic = IMG_CHAR_EXCLAM;
1699 int max_num_images = getImageListSize();
1700 int clone_graphic = graphic_info[graphic].clone_from;
1701 int num_references_followed = 1;
1703 while (graphic_info[clone_graphic].clone_from != -1 &&
1704 num_references_followed < max_num_images)
1706 clone_graphic = graphic_info[clone_graphic].clone_from;
1708 num_references_followed++;
1711 if (num_references_followed >= max_num_images)
1714 Warn("error found in config file:");
1715 Warn("- config file: '%s'", getImageConfigFilename());
1716 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1717 Warn("error: loop discovered when resolving cloned graphics");
1718 Warn("custom graphic rejected for this element/action");
1720 if (graphic == fallback_graphic)
1721 Fail("no fallback graphic available");
1723 Warn("fallback done to 'char_exclam' for this graphic");
1726 graphic_info[graphic] = graphic_info[fallback_graphic];
1730 graphic_info[graphic] = graphic_info[clone_graphic];
1731 graphic_info[graphic].clone_from = clone_graphic;
1735 static void InitGraphicInfo(void)
1737 int fallback_graphic = IMG_CHAR_EXCLAM;
1738 int num_images = getImageListSize();
1741 // use image size as default values for width and height for these images
1742 static int full_size_graphics[] =
1745 IMG_GLOBAL_BORDER_MAIN,
1746 IMG_GLOBAL_BORDER_SCORES,
1747 IMG_GLOBAL_BORDER_EDITOR,
1748 IMG_GLOBAL_BORDER_PLAYING,
1751 IMG_BACKGROUND_ENVELOPE_1,
1752 IMG_BACKGROUND_ENVELOPE_2,
1753 IMG_BACKGROUND_ENVELOPE_3,
1754 IMG_BACKGROUND_ENVELOPE_4,
1755 IMG_BACKGROUND_REQUEST,
1758 IMG_BACKGROUND_LOADING_INITIAL,
1759 IMG_BACKGROUND_LOADING,
1760 IMG_BACKGROUND_TITLE_INITIAL,
1761 IMG_BACKGROUND_TITLE,
1762 IMG_BACKGROUND_MAIN,
1763 IMG_BACKGROUND_NAMES,
1764 IMG_BACKGROUND_LEVELS,
1765 IMG_BACKGROUND_LEVELNR,
1766 IMG_BACKGROUND_SCORES,
1767 IMG_BACKGROUND_SCOREINFO,
1768 IMG_BACKGROUND_EDITOR,
1769 IMG_BACKGROUND_INFO,
1770 IMG_BACKGROUND_INFO_ELEMENTS,
1771 IMG_BACKGROUND_INFO_MUSIC,
1772 IMG_BACKGROUND_INFO_CREDITS,
1773 IMG_BACKGROUND_INFO_PROGRAM,
1774 IMG_BACKGROUND_INFO_VERSION,
1775 IMG_BACKGROUND_INFO_LEVELSET,
1776 IMG_BACKGROUND_SETUP,
1777 IMG_BACKGROUND_PLAYING,
1778 IMG_BACKGROUND_DOOR,
1779 IMG_BACKGROUND_TAPE,
1780 IMG_BACKGROUND_PANEL,
1781 IMG_BACKGROUND_PALETTE,
1782 IMG_BACKGROUND_TOOLBOX,
1784 IMG_TITLESCREEN_INITIAL_1,
1785 IMG_TITLESCREEN_INITIAL_2,
1786 IMG_TITLESCREEN_INITIAL_3,
1787 IMG_TITLESCREEN_INITIAL_4,
1788 IMG_TITLESCREEN_INITIAL_5,
1795 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1796 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1797 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1798 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1799 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1800 IMG_BACKGROUND_TITLEMESSAGE_1,
1801 IMG_BACKGROUND_TITLEMESSAGE_2,
1802 IMG_BACKGROUND_TITLEMESSAGE_3,
1803 IMG_BACKGROUND_TITLEMESSAGE_4,
1804 IMG_BACKGROUND_TITLEMESSAGE_5,
1809 FreeGlobalAnimEventInfo();
1811 checked_free(graphic_info);
1813 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1815 // initialize "use_image_size" flag with default value
1816 for (i = 0; i < num_images; i++)
1817 graphic_info[i].use_image_size = FALSE;
1819 // initialize "use_image_size" flag from static configuration above
1820 for (i = 0; full_size_graphics[i] != -1; i++)
1821 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1823 // first set all graphic paramaters ...
1824 for (i = 0; i < num_images; i++)
1825 set_graphic_parameters(i);
1827 // ... then copy these parameters for cloned graphics
1828 for (i = 0; i < num_images; i++)
1829 if (graphic_info[i].clone_from != -1)
1830 set_cloned_graphic_parameters(i);
1832 for (i = 0; i < num_images; i++)
1834 Bitmap *src_bitmap = graphic_info[i].bitmap;
1838 int src_bitmap_width, src_bitmap_height;
1840 // now check if no animation frames are outside of the loaded image
1842 if (graphic_info[i].bitmap == NULL)
1843 continue; // skip check for optional images that are undefined
1845 // get image size (this can differ from the standard element tile size!)
1846 width = graphic_info[i].width;
1847 height = graphic_info[i].height;
1849 // get final bitmap size (with scaling, but without small images)
1850 src_bitmap_width = graphic_info[i].src_image_width;
1851 src_bitmap_height = graphic_info[i].src_image_height;
1853 // check if first animation frame is inside specified bitmap
1855 // do not use getGraphicSourceXY() here to get position of first frame;
1856 // this avoids calculating wrong start position for out-of-bounds frame
1857 src_x = graphic_info[i].src_x;
1858 src_y = graphic_info[i].src_y;
1860 if (program.headless)
1863 if (src_x < 0 || src_y < 0 ||
1864 src_x + width > src_bitmap_width ||
1865 src_y + height > src_bitmap_height)
1868 Warn("error found in config file:");
1869 Warn("- config file: '%s'", getImageConfigFilename());
1870 Warn("- config token: '%s'", getTokenFromImageID(i));
1871 Warn("- image file: '%s'", src_bitmap->source_filename);
1872 Warn("- frame size: %d, %d", width, height);
1873 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1874 src_x, src_y, src_bitmap_width, src_bitmap_height);
1875 Warn("custom graphic rejected for this element/action");
1877 if (i == fallback_graphic)
1878 Fail("no fallback graphic available");
1880 Warn("fallback done to 'char_exclam' for this graphic");
1883 graphic_info[i] = graphic_info[fallback_graphic];
1885 // if first frame out of bounds, do not check last frame anymore
1889 // check if last animation frame is inside specified bitmap
1891 last_frame = graphic_info[i].anim_frames - 1;
1892 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1894 if (src_x < 0 || src_y < 0 ||
1895 src_x + width > src_bitmap_width ||
1896 src_y + height > src_bitmap_height)
1899 Warn("error found in config file:");
1900 Warn("- config file: '%s'", getImageConfigFilename());
1901 Warn("- config token: '%s'", getTokenFromImageID(i));
1902 Warn("- image file: '%s'", src_bitmap->source_filename);
1903 Warn("- frame size: %d, %d", width, height);
1904 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1905 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1906 Warn("custom graphic rejected for this element/action");
1908 if (i == fallback_graphic)
1909 Fail("no fallback graphic available");
1911 Warn("fallback done to 'char_exclam' for this graphic");
1914 graphic_info[i] = graphic_info[fallback_graphic];
1919 static void InitGraphicCompatibilityInfo(void)
1921 struct FileInfo *fi_global_door =
1922 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1923 int num_images = getImageListSize();
1926 /* the following compatibility handling is needed for the following case:
1927 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1928 graphics mainly used for door and panel graphics, like editor, tape and
1929 in-game buttons with hard-coded bitmap positions and button sizes; as
1930 these graphics now have individual definitions, redefining "global.door"
1931 to change all these graphics at once like before does not work anymore
1932 (because all those individual definitions still have their default values);
1933 to solve this, remap all those individual definitions that are not
1934 redefined to the new bitmap of "global.door" if it was redefined */
1936 // special compatibility handling if image "global.door" was redefined
1937 if (fi_global_door->redefined)
1939 for (i = 0; i < num_images; i++)
1941 struct FileInfo *fi = getImageListEntryFromImageID(i);
1943 // process only those images that still use the default settings
1946 // process all images which default to same image as "global.door"
1947 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1949 // skip all images that are cloned from images that default to same
1950 // image as "global.door", but that are redefined to something else
1951 if (graphic_info[i].clone_from != -1)
1953 int cloned_graphic = graphic_info[i].clone_from;
1955 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
1960 Debug("init:InitGraphicCompatibilityInfo",
1961 "special treatment needed for token '%s'", fi->token);
1964 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1965 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1971 // special compatibility handling for "Snake Bite" graphics set
1972 if (strPrefix(leveldir_current->identifier, "snake_bite"))
1974 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
1976 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
1977 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
1979 ClearRectangle(bitmap, 2, 66, 32, 480);
1980 ClearRectangle(bitmap, 514, 66, 32, 480);
1983 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
1984 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
1985 if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
2003 int mode_old = GAME_MODE_SCORES;
2004 int mode_new = GAME_MODE_SCOREINFO;
2007 // adjust title screens on score info page
2008 for (i = 0; font_title[i] != -1; i++)
2010 struct FontInfo *fi = &font_info[font_title[i]];
2012 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
2013 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2016 // adjust vertical text and button positions on scores page
2017 for (i = 0; font_text[i] != -1; i++)
2019 for (j = 0; j < 2; j++)
2021 boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2022 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2023 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2024 int font_yoffset = (jue0 ? 10 : 5);
2026 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2030 // adjust page offsets on score info page
2031 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2032 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2035 InitGraphicCompatibilityInfo_Doors();
2038 static void InitElementSoundInfo(void)
2040 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2041 int num_property_mappings = getSoundListPropertyMappingSize();
2044 // set values to -1 to identify later as "uninitialized" values
2045 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2046 for (act = 0; act < NUM_ACTIONS; act++)
2047 element_info[i].sound[act] = -1;
2049 // initialize element/sound mapping from static configuration
2050 for (i = 0; element_to_sound[i].element > -1; i++)
2052 int element = element_to_sound[i].element;
2053 int action = element_to_sound[i].action;
2054 int sound = element_to_sound[i].sound;
2055 boolean is_class = element_to_sound[i].is_class;
2058 action = ACTION_DEFAULT;
2061 element_info[element].sound[action] = sound;
2063 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2064 if (strEqual(element_info[j].class_name,
2065 element_info[element].class_name))
2066 element_info[j].sound[action] = sound;
2069 // initialize element class/sound mapping from dynamic configuration
2070 for (i = 0; i < num_property_mappings; i++)
2072 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2073 int action = property_mapping[i].ext1_index;
2074 int sound = property_mapping[i].artwork_index;
2076 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2080 action = ACTION_DEFAULT;
2082 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2083 if (strEqual(element_info[j].class_name,
2084 element_info[element_class].class_name))
2085 element_info[j].sound[action] = sound;
2088 // initialize element/sound mapping from dynamic configuration
2089 for (i = 0; i < num_property_mappings; i++)
2091 int element = property_mapping[i].base_index;
2092 int action = property_mapping[i].ext1_index;
2093 int sound = property_mapping[i].artwork_index;
2095 if (element >= MAX_NUM_ELEMENTS)
2099 action = ACTION_DEFAULT;
2101 element_info[element].sound[action] = sound;
2104 // now set all '-1' values to element specific default values
2105 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2107 for (act = 0; act < NUM_ACTIONS; act++)
2109 // generic default action sound (defined by "[default]" directive)
2110 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2112 // look for special default action sound (classic game specific)
2113 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2114 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2115 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2116 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2117 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2118 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2119 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2120 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2122 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2123 // !!! make this better !!!
2124 if (i == EL_EMPTY_SPACE)
2125 default_action_sound = element_info[EL_DEFAULT].sound[act];
2127 // no sound for this specific action -- use default action sound
2128 if (element_info[i].sound[act] == -1)
2129 element_info[i].sound[act] = default_action_sound;
2133 // copy sound settings to some elements that are only stored in level file
2134 // in native R'n'D levels, but are used by game engine in native EM levels
2135 for (i = 0; copy_properties[i][0] != -1; i++)
2136 for (j = 1; j <= 4; j++)
2137 for (act = 0; act < NUM_ACTIONS; act++)
2138 element_info[copy_properties[i][j]].sound[act] =
2139 element_info[copy_properties[i][0]].sound[act];
2142 static void InitGameModeSoundInfo(void)
2146 // set values to -1 to identify later as "uninitialized" values
2147 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2150 // initialize gamemode/sound mapping from static configuration
2151 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2153 int gamemode = gamemode_to_sound[i].gamemode;
2154 int sound = gamemode_to_sound[i].sound;
2157 gamemode = GAME_MODE_DEFAULT;
2159 menu.sound[gamemode] = sound;
2162 // now set all '-1' values to levelset specific default values
2163 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2164 if (menu.sound[i] == -1)
2165 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2168 static void set_sound_parameters(int sound, char **parameter_raw)
2170 int parameter[NUM_SND_ARGS];
2173 // get integer values from string parameters
2174 for (i = 0; i < NUM_SND_ARGS; i++)
2176 get_parameter_value(parameter_raw[i],
2177 sound_config_suffix[i].token,
2178 sound_config_suffix[i].type);
2180 // explicit loop mode setting in configuration overrides default value
2181 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2182 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2184 // sound volume to change the original volume when loading the sound file
2185 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2187 // sound priority to give certain sounds a higher or lower priority
2188 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2191 static void InitSoundInfo(void)
2193 int *sound_effect_properties;
2194 int num_sounds = getSoundListSize();
2197 checked_free(sound_info);
2199 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2200 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2202 // initialize sound effect for all elements to "no sound"
2203 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2204 for (j = 0; j < NUM_ACTIONS; j++)
2205 element_info[i].sound[j] = SND_UNDEFINED;
2207 for (i = 0; i < num_sounds; i++)
2209 struct FileInfo *sound = getSoundListEntry(i);
2210 int len_effect_text = strlen(sound->token);
2212 sound_effect_properties[i] = ACTION_OTHER;
2213 sound_info[i].loop = FALSE; // default: play sound only once
2215 // determine all loop sounds and identify certain sound classes
2217 for (j = 0; element_action_info[j].suffix; j++)
2219 int len_action_text = strlen(element_action_info[j].suffix);
2221 if (len_action_text < len_effect_text &&
2222 strEqual(&sound->token[len_effect_text - len_action_text],
2223 element_action_info[j].suffix))
2225 sound_effect_properties[i] = element_action_info[j].value;
2226 sound_info[i].loop = element_action_info[j].is_loop_sound;
2232 // associate elements and some selected sound actions
2234 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2236 if (element_info[j].class_name)
2238 int len_class_text = strlen(element_info[j].class_name);
2240 if (len_class_text + 1 < len_effect_text &&
2241 strncmp(sound->token,
2242 element_info[j].class_name, len_class_text) == 0 &&
2243 sound->token[len_class_text] == '.')
2245 int sound_action_value = sound_effect_properties[i];
2247 element_info[j].sound[sound_action_value] = i;
2252 set_sound_parameters(i, sound->parameter);
2255 free(sound_effect_properties);
2258 static void InitGameModeMusicInfo(void)
2260 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2261 int num_property_mappings = getMusicListPropertyMappingSize();
2262 int default_levelset_music = -1;
2265 // set values to -1 to identify later as "uninitialized" values
2266 for (i = 0; i < MAX_LEVELS; i++)
2267 levelset.music[i] = -1;
2268 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2271 // initialize gamemode/music mapping from static configuration
2272 for (i = 0; gamemode_to_music[i].music > -1; i++)
2274 int gamemode = gamemode_to_music[i].gamemode;
2275 int music = gamemode_to_music[i].music;
2278 gamemode = GAME_MODE_DEFAULT;
2280 menu.music[gamemode] = music;
2283 // initialize gamemode/music mapping from dynamic configuration
2284 for (i = 0; i < num_property_mappings; i++)
2286 int prefix = property_mapping[i].base_index;
2287 int gamemode = property_mapping[i].ext2_index;
2288 int level = property_mapping[i].ext3_index;
2289 int music = property_mapping[i].artwork_index;
2291 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2295 gamemode = GAME_MODE_DEFAULT;
2297 // level specific music only allowed for in-game music
2298 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2299 gamemode = GAME_MODE_PLAYING;
2304 default_levelset_music = music;
2307 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2308 levelset.music[level] = music;
2309 if (gamemode != GAME_MODE_PLAYING)
2310 menu.music[gamemode] = music;
2313 // now set all '-1' values to menu specific default values
2314 // (undefined values of "levelset.music[]" might stay at "-1" to
2315 // allow dynamic selection of music files from music directory!)
2316 for (i = 0; i < MAX_LEVELS; i++)
2317 if (levelset.music[i] == -1)
2318 levelset.music[i] = default_levelset_music;
2319 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2320 if (menu.music[i] == -1)
2321 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2324 static void set_music_parameters(int music, char **parameter_raw)
2326 int parameter[NUM_MUS_ARGS];
2329 // get integer values from string parameters
2330 for (i = 0; i < NUM_MUS_ARGS; i++)
2332 get_parameter_value(parameter_raw[i],
2333 music_config_suffix[i].token,
2334 music_config_suffix[i].type);
2336 // explicit loop mode setting in configuration overrides default value
2337 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2338 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2341 static void InitMusicInfo(void)
2343 int num_music = getMusicListSize();
2346 checked_free(music_info);
2348 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2350 for (i = 0; i < num_music; i++)
2352 struct FileInfo *music = getMusicListEntry(i);
2353 int len_music_text = strlen(music->token);
2355 music_info[i].loop = TRUE; // default: play music in loop mode
2357 // determine all loop music
2359 for (j = 0; music_prefix_info[j].prefix; j++)
2361 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2363 if (len_prefix_text < len_music_text &&
2364 strncmp(music->token,
2365 music_prefix_info[j].prefix, len_prefix_text) == 0)
2367 music_info[i].loop = music_prefix_info[j].is_loop_music;
2373 set_music_parameters(i, music->parameter);
2378 static void InitGameInfoFromArtworkInfo(void)
2380 // special case: store initial value of custom artwork setting
2381 game.use_masked_elements_initial = game.use_masked_elements;
2384 static void ReinitializeGraphics(void)
2386 print_timestamp_init("ReinitializeGraphics");
2388 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2390 InitGraphicInfo(); // graphic properties mapping
2391 print_timestamp_time("InitGraphicInfo");
2392 InitElementGraphicInfo(); // element game graphic mapping
2393 print_timestamp_time("InitElementGraphicInfo");
2394 InitElementSpecialGraphicInfo(); // element special graphic mapping
2395 print_timestamp_time("InitElementSpecialGraphicInfo");
2397 InitElementSmallImages(); // scale elements to all needed sizes
2398 print_timestamp_time("InitElementSmallImages");
2399 InitScaledImages(); // scale all other images, if needed
2400 print_timestamp_time("InitScaledImages");
2401 InitBitmapPointers(); // set standard size bitmap pointers
2402 print_timestamp_time("InitBitmapPointers");
2403 InitFontGraphicInfo(); // initialize text drawing functions
2404 print_timestamp_time("InitFontGraphicInfo");
2405 InitGlobalAnimGraphicInfo(); // initialize global animation config
2406 print_timestamp_time("InitGlobalAnimGraphicInfo");
2408 InitImageTextures(); // create textures for certain images
2409 print_timestamp_time("InitImageTextures");
2411 InitGraphicInfo_EM(); // graphic mapping for EM engine
2412 print_timestamp_time("InitGraphicInfo_EM");
2414 InitGraphicCompatibilityInfo();
2415 print_timestamp_time("InitGraphicCompatibilityInfo");
2418 print_timestamp_time("InitGadgets");
2420 print_timestamp_time("InitDoors");
2422 InitGameInfoFromArtworkInfo();
2424 print_timestamp_done("ReinitializeGraphics");
2427 static void ReinitializeSounds(void)
2429 InitSoundInfo(); // sound properties mapping
2430 InitElementSoundInfo(); // element game sound mapping
2431 InitGameModeSoundInfo(); // game mode sound mapping
2432 InitGlobalAnimSoundInfo(); // global animation sound settings
2434 InitPlayLevelSound(); // internal game sound settings
2437 static void ReinitializeMusic(void)
2439 InitMusicInfo(); // music properties mapping
2440 InitGameModeMusicInfo(); // game mode music mapping
2441 InitGlobalAnimMusicInfo(); // global animation music settings
2444 static int get_special_property_bit(int element, int property_bit_nr)
2446 struct PropertyBitInfo
2452 static struct PropertyBitInfo pb_can_move_into_acid[] =
2454 // the player may be able fall into acid when gravity is activated
2459 { EL_SP_MURPHY, 0 },
2460 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2462 // all elements that can move may be able to also move into acid
2465 { EL_BUG_RIGHT, 1 },
2468 { EL_SPACESHIP, 2 },
2469 { EL_SPACESHIP_LEFT, 2 },
2470 { EL_SPACESHIP_RIGHT, 2 },
2471 { EL_SPACESHIP_UP, 2 },
2472 { EL_SPACESHIP_DOWN, 2 },
2473 { EL_BD_BUTTERFLY, 3 },
2474 { EL_BD_BUTTERFLY_LEFT, 3 },
2475 { EL_BD_BUTTERFLY_RIGHT, 3 },
2476 { EL_BD_BUTTERFLY_UP, 3 },
2477 { EL_BD_BUTTERFLY_DOWN, 3 },
2478 { EL_BD_FIREFLY, 4 },
2479 { EL_BD_FIREFLY_LEFT, 4 },
2480 { EL_BD_FIREFLY_RIGHT, 4 },
2481 { EL_BD_FIREFLY_UP, 4 },
2482 { EL_BD_FIREFLY_DOWN, 4 },
2484 { EL_YAMYAM_LEFT, 5 },
2485 { EL_YAMYAM_RIGHT, 5 },
2486 { EL_YAMYAM_UP, 5 },
2487 { EL_YAMYAM_DOWN, 5 },
2488 { EL_DARK_YAMYAM, 6 },
2491 { EL_PACMAN_LEFT, 8 },
2492 { EL_PACMAN_RIGHT, 8 },
2493 { EL_PACMAN_UP, 8 },
2494 { EL_PACMAN_DOWN, 8 },
2496 { EL_MOLE_LEFT, 9 },
2497 { EL_MOLE_RIGHT, 9 },
2499 { EL_MOLE_DOWN, 9 },
2503 { EL_SATELLITE, 13 },
2504 { EL_SP_SNIKSNAK, 14 },
2505 { EL_SP_ELECTRON, 15 },
2508 { EL_SPRING_LEFT, 17 },
2509 { EL_SPRING_RIGHT, 17 },
2510 { EL_EMC_ANDROID, 18 },
2515 static struct PropertyBitInfo pb_dont_collide_with[] =
2517 { EL_SP_SNIKSNAK, 0 },
2518 { EL_SP_ELECTRON, 1 },
2526 struct PropertyBitInfo *pb_info;
2529 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2530 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2535 struct PropertyBitInfo *pb_info = NULL;
2538 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2539 if (pb_definition[i].bit_nr == property_bit_nr)
2540 pb_info = pb_definition[i].pb_info;
2542 if (pb_info == NULL)
2545 for (i = 0; pb_info[i].element != -1; i++)
2546 if (pb_info[i].element == element)
2547 return pb_info[i].bit_nr;
2552 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2553 boolean property_value)
2555 int bit_nr = get_special_property_bit(element, property_bit_nr);
2560 *bitfield |= (1 << bit_nr);
2562 *bitfield &= ~(1 << bit_nr);
2566 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2568 int bit_nr = get_special_property_bit(element, property_bit_nr);
2571 return ((*bitfield & (1 << bit_nr)) != 0);
2576 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2578 static int group_nr;
2579 static struct ElementGroupInfo *group;
2580 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2583 if (actual_group == NULL) // not yet initialized
2586 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2588 Warn("recursion too deep when resolving group element %d",
2589 group_element - EL_GROUP_START + 1);
2591 // replace element which caused too deep recursion by question mark
2592 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2597 if (recursion_depth == 0) // initialization
2599 group = actual_group;
2600 group_nr = GROUP_NR(group_element);
2602 group->num_elements_resolved = 0;
2603 group->choice_pos = 0;
2605 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2606 element_info[i].in_group[group_nr] = FALSE;
2609 for (i = 0; i < actual_group->num_elements; i++)
2611 int element = actual_group->element[i];
2613 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2616 if (IS_GROUP_ELEMENT(element))
2617 ResolveGroupElementExt(element, recursion_depth + 1);
2620 group->element_resolved[group->num_elements_resolved++] = element;
2621 element_info[element].in_group[group_nr] = TRUE;
2626 void ResolveGroupElement(int group_element)
2628 ResolveGroupElementExt(group_element, 0);
2631 void InitElementPropertiesStatic(void)
2633 static boolean clipboard_elements_initialized = FALSE;
2635 static int ep_diggable[] =
2640 EL_SP_BUGGY_BASE_ACTIVATING,
2643 EL_INVISIBLE_SAND_ACTIVE,
2646 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2647 // (if amoeba can grow into anything diggable, maybe keep these out)
2652 EL_SP_BUGGY_BASE_ACTIVE,
2659 static int ep_collectible_only[] =
2681 EL_DYNABOMB_INCREASE_NUMBER,
2682 EL_DYNABOMB_INCREASE_SIZE,
2683 EL_DYNABOMB_INCREASE_POWER,
2701 // !!! handle separately !!!
2702 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2708 static int ep_dont_run_into[] =
2710 // same elements as in 'ep_dont_touch'
2716 // same elements as in 'ep_dont_collide_with'
2728 // !!! maybe this should better be handled by 'ep_diggable' !!!
2733 EL_SP_BUGGY_BASE_ACTIVE,
2740 static int ep_dont_collide_with[] =
2742 // same elements as in 'ep_dont_touch'
2759 static int ep_dont_touch[] =
2769 static int ep_indestructible[] =
2773 EL_ACID_POOL_TOPLEFT,
2774 EL_ACID_POOL_TOPRIGHT,
2775 EL_ACID_POOL_BOTTOMLEFT,
2776 EL_ACID_POOL_BOTTOM,
2777 EL_ACID_POOL_BOTTOMRIGHT,
2778 EL_SP_HARDWARE_GRAY,
2779 EL_SP_HARDWARE_GREEN,
2780 EL_SP_HARDWARE_BLUE,
2782 EL_SP_HARDWARE_YELLOW,
2783 EL_SP_HARDWARE_BASE_1,
2784 EL_SP_HARDWARE_BASE_2,
2785 EL_SP_HARDWARE_BASE_3,
2786 EL_SP_HARDWARE_BASE_4,
2787 EL_SP_HARDWARE_BASE_5,
2788 EL_SP_HARDWARE_BASE_6,
2789 EL_INVISIBLE_STEELWALL,
2790 EL_INVISIBLE_STEELWALL_ACTIVE,
2791 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2792 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2793 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2794 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2795 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2796 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2797 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2798 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2799 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2800 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2801 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2802 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2804 EL_LIGHT_SWITCH_ACTIVE,
2805 EL_SIGN_EXCLAMATION,
2806 EL_SIGN_RADIOACTIVITY,
2813 EL_SIGN_ENTRY_FORBIDDEN,
2814 EL_SIGN_EMERGENCY_EXIT,
2822 EL_STEEL_EXIT_CLOSED,
2824 EL_STEEL_EXIT_OPENING,
2825 EL_STEEL_EXIT_CLOSING,
2826 EL_EM_STEEL_EXIT_CLOSED,
2827 EL_EM_STEEL_EXIT_OPEN,
2828 EL_EM_STEEL_EXIT_OPENING,
2829 EL_EM_STEEL_EXIT_CLOSING,
2830 EL_DC_STEELWALL_1_LEFT,
2831 EL_DC_STEELWALL_1_RIGHT,
2832 EL_DC_STEELWALL_1_TOP,
2833 EL_DC_STEELWALL_1_BOTTOM,
2834 EL_DC_STEELWALL_1_HORIZONTAL,
2835 EL_DC_STEELWALL_1_VERTICAL,
2836 EL_DC_STEELWALL_1_TOPLEFT,
2837 EL_DC_STEELWALL_1_TOPRIGHT,
2838 EL_DC_STEELWALL_1_BOTTOMLEFT,
2839 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2840 EL_DC_STEELWALL_1_TOPLEFT_2,
2841 EL_DC_STEELWALL_1_TOPRIGHT_2,
2842 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2843 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2844 EL_DC_STEELWALL_2_LEFT,
2845 EL_DC_STEELWALL_2_RIGHT,
2846 EL_DC_STEELWALL_2_TOP,
2847 EL_DC_STEELWALL_2_BOTTOM,
2848 EL_DC_STEELWALL_2_HORIZONTAL,
2849 EL_DC_STEELWALL_2_VERTICAL,
2850 EL_DC_STEELWALL_2_MIDDLE,
2851 EL_DC_STEELWALL_2_SINGLE,
2852 EL_STEELWALL_SLIPPERY,
2866 EL_GATE_1_GRAY_ACTIVE,
2867 EL_GATE_2_GRAY_ACTIVE,
2868 EL_GATE_3_GRAY_ACTIVE,
2869 EL_GATE_4_GRAY_ACTIVE,
2878 EL_EM_GATE_1_GRAY_ACTIVE,
2879 EL_EM_GATE_2_GRAY_ACTIVE,
2880 EL_EM_GATE_3_GRAY_ACTIVE,
2881 EL_EM_GATE_4_GRAY_ACTIVE,
2890 EL_EMC_GATE_5_GRAY_ACTIVE,
2891 EL_EMC_GATE_6_GRAY_ACTIVE,
2892 EL_EMC_GATE_7_GRAY_ACTIVE,
2893 EL_EMC_GATE_8_GRAY_ACTIVE,
2895 EL_DC_GATE_WHITE_GRAY,
2896 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2897 EL_DC_GATE_FAKE_GRAY,
2899 EL_SWITCHGATE_OPENING,
2900 EL_SWITCHGATE_CLOSED,
2901 EL_SWITCHGATE_CLOSING,
2902 EL_DC_SWITCHGATE_SWITCH_UP,
2903 EL_DC_SWITCHGATE_SWITCH_DOWN,
2905 EL_TIMEGATE_OPENING,
2907 EL_TIMEGATE_CLOSING,
2908 EL_DC_TIMEGATE_SWITCH,
2909 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2913 EL_TUBE_VERTICAL_LEFT,
2914 EL_TUBE_VERTICAL_RIGHT,
2915 EL_TUBE_HORIZONTAL_UP,
2916 EL_TUBE_HORIZONTAL_DOWN,
2921 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2922 EL_EXPANDABLE_STEELWALL_VERTICAL,
2923 EL_EXPANDABLE_STEELWALL_ANY,
2928 static int ep_slippery[] =
2942 EL_ROBOT_WHEEL_ACTIVE,
2948 EL_ACID_POOL_TOPLEFT,
2949 EL_ACID_POOL_TOPRIGHT,
2959 EL_STEELWALL_SLIPPERY,
2962 EL_EMC_WALL_SLIPPERY_1,
2963 EL_EMC_WALL_SLIPPERY_2,
2964 EL_EMC_WALL_SLIPPERY_3,
2965 EL_EMC_WALL_SLIPPERY_4,
2967 EL_EMC_MAGIC_BALL_ACTIVE,
2972 static int ep_can_change[] =
2977 static int ep_can_move[] =
2979 // same elements as in 'pb_can_move_into_acid'
3002 static int ep_can_fall[] =
3017 EL_QUICKSAND_FAST_FULL,
3019 EL_BD_MAGIC_WALL_FULL,
3020 EL_DC_MAGIC_WALL_FULL,
3034 static int ep_can_smash_player[] =
3060 static int ep_can_smash_enemies[] =
3069 static int ep_can_smash_everything[] =
3078 static int ep_explodes_by_fire[] =
3080 // same elements as in 'ep_explodes_impact'
3085 // same elements as in 'ep_explodes_smashed'
3095 EL_EM_DYNAMITE_ACTIVE,
3096 EL_DYNABOMB_PLAYER_1_ACTIVE,
3097 EL_DYNABOMB_PLAYER_2_ACTIVE,
3098 EL_DYNABOMB_PLAYER_3_ACTIVE,
3099 EL_DYNABOMB_PLAYER_4_ACTIVE,
3100 EL_DYNABOMB_INCREASE_NUMBER,
3101 EL_DYNABOMB_INCREASE_SIZE,
3102 EL_DYNABOMB_INCREASE_POWER,
3103 EL_SP_DISK_RED_ACTIVE,
3117 static int ep_explodes_smashed[] =
3119 // same elements as in 'ep_explodes_impact'
3133 static int ep_explodes_impact[] =
3142 static int ep_walkable_over[] =
3162 EL_SOKOBAN_FIELD_EMPTY,
3169 EL_EM_STEEL_EXIT_OPEN,
3170 EL_EM_STEEL_EXIT_OPENING,
3179 EL_GATE_1_GRAY_ACTIVE,
3180 EL_GATE_2_GRAY_ACTIVE,
3181 EL_GATE_3_GRAY_ACTIVE,
3182 EL_GATE_4_GRAY_ACTIVE,
3190 static int ep_walkable_inside[] =
3195 EL_TUBE_VERTICAL_LEFT,
3196 EL_TUBE_VERTICAL_RIGHT,
3197 EL_TUBE_HORIZONTAL_UP,
3198 EL_TUBE_HORIZONTAL_DOWN,
3207 static int ep_walkable_under[] =
3212 static int ep_passable_over[] =
3222 EL_EM_GATE_1_GRAY_ACTIVE,
3223 EL_EM_GATE_2_GRAY_ACTIVE,
3224 EL_EM_GATE_3_GRAY_ACTIVE,
3225 EL_EM_GATE_4_GRAY_ACTIVE,
3234 EL_EMC_GATE_5_GRAY_ACTIVE,
3235 EL_EMC_GATE_6_GRAY_ACTIVE,
3236 EL_EMC_GATE_7_GRAY_ACTIVE,
3237 EL_EMC_GATE_8_GRAY_ACTIVE,
3239 EL_DC_GATE_WHITE_GRAY,
3240 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3247 static int ep_passable_inside[] =
3253 EL_SP_PORT_HORIZONTAL,
3254 EL_SP_PORT_VERTICAL,
3256 EL_SP_GRAVITY_PORT_LEFT,
3257 EL_SP_GRAVITY_PORT_RIGHT,
3258 EL_SP_GRAVITY_PORT_UP,
3259 EL_SP_GRAVITY_PORT_DOWN,
3260 EL_SP_GRAVITY_ON_PORT_LEFT,
3261 EL_SP_GRAVITY_ON_PORT_RIGHT,
3262 EL_SP_GRAVITY_ON_PORT_UP,
3263 EL_SP_GRAVITY_ON_PORT_DOWN,
3264 EL_SP_GRAVITY_OFF_PORT_LEFT,
3265 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3266 EL_SP_GRAVITY_OFF_PORT_UP,
3267 EL_SP_GRAVITY_OFF_PORT_DOWN,
3272 static int ep_passable_under[] =
3277 static int ep_droppable[] =
3282 static int ep_explodes_1x1_old[] =
3287 static int ep_pushable[] =
3299 EL_SOKOBAN_FIELD_FULL,
3308 static int ep_explodes_cross_old[] =
3313 static int ep_protected[] =
3315 // same elements as in 'ep_walkable_inside'
3319 EL_TUBE_VERTICAL_LEFT,
3320 EL_TUBE_VERTICAL_RIGHT,
3321 EL_TUBE_HORIZONTAL_UP,
3322 EL_TUBE_HORIZONTAL_DOWN,
3328 // same elements as in 'ep_passable_over'
3337 EL_EM_GATE_1_GRAY_ACTIVE,
3338 EL_EM_GATE_2_GRAY_ACTIVE,
3339 EL_EM_GATE_3_GRAY_ACTIVE,
3340 EL_EM_GATE_4_GRAY_ACTIVE,
3349 EL_EMC_GATE_5_GRAY_ACTIVE,
3350 EL_EMC_GATE_6_GRAY_ACTIVE,
3351 EL_EMC_GATE_7_GRAY_ACTIVE,
3352 EL_EMC_GATE_8_GRAY_ACTIVE,
3354 EL_DC_GATE_WHITE_GRAY,
3355 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3359 // same elements as in 'ep_passable_inside'
3364 EL_SP_PORT_HORIZONTAL,
3365 EL_SP_PORT_VERTICAL,
3367 EL_SP_GRAVITY_PORT_LEFT,
3368 EL_SP_GRAVITY_PORT_RIGHT,
3369 EL_SP_GRAVITY_PORT_UP,
3370 EL_SP_GRAVITY_PORT_DOWN,
3371 EL_SP_GRAVITY_ON_PORT_LEFT,
3372 EL_SP_GRAVITY_ON_PORT_RIGHT,
3373 EL_SP_GRAVITY_ON_PORT_UP,
3374 EL_SP_GRAVITY_ON_PORT_DOWN,
3375 EL_SP_GRAVITY_OFF_PORT_LEFT,
3376 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3377 EL_SP_GRAVITY_OFF_PORT_UP,
3378 EL_SP_GRAVITY_OFF_PORT_DOWN,
3383 static int ep_throwable[] =
3388 static int ep_can_explode[] =
3390 // same elements as in 'ep_explodes_impact'
3395 // same elements as in 'ep_explodes_smashed'
3401 // elements that can explode by explosion or by dragonfire
3405 EL_EM_DYNAMITE_ACTIVE,
3406 EL_DYNABOMB_PLAYER_1_ACTIVE,
3407 EL_DYNABOMB_PLAYER_2_ACTIVE,
3408 EL_DYNABOMB_PLAYER_3_ACTIVE,
3409 EL_DYNABOMB_PLAYER_4_ACTIVE,
3410 EL_DYNABOMB_INCREASE_NUMBER,
3411 EL_DYNABOMB_INCREASE_SIZE,
3412 EL_DYNABOMB_INCREASE_POWER,
3413 EL_SP_DISK_RED_ACTIVE,
3421 // elements that can explode only by explosion
3427 static int ep_gravity_reachable[] =
3433 EL_INVISIBLE_SAND_ACTIVE,
3438 EL_SP_PORT_HORIZONTAL,
3439 EL_SP_PORT_VERTICAL,
3441 EL_SP_GRAVITY_PORT_LEFT,
3442 EL_SP_GRAVITY_PORT_RIGHT,
3443 EL_SP_GRAVITY_PORT_UP,
3444 EL_SP_GRAVITY_PORT_DOWN,
3445 EL_SP_GRAVITY_ON_PORT_LEFT,
3446 EL_SP_GRAVITY_ON_PORT_RIGHT,
3447 EL_SP_GRAVITY_ON_PORT_UP,
3448 EL_SP_GRAVITY_ON_PORT_DOWN,
3449 EL_SP_GRAVITY_OFF_PORT_LEFT,
3450 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3451 EL_SP_GRAVITY_OFF_PORT_UP,
3452 EL_SP_GRAVITY_OFF_PORT_DOWN,
3458 static int ep_empty_space[] =
3481 static int ep_player[] =
3488 EL_SOKOBAN_FIELD_PLAYER,
3494 static int ep_can_pass_magic_wall[] =
3508 static int ep_can_pass_dc_magic_wall[] =
3524 static int ep_switchable[] =
3528 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3534 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3537 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3538 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3539 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3540 EL_SWITCHGATE_SWITCH_UP,
3541 EL_SWITCHGATE_SWITCH_DOWN,
3542 EL_DC_SWITCHGATE_SWITCH_UP,
3543 EL_DC_SWITCHGATE_SWITCH_DOWN,
3545 EL_LIGHT_SWITCH_ACTIVE,
3547 EL_DC_TIMEGATE_SWITCH,
3548 EL_BALLOON_SWITCH_LEFT,
3549 EL_BALLOON_SWITCH_RIGHT,
3550 EL_BALLOON_SWITCH_UP,
3551 EL_BALLOON_SWITCH_DOWN,
3552 EL_BALLOON_SWITCH_ANY,
3553 EL_BALLOON_SWITCH_NONE,
3556 EL_EMC_MAGIC_BALL_SWITCH,
3557 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3562 static int ep_bd_element[] =
3596 static int ep_sp_element[] =
3598 // should always be valid
3601 // standard classic Supaplex elements
3608 EL_SP_HARDWARE_GRAY,
3616 EL_SP_GRAVITY_PORT_RIGHT,
3617 EL_SP_GRAVITY_PORT_DOWN,
3618 EL_SP_GRAVITY_PORT_LEFT,
3619 EL_SP_GRAVITY_PORT_UP,
3624 EL_SP_PORT_VERTICAL,
3625 EL_SP_PORT_HORIZONTAL,
3631 EL_SP_HARDWARE_BASE_1,
3632 EL_SP_HARDWARE_GREEN,
3633 EL_SP_HARDWARE_BLUE,
3635 EL_SP_HARDWARE_YELLOW,
3636 EL_SP_HARDWARE_BASE_2,
3637 EL_SP_HARDWARE_BASE_3,
3638 EL_SP_HARDWARE_BASE_4,
3639 EL_SP_HARDWARE_BASE_5,
3640 EL_SP_HARDWARE_BASE_6,
3644 // additional elements that appeared in newer Supaplex levels
3647 // additional gravity port elements (not switching, but setting gravity)
3648 EL_SP_GRAVITY_ON_PORT_LEFT,
3649 EL_SP_GRAVITY_ON_PORT_RIGHT,
3650 EL_SP_GRAVITY_ON_PORT_UP,
3651 EL_SP_GRAVITY_ON_PORT_DOWN,
3652 EL_SP_GRAVITY_OFF_PORT_LEFT,
3653 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3654 EL_SP_GRAVITY_OFF_PORT_UP,
3655 EL_SP_GRAVITY_OFF_PORT_DOWN,
3657 // more than one Murphy in a level results in an inactive clone
3660 // runtime Supaplex elements
3661 EL_SP_DISK_RED_ACTIVE,
3662 EL_SP_TERMINAL_ACTIVE,
3663 EL_SP_BUGGY_BASE_ACTIVATING,
3664 EL_SP_BUGGY_BASE_ACTIVE,
3671 static int ep_sb_element[] =
3676 EL_SOKOBAN_FIELD_EMPTY,
3677 EL_SOKOBAN_FIELD_FULL,
3678 EL_SOKOBAN_FIELD_PLAYER,
3683 EL_INVISIBLE_STEELWALL,
3688 static int ep_gem[] =
3700 static int ep_food_dark_yamyam[] =
3728 static int ep_food_penguin[] =
3742 static int ep_food_pig[] =
3754 static int ep_historic_wall[] =
3765 EL_GATE_1_GRAY_ACTIVE,
3766 EL_GATE_2_GRAY_ACTIVE,
3767 EL_GATE_3_GRAY_ACTIVE,
3768 EL_GATE_4_GRAY_ACTIVE,
3777 EL_EM_GATE_1_GRAY_ACTIVE,
3778 EL_EM_GATE_2_GRAY_ACTIVE,
3779 EL_EM_GATE_3_GRAY_ACTIVE,
3780 EL_EM_GATE_4_GRAY_ACTIVE,
3787 EL_EXPANDABLE_WALL_HORIZONTAL,
3788 EL_EXPANDABLE_WALL_VERTICAL,
3789 EL_EXPANDABLE_WALL_ANY,
3790 EL_EXPANDABLE_WALL_GROWING,
3791 EL_BD_EXPANDABLE_WALL,
3798 EL_SP_HARDWARE_GRAY,
3799 EL_SP_HARDWARE_GREEN,
3800 EL_SP_HARDWARE_BLUE,
3802 EL_SP_HARDWARE_YELLOW,
3803 EL_SP_HARDWARE_BASE_1,
3804 EL_SP_HARDWARE_BASE_2,
3805 EL_SP_HARDWARE_BASE_3,
3806 EL_SP_HARDWARE_BASE_4,
3807 EL_SP_HARDWARE_BASE_5,
3808 EL_SP_HARDWARE_BASE_6,
3810 EL_SP_TERMINAL_ACTIVE,
3813 EL_INVISIBLE_STEELWALL,
3814 EL_INVISIBLE_STEELWALL_ACTIVE,
3816 EL_INVISIBLE_WALL_ACTIVE,
3817 EL_STEELWALL_SLIPPERY,
3834 static int ep_historic_solid[] =
3838 EL_EXPANDABLE_WALL_HORIZONTAL,
3839 EL_EXPANDABLE_WALL_VERTICAL,
3840 EL_EXPANDABLE_WALL_ANY,
3841 EL_BD_EXPANDABLE_WALL,
3854 EL_QUICKSAND_FILLING,
3855 EL_QUICKSAND_EMPTYING,
3857 EL_MAGIC_WALL_ACTIVE,
3858 EL_MAGIC_WALL_EMPTYING,
3859 EL_MAGIC_WALL_FILLING,
3863 EL_BD_MAGIC_WALL_ACTIVE,
3864 EL_BD_MAGIC_WALL_EMPTYING,
3865 EL_BD_MAGIC_WALL_FULL,
3866 EL_BD_MAGIC_WALL_FILLING,
3867 EL_BD_MAGIC_WALL_DEAD,
3876 EL_SP_TERMINAL_ACTIVE,
3880 EL_INVISIBLE_WALL_ACTIVE,
3881 EL_SWITCHGATE_SWITCH_UP,
3882 EL_SWITCHGATE_SWITCH_DOWN,
3884 EL_TIMEGATE_SWITCH_ACTIVE,
3896 // the following elements are a direct copy of "indestructible" elements,
3897 // except "EL_ACID", which is "indestructible", but not "solid"!
3902 EL_ACID_POOL_TOPLEFT,
3903 EL_ACID_POOL_TOPRIGHT,
3904 EL_ACID_POOL_BOTTOMLEFT,
3905 EL_ACID_POOL_BOTTOM,
3906 EL_ACID_POOL_BOTTOMRIGHT,
3907 EL_SP_HARDWARE_GRAY,
3908 EL_SP_HARDWARE_GREEN,
3909 EL_SP_HARDWARE_BLUE,
3911 EL_SP_HARDWARE_YELLOW,
3912 EL_SP_HARDWARE_BASE_1,
3913 EL_SP_HARDWARE_BASE_2,
3914 EL_SP_HARDWARE_BASE_3,
3915 EL_SP_HARDWARE_BASE_4,
3916 EL_SP_HARDWARE_BASE_5,
3917 EL_SP_HARDWARE_BASE_6,
3918 EL_INVISIBLE_STEELWALL,
3919 EL_INVISIBLE_STEELWALL_ACTIVE,
3920 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3921 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3922 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3923 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3924 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3925 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3926 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3929 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3930 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3931 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3933 EL_LIGHT_SWITCH_ACTIVE,
3934 EL_SIGN_EXCLAMATION,
3935 EL_SIGN_RADIOACTIVITY,
3942 EL_SIGN_ENTRY_FORBIDDEN,
3943 EL_SIGN_EMERGENCY_EXIT,
3951 EL_STEEL_EXIT_CLOSED,
3953 EL_STEEL_EXIT_OPENING,
3954 EL_STEEL_EXIT_CLOSING,
3955 EL_EM_STEEL_EXIT_CLOSED,
3956 EL_EM_STEEL_EXIT_OPEN,
3957 EL_EM_STEEL_EXIT_OPENING,
3958 EL_EM_STEEL_EXIT_CLOSING,
3959 EL_DC_STEELWALL_1_LEFT,
3960 EL_DC_STEELWALL_1_RIGHT,
3961 EL_DC_STEELWALL_1_TOP,
3962 EL_DC_STEELWALL_1_BOTTOM,
3963 EL_DC_STEELWALL_1_HORIZONTAL,
3964 EL_DC_STEELWALL_1_VERTICAL,
3965 EL_DC_STEELWALL_1_TOPLEFT,
3966 EL_DC_STEELWALL_1_TOPRIGHT,
3967 EL_DC_STEELWALL_1_BOTTOMLEFT,
3968 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3969 EL_DC_STEELWALL_1_TOPLEFT_2,
3970 EL_DC_STEELWALL_1_TOPRIGHT_2,
3971 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3972 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3973 EL_DC_STEELWALL_2_LEFT,
3974 EL_DC_STEELWALL_2_RIGHT,
3975 EL_DC_STEELWALL_2_TOP,
3976 EL_DC_STEELWALL_2_BOTTOM,
3977 EL_DC_STEELWALL_2_HORIZONTAL,
3978 EL_DC_STEELWALL_2_VERTICAL,
3979 EL_DC_STEELWALL_2_MIDDLE,
3980 EL_DC_STEELWALL_2_SINGLE,
3981 EL_STEELWALL_SLIPPERY,
3995 EL_GATE_1_GRAY_ACTIVE,
3996 EL_GATE_2_GRAY_ACTIVE,
3997 EL_GATE_3_GRAY_ACTIVE,
3998 EL_GATE_4_GRAY_ACTIVE,
4007 EL_EM_GATE_1_GRAY_ACTIVE,
4008 EL_EM_GATE_2_GRAY_ACTIVE,
4009 EL_EM_GATE_3_GRAY_ACTIVE,
4010 EL_EM_GATE_4_GRAY_ACTIVE,
4019 EL_EMC_GATE_5_GRAY_ACTIVE,
4020 EL_EMC_GATE_6_GRAY_ACTIVE,
4021 EL_EMC_GATE_7_GRAY_ACTIVE,
4022 EL_EMC_GATE_8_GRAY_ACTIVE,
4024 EL_DC_GATE_WHITE_GRAY,
4025 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4026 EL_DC_GATE_FAKE_GRAY,
4028 EL_SWITCHGATE_OPENING,
4029 EL_SWITCHGATE_CLOSED,
4030 EL_SWITCHGATE_CLOSING,
4031 EL_DC_SWITCHGATE_SWITCH_UP,
4032 EL_DC_SWITCHGATE_SWITCH_DOWN,
4034 EL_TIMEGATE_OPENING,
4036 EL_TIMEGATE_CLOSING,
4037 EL_DC_TIMEGATE_SWITCH,
4038 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4042 EL_TUBE_VERTICAL_LEFT,
4043 EL_TUBE_VERTICAL_RIGHT,
4044 EL_TUBE_HORIZONTAL_UP,
4045 EL_TUBE_HORIZONTAL_DOWN,
4050 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4051 EL_EXPANDABLE_STEELWALL_VERTICAL,
4052 EL_EXPANDABLE_STEELWALL_ANY,
4057 static int ep_classic_enemy[] =
4074 static int ep_belt[] =
4076 EL_CONVEYOR_BELT_1_LEFT,
4077 EL_CONVEYOR_BELT_1_MIDDLE,
4078 EL_CONVEYOR_BELT_1_RIGHT,
4079 EL_CONVEYOR_BELT_2_LEFT,
4080 EL_CONVEYOR_BELT_2_MIDDLE,
4081 EL_CONVEYOR_BELT_2_RIGHT,
4082 EL_CONVEYOR_BELT_3_LEFT,
4083 EL_CONVEYOR_BELT_3_MIDDLE,
4084 EL_CONVEYOR_BELT_3_RIGHT,
4085 EL_CONVEYOR_BELT_4_LEFT,
4086 EL_CONVEYOR_BELT_4_MIDDLE,
4087 EL_CONVEYOR_BELT_4_RIGHT,
4092 static int ep_belt_active[] =
4094 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4095 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4096 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4097 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4098 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4099 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4100 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4101 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4102 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4103 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4104 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4105 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4110 static int ep_belt_switch[] =
4112 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4113 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4114 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4115 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4116 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4117 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4118 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4119 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4120 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4121 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4122 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4123 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4128 static int ep_tube[] =
4135 EL_TUBE_HORIZONTAL_UP,
4136 EL_TUBE_HORIZONTAL_DOWN,
4138 EL_TUBE_VERTICAL_LEFT,
4139 EL_TUBE_VERTICAL_RIGHT,
4145 static int ep_acid_pool[] =
4147 EL_ACID_POOL_TOPLEFT,
4148 EL_ACID_POOL_TOPRIGHT,
4149 EL_ACID_POOL_BOTTOMLEFT,
4150 EL_ACID_POOL_BOTTOM,
4151 EL_ACID_POOL_BOTTOMRIGHT,
4156 static int ep_keygate[] =
4166 EL_GATE_1_GRAY_ACTIVE,
4167 EL_GATE_2_GRAY_ACTIVE,
4168 EL_GATE_3_GRAY_ACTIVE,
4169 EL_GATE_4_GRAY_ACTIVE,
4178 EL_EM_GATE_1_GRAY_ACTIVE,
4179 EL_EM_GATE_2_GRAY_ACTIVE,
4180 EL_EM_GATE_3_GRAY_ACTIVE,
4181 EL_EM_GATE_4_GRAY_ACTIVE,
4190 EL_EMC_GATE_5_GRAY_ACTIVE,
4191 EL_EMC_GATE_6_GRAY_ACTIVE,
4192 EL_EMC_GATE_7_GRAY_ACTIVE,
4193 EL_EMC_GATE_8_GRAY_ACTIVE,
4195 EL_DC_GATE_WHITE_GRAY,
4196 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4201 static int ep_amoeboid[] =
4213 static int ep_amoebalive[] =
4224 static int ep_has_editor_content[] =
4230 EL_SOKOBAN_FIELD_PLAYER,
4247 static int ep_can_turn_each_move[] =
4249 // !!! do something with this one !!!
4253 static int ep_can_grow[] =
4267 static int ep_active_bomb[] =
4270 EL_EM_DYNAMITE_ACTIVE,
4271 EL_DYNABOMB_PLAYER_1_ACTIVE,
4272 EL_DYNABOMB_PLAYER_2_ACTIVE,
4273 EL_DYNABOMB_PLAYER_3_ACTIVE,
4274 EL_DYNABOMB_PLAYER_4_ACTIVE,
4275 EL_SP_DISK_RED_ACTIVE,
4280 static int ep_inactive[] =
4306 EL_QUICKSAND_FAST_EMPTY,
4329 EL_GATE_1_GRAY_ACTIVE,
4330 EL_GATE_2_GRAY_ACTIVE,
4331 EL_GATE_3_GRAY_ACTIVE,
4332 EL_GATE_4_GRAY_ACTIVE,
4341 EL_EM_GATE_1_GRAY_ACTIVE,
4342 EL_EM_GATE_2_GRAY_ACTIVE,
4343 EL_EM_GATE_3_GRAY_ACTIVE,
4344 EL_EM_GATE_4_GRAY_ACTIVE,
4353 EL_EMC_GATE_5_GRAY_ACTIVE,
4354 EL_EMC_GATE_6_GRAY_ACTIVE,
4355 EL_EMC_GATE_7_GRAY_ACTIVE,
4356 EL_EMC_GATE_8_GRAY_ACTIVE,
4358 EL_DC_GATE_WHITE_GRAY,
4359 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4360 EL_DC_GATE_FAKE_GRAY,
4363 EL_INVISIBLE_STEELWALL,
4371 EL_WALL_EMERALD_YELLOW,
4372 EL_DYNABOMB_INCREASE_NUMBER,
4373 EL_DYNABOMB_INCREASE_SIZE,
4374 EL_DYNABOMB_INCREASE_POWER,
4378 EL_SOKOBAN_FIELD_EMPTY,
4379 EL_SOKOBAN_FIELD_FULL,
4380 EL_WALL_EMERALD_RED,
4381 EL_WALL_EMERALD_PURPLE,
4382 EL_ACID_POOL_TOPLEFT,
4383 EL_ACID_POOL_TOPRIGHT,
4384 EL_ACID_POOL_BOTTOMLEFT,
4385 EL_ACID_POOL_BOTTOM,
4386 EL_ACID_POOL_BOTTOMRIGHT,
4390 EL_BD_MAGIC_WALL_DEAD,
4392 EL_DC_MAGIC_WALL_DEAD,
4393 EL_AMOEBA_TO_DIAMOND,
4401 EL_SP_GRAVITY_PORT_RIGHT,
4402 EL_SP_GRAVITY_PORT_DOWN,
4403 EL_SP_GRAVITY_PORT_LEFT,
4404 EL_SP_GRAVITY_PORT_UP,
4405 EL_SP_PORT_HORIZONTAL,
4406 EL_SP_PORT_VERTICAL,
4417 EL_SP_HARDWARE_GRAY,
4418 EL_SP_HARDWARE_GREEN,
4419 EL_SP_HARDWARE_BLUE,
4421 EL_SP_HARDWARE_YELLOW,
4422 EL_SP_HARDWARE_BASE_1,
4423 EL_SP_HARDWARE_BASE_2,
4424 EL_SP_HARDWARE_BASE_3,
4425 EL_SP_HARDWARE_BASE_4,
4426 EL_SP_HARDWARE_BASE_5,
4427 EL_SP_HARDWARE_BASE_6,
4428 EL_SP_GRAVITY_ON_PORT_LEFT,
4429 EL_SP_GRAVITY_ON_PORT_RIGHT,
4430 EL_SP_GRAVITY_ON_PORT_UP,
4431 EL_SP_GRAVITY_ON_PORT_DOWN,
4432 EL_SP_GRAVITY_OFF_PORT_LEFT,
4433 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4434 EL_SP_GRAVITY_OFF_PORT_UP,
4435 EL_SP_GRAVITY_OFF_PORT_DOWN,
4436 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4437 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4438 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4439 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4440 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4441 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4442 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4443 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4444 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4445 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4446 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4447 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4448 EL_SIGN_EXCLAMATION,
4449 EL_SIGN_RADIOACTIVITY,
4456 EL_SIGN_ENTRY_FORBIDDEN,
4457 EL_SIGN_EMERGENCY_EXIT,
4465 EL_DC_STEELWALL_1_LEFT,
4466 EL_DC_STEELWALL_1_RIGHT,
4467 EL_DC_STEELWALL_1_TOP,
4468 EL_DC_STEELWALL_1_BOTTOM,
4469 EL_DC_STEELWALL_1_HORIZONTAL,
4470 EL_DC_STEELWALL_1_VERTICAL,
4471 EL_DC_STEELWALL_1_TOPLEFT,
4472 EL_DC_STEELWALL_1_TOPRIGHT,
4473 EL_DC_STEELWALL_1_BOTTOMLEFT,
4474 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4475 EL_DC_STEELWALL_1_TOPLEFT_2,
4476 EL_DC_STEELWALL_1_TOPRIGHT_2,
4477 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4478 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4479 EL_DC_STEELWALL_2_LEFT,
4480 EL_DC_STEELWALL_2_RIGHT,
4481 EL_DC_STEELWALL_2_TOP,
4482 EL_DC_STEELWALL_2_BOTTOM,
4483 EL_DC_STEELWALL_2_HORIZONTAL,
4484 EL_DC_STEELWALL_2_VERTICAL,
4485 EL_DC_STEELWALL_2_MIDDLE,
4486 EL_DC_STEELWALL_2_SINGLE,
4487 EL_STEELWALL_SLIPPERY,
4492 EL_EMC_WALL_SLIPPERY_1,
4493 EL_EMC_WALL_SLIPPERY_2,
4494 EL_EMC_WALL_SLIPPERY_3,
4495 EL_EMC_WALL_SLIPPERY_4,
4516 static int ep_em_slippery_wall[] =
4521 static int ep_gfx_crumbled[] =
4532 static int ep_editor_cascade_active[] =
4534 EL_INTERNAL_CASCADE_BD_ACTIVE,
4535 EL_INTERNAL_CASCADE_EM_ACTIVE,
4536 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4537 EL_INTERNAL_CASCADE_RND_ACTIVE,
4538 EL_INTERNAL_CASCADE_SB_ACTIVE,
4539 EL_INTERNAL_CASCADE_SP_ACTIVE,
4540 EL_INTERNAL_CASCADE_DC_ACTIVE,
4541 EL_INTERNAL_CASCADE_DX_ACTIVE,
4542 EL_INTERNAL_CASCADE_MM_ACTIVE,
4543 EL_INTERNAL_CASCADE_DF_ACTIVE,
4544 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4545 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4546 EL_INTERNAL_CASCADE_CE_ACTIVE,
4547 EL_INTERNAL_CASCADE_GE_ACTIVE,
4548 EL_INTERNAL_CASCADE_ES_ACTIVE,
4549 EL_INTERNAL_CASCADE_REF_ACTIVE,
4550 EL_INTERNAL_CASCADE_USER_ACTIVE,
4551 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4556 static int ep_editor_cascade_inactive[] =
4558 EL_INTERNAL_CASCADE_BD,
4559 EL_INTERNAL_CASCADE_EM,
4560 EL_INTERNAL_CASCADE_EMC,
4561 EL_INTERNAL_CASCADE_RND,
4562 EL_INTERNAL_CASCADE_SB,
4563 EL_INTERNAL_CASCADE_SP,
4564 EL_INTERNAL_CASCADE_DC,
4565 EL_INTERNAL_CASCADE_DX,
4566 EL_INTERNAL_CASCADE_MM,
4567 EL_INTERNAL_CASCADE_DF,
4568 EL_INTERNAL_CASCADE_CHARS,
4569 EL_INTERNAL_CASCADE_STEEL_CHARS,
4570 EL_INTERNAL_CASCADE_CE,
4571 EL_INTERNAL_CASCADE_GE,
4572 EL_INTERNAL_CASCADE_ES,
4573 EL_INTERNAL_CASCADE_REF,
4574 EL_INTERNAL_CASCADE_USER,
4575 EL_INTERNAL_CASCADE_DYNAMIC,
4580 static int ep_obsolete[] =
4584 EL_EM_KEY_1_FILE_OBSOLETE,
4585 EL_EM_KEY_2_FILE_OBSOLETE,
4586 EL_EM_KEY_3_FILE_OBSOLETE,
4587 EL_EM_KEY_4_FILE_OBSOLETE,
4588 EL_ENVELOPE_OBSOLETE,
4597 } element_properties[] =
4599 { ep_diggable, EP_DIGGABLE },
4600 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4601 { ep_dont_run_into, EP_DONT_RUN_INTO },
4602 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4603 { ep_dont_touch, EP_DONT_TOUCH },
4604 { ep_indestructible, EP_INDESTRUCTIBLE },
4605 { ep_slippery, EP_SLIPPERY },
4606 { ep_can_change, EP_CAN_CHANGE },
4607 { ep_can_move, EP_CAN_MOVE },
4608 { ep_can_fall, EP_CAN_FALL },
4609 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4610 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4611 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4612 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4613 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4614 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4615 { ep_walkable_over, EP_WALKABLE_OVER },
4616 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4617 { ep_walkable_under, EP_WALKABLE_UNDER },
4618 { ep_passable_over, EP_PASSABLE_OVER },
4619 { ep_passable_inside, EP_PASSABLE_INSIDE },
4620 { ep_passable_under, EP_PASSABLE_UNDER },
4621 { ep_droppable, EP_DROPPABLE },
4622 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4623 { ep_pushable, EP_PUSHABLE },
4624 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4625 { ep_protected, EP_PROTECTED },
4626 { ep_throwable, EP_THROWABLE },
4627 { ep_can_explode, EP_CAN_EXPLODE },
4628 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4630 { ep_empty_space, EP_EMPTY_SPACE },
4631 { ep_player, EP_PLAYER },
4632 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4633 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4634 { ep_switchable, EP_SWITCHABLE },
4635 { ep_bd_element, EP_BD_ELEMENT },
4636 { ep_sp_element, EP_SP_ELEMENT },
4637 { ep_sb_element, EP_SB_ELEMENT },
4639 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4640 { ep_food_penguin, EP_FOOD_PENGUIN },
4641 { ep_food_pig, EP_FOOD_PIG },
4642 { ep_historic_wall, EP_HISTORIC_WALL },
4643 { ep_historic_solid, EP_HISTORIC_SOLID },
4644 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4645 { ep_belt, EP_BELT },
4646 { ep_belt_active, EP_BELT_ACTIVE },
4647 { ep_belt_switch, EP_BELT_SWITCH },
4648 { ep_tube, EP_TUBE },
4649 { ep_acid_pool, EP_ACID_POOL },
4650 { ep_keygate, EP_KEYGATE },
4651 { ep_amoeboid, EP_AMOEBOID },
4652 { ep_amoebalive, EP_AMOEBALIVE },
4653 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4654 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4655 { ep_can_grow, EP_CAN_GROW },
4656 { ep_active_bomb, EP_ACTIVE_BOMB },
4657 { ep_inactive, EP_INACTIVE },
4659 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4661 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4663 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4664 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4666 { ep_obsolete, EP_OBSOLETE },
4673 // always start with reliable default values (element has no properties)
4674 // (but never initialize clipboard elements after the very first time)
4675 // (to be able to use clipboard elements between several levels)
4676 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4677 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4678 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4679 SET_PROPERTY(i, j, FALSE);
4681 // set all base element properties from above array definitions
4682 for (i = 0; element_properties[i].elements != NULL; i++)
4683 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4684 SET_PROPERTY((element_properties[i].elements)[j],
4685 element_properties[i].property, TRUE);
4687 // copy properties to some elements that are only stored in level file
4688 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4689 for (j = 0; copy_properties[j][0] != -1; j++)
4690 if (HAS_PROPERTY(copy_properties[j][0], i))
4691 for (k = 1; k <= 4; k++)
4692 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4694 // set static element properties that are not listed in array definitions
4695 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4696 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4698 clipboard_elements_initialized = TRUE;
4701 void InitElementPropertiesEngine(int engine_version)
4703 static int no_wall_properties[] =
4706 EP_COLLECTIBLE_ONLY,
4708 EP_DONT_COLLIDE_WITH,
4711 EP_CAN_SMASH_PLAYER,
4712 EP_CAN_SMASH_ENEMIES,
4713 EP_CAN_SMASH_EVERYTHING,
4718 EP_FOOD_DARK_YAMYAM,
4734 /* important: after initialization in InitElementPropertiesStatic(), the
4735 elements are not again initialized to a default value; therefore all
4736 changes have to make sure that they leave the element with a defined
4737 property (which means that conditional property changes must be set to
4738 a reliable default value before) */
4740 // resolve group elements
4741 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4742 ResolveGroupElement(EL_GROUP_START + i);
4744 // set all special, combined or engine dependent element properties
4745 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4747 // do not change (already initialized) clipboard elements here
4748 if (IS_CLIPBOARD_ELEMENT(i))
4751 // ---------- INACTIVE ----------------------------------------------------
4752 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4753 i <= EL_CHAR_END) ||
4754 (i >= EL_STEEL_CHAR_START &&
4755 i <= EL_STEEL_CHAR_END)));
4757 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4758 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4759 IS_WALKABLE_INSIDE(i) ||
4760 IS_WALKABLE_UNDER(i)));
4762 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4763 IS_PASSABLE_INSIDE(i) ||
4764 IS_PASSABLE_UNDER(i)));
4766 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4767 IS_PASSABLE_OVER(i)));
4769 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4770 IS_PASSABLE_INSIDE(i)));
4772 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4773 IS_PASSABLE_UNDER(i)));
4775 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4778 // ---------- COLLECTIBLE -------------------------------------------------
4779 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4783 // ---------- SNAPPABLE ---------------------------------------------------
4784 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4785 IS_COLLECTIBLE(i) ||
4789 // ---------- WALL --------------------------------------------------------
4790 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4792 for (j = 0; no_wall_properties[j] != -1; j++)
4793 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4794 i >= EL_FIRST_RUNTIME_UNREAL)
4795 SET_PROPERTY(i, EP_WALL, FALSE);
4797 if (IS_HISTORIC_WALL(i))
4798 SET_PROPERTY(i, EP_WALL, TRUE);
4800 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4801 if (engine_version < VERSION_IDENT(2,2,0,0))
4802 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4804 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4806 !IS_COLLECTIBLE(i)));
4808 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4809 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4810 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4812 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4815 // ---------- EXPLOSION_PROOF ---------------------------------------------
4817 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4818 else if (engine_version < VERSION_IDENT(2,2,0,0))
4819 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4821 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4825 if (IS_CUSTOM_ELEMENT(i))
4827 // these are additional properties which are initially false when set
4829 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4831 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4832 if (DONT_COLLIDE_WITH(i))
4833 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4835 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4836 if (CAN_SMASH_EVERYTHING(i))
4837 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4838 if (CAN_SMASH_ENEMIES(i))
4839 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4842 // ---------- CAN_SMASH ---------------------------------------------------
4843 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4844 CAN_SMASH_ENEMIES(i) ||
4845 CAN_SMASH_EVERYTHING(i)));
4847 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4848 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4849 EXPLODES_BY_FIRE(i)));
4851 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4852 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4853 EXPLODES_SMASHED(i)));
4855 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4856 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4857 EXPLODES_IMPACT(i)));
4859 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4860 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4862 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4863 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4864 i == EL_BLACK_ORB));
4866 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4867 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4869 IS_CUSTOM_ELEMENT(i)));
4871 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4872 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4873 i == EL_SP_ELECTRON));
4875 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4876 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4877 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4878 getMoveIntoAcidProperty(&level, i));
4880 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4881 if (MAYBE_DONT_COLLIDE_WITH(i))
4882 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4883 getDontCollideWithProperty(&level, i));
4885 // ---------- SP_PORT -----------------------------------------------------
4886 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4887 IS_PASSABLE_INSIDE(i)));
4889 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4890 for (j = 0; j < level.num_android_clone_elements; j++)
4891 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4893 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4895 // ---------- CAN_CHANGE --------------------------------------------------
4896 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4897 for (j = 0; j < element_info[i].num_change_pages; j++)
4898 if (element_info[i].change_page[j].can_change)
4899 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4901 // ---------- HAS_ACTION --------------------------------------------------
4902 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4903 for (j = 0; j < element_info[i].num_change_pages; j++)
4904 if (element_info[i].change_page[j].has_action)
4905 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4907 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4908 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4911 // ---------- GFX_CRUMBLED ------------------------------------------------
4912 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4913 element_info[i].crumbled[ACTION_DEFAULT] !=
4914 element_info[i].graphic[ACTION_DEFAULT]);
4916 // ---------- EDITOR_CASCADE ----------------------------------------------
4917 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4918 IS_EDITOR_CASCADE_INACTIVE(i)));
4921 // dynamically adjust element properties according to game engine version
4923 static int ep_em_slippery_wall[] =
4928 EL_EXPANDABLE_WALL_HORIZONTAL,
4929 EL_EXPANDABLE_WALL_VERTICAL,
4930 EL_EXPANDABLE_WALL_ANY,
4931 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4932 EL_EXPANDABLE_STEELWALL_VERTICAL,
4933 EL_EXPANDABLE_STEELWALL_ANY,
4934 EL_EXPANDABLE_STEELWALL_GROWING,
4938 static int ep_em_explodes_by_fire[] =
4941 EL_EM_DYNAMITE_ACTIVE,
4946 // special EM style gems behaviour
4947 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4948 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4949 level.em_slippery_gems);
4951 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4952 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4953 (level.em_slippery_gems &&
4954 engine_version > VERSION_IDENT(2,0,1,0)));
4956 // special EM style explosion behaviour regarding chain reactions
4957 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4958 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4959 level.em_explodes_by_fire);
4962 // this is needed because some graphics depend on element properties
4963 if (game_status == GAME_MODE_PLAYING)
4964 InitElementGraphicInfo();
4967 void InitElementPropertiesGfxElement(void)
4971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4973 struct ElementInfo *ei = &element_info[i];
4975 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4979 static void InitGlobal(void)
4984 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4986 // check if element_name_info entry defined for each element in "main.h"
4987 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4988 Fail("undefined 'element_name_info' entry for element %d", i);
4990 element_info[i].token_name = element_name_info[i].token_name;
4991 element_info[i].class_name = element_name_info[i].class_name;
4992 element_info[i].editor_description= element_name_info[i].editor_description;
4995 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4997 // check if global_anim_name_info defined for each entry in "main.h"
4998 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4999 global_anim_name_info[i].token_name == NULL)
5000 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
5002 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
5005 // create hash to store URLs for global animations
5006 anim_url_hash = newSetupFileHash();
5008 // create hash from image config list
5009 image_config_hash = newSetupFileHash();
5010 for (i = 0; image_config[i].token != NULL; i++)
5011 setHashEntry(image_config_hash,
5012 image_config[i].token,
5013 image_config[i].value);
5015 // create hash from element token list
5016 element_token_hash = newSetupFileHash();
5017 for (i = 0; element_name_info[i].token_name != NULL; i++)
5018 setHashEntry(element_token_hash,
5019 element_name_info[i].token_name,
5022 // create hash from graphic token list
5023 graphic_token_hash = newSetupFileHash();
5024 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5025 if (strSuffix(image_config[i].value, ".png") ||
5026 strSuffix(image_config[i].value, ".pcx") ||
5027 strSuffix(image_config[i].value, ".wav") ||
5028 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5029 setHashEntry(graphic_token_hash,
5030 image_config[i].token,
5031 int2str(graphic++, 0));
5033 // create hash from font token list
5034 font_token_hash = newSetupFileHash();
5035 for (i = 0; font_info[i].token_name != NULL; i++)
5036 setHashEntry(font_token_hash,
5037 font_info[i].token_name,
5040 // set default filenames for all cloned graphics in static configuration
5041 for (i = 0; image_config[i].token != NULL; i++)
5043 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5045 char *token = image_config[i].token;
5046 char *token_clone_from = getStringCat2(token, ".clone_from");
5047 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5049 if (token_cloned != NULL)
5051 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5053 if (value_cloned != NULL)
5055 // set default filename in static configuration
5056 image_config[i].value = value_cloned;
5058 // set default filename in image config hash
5059 setHashEntry(image_config_hash, token, value_cloned);
5063 free(token_clone_from);
5067 // always start with reliable default values (all elements)
5068 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5069 ActiveElement[i] = i;
5071 // now add all entries that have an active state (active elements)
5072 for (i = 0; element_with_active_state[i].element != -1; i++)
5074 int element = element_with_active_state[i].element;
5075 int element_active = element_with_active_state[i].element_active;
5077 ActiveElement[element] = element_active;
5080 // always start with reliable default values (all buttons)
5081 for (i = 0; i < NUM_IMAGE_FILES; i++)
5082 ActiveButton[i] = i;
5084 // now add all entries that have an active state (active buttons)
5085 for (i = 0; button_with_active_state[i].button != -1; i++)
5087 int button = button_with_active_state[i].button;
5088 int button_active = button_with_active_state[i].button_active;
5090 ActiveButton[button] = button_active;
5093 // always start with reliable default values (all fonts)
5094 for (i = 0; i < NUM_FONTS; i++)
5097 // now add all entries that have an active state (active fonts)
5098 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5100 int font = font_with_active_state[i].font_nr;
5101 int font_active = font_with_active_state[i].font_nr_active;
5103 ActiveFont[font] = font_active;
5106 global.autoplay_leveldir = NULL;
5107 global.patchtapes_leveldir = NULL;
5108 global.convert_leveldir = NULL;
5109 global.dumplevel_leveldir = NULL;
5110 global.dumptape_leveldir = NULL;
5111 global.create_sketch_images_dir = NULL;
5112 global.create_collect_images_dir = NULL;
5114 global.frames_per_second = 0;
5115 global.show_frames_per_second = FALSE;
5117 global.border_status = GAME_MODE_LOADING;
5118 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5120 global.use_envelope_request = FALSE;
5122 global.user_names = NULL;
5125 static void Execute_Command(char *command)
5129 if (strEqual(command, "print graphicsinfo.conf"))
5131 Print("# You can configure additional/alternative image files here.\n");
5132 Print("# (The entries below are default and therefore commented out.)\n");
5134 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5136 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5139 for (i = 0; image_config[i].token != NULL; i++)
5140 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5141 image_config[i].value));
5145 else if (strEqual(command, "print soundsinfo.conf"))
5147 Print("# You can configure additional/alternative sound files here.\n");
5148 Print("# (The entries below are default and therefore commented out.)\n");
5150 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5152 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5155 for (i = 0; sound_config[i].token != NULL; i++)
5156 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5157 sound_config[i].value));
5161 else if (strEqual(command, "print musicinfo.conf"))
5163 Print("# You can configure additional/alternative music files here.\n");
5164 Print("# (The entries below are default and therefore commented out.)\n");
5166 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5168 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5171 for (i = 0; music_config[i].token != NULL; i++)
5172 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5173 music_config[i].value));
5177 else if (strEqual(command, "print editorsetup.conf"))
5179 Print("# You can configure your personal editor element list here.\n");
5180 Print("# (The entries below are default and therefore commented out.)\n");
5183 // this is needed to be able to check element list for cascade elements
5184 InitElementPropertiesStatic();
5185 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5187 PrintEditorElementList();
5191 else if (strEqual(command, "print helpanim.conf"))
5193 Print("# You can configure different element help animations here.\n");
5194 Print("# (The entries below are default and therefore commented out.)\n");
5197 for (i = 0; helpanim_config[i].token != NULL; i++)
5199 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5200 helpanim_config[i].value));
5202 if (strEqual(helpanim_config[i].token, "end"))
5208 else if (strEqual(command, "print helptext.conf"))
5210 Print("# You can configure different element help text here.\n");
5211 Print("# (The entries below are default and therefore commented out.)\n");
5214 for (i = 0; helptext_config[i].token != NULL; i++)
5215 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5216 helptext_config[i].value));
5220 else if (strPrefix(command, "dump level "))
5222 char *filename = &command[11];
5224 if (fileExists(filename))
5226 LoadLevelFromFilename(&level, filename);
5232 char *leveldir = getStringCopy(filename); // read command parameters
5233 char *level_nr = strchr(leveldir, ' ');
5235 if (level_nr == NULL)
5236 Fail("cannot open file '%s'", filename);
5240 global.dumplevel_leveldir = leveldir;
5241 global.dumplevel_level_nr = atoi(level_nr);
5243 program.headless = TRUE;
5245 else if (strPrefix(command, "dump tape "))
5247 char *filename = &command[10];
5249 if (fileExists(filename))
5251 LoadTapeFromFilename(filename);
5257 char *leveldir = getStringCopy(filename); // read command parameters
5258 char *level_nr = strchr(leveldir, ' ');
5260 if (level_nr == NULL)
5261 Fail("cannot open file '%s'", filename);
5265 global.dumptape_leveldir = leveldir;
5266 global.dumptape_level_nr = atoi(level_nr);
5268 program.headless = TRUE;
5270 else if (strPrefix(command, "autoplay ") ||
5271 strPrefix(command, "autoffwd ") ||
5272 strPrefix(command, "autowarp ") ||
5273 strPrefix(command, "autotest ") ||
5274 strPrefix(command, "autosave ") ||
5275 strPrefix(command, "autoupload ") ||
5276 strPrefix(command, "autofix "))
5278 char *arg_ptr = strchr(command, ' ');
5279 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5281 global.autoplay_mode =
5282 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5283 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5284 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5285 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5286 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5287 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5288 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5289 AUTOPLAY_MODE_NONE);
5291 while (*str_ptr != '\0') // continue parsing string
5293 // cut leading whitespace from string, replace it by string terminator
5294 while (*str_ptr == ' ' || *str_ptr == '\t')
5297 if (*str_ptr == '\0') // end of string reached
5300 if (global.autoplay_leveldir == NULL) // read level set string
5302 global.autoplay_leveldir = str_ptr;
5303 global.autoplay_all = TRUE; // default: play all tapes
5305 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5306 global.autoplay_level[i] = FALSE;
5308 else // read level number string
5310 int level_nr = atoi(str_ptr); // get level_nr value
5312 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5313 global.autoplay_level[level_nr] = TRUE;
5315 global.autoplay_all = FALSE;
5318 // advance string pointer to the next whitespace (or end of string)
5319 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5323 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5324 program.headless = TRUE;
5326 else if (strPrefix(command, "patch tapes "))
5328 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5330 // skip leading whitespace
5331 while (*str_ptr == ' ' || *str_ptr == '\t')
5334 if (*str_ptr == '\0')
5335 Fail("cannot find MODE in command '%s'", command);
5337 global.patchtapes_mode = str_ptr; // store patch mode
5339 // advance to next whitespace (or end of string)
5340 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5343 while (*str_ptr != '\0') // continue parsing string
5345 // cut leading whitespace from string, replace it by string terminator
5346 while (*str_ptr == ' ' || *str_ptr == '\t')
5349 if (*str_ptr == '\0') // end of string reached
5352 if (global.patchtapes_leveldir == NULL) // read level set string
5354 global.patchtapes_leveldir = str_ptr;
5355 global.patchtapes_all = TRUE; // default: patch all tapes
5357 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5358 global.patchtapes_level[i] = FALSE;
5360 else // read level number string
5362 int level_nr = atoi(str_ptr); // get level_nr value
5364 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5365 global.patchtapes_level[level_nr] = TRUE;
5367 global.patchtapes_all = FALSE;
5370 // advance string pointer to the next whitespace (or end of string)
5371 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5375 if (global.patchtapes_leveldir == NULL)
5377 if (strEqual(global.patchtapes_mode, "help"))
5378 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5380 Fail("cannot find LEVELDIR in command '%s'", command);
5383 program.headless = TRUE;
5385 else if (strPrefix(command, "convert "))
5387 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5388 char *str_ptr = strchr(str_copy, ' ');
5390 global.convert_leveldir = str_copy;
5391 global.convert_level_nr = -1;
5393 if (str_ptr != NULL) // level number follows
5395 *str_ptr++ = '\0'; // terminate leveldir string
5396 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5399 program.headless = TRUE;
5401 else if (strPrefix(command, "create sketch images "))
5403 global.create_sketch_images_dir = getStringCopy(&command[21]);
5405 if (access(global.create_sketch_images_dir, W_OK) != 0)
5406 Fail("image target directory '%s' not found or not writable",
5407 global.create_sketch_images_dir);
5409 else if (strPrefix(command, "create collect image "))
5411 global.create_collect_images_dir = getStringCopy(&command[21]);
5413 if (access(global.create_collect_images_dir, W_OK) != 0)
5414 Fail("image target directory '%s' not found or not writable",
5415 global.create_collect_images_dir);
5417 else if (strPrefix(command, "create CE image "))
5419 CreateCustomElementImages(&command[16]);
5425 FailWithHelp("unrecognized command '%s'", command);
5428 // disable networking if any valid command was recognized
5429 options.network = setup.network_mode = FALSE;
5432 static void InitSetup(void)
5434 LoadUserNames(); // global user names
5435 LoadUserSetup(); // global user number
5437 LoadSetup(); // global setup info
5439 // set some options from setup file
5441 if (setup.options.verbose)
5442 options.verbose = TRUE;
5444 if (setup.debug.show_frames_per_second)
5445 global.show_frames_per_second = TRUE;
5448 static void InitGameInfo(void)
5450 game.restart_level = FALSE;
5451 game.restart_game_message = NULL;
5453 game.request_active = FALSE;
5454 game.request_active_or_moving = FALSE;
5456 game.use_masked_elements_initial = FALSE;
5459 static void InitPlayerInfo(void)
5463 // choose default local player
5464 local_player = &stored_player[0];
5466 for (i = 0; i < MAX_PLAYERS; i++)
5468 stored_player[i].connected_locally = FALSE;
5469 stored_player[i].connected_network = FALSE;
5472 local_player->connected_locally = TRUE;
5475 static void InitArtworkInfo(void)
5480 static char *get_string_in_brackets(char *string)
5482 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5484 sprintf(string_in_brackets, "[%s]", string);
5486 return string_in_brackets;
5489 static char *get_level_id_suffix(int id_nr)
5491 char *id_suffix = checked_malloc(1 + 3 + 1);
5493 if (id_nr < 0 || id_nr > 999)
5496 sprintf(id_suffix, ".%03d", id_nr);
5501 static void InitArtworkConfig(void)
5503 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5505 NUM_GLOBAL_ANIM_TOKENS + 1];
5506 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5507 NUM_GLOBAL_ANIM_TOKENS + 1];
5508 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5509 NUM_GLOBAL_ANIM_TOKENS + 1];
5510 static char *action_id_suffix[NUM_ACTIONS + 1];
5511 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5512 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5513 static char *level_id_suffix[MAX_LEVELS + 1];
5514 static char *dummy[1] = { NULL };
5515 static char *ignore_generic_tokens[] =
5520 "program_copyright",
5525 static char **ignore_image_tokens;
5526 static char **ignore_sound_tokens;
5527 static char **ignore_music_tokens;
5528 int num_ignore_generic_tokens;
5529 int num_ignore_image_tokens;
5530 int num_ignore_sound_tokens;
5531 int num_ignore_music_tokens;
5534 // dynamically determine list of generic tokens to be ignored
5535 num_ignore_generic_tokens = 0;
5536 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5537 num_ignore_generic_tokens++;
5539 // dynamically determine list of image tokens to be ignored
5540 num_ignore_image_tokens = num_ignore_generic_tokens;
5541 for (i = 0; image_config_vars[i].token != NULL; i++)
5542 num_ignore_image_tokens++;
5543 ignore_image_tokens =
5544 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5545 for (i = 0; i < num_ignore_generic_tokens; i++)
5546 ignore_image_tokens[i] = ignore_generic_tokens[i];
5547 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5548 ignore_image_tokens[num_ignore_generic_tokens + i] =
5549 image_config_vars[i].token;
5550 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5552 // dynamically determine list of sound tokens to be ignored
5553 num_ignore_sound_tokens = num_ignore_generic_tokens;
5554 ignore_sound_tokens =
5555 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5556 for (i = 0; i < num_ignore_generic_tokens; i++)
5557 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5558 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5560 // dynamically determine list of music tokens to be ignored
5561 num_ignore_music_tokens = num_ignore_generic_tokens;
5562 ignore_music_tokens =
5563 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5564 for (i = 0; i < num_ignore_generic_tokens; i++)
5565 ignore_music_tokens[i] = ignore_generic_tokens[i];
5566 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5568 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5569 image_id_prefix[i] = element_info[i].token_name;
5570 for (i = 0; i < NUM_FONTS; i++)
5571 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5572 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5573 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5574 global_anim_info[i].token_name;
5575 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5577 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5578 sound_id_prefix[i] = element_info[i].token_name;
5579 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5580 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5581 get_string_in_brackets(element_info[i].class_name);
5582 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5583 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5584 global_anim_info[i].token_name;
5585 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5587 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5588 music_id_prefix[i] = music_prefix_info[i].prefix;
5589 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5590 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5591 global_anim_info[i].token_name;
5592 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5594 for (i = 0; i < NUM_ACTIONS; i++)
5595 action_id_suffix[i] = element_action_info[i].suffix;
5596 action_id_suffix[NUM_ACTIONS] = NULL;
5598 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5599 direction_id_suffix[i] = element_direction_info[i].suffix;
5600 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5602 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5603 special_id_suffix[i] = special_suffix_info[i].suffix;
5604 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5606 for (i = 0; i < MAX_LEVELS; i++)
5607 level_id_suffix[i] = get_level_id_suffix(i);
5608 level_id_suffix[MAX_LEVELS] = NULL;
5610 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5611 image_id_prefix, action_id_suffix, direction_id_suffix,
5612 special_id_suffix, ignore_image_tokens);
5613 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5614 sound_id_prefix, action_id_suffix, dummy,
5615 special_id_suffix, ignore_sound_tokens);
5616 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5617 music_id_prefix, action_id_suffix, special_id_suffix,
5618 level_id_suffix, ignore_music_tokens);
5621 static void InitMixer(void)
5628 static void InitVideoOverlay(void)
5630 // if virtual buttons are not loaded from setup file, repeat initializing
5631 // virtual buttons grid with default values now that video is initialized
5632 if (!setup.touch.grid_initialized)
5635 InitTileCursorInfo();
5639 void InitGfxBuffers(void)
5641 static int win_xsize_last = -1;
5642 static int win_ysize_last = -1;
5644 // create additional image buffers for double-buffering and cross-fading
5646 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5648 // used to temporarily store the backbuffer -- only re-create if changed
5649 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5650 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5652 win_xsize_last = WIN_XSIZE;
5653 win_ysize_last = WIN_YSIZE;
5656 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5657 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5658 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5659 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5661 // initialize screen properties
5662 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5663 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5665 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5666 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5667 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5668 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5669 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5670 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5672 // required if door size definitions have changed
5673 InitGraphicCompatibilityInfo_Doors();
5675 InitGfxBuffers_EM();
5676 InitGfxBuffers_SP();
5679 static void InitGfx(void)
5681 struct GraphicInfo *graphic_info_last = graphic_info;
5682 char *filename_font_initial = NULL;
5683 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5684 char *image_token[NUM_INITIAL_IMAGES] =
5686 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5687 CONFIG_TOKEN_GLOBAL_BUSY,
5688 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5689 CONFIG_TOKEN_BACKGROUND,
5690 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5691 CONFIG_TOKEN_BACKGROUND_LOADING
5693 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5697 &init.busy_playfield
5699 Bitmap *bitmap_font_initial = NULL;
5700 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5703 // determine settings for initial font (for displaying startup messages)
5704 for (i = 0; image_config[i].token != NULL; i++)
5706 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5708 char font_token[128];
5711 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5712 len_font_token = strlen(font_token);
5714 if (strEqual(image_config[i].token, font_token))
5716 filename_font_initial = image_config[i].value;
5718 else if (strlen(image_config[i].token) > len_font_token &&
5719 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5721 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5722 font_initial[j].src_x = atoi(image_config[i].value);
5723 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5724 font_initial[j].src_y = atoi(image_config[i].value);
5725 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5726 font_initial[j].width = atoi(image_config[i].value);
5727 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5728 font_initial[j].height = atoi(image_config[i].value);
5733 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5735 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5736 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5739 if (filename_font_initial == NULL) // should not happen
5740 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5743 InitGfxCustomArtworkInfo();
5744 InitGfxOtherSettings();
5746 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5748 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5750 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5751 font_initial[j].bitmap = bitmap_font_initial;
5753 InitFontGraphicInfo();
5757 DrawInitTextHead("Loading graphics");
5759 InitMenuDesignSettings_Static();
5761 // initialize settings for initial images with default values
5762 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5763 for (j = 0; j < NUM_GFX_ARGS; j++)
5765 get_graphic_parameter_value(image_config_suffix[j].value,
5766 image_config_suffix[j].token,
5767 image_config_suffix[j].type);
5769 // read settings for initial images from default custom artwork config
5770 char *gfx_config_filename = getPath3(options.graphics_directory,
5772 GRAPHICSINFO_FILENAME);
5774 if (fileExists(gfx_config_filename))
5776 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5778 if (setup_file_hash)
5780 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5782 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5786 filename_image_initial[i] = getStringCopy(filename);
5788 for (j = 0; image_config_suffix[j].token != NULL; j++)
5790 int type = image_config_suffix[j].type;
5791 char *suffix = image_config_suffix[j].token;
5792 char *token = getStringCat2(image_token[i], suffix);
5793 char *value = getHashEntry(setup_file_hash, token);
5795 checked_free(token);
5799 get_graphic_parameter_value(value, suffix, type);
5804 // read values from custom graphics config file
5805 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5807 freeSetupFileHash(setup_file_hash);
5811 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5813 if (filename_image_initial[i] == NULL)
5815 int len_token = strlen(image_token[i]);
5817 // read settings for initial images from static default artwork config
5818 for (j = 0; image_config[j].token != NULL; j++)
5820 if (strEqual(image_config[j].token, image_token[i]))
5822 filename_image_initial[i] = getStringCopy(image_config[j].value);
5824 else if (strlen(image_config[j].token) > len_token &&
5825 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5827 for (k = 0; image_config_suffix[k].token != NULL; k++)
5829 if (strEqual(&image_config[j].token[len_token],
5830 image_config_suffix[k].token))
5832 get_graphic_parameter_value(image_config[j].value,
5833 image_config_suffix[k].token,
5834 image_config_suffix[k].type);
5841 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5843 if (filename_image_initial[i] == NULL) // should not happen
5844 Fail("cannot get filename for '%s'", image_token[i]);
5846 image_initial[i].bitmaps =
5847 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5849 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5850 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5851 LoadCustomImage(filename_image_initial[i]);
5853 checked_free(filename_image_initial[i]);
5856 graphic_info = image_initial; // graphic == 0 => image_initial
5858 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5859 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5861 graphic_info = graphic_info_last;
5863 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5865 // set image size for busy animations
5866 init_busy[i]->width = image_initial[i].width;
5867 init_busy[i]->height = image_initial[i].height;
5870 SetLoadingBackgroundImage();
5872 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5874 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5875 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5876 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5877 InitGfxDrawTileCursorFunction(DrawTileCursor);
5879 gfx.fade_border_source_status = global.border_status;
5880 gfx.fade_border_target_status = global.border_status;
5881 gfx.masked_border_bitmap_ptr = backbuffer;
5883 // use copy of busy animation to prevent change while reloading artwork
5887 static void InitGfxBackground(void)
5889 fieldbuffer = bitmap_db_field;
5890 SetDrawtoField(DRAW_TO_BACKBUFFER);
5892 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5894 redraw_mask = REDRAW_ALL;
5897 static void InitLevelInfo(void)
5899 LoadLevelInfo(); // global level info
5900 LoadLevelSetup_LastSeries(); // last played series info
5901 LoadLevelSetup_SeriesInfo(); // last played level info
5903 if (global.autoplay_leveldir &&
5904 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5906 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5907 global.autoplay_leveldir);
5908 if (leveldir_current == NULL)
5909 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5912 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5915 static void InitLevelArtworkInfo(void)
5917 LoadLevelArtworkInfo();
5920 static void InitImages(void)
5922 print_timestamp_init("InitImages");
5925 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5926 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5927 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5928 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5929 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5930 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5931 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5932 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5935 setLevelArtworkDir(artwork.gfx_first);
5938 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5939 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5940 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5941 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5942 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5943 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5944 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5945 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5949 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5950 leveldir_current->identifier,
5951 artwork.gfx_current_identifier,
5952 artwork.gfx_current->identifier,
5953 leveldir_current->graphics_set,
5954 leveldir_current->graphics_path);
5957 UPDATE_BUSY_STATE();
5959 ReloadCustomImages();
5960 print_timestamp_time("ReloadCustomImages");
5962 UPDATE_BUSY_STATE();
5964 LoadCustomElementDescriptions();
5965 print_timestamp_time("LoadCustomElementDescriptions");
5967 UPDATE_BUSY_STATE();
5969 LoadMenuDesignSettings();
5970 print_timestamp_time("LoadMenuDesignSettings");
5972 UPDATE_BUSY_STATE();
5974 ReinitializeGraphics();
5975 print_timestamp_time("ReinitializeGraphics");
5977 LoadMenuDesignSettings_AfterGraphics();
5978 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5980 UPDATE_BUSY_STATE();
5982 print_timestamp_done("InitImages");
5985 static void InitSound(void)
5987 print_timestamp_init("InitSound");
5989 // set artwork path to send it to the sound server process
5990 setLevelArtworkDir(artwork.snd_first);
5992 InitReloadCustomSounds();
5993 print_timestamp_time("InitReloadCustomSounds");
5995 ReinitializeSounds();
5996 print_timestamp_time("ReinitializeSounds");
5998 print_timestamp_done("InitSound");
6001 static void InitMusic(void)
6003 print_timestamp_init("InitMusic");
6005 // set artwork path to send it to the sound server process
6006 setLevelArtworkDir(artwork.mus_first);
6008 InitReloadCustomMusic();
6009 print_timestamp_time("InitReloadCustomMusic");
6011 ReinitializeMusic();
6012 print_timestamp_time("ReinitializeMusic");
6014 print_timestamp_done("InitMusic");
6017 static void InitArtworkDone(void)
6019 if (program.headless)
6022 InitGlobalAnimations();
6025 static void InitNetworkSettings(void)
6027 boolean network_enabled = (options.network || setup.network_mode);
6028 char *network_server = (options.server_host != NULL ? options.server_host :
6029 setup.network_server_hostname);
6031 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6032 network_server = NULL;
6034 InitNetworkInfo(network_enabled,
6038 options.server_port);
6041 void InitNetworkServer(void)
6043 if (!network.enabled || network.connected)
6046 LimitScreenUpdates(FALSE);
6048 if (game_status == GAME_MODE_LOADING)
6051 if (!ConnectToServer(network.server_host, network.server_port))
6053 network.enabled = FALSE;
6055 setup.network_mode = FALSE;
6059 SendToServer_ProtocolVersion();
6060 SendToServer_PlayerName(setup.player_name);
6061 SendToServer_NrWanted(setup.network_player_nr + 1);
6063 network.connected = TRUE;
6066 // short time to recognize result of network initialization
6067 if (game_status == GAME_MODE_LOADING)
6068 Delay_WithScreenUpdates(1000);
6071 static boolean CheckArtworkConfigForCustomElements(char *filename)
6073 SetupFileHash *setup_file_hash;
6074 boolean redefined_ce_found = FALSE;
6076 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6078 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6080 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6082 char *token = HASH_ITERATION_TOKEN(itr);
6084 if (strPrefix(token, "custom_"))
6086 redefined_ce_found = TRUE;
6091 END_HASH_ITERATION(setup_file_hash, itr)
6093 freeSetupFileHash(setup_file_hash);
6096 return redefined_ce_found;
6099 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6101 char *filename_base, *filename_local;
6102 boolean redefined_ce_found = FALSE;
6104 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6107 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6108 "leveldir_current->identifier == '%s'",
6109 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6110 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6111 "leveldir_current->graphics_path == '%s'",
6112 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6113 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6114 "leveldir_current->graphics_set == '%s'",
6115 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6116 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6117 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6118 leveldir_current == NULL ? "[NULL]" :
6119 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6122 // first look for special artwork configured in level series config
6123 filename_base = getCustomArtworkLevelConfigFilename(type);
6126 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6127 "filename_base == '%s'", filename_base);
6130 if (fileExists(filename_base))
6131 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6133 filename_local = getCustomArtworkConfigFilename(type);
6136 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6137 "filename_local == '%s'", filename_local);
6140 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6141 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6144 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6145 "redefined_ce_found == %d", redefined_ce_found);
6148 return redefined_ce_found;
6151 static void InitOverrideArtwork(void)
6153 boolean redefined_ce_found = FALSE;
6155 // to check if this level set redefines any CEs, do not use overriding
6156 gfx.override_level_graphics = FALSE;
6157 gfx.override_level_sounds = FALSE;
6158 gfx.override_level_music = FALSE;
6160 // now check if this level set has definitions for custom elements
6161 if (setup.override_level_graphics == AUTO ||
6162 setup.override_level_sounds == AUTO ||
6163 setup.override_level_music == AUTO)
6164 redefined_ce_found =
6165 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6166 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6167 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6170 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6171 redefined_ce_found);
6174 if (redefined_ce_found)
6176 // this level set has CE definitions: change "AUTO" to "FALSE"
6177 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6178 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6179 gfx.override_level_music = (setup.override_level_music == TRUE);
6183 // this level set has no CE definitions: change "AUTO" to "TRUE"
6184 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6185 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6186 gfx.override_level_music = (setup.override_level_music != FALSE);
6190 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6191 gfx.override_level_graphics,
6192 gfx.override_level_sounds,
6193 gfx.override_level_music);
6197 static char *setNewArtworkIdentifier(int type)
6199 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6200 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6201 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6202 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6203 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6204 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6205 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6206 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6207 char *leveldir_identifier = leveldir_current->identifier;
6208 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6209 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6210 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6211 TreeInfo *custom_artwork_set =
6212 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6213 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6214 char *artwork_current_identifier;
6215 char *artwork_new_identifier = NULL; // default: nothing has changed
6217 // leveldir_current may be invalid (level group, parent link)
6218 if (!validLevelSeries(leveldir_current))
6221 /* 1st step: determine artwork set to be activated in descending order:
6222 --------------------------------------------------------------------
6223 1. setup artwork (when configured to override everything else)
6224 2. artwork set configured in "levelinfo.conf" of current level set
6225 (artwork in level directory will have priority when loading later)
6226 3. artwork in level directory (stored in artwork sub-directory)
6227 4. setup artwork (currently configured in setup menu) */
6229 if (setup_override_artwork)
6230 artwork_current_identifier = setup_artwork_set;
6231 else if (has_level_artwork_set)
6232 artwork_current_identifier = leveldir_artwork_set;
6233 else if (has_custom_artwork_set)
6234 artwork_current_identifier = leveldir_identifier;
6236 artwork_current_identifier = setup_artwork_set;
6238 /* 2nd step: check if it is really needed to reload artwork set
6239 ------------------------------------------------------------ */
6241 // ---------- reload if level set and also artwork set has changed ----------
6242 if (last_leveldir_identifier[type] != leveldir_identifier &&
6243 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6244 artwork_new_identifier = artwork_current_identifier;
6246 last_leveldir_identifier[type] = leveldir_identifier;
6247 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6249 // ---------- reload if "override artwork" setting has changed --------------
6250 if (last_override_level_artwork[type] != setup_override_artwork)
6251 artwork_new_identifier = artwork_current_identifier;
6253 last_override_level_artwork[type] = setup_override_artwork;
6255 // ---------- reload if current artwork identifier has changed --------------
6256 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6257 artwork_new_identifier = artwork_current_identifier;
6259 // (we cannot compare string pointers here, so copy string content itself)
6260 setString(&last_artwork_identifier[type], artwork_current_identifier);
6262 // ---------- set new artwork identifier ----------
6263 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6265 // ---------- do not reload directly after starting -------------------------
6266 if (!initialized[type])
6267 artwork_new_identifier = NULL;
6269 initialized[type] = TRUE;
6271 return artwork_new_identifier;
6274 static void InitArtworkIdentifier(void)
6276 setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6277 setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6278 setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6281 void ReloadCustomArtwork(int force_reload)
6283 int last_game_status = game_status; // save current game status
6284 char *gfx_new_identifier;
6285 char *snd_new_identifier;
6286 char *mus_new_identifier;
6287 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6288 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6289 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6290 boolean reload_needed;
6292 InitOverrideArtwork();
6294 AdjustGraphicsForEMC();
6295 AdjustSoundsForEMC();
6297 gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6298 snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6299 mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6301 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6302 snd_new_identifier != NULL || force_reload_snd ||
6303 mus_new_identifier != NULL || force_reload_mus);
6308 print_timestamp_init("ReloadCustomArtwork");
6310 SetGameStatus(GAME_MODE_LOADING);
6312 FadeOut(REDRAW_ALL);
6314 SetLoadingBackgroundImage();
6316 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6317 print_timestamp_time("ClearRectangleOnBackground");
6321 UPDATE_BUSY_STATE();
6323 InitMissingFileHash();
6325 if (gfx_new_identifier != NULL || force_reload_gfx)
6328 Debug("init:ReloadCustomArtwork",
6329 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6330 artwork.gfx_current_identifier,
6332 artwork.gfx_current->identifier,
6333 leveldir_current->graphics_set);
6337 print_timestamp_time("InitImages");
6340 if (snd_new_identifier != NULL || force_reload_snd)
6343 print_timestamp_time("InitSound");
6346 if (mus_new_identifier != NULL || force_reload_mus)
6349 print_timestamp_time("InitMusic");
6354 SetGameStatus(last_game_status); // restore current game status
6356 FadeOut(REDRAW_ALL);
6358 RedrawGlobalBorder();
6360 // force redraw of (open or closed) door graphics
6361 SetDoorState(DOOR_OPEN_ALL);
6362 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6364 FadeSetEnterScreen();
6365 FadeSkipNextFadeOut();
6367 print_timestamp_done("ReloadCustomArtwork");
6369 LimitScreenUpdates(FALSE);
6372 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6374 if (global.autoplay_leveldir == NULL)
6375 KeyboardAutoRepeatOff();
6378 void DisplayExitMessage(char *format, va_list ap)
6380 // also check for initialized video (headless flag may be temporarily unset)
6381 if (program.headless || !video.initialized)
6384 // check if draw buffer and fonts for exit message are already available
6385 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6388 int font_1 = FC_RED;
6389 int font_2 = FC_YELLOW;
6390 int font_3 = FC_BLUE;
6391 int font_width = getFontWidth(font_2);
6392 int font_height = getFontHeight(font_2);
6395 int sxsize = WIN_XSIZE - 2 * sx;
6396 int sysize = WIN_YSIZE - 2 * sy;
6397 int line_length = sxsize / font_width;
6398 int max_lines = sysize / font_height;
6399 int num_lines_printed;
6403 gfx.sxsize = sxsize;
6404 gfx.sysize = sysize;
6408 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6410 DrawTextSCentered(sy, font_1, "Fatal error:");
6411 sy += 3 * font_height;;
6414 DrawTextBufferVA(sx, sy, format, ap, font_2,
6415 line_length, line_length, max_lines,
6416 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6417 sy += (num_lines_printed + 3) * font_height;
6419 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6420 sy += 3 * font_height;
6423 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6424 line_length, line_length, max_lines,
6425 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6427 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6429 redraw_mask = REDRAW_ALL;
6431 // force drawing exit message even if screen updates are currently limited
6432 LimitScreenUpdates(FALSE);
6436 // deactivate toons on error message screen
6437 setup.toons = FALSE;
6439 WaitForEventToContinue();
6443 // ============================================================================
6445 // ============================================================================
6449 print_timestamp_init("OpenAll");
6451 SetGameStatus(GAME_MODE_LOADING);
6455 InitGlobal(); // initialize some global variables
6457 InitRND(NEW_RANDOMIZE);
6458 InitSimpleRandom(NEW_RANDOMIZE);
6459 InitBetterRandom(NEW_RANDOMIZE);
6461 InitMissingFileHash();
6463 print_timestamp_time("[init global stuff]");
6467 print_timestamp_time("[init setup/config stuff (1)]");
6469 if (options.execute_command)
6470 Execute_Command(options.execute_command);
6472 InitNetworkSettings();
6476 if (network.serveronly)
6478 #if defined(PLATFORM_UNIX)
6479 NetworkServer(network.server_port, TRUE);
6481 Warn("networking only supported in Unix version");
6484 exit(0); // never reached, server loops forever
6488 print_timestamp_time("[init setup/config stuff (2)]");
6490 print_timestamp_time("[init setup/config stuff (3)]");
6491 InitArtworkInfo(); // needed before loading gfx, sound & music
6492 print_timestamp_time("[init setup/config stuff (4)]");
6493 InitArtworkConfig(); // needed before forking sound child process
6494 print_timestamp_time("[init setup/config stuff (5)]");
6496 print_timestamp_time("[init setup/config stuff (6)]");
6500 print_timestamp_time("[init setup/config stuff]");
6502 InitVideoDefaults();
6504 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6507 InitEventFilter(FilterMouseMotionEvents);
6509 print_timestamp_time("[init video stuff]");
6511 InitElementPropertiesStatic();
6512 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6513 InitElementPropertiesGfxElement();
6515 print_timestamp_time("[init element properties stuff]");
6519 print_timestamp_time("InitGfx");
6522 print_timestamp_time("InitLevelInfo");
6524 InitLevelArtworkInfo();
6525 print_timestamp_time("InitLevelArtworkInfo");
6527 InitOverrideArtwork(); // needs to know current level directory
6528 print_timestamp_time("InitOverrideArtwork");
6530 InitArtworkIdentifier(); // needs to know current level directory
6531 print_timestamp_time("InitArtworkIdentifier");
6533 InitImages(); // needs to know current level directory
6534 print_timestamp_time("InitImages");
6536 InitSound(); // needs to know current level directory
6537 print_timestamp_time("InitSound");
6539 InitMusic(); // needs to know current level directory
6540 print_timestamp_time("InitMusic");
6544 InitGfxBackground();
6550 if (global.autoplay_leveldir)
6555 else if (global.patchtapes_leveldir)
6560 else if (global.convert_leveldir)
6565 else if (global.dumplevel_leveldir)
6570 else if (global.dumptape_leveldir)
6575 else if (global.create_sketch_images_dir)
6577 CreateLevelSketchImages();
6580 else if (global.create_collect_images_dir)
6582 CreateCollectElementImages();
6586 InitNetworkServer();
6588 SetGameStatus(GAME_MODE_MAIN);
6590 FadeSetEnterScreen();
6591 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6592 FadeSkipNextFadeOut();
6594 print_timestamp_time("[post-artwork]");
6596 print_timestamp_done("OpenAll");
6598 if (setup.ask_for_remaining_tapes)
6599 setup.ask_for_uploading_tapes = TRUE;
6604 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6606 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6607 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6608 #if defined(PLATFORM_ANDROID)
6609 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6610 SDL_AndroidGetInternalStoragePath());
6611 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6612 SDL_AndroidGetExternalStoragePath());
6613 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6614 (SDL_AndroidGetExternalStorageState() &
6615 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6616 SDL_AndroidGetExternalStorageState() &
6617 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6622 static boolean WaitForApiThreads(void)
6624 DelayCounter thread_delay = { 10000 };
6626 if (program.api_thread_count == 0)
6629 // deactivate global animations (not accessible in game state "loading")
6630 setup.toons = FALSE;
6632 // set game state to "loading" to be able to show busy animation
6633 SetGameStatus(GAME_MODE_LOADING);
6635 ResetDelayCounter(&thread_delay);
6637 // wait for threads to finish (and fail on timeout)
6638 while (program.api_thread_count > 0)
6640 if (DelayReached(&thread_delay))
6642 Error("failed waiting for threads - TIMEOUT");
6647 UPDATE_BUSY_STATE();
6655 void CloseAllAndExit(int exit_value)
6657 WaitForApiThreads();
6662 CloseAudio(); // called after freeing sounds (needed for SDL)
6670 // set a flag to tell the network server thread to quit and wait for it
6671 // using SDL_WaitThread()
6673 // Code used with SDL 1.2:
6674 // if (network.server_thread) // terminate network server
6675 // SDL_KillThread(network.server_thread);
6677 CloseVideoDisplay();
6678 ClosePlatformDependentStuff();
6680 if (exit_value != 0 && !options.execute_command)
6682 // fall back to default level set (current set may have caused an error)
6683 SaveLevelSetup_LastSeries_Deactivate();
6685 // tell user where to find error log file which may contain more details
6686 // (error notification now directly displayed on screen inside R'n'D
6687 // NotifyUserAboutErrorFile(); // currently only works for Windows