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 // optional element for cloning crumble graphics
1565 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1566 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1568 // optional element for cloning digging graphics
1569 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1570 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1572 // optional border size for "crumbling" diggable graphics
1573 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1574 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1576 // used for global animations and player "boring" and "sleeping" actions
1577 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1578 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1579 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1580 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1581 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1582 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1583 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1584 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1585 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1586 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1587 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1588 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1590 // used for global animations
1591 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1592 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1593 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1594 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1595 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1596 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1597 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1598 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1599 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1600 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1601 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1602 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1603 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1604 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1606 // used for toon animations and global animations
1607 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1608 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1609 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1610 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1611 g->direction = parameter[GFX_ARG_DIRECTION];
1612 g->position = parameter[GFX_ARG_POSITION];
1613 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1614 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1616 if (g->step_delay < 1) // delay must be at least 1
1619 // this is only used for drawing font characters
1620 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1621 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1623 // use a different default value for global animations and toons
1624 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1625 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1626 g->draw_masked = TRUE;
1628 // this is used for drawing envelopes, global animations and toons
1629 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1630 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1632 // used for toon animations and global animations
1633 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1634 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1636 // optional graphic for cloning all graphics settings
1637 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1638 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1640 // optional settings for drawing title screens and title messages
1641 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1642 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1643 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1644 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1645 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1646 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1647 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1648 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1649 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1650 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1651 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1652 g->align = parameter[GFX_ARG_ALIGN];
1653 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1654 g->valign = parameter[GFX_ARG_VALIGN];
1655 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1656 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1658 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1659 g->class = parameter[GFX_ARG_CLASS];
1660 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1661 g->style = parameter[GFX_ARG_STYLE];
1663 // this is only used for drawing menu buttons and text
1664 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1665 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1666 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1667 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1670 static void set_graphic_parameters(int graphic)
1672 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1673 char **parameter_raw = image->parameter;
1674 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1675 int parameter[NUM_GFX_ARGS];
1678 // if fallback to default artwork is done, also use the default parameters
1679 if (image->fallback_to_default)
1680 parameter_raw = image->default_parameter;
1682 // get integer values from string parameters
1683 for (i = 0; i < NUM_GFX_ARGS; i++)
1684 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1685 image_config_suffix[i].token,
1686 image_config_suffix[i].type);
1688 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1690 UPDATE_BUSY_STATE();
1693 static void set_cloned_graphic_parameters(int graphic)
1695 int fallback_graphic = IMG_CHAR_EXCLAM;
1696 int max_num_images = getImageListSize();
1697 int clone_graphic = graphic_info[graphic].clone_from;
1698 int num_references_followed = 1;
1700 while (graphic_info[clone_graphic].clone_from != -1 &&
1701 num_references_followed < max_num_images)
1703 clone_graphic = graphic_info[clone_graphic].clone_from;
1705 num_references_followed++;
1708 if (num_references_followed >= max_num_images)
1711 Warn("error found in config file:");
1712 Warn("- config file: '%s'", getImageConfigFilename());
1713 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1714 Warn("error: loop discovered when resolving cloned graphics");
1715 Warn("custom graphic rejected for this element/action");
1717 if (graphic == fallback_graphic)
1718 Fail("no fallback graphic available");
1720 Warn("fallback done to 'char_exclam' for this graphic");
1723 graphic_info[graphic] = graphic_info[fallback_graphic];
1727 graphic_info[graphic] = graphic_info[clone_graphic];
1728 graphic_info[graphic].clone_from = clone_graphic;
1732 static void InitGraphicInfo(void)
1734 int fallback_graphic = IMG_CHAR_EXCLAM;
1735 int num_images = getImageListSize();
1738 // use image size as default values for width and height for these images
1739 static int full_size_graphics[] =
1742 IMG_GLOBAL_BORDER_MAIN,
1743 IMG_GLOBAL_BORDER_SCORES,
1744 IMG_GLOBAL_BORDER_EDITOR,
1745 IMG_GLOBAL_BORDER_PLAYING,
1748 IMG_BACKGROUND_ENVELOPE_1,
1749 IMG_BACKGROUND_ENVELOPE_2,
1750 IMG_BACKGROUND_ENVELOPE_3,
1751 IMG_BACKGROUND_ENVELOPE_4,
1752 IMG_BACKGROUND_REQUEST,
1755 IMG_BACKGROUND_LOADING_INITIAL,
1756 IMG_BACKGROUND_LOADING,
1757 IMG_BACKGROUND_TITLE_INITIAL,
1758 IMG_BACKGROUND_TITLE,
1759 IMG_BACKGROUND_MAIN,
1760 IMG_BACKGROUND_NAMES,
1761 IMG_BACKGROUND_LEVELS,
1762 IMG_BACKGROUND_LEVELNR,
1763 IMG_BACKGROUND_SCORES,
1764 IMG_BACKGROUND_SCOREINFO,
1765 IMG_BACKGROUND_EDITOR,
1766 IMG_BACKGROUND_INFO,
1767 IMG_BACKGROUND_INFO_ELEMENTS,
1768 IMG_BACKGROUND_INFO_MUSIC,
1769 IMG_BACKGROUND_INFO_CREDITS,
1770 IMG_BACKGROUND_INFO_PROGRAM,
1771 IMG_BACKGROUND_INFO_VERSION,
1772 IMG_BACKGROUND_INFO_LEVELSET,
1773 IMG_BACKGROUND_SETUP,
1774 IMG_BACKGROUND_PLAYING,
1775 IMG_BACKGROUND_DOOR,
1776 IMG_BACKGROUND_TAPE,
1777 IMG_BACKGROUND_PANEL,
1778 IMG_BACKGROUND_PALETTE,
1779 IMG_BACKGROUND_TOOLBOX,
1781 IMG_TITLESCREEN_INITIAL_1,
1782 IMG_TITLESCREEN_INITIAL_2,
1783 IMG_TITLESCREEN_INITIAL_3,
1784 IMG_TITLESCREEN_INITIAL_4,
1785 IMG_TITLESCREEN_INITIAL_5,
1792 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1793 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1794 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1795 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1796 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1797 IMG_BACKGROUND_TITLEMESSAGE_1,
1798 IMG_BACKGROUND_TITLEMESSAGE_2,
1799 IMG_BACKGROUND_TITLEMESSAGE_3,
1800 IMG_BACKGROUND_TITLEMESSAGE_4,
1801 IMG_BACKGROUND_TITLEMESSAGE_5,
1806 FreeGlobalAnimEventInfo();
1808 checked_free(graphic_info);
1810 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1812 // initialize "use_image_size" flag with default value
1813 for (i = 0; i < num_images; i++)
1814 graphic_info[i].use_image_size = FALSE;
1816 // initialize "use_image_size" flag from static configuration above
1817 for (i = 0; full_size_graphics[i] != -1; i++)
1818 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1820 // first set all graphic paramaters ...
1821 for (i = 0; i < num_images; i++)
1822 set_graphic_parameters(i);
1824 // ... then copy these parameters for cloned graphics
1825 for (i = 0; i < num_images; i++)
1826 if (graphic_info[i].clone_from != -1)
1827 set_cloned_graphic_parameters(i);
1829 for (i = 0; i < num_images; i++)
1831 Bitmap *src_bitmap = graphic_info[i].bitmap;
1835 int src_bitmap_width, src_bitmap_height;
1837 // now check if no animation frames are outside of the loaded image
1839 if (graphic_info[i].bitmap == NULL)
1840 continue; // skip check for optional images that are undefined
1842 // get image size (this can differ from the standard element tile size!)
1843 width = graphic_info[i].width;
1844 height = graphic_info[i].height;
1846 // get final bitmap size (with scaling, but without small images)
1847 src_bitmap_width = graphic_info[i].src_image_width;
1848 src_bitmap_height = graphic_info[i].src_image_height;
1850 // check if first animation frame is inside specified bitmap
1852 // do not use getGraphicSourceXY() here to get position of first frame;
1853 // this avoids calculating wrong start position for out-of-bounds frame
1854 src_x = graphic_info[i].src_x;
1855 src_y = graphic_info[i].src_y;
1857 if (program.headless)
1860 if (src_x < 0 || src_y < 0 ||
1861 src_x + width > src_bitmap_width ||
1862 src_y + height > src_bitmap_height)
1865 Warn("error found in config file:");
1866 Warn("- config file: '%s'", getImageConfigFilename());
1867 Warn("- config token: '%s'", getTokenFromImageID(i));
1868 Warn("- image file: '%s'", src_bitmap->source_filename);
1869 Warn("- frame size: %d, %d", width, height);
1870 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1871 src_x, src_y, src_bitmap_width, src_bitmap_height);
1872 Warn("custom graphic rejected for this element/action");
1874 if (i == fallback_graphic)
1875 Fail("no fallback graphic available");
1877 Warn("fallback done to 'char_exclam' for this graphic");
1880 graphic_info[i] = graphic_info[fallback_graphic];
1882 // if first frame out of bounds, do not check last frame anymore
1886 // check if last animation frame is inside specified bitmap
1888 last_frame = graphic_info[i].anim_frames - 1;
1889 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1891 if (src_x < 0 || src_y < 0 ||
1892 src_x + width > src_bitmap_width ||
1893 src_y + height > src_bitmap_height)
1896 Warn("error found in config file:");
1897 Warn("- config file: '%s'", getImageConfigFilename());
1898 Warn("- config token: '%s'", getTokenFromImageID(i));
1899 Warn("- image file: '%s'", src_bitmap->source_filename);
1900 Warn("- frame size: %d, %d", width, height);
1901 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1902 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1903 Warn("custom graphic rejected for this element/action");
1905 if (i == fallback_graphic)
1906 Fail("no fallback graphic available");
1908 Warn("fallback done to 'char_exclam' for this graphic");
1911 graphic_info[i] = graphic_info[fallback_graphic];
1916 static void InitGraphicCompatibilityInfo(void)
1918 struct FileInfo *fi_global_door =
1919 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1920 int num_images = getImageListSize();
1923 /* the following compatibility handling is needed for the following case:
1924 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1925 graphics mainly used for door and panel graphics, like editor, tape and
1926 in-game buttons with hard-coded bitmap positions and button sizes; as
1927 these graphics now have individual definitions, redefining "global.door"
1928 to change all these graphics at once like before does not work anymore
1929 (because all those individual definitions still have their default values);
1930 to solve this, remap all those individual definitions that are not
1931 redefined to the new bitmap of "global.door" if it was redefined */
1933 // special compatibility handling if image "global.door" was redefined
1934 if (fi_global_door->redefined)
1936 for (i = 0; i < num_images; i++)
1938 struct FileInfo *fi = getImageListEntryFromImageID(i);
1940 // process only those images that still use the default settings
1943 // process all images which default to same image as "global.door"
1944 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1946 // skip all images that are cloned from images that default to same
1947 // image as "global.door", but that are redefined to something else
1948 if (graphic_info[i].clone_from != -1)
1950 int cloned_graphic = graphic_info[i].clone_from;
1952 if (getImageListEntryFromImageID(cloned_graphic)->redefined)
1957 Debug("init:InitGraphicCompatibilityInfo",
1958 "special treatment needed for token '%s'", fi->token);
1961 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1962 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1968 // special compatibility handling for "Snake Bite" graphics set
1969 if (strPrefix(leveldir_current->identifier, "snake_bite"))
1971 Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
1973 BlitBitmap(bitmap, bitmap, 18, 66, 32, 480, 50, 66);
1974 BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
1976 ClearRectangle(bitmap, 2, 66, 32, 480);
1977 ClearRectangle(bitmap, 514, 66, 32, 480);
1980 // special compatibility handling for "Jue" graphics sets (2007 and 2019)
1981 boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
1982 if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
2000 int mode_old = GAME_MODE_SCORES;
2001 int mode_new = GAME_MODE_SCOREINFO;
2004 // adjust title screens on score info page
2005 for (i = 0; font_title[i] != -1; i++)
2007 struct FontInfo *fi = &font_info[font_title[i]];
2009 fi->special_graphic[mode_new] = fi->special_graphic[mode_old];
2010 fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2013 // adjust vertical text and button positions on scores page
2014 for (i = 0; font_text[i] != -1; i++)
2016 for (j = 0; j < 2; j++)
2018 boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2019 int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2020 int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2021 int font_yoffset = (jue0 ? 10 : 5);
2023 gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2027 // adjust page offsets on score info page
2028 menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2029 menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2032 InitGraphicCompatibilityInfo_Doors();
2035 static void InitElementSoundInfo(void)
2037 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2038 int num_property_mappings = getSoundListPropertyMappingSize();
2041 // set values to -1 to identify later as "uninitialized" values
2042 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2043 for (act = 0; act < NUM_ACTIONS; act++)
2044 element_info[i].sound[act] = -1;
2046 // initialize element/sound mapping from static configuration
2047 for (i = 0; element_to_sound[i].element > -1; i++)
2049 int element = element_to_sound[i].element;
2050 int action = element_to_sound[i].action;
2051 int sound = element_to_sound[i].sound;
2052 boolean is_class = element_to_sound[i].is_class;
2055 action = ACTION_DEFAULT;
2058 element_info[element].sound[action] = sound;
2060 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2061 if (strEqual(element_info[j].class_name,
2062 element_info[element].class_name))
2063 element_info[j].sound[action] = sound;
2066 // initialize element class/sound mapping from dynamic configuration
2067 for (i = 0; i < num_property_mappings; i++)
2069 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2070 int action = property_mapping[i].ext1_index;
2071 int sound = property_mapping[i].artwork_index;
2073 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2077 action = ACTION_DEFAULT;
2079 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2080 if (strEqual(element_info[j].class_name,
2081 element_info[element_class].class_name))
2082 element_info[j].sound[action] = sound;
2085 // initialize element/sound mapping from dynamic configuration
2086 for (i = 0; i < num_property_mappings; i++)
2088 int element = property_mapping[i].base_index;
2089 int action = property_mapping[i].ext1_index;
2090 int sound = property_mapping[i].artwork_index;
2092 if (element >= MAX_NUM_ELEMENTS)
2096 action = ACTION_DEFAULT;
2098 element_info[element].sound[action] = sound;
2101 // now set all '-1' values to element specific default values
2102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2104 for (act = 0; act < NUM_ACTIONS; act++)
2106 // generic default action sound (defined by "[default]" directive)
2107 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2109 // look for special default action sound (classic game specific)
2110 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2111 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2112 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2113 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2114 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2115 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2116 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2117 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2119 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2120 // !!! make this better !!!
2121 if (i == EL_EMPTY_SPACE)
2122 default_action_sound = element_info[EL_DEFAULT].sound[act];
2124 // no sound for this specific action -- use default action sound
2125 if (element_info[i].sound[act] == -1)
2126 element_info[i].sound[act] = default_action_sound;
2130 // copy sound settings to some elements that are only stored in level file
2131 // in native R'n'D levels, but are used by game engine in native EM levels
2132 for (i = 0; copy_properties[i][0] != -1; i++)
2133 for (j = 1; j <= 4; j++)
2134 for (act = 0; act < NUM_ACTIONS; act++)
2135 element_info[copy_properties[i][j]].sound[act] =
2136 element_info[copy_properties[i][0]].sound[act];
2139 static void InitGameModeSoundInfo(void)
2143 // set values to -1 to identify later as "uninitialized" values
2144 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2147 // initialize gamemode/sound mapping from static configuration
2148 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2150 int gamemode = gamemode_to_sound[i].gamemode;
2151 int sound = gamemode_to_sound[i].sound;
2154 gamemode = GAME_MODE_DEFAULT;
2156 menu.sound[gamemode] = sound;
2159 // now set all '-1' values to levelset specific default values
2160 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2161 if (menu.sound[i] == -1)
2162 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2165 static void set_sound_parameters(int sound, char **parameter_raw)
2167 int parameter[NUM_SND_ARGS];
2170 // get integer values from string parameters
2171 for (i = 0; i < NUM_SND_ARGS; i++)
2173 get_parameter_value(parameter_raw[i],
2174 sound_config_suffix[i].token,
2175 sound_config_suffix[i].type);
2177 // explicit loop mode setting in configuration overrides default value
2178 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2179 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2181 // sound volume to change the original volume when loading the sound file
2182 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2184 // sound priority to give certain sounds a higher or lower priority
2185 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2188 static void InitSoundInfo(void)
2190 int *sound_effect_properties;
2191 int num_sounds = getSoundListSize();
2194 checked_free(sound_info);
2196 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2197 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2199 // initialize sound effect for all elements to "no sound"
2200 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2201 for (j = 0; j < NUM_ACTIONS; j++)
2202 element_info[i].sound[j] = SND_UNDEFINED;
2204 for (i = 0; i < num_sounds; i++)
2206 struct FileInfo *sound = getSoundListEntry(i);
2207 int len_effect_text = strlen(sound->token);
2209 sound_effect_properties[i] = ACTION_OTHER;
2210 sound_info[i].loop = FALSE; // default: play sound only once
2212 // determine all loop sounds and identify certain sound classes
2214 for (j = 0; element_action_info[j].suffix; j++)
2216 int len_action_text = strlen(element_action_info[j].suffix);
2218 if (len_action_text < len_effect_text &&
2219 strEqual(&sound->token[len_effect_text - len_action_text],
2220 element_action_info[j].suffix))
2222 sound_effect_properties[i] = element_action_info[j].value;
2223 sound_info[i].loop = element_action_info[j].is_loop_sound;
2229 // associate elements and some selected sound actions
2231 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2233 if (element_info[j].class_name)
2235 int len_class_text = strlen(element_info[j].class_name);
2237 if (len_class_text + 1 < len_effect_text &&
2238 strncmp(sound->token,
2239 element_info[j].class_name, len_class_text) == 0 &&
2240 sound->token[len_class_text] == '.')
2242 int sound_action_value = sound_effect_properties[i];
2244 element_info[j].sound[sound_action_value] = i;
2249 set_sound_parameters(i, sound->parameter);
2252 free(sound_effect_properties);
2255 static void InitGameModeMusicInfo(void)
2257 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2258 int num_property_mappings = getMusicListPropertyMappingSize();
2259 int default_levelset_music = -1;
2262 // set values to -1 to identify later as "uninitialized" values
2263 for (i = 0; i < MAX_LEVELS; i++)
2264 levelset.music[i] = -1;
2265 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2268 // initialize gamemode/music mapping from static configuration
2269 for (i = 0; gamemode_to_music[i].music > -1; i++)
2271 int gamemode = gamemode_to_music[i].gamemode;
2272 int music = gamemode_to_music[i].music;
2275 gamemode = GAME_MODE_DEFAULT;
2277 menu.music[gamemode] = music;
2280 // initialize gamemode/music mapping from dynamic configuration
2281 for (i = 0; i < num_property_mappings; i++)
2283 int prefix = property_mapping[i].base_index;
2284 int gamemode = property_mapping[i].ext2_index;
2285 int level = property_mapping[i].ext3_index;
2286 int music = property_mapping[i].artwork_index;
2288 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2292 gamemode = GAME_MODE_DEFAULT;
2294 // level specific music only allowed for in-game music
2295 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2296 gamemode = GAME_MODE_PLAYING;
2301 default_levelset_music = music;
2304 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2305 levelset.music[level] = music;
2306 if (gamemode != GAME_MODE_PLAYING)
2307 menu.music[gamemode] = music;
2310 // now set all '-1' values to menu specific default values
2311 // (undefined values of "levelset.music[]" might stay at "-1" to
2312 // allow dynamic selection of music files from music directory!)
2313 for (i = 0; i < MAX_LEVELS; i++)
2314 if (levelset.music[i] == -1)
2315 levelset.music[i] = default_levelset_music;
2316 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2317 if (menu.music[i] == -1)
2318 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2321 static void set_music_parameters(int music, char **parameter_raw)
2323 int parameter[NUM_MUS_ARGS];
2326 // get integer values from string parameters
2327 for (i = 0; i < NUM_MUS_ARGS; i++)
2329 get_parameter_value(parameter_raw[i],
2330 music_config_suffix[i].token,
2331 music_config_suffix[i].type);
2333 // explicit loop mode setting in configuration overrides default value
2334 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2335 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2338 static void InitMusicInfo(void)
2340 int num_music = getMusicListSize();
2343 checked_free(music_info);
2345 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2347 for (i = 0; i < num_music; i++)
2349 struct FileInfo *music = getMusicListEntry(i);
2350 int len_music_text = strlen(music->token);
2352 music_info[i].loop = TRUE; // default: play music in loop mode
2354 // determine all loop music
2356 for (j = 0; music_prefix_info[j].prefix; j++)
2358 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2360 if (len_prefix_text < len_music_text &&
2361 strncmp(music->token,
2362 music_prefix_info[j].prefix, len_prefix_text) == 0)
2364 music_info[i].loop = music_prefix_info[j].is_loop_music;
2370 set_music_parameters(i, music->parameter);
2375 static void InitGameInfoFromArtworkInfo(void)
2377 // special case: store initial value of custom artwork setting
2378 game.use_masked_elements_initial = game.use_masked_elements;
2381 static void ReinitializeGraphics(void)
2383 print_timestamp_init("ReinitializeGraphics");
2385 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2387 InitGraphicInfo(); // graphic properties mapping
2388 print_timestamp_time("InitGraphicInfo");
2389 InitElementGraphicInfo(); // element game graphic mapping
2390 print_timestamp_time("InitElementGraphicInfo");
2391 InitElementSpecialGraphicInfo(); // element special graphic mapping
2392 print_timestamp_time("InitElementSpecialGraphicInfo");
2394 InitElementSmallImages(); // scale elements to all needed sizes
2395 print_timestamp_time("InitElementSmallImages");
2396 InitScaledImages(); // scale all other images, if needed
2397 print_timestamp_time("InitScaledImages");
2398 InitBitmapPointers(); // set standard size bitmap pointers
2399 print_timestamp_time("InitBitmapPointers");
2400 InitFontGraphicInfo(); // initialize text drawing functions
2401 print_timestamp_time("InitFontGraphicInfo");
2402 InitGlobalAnimGraphicInfo(); // initialize global animation config
2403 print_timestamp_time("InitGlobalAnimGraphicInfo");
2405 InitImageTextures(); // create textures for certain images
2406 print_timestamp_time("InitImageTextures");
2408 InitGraphicInfo_EM(); // graphic mapping for EM engine
2409 print_timestamp_time("InitGraphicInfo_EM");
2411 InitGraphicCompatibilityInfo();
2412 print_timestamp_time("InitGraphicCompatibilityInfo");
2415 print_timestamp_time("InitGadgets");
2417 print_timestamp_time("InitDoors");
2419 InitGameInfoFromArtworkInfo();
2421 print_timestamp_done("ReinitializeGraphics");
2424 static void ReinitializeSounds(void)
2426 InitSoundInfo(); // sound properties mapping
2427 InitElementSoundInfo(); // element game sound mapping
2428 InitGameModeSoundInfo(); // game mode sound mapping
2429 InitGlobalAnimSoundInfo(); // global animation sound settings
2431 InitPlayLevelSound(); // internal game sound settings
2434 static void ReinitializeMusic(void)
2436 InitMusicInfo(); // music properties mapping
2437 InitGameModeMusicInfo(); // game mode music mapping
2438 InitGlobalAnimMusicInfo(); // global animation music settings
2441 static int get_special_property_bit(int element, int property_bit_nr)
2443 struct PropertyBitInfo
2449 static struct PropertyBitInfo pb_can_move_into_acid[] =
2451 // the player may be able fall into acid when gravity is activated
2456 { EL_SP_MURPHY, 0 },
2457 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2459 // all elements that can move may be able to also move into acid
2462 { EL_BUG_RIGHT, 1 },
2465 { EL_SPACESHIP, 2 },
2466 { EL_SPACESHIP_LEFT, 2 },
2467 { EL_SPACESHIP_RIGHT, 2 },
2468 { EL_SPACESHIP_UP, 2 },
2469 { EL_SPACESHIP_DOWN, 2 },
2470 { EL_BD_BUTTERFLY, 3 },
2471 { EL_BD_BUTTERFLY_LEFT, 3 },
2472 { EL_BD_BUTTERFLY_RIGHT, 3 },
2473 { EL_BD_BUTTERFLY_UP, 3 },
2474 { EL_BD_BUTTERFLY_DOWN, 3 },
2475 { EL_BD_FIREFLY, 4 },
2476 { EL_BD_FIREFLY_LEFT, 4 },
2477 { EL_BD_FIREFLY_RIGHT, 4 },
2478 { EL_BD_FIREFLY_UP, 4 },
2479 { EL_BD_FIREFLY_DOWN, 4 },
2481 { EL_YAMYAM_LEFT, 5 },
2482 { EL_YAMYAM_RIGHT, 5 },
2483 { EL_YAMYAM_UP, 5 },
2484 { EL_YAMYAM_DOWN, 5 },
2485 { EL_DARK_YAMYAM, 6 },
2488 { EL_PACMAN_LEFT, 8 },
2489 { EL_PACMAN_RIGHT, 8 },
2490 { EL_PACMAN_UP, 8 },
2491 { EL_PACMAN_DOWN, 8 },
2493 { EL_MOLE_LEFT, 9 },
2494 { EL_MOLE_RIGHT, 9 },
2496 { EL_MOLE_DOWN, 9 },
2500 { EL_SATELLITE, 13 },
2501 { EL_SP_SNIKSNAK, 14 },
2502 { EL_SP_ELECTRON, 15 },
2505 { EL_SPRING_LEFT, 17 },
2506 { EL_SPRING_RIGHT, 17 },
2507 { EL_EMC_ANDROID, 18 },
2512 static struct PropertyBitInfo pb_dont_collide_with[] =
2514 { EL_SP_SNIKSNAK, 0 },
2515 { EL_SP_ELECTRON, 1 },
2523 struct PropertyBitInfo *pb_info;
2526 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2527 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2532 struct PropertyBitInfo *pb_info = NULL;
2535 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2536 if (pb_definition[i].bit_nr == property_bit_nr)
2537 pb_info = pb_definition[i].pb_info;
2539 if (pb_info == NULL)
2542 for (i = 0; pb_info[i].element != -1; i++)
2543 if (pb_info[i].element == element)
2544 return pb_info[i].bit_nr;
2549 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2550 boolean property_value)
2552 int bit_nr = get_special_property_bit(element, property_bit_nr);
2557 *bitfield |= (1 << bit_nr);
2559 *bitfield &= ~(1 << bit_nr);
2563 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2565 int bit_nr = get_special_property_bit(element, property_bit_nr);
2568 return ((*bitfield & (1 << bit_nr)) != 0);
2573 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2575 static int group_nr;
2576 static struct ElementGroupInfo *group;
2577 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2580 if (actual_group == NULL) // not yet initialized
2583 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2585 Warn("recursion too deep when resolving group element %d",
2586 group_element - EL_GROUP_START + 1);
2588 // replace element which caused too deep recursion by question mark
2589 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2594 if (recursion_depth == 0) // initialization
2596 group = actual_group;
2597 group_nr = GROUP_NR(group_element);
2599 group->num_elements_resolved = 0;
2600 group->choice_pos = 0;
2602 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2603 element_info[i].in_group[group_nr] = FALSE;
2606 for (i = 0; i < actual_group->num_elements; i++)
2608 int element = actual_group->element[i];
2610 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2613 if (IS_GROUP_ELEMENT(element))
2614 ResolveGroupElementExt(element, recursion_depth + 1);
2617 group->element_resolved[group->num_elements_resolved++] = element;
2618 element_info[element].in_group[group_nr] = TRUE;
2623 void ResolveGroupElement(int group_element)
2625 ResolveGroupElementExt(group_element, 0);
2628 void InitElementPropertiesStatic(void)
2630 static boolean clipboard_elements_initialized = FALSE;
2632 static int ep_diggable[] =
2637 EL_SP_BUGGY_BASE_ACTIVATING,
2640 EL_INVISIBLE_SAND_ACTIVE,
2643 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2644 // (if amoeba can grow into anything diggable, maybe keep these out)
2649 EL_SP_BUGGY_BASE_ACTIVE,
2656 static int ep_collectible_only[] =
2678 EL_DYNABOMB_INCREASE_NUMBER,
2679 EL_DYNABOMB_INCREASE_SIZE,
2680 EL_DYNABOMB_INCREASE_POWER,
2698 // !!! handle separately !!!
2699 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2705 static int ep_dont_run_into[] =
2707 // same elements as in 'ep_dont_touch'
2713 // same elements as in 'ep_dont_collide_with'
2725 // !!! maybe this should better be handled by 'ep_diggable' !!!
2730 EL_SP_BUGGY_BASE_ACTIVE,
2737 static int ep_dont_collide_with[] =
2739 // same elements as in 'ep_dont_touch'
2756 static int ep_dont_touch[] =
2766 static int ep_indestructible[] =
2770 EL_ACID_POOL_TOPLEFT,
2771 EL_ACID_POOL_TOPRIGHT,
2772 EL_ACID_POOL_BOTTOMLEFT,
2773 EL_ACID_POOL_BOTTOM,
2774 EL_ACID_POOL_BOTTOMRIGHT,
2775 EL_SP_HARDWARE_GRAY,
2776 EL_SP_HARDWARE_GREEN,
2777 EL_SP_HARDWARE_BLUE,
2779 EL_SP_HARDWARE_YELLOW,
2780 EL_SP_HARDWARE_BASE_1,
2781 EL_SP_HARDWARE_BASE_2,
2782 EL_SP_HARDWARE_BASE_3,
2783 EL_SP_HARDWARE_BASE_4,
2784 EL_SP_HARDWARE_BASE_5,
2785 EL_SP_HARDWARE_BASE_6,
2786 EL_INVISIBLE_STEELWALL,
2787 EL_INVISIBLE_STEELWALL_ACTIVE,
2788 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2789 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2790 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2791 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2792 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2793 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2794 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2795 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2796 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2797 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2798 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2799 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2801 EL_LIGHT_SWITCH_ACTIVE,
2802 EL_SIGN_EXCLAMATION,
2803 EL_SIGN_RADIOACTIVITY,
2810 EL_SIGN_ENTRY_FORBIDDEN,
2811 EL_SIGN_EMERGENCY_EXIT,
2819 EL_STEEL_EXIT_CLOSED,
2821 EL_STEEL_EXIT_OPENING,
2822 EL_STEEL_EXIT_CLOSING,
2823 EL_EM_STEEL_EXIT_CLOSED,
2824 EL_EM_STEEL_EXIT_OPEN,
2825 EL_EM_STEEL_EXIT_OPENING,
2826 EL_EM_STEEL_EXIT_CLOSING,
2827 EL_DC_STEELWALL_1_LEFT,
2828 EL_DC_STEELWALL_1_RIGHT,
2829 EL_DC_STEELWALL_1_TOP,
2830 EL_DC_STEELWALL_1_BOTTOM,
2831 EL_DC_STEELWALL_1_HORIZONTAL,
2832 EL_DC_STEELWALL_1_VERTICAL,
2833 EL_DC_STEELWALL_1_TOPLEFT,
2834 EL_DC_STEELWALL_1_TOPRIGHT,
2835 EL_DC_STEELWALL_1_BOTTOMLEFT,
2836 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2837 EL_DC_STEELWALL_1_TOPLEFT_2,
2838 EL_DC_STEELWALL_1_TOPRIGHT_2,
2839 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2840 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2841 EL_DC_STEELWALL_2_LEFT,
2842 EL_DC_STEELWALL_2_RIGHT,
2843 EL_DC_STEELWALL_2_TOP,
2844 EL_DC_STEELWALL_2_BOTTOM,
2845 EL_DC_STEELWALL_2_HORIZONTAL,
2846 EL_DC_STEELWALL_2_VERTICAL,
2847 EL_DC_STEELWALL_2_MIDDLE,
2848 EL_DC_STEELWALL_2_SINGLE,
2849 EL_STEELWALL_SLIPPERY,
2863 EL_GATE_1_GRAY_ACTIVE,
2864 EL_GATE_2_GRAY_ACTIVE,
2865 EL_GATE_3_GRAY_ACTIVE,
2866 EL_GATE_4_GRAY_ACTIVE,
2875 EL_EM_GATE_1_GRAY_ACTIVE,
2876 EL_EM_GATE_2_GRAY_ACTIVE,
2877 EL_EM_GATE_3_GRAY_ACTIVE,
2878 EL_EM_GATE_4_GRAY_ACTIVE,
2887 EL_EMC_GATE_5_GRAY_ACTIVE,
2888 EL_EMC_GATE_6_GRAY_ACTIVE,
2889 EL_EMC_GATE_7_GRAY_ACTIVE,
2890 EL_EMC_GATE_8_GRAY_ACTIVE,
2892 EL_DC_GATE_WHITE_GRAY,
2893 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2894 EL_DC_GATE_FAKE_GRAY,
2896 EL_SWITCHGATE_OPENING,
2897 EL_SWITCHGATE_CLOSED,
2898 EL_SWITCHGATE_CLOSING,
2899 EL_DC_SWITCHGATE_SWITCH_UP,
2900 EL_DC_SWITCHGATE_SWITCH_DOWN,
2902 EL_TIMEGATE_OPENING,
2904 EL_TIMEGATE_CLOSING,
2905 EL_DC_TIMEGATE_SWITCH,
2906 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2910 EL_TUBE_VERTICAL_LEFT,
2911 EL_TUBE_VERTICAL_RIGHT,
2912 EL_TUBE_HORIZONTAL_UP,
2913 EL_TUBE_HORIZONTAL_DOWN,
2918 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2919 EL_EXPANDABLE_STEELWALL_VERTICAL,
2920 EL_EXPANDABLE_STEELWALL_ANY,
2925 static int ep_slippery[] =
2939 EL_ROBOT_WHEEL_ACTIVE,
2945 EL_ACID_POOL_TOPLEFT,
2946 EL_ACID_POOL_TOPRIGHT,
2956 EL_STEELWALL_SLIPPERY,
2959 EL_EMC_WALL_SLIPPERY_1,
2960 EL_EMC_WALL_SLIPPERY_2,
2961 EL_EMC_WALL_SLIPPERY_3,
2962 EL_EMC_WALL_SLIPPERY_4,
2964 EL_EMC_MAGIC_BALL_ACTIVE,
2969 static int ep_can_change[] =
2974 static int ep_can_move[] =
2976 // same elements as in 'pb_can_move_into_acid'
2999 static int ep_can_fall[] =
3014 EL_QUICKSAND_FAST_FULL,
3016 EL_BD_MAGIC_WALL_FULL,
3017 EL_DC_MAGIC_WALL_FULL,
3031 static int ep_can_smash_player[] =
3057 static int ep_can_smash_enemies[] =
3066 static int ep_can_smash_everything[] =
3075 static int ep_explodes_by_fire[] =
3077 // same elements as in 'ep_explodes_impact'
3082 // same elements as in 'ep_explodes_smashed'
3092 EL_EM_DYNAMITE_ACTIVE,
3093 EL_DYNABOMB_PLAYER_1_ACTIVE,
3094 EL_DYNABOMB_PLAYER_2_ACTIVE,
3095 EL_DYNABOMB_PLAYER_3_ACTIVE,
3096 EL_DYNABOMB_PLAYER_4_ACTIVE,
3097 EL_DYNABOMB_INCREASE_NUMBER,
3098 EL_DYNABOMB_INCREASE_SIZE,
3099 EL_DYNABOMB_INCREASE_POWER,
3100 EL_SP_DISK_RED_ACTIVE,
3114 static int ep_explodes_smashed[] =
3116 // same elements as in 'ep_explodes_impact'
3130 static int ep_explodes_impact[] =
3139 static int ep_walkable_over[] =
3159 EL_SOKOBAN_FIELD_EMPTY,
3166 EL_EM_STEEL_EXIT_OPEN,
3167 EL_EM_STEEL_EXIT_OPENING,
3176 EL_GATE_1_GRAY_ACTIVE,
3177 EL_GATE_2_GRAY_ACTIVE,
3178 EL_GATE_3_GRAY_ACTIVE,
3179 EL_GATE_4_GRAY_ACTIVE,
3187 static int ep_walkable_inside[] =
3192 EL_TUBE_VERTICAL_LEFT,
3193 EL_TUBE_VERTICAL_RIGHT,
3194 EL_TUBE_HORIZONTAL_UP,
3195 EL_TUBE_HORIZONTAL_DOWN,
3204 static int ep_walkable_under[] =
3209 static int ep_passable_over[] =
3219 EL_EM_GATE_1_GRAY_ACTIVE,
3220 EL_EM_GATE_2_GRAY_ACTIVE,
3221 EL_EM_GATE_3_GRAY_ACTIVE,
3222 EL_EM_GATE_4_GRAY_ACTIVE,
3231 EL_EMC_GATE_5_GRAY_ACTIVE,
3232 EL_EMC_GATE_6_GRAY_ACTIVE,
3233 EL_EMC_GATE_7_GRAY_ACTIVE,
3234 EL_EMC_GATE_8_GRAY_ACTIVE,
3236 EL_DC_GATE_WHITE_GRAY,
3237 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3244 static int ep_passable_inside[] =
3250 EL_SP_PORT_HORIZONTAL,
3251 EL_SP_PORT_VERTICAL,
3253 EL_SP_GRAVITY_PORT_LEFT,
3254 EL_SP_GRAVITY_PORT_RIGHT,
3255 EL_SP_GRAVITY_PORT_UP,
3256 EL_SP_GRAVITY_PORT_DOWN,
3257 EL_SP_GRAVITY_ON_PORT_LEFT,
3258 EL_SP_GRAVITY_ON_PORT_RIGHT,
3259 EL_SP_GRAVITY_ON_PORT_UP,
3260 EL_SP_GRAVITY_ON_PORT_DOWN,
3261 EL_SP_GRAVITY_OFF_PORT_LEFT,
3262 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3263 EL_SP_GRAVITY_OFF_PORT_UP,
3264 EL_SP_GRAVITY_OFF_PORT_DOWN,
3269 static int ep_passable_under[] =
3274 static int ep_droppable[] =
3279 static int ep_explodes_1x1_old[] =
3284 static int ep_pushable[] =
3296 EL_SOKOBAN_FIELD_FULL,
3305 static int ep_explodes_cross_old[] =
3310 static int ep_protected[] =
3312 // same elements as in 'ep_walkable_inside'
3316 EL_TUBE_VERTICAL_LEFT,
3317 EL_TUBE_VERTICAL_RIGHT,
3318 EL_TUBE_HORIZONTAL_UP,
3319 EL_TUBE_HORIZONTAL_DOWN,
3325 // same elements as in 'ep_passable_over'
3334 EL_EM_GATE_1_GRAY_ACTIVE,
3335 EL_EM_GATE_2_GRAY_ACTIVE,
3336 EL_EM_GATE_3_GRAY_ACTIVE,
3337 EL_EM_GATE_4_GRAY_ACTIVE,
3346 EL_EMC_GATE_5_GRAY_ACTIVE,
3347 EL_EMC_GATE_6_GRAY_ACTIVE,
3348 EL_EMC_GATE_7_GRAY_ACTIVE,
3349 EL_EMC_GATE_8_GRAY_ACTIVE,
3351 EL_DC_GATE_WHITE_GRAY,
3352 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3356 // same elements as in 'ep_passable_inside'
3361 EL_SP_PORT_HORIZONTAL,
3362 EL_SP_PORT_VERTICAL,
3364 EL_SP_GRAVITY_PORT_LEFT,
3365 EL_SP_GRAVITY_PORT_RIGHT,
3366 EL_SP_GRAVITY_PORT_UP,
3367 EL_SP_GRAVITY_PORT_DOWN,
3368 EL_SP_GRAVITY_ON_PORT_LEFT,
3369 EL_SP_GRAVITY_ON_PORT_RIGHT,
3370 EL_SP_GRAVITY_ON_PORT_UP,
3371 EL_SP_GRAVITY_ON_PORT_DOWN,
3372 EL_SP_GRAVITY_OFF_PORT_LEFT,
3373 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3374 EL_SP_GRAVITY_OFF_PORT_UP,
3375 EL_SP_GRAVITY_OFF_PORT_DOWN,
3380 static int ep_throwable[] =
3385 static int ep_can_explode[] =
3387 // same elements as in 'ep_explodes_impact'
3392 // same elements as in 'ep_explodes_smashed'
3398 // elements that can explode by explosion or by dragonfire
3402 EL_EM_DYNAMITE_ACTIVE,
3403 EL_DYNABOMB_PLAYER_1_ACTIVE,
3404 EL_DYNABOMB_PLAYER_2_ACTIVE,
3405 EL_DYNABOMB_PLAYER_3_ACTIVE,
3406 EL_DYNABOMB_PLAYER_4_ACTIVE,
3407 EL_DYNABOMB_INCREASE_NUMBER,
3408 EL_DYNABOMB_INCREASE_SIZE,
3409 EL_DYNABOMB_INCREASE_POWER,
3410 EL_SP_DISK_RED_ACTIVE,
3418 // elements that can explode only by explosion
3424 static int ep_gravity_reachable[] =
3430 EL_INVISIBLE_SAND_ACTIVE,
3435 EL_SP_PORT_HORIZONTAL,
3436 EL_SP_PORT_VERTICAL,
3438 EL_SP_GRAVITY_PORT_LEFT,
3439 EL_SP_GRAVITY_PORT_RIGHT,
3440 EL_SP_GRAVITY_PORT_UP,
3441 EL_SP_GRAVITY_PORT_DOWN,
3442 EL_SP_GRAVITY_ON_PORT_LEFT,
3443 EL_SP_GRAVITY_ON_PORT_RIGHT,
3444 EL_SP_GRAVITY_ON_PORT_UP,
3445 EL_SP_GRAVITY_ON_PORT_DOWN,
3446 EL_SP_GRAVITY_OFF_PORT_LEFT,
3447 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3448 EL_SP_GRAVITY_OFF_PORT_UP,
3449 EL_SP_GRAVITY_OFF_PORT_DOWN,
3455 static int ep_empty_space[] =
3478 static int ep_player[] =
3485 EL_SOKOBAN_FIELD_PLAYER,
3491 static int ep_can_pass_magic_wall[] =
3505 static int ep_can_pass_dc_magic_wall[] =
3521 static int ep_switchable[] =
3525 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3534 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3537 EL_SWITCHGATE_SWITCH_UP,
3538 EL_SWITCHGATE_SWITCH_DOWN,
3539 EL_DC_SWITCHGATE_SWITCH_UP,
3540 EL_DC_SWITCHGATE_SWITCH_DOWN,
3542 EL_LIGHT_SWITCH_ACTIVE,
3544 EL_DC_TIMEGATE_SWITCH,
3545 EL_BALLOON_SWITCH_LEFT,
3546 EL_BALLOON_SWITCH_RIGHT,
3547 EL_BALLOON_SWITCH_UP,
3548 EL_BALLOON_SWITCH_DOWN,
3549 EL_BALLOON_SWITCH_ANY,
3550 EL_BALLOON_SWITCH_NONE,
3553 EL_EMC_MAGIC_BALL_SWITCH,
3554 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3559 static int ep_bd_element[] =
3593 static int ep_sp_element[] =
3595 // should always be valid
3598 // standard classic Supaplex elements
3605 EL_SP_HARDWARE_GRAY,
3613 EL_SP_GRAVITY_PORT_RIGHT,
3614 EL_SP_GRAVITY_PORT_DOWN,
3615 EL_SP_GRAVITY_PORT_LEFT,
3616 EL_SP_GRAVITY_PORT_UP,
3621 EL_SP_PORT_VERTICAL,
3622 EL_SP_PORT_HORIZONTAL,
3628 EL_SP_HARDWARE_BASE_1,
3629 EL_SP_HARDWARE_GREEN,
3630 EL_SP_HARDWARE_BLUE,
3632 EL_SP_HARDWARE_YELLOW,
3633 EL_SP_HARDWARE_BASE_2,
3634 EL_SP_HARDWARE_BASE_3,
3635 EL_SP_HARDWARE_BASE_4,
3636 EL_SP_HARDWARE_BASE_5,
3637 EL_SP_HARDWARE_BASE_6,
3641 // additional elements that appeared in newer Supaplex levels
3644 // additional gravity port elements (not switching, but setting gravity)
3645 EL_SP_GRAVITY_ON_PORT_LEFT,
3646 EL_SP_GRAVITY_ON_PORT_RIGHT,
3647 EL_SP_GRAVITY_ON_PORT_UP,
3648 EL_SP_GRAVITY_ON_PORT_DOWN,
3649 EL_SP_GRAVITY_OFF_PORT_LEFT,
3650 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3651 EL_SP_GRAVITY_OFF_PORT_UP,
3652 EL_SP_GRAVITY_OFF_PORT_DOWN,
3654 // more than one Murphy in a level results in an inactive clone
3657 // runtime Supaplex elements
3658 EL_SP_DISK_RED_ACTIVE,
3659 EL_SP_TERMINAL_ACTIVE,
3660 EL_SP_BUGGY_BASE_ACTIVATING,
3661 EL_SP_BUGGY_BASE_ACTIVE,
3668 static int ep_sb_element[] =
3673 EL_SOKOBAN_FIELD_EMPTY,
3674 EL_SOKOBAN_FIELD_FULL,
3675 EL_SOKOBAN_FIELD_PLAYER,
3680 EL_INVISIBLE_STEELWALL,
3685 static int ep_gem[] =
3697 static int ep_food_dark_yamyam[] =
3725 static int ep_food_penguin[] =
3739 static int ep_food_pig[] =
3751 static int ep_historic_wall[] =
3762 EL_GATE_1_GRAY_ACTIVE,
3763 EL_GATE_2_GRAY_ACTIVE,
3764 EL_GATE_3_GRAY_ACTIVE,
3765 EL_GATE_4_GRAY_ACTIVE,
3774 EL_EM_GATE_1_GRAY_ACTIVE,
3775 EL_EM_GATE_2_GRAY_ACTIVE,
3776 EL_EM_GATE_3_GRAY_ACTIVE,
3777 EL_EM_GATE_4_GRAY_ACTIVE,
3784 EL_EXPANDABLE_WALL_HORIZONTAL,
3785 EL_EXPANDABLE_WALL_VERTICAL,
3786 EL_EXPANDABLE_WALL_ANY,
3787 EL_EXPANDABLE_WALL_GROWING,
3788 EL_BD_EXPANDABLE_WALL,
3795 EL_SP_HARDWARE_GRAY,
3796 EL_SP_HARDWARE_GREEN,
3797 EL_SP_HARDWARE_BLUE,
3799 EL_SP_HARDWARE_YELLOW,
3800 EL_SP_HARDWARE_BASE_1,
3801 EL_SP_HARDWARE_BASE_2,
3802 EL_SP_HARDWARE_BASE_3,
3803 EL_SP_HARDWARE_BASE_4,
3804 EL_SP_HARDWARE_BASE_5,
3805 EL_SP_HARDWARE_BASE_6,
3807 EL_SP_TERMINAL_ACTIVE,
3810 EL_INVISIBLE_STEELWALL,
3811 EL_INVISIBLE_STEELWALL_ACTIVE,
3813 EL_INVISIBLE_WALL_ACTIVE,
3814 EL_STEELWALL_SLIPPERY,
3831 static int ep_historic_solid[] =
3835 EL_EXPANDABLE_WALL_HORIZONTAL,
3836 EL_EXPANDABLE_WALL_VERTICAL,
3837 EL_EXPANDABLE_WALL_ANY,
3838 EL_BD_EXPANDABLE_WALL,
3851 EL_QUICKSAND_FILLING,
3852 EL_QUICKSAND_EMPTYING,
3854 EL_MAGIC_WALL_ACTIVE,
3855 EL_MAGIC_WALL_EMPTYING,
3856 EL_MAGIC_WALL_FILLING,
3860 EL_BD_MAGIC_WALL_ACTIVE,
3861 EL_BD_MAGIC_WALL_EMPTYING,
3862 EL_BD_MAGIC_WALL_FULL,
3863 EL_BD_MAGIC_WALL_FILLING,
3864 EL_BD_MAGIC_WALL_DEAD,
3873 EL_SP_TERMINAL_ACTIVE,
3877 EL_INVISIBLE_WALL_ACTIVE,
3878 EL_SWITCHGATE_SWITCH_UP,
3879 EL_SWITCHGATE_SWITCH_DOWN,
3881 EL_TIMEGATE_SWITCH_ACTIVE,
3893 // the following elements are a direct copy of "indestructible" elements,
3894 // except "EL_ACID", which is "indestructible", but not "solid"!
3899 EL_ACID_POOL_TOPLEFT,
3900 EL_ACID_POOL_TOPRIGHT,
3901 EL_ACID_POOL_BOTTOMLEFT,
3902 EL_ACID_POOL_BOTTOM,
3903 EL_ACID_POOL_BOTTOMRIGHT,
3904 EL_SP_HARDWARE_GRAY,
3905 EL_SP_HARDWARE_GREEN,
3906 EL_SP_HARDWARE_BLUE,
3908 EL_SP_HARDWARE_YELLOW,
3909 EL_SP_HARDWARE_BASE_1,
3910 EL_SP_HARDWARE_BASE_2,
3911 EL_SP_HARDWARE_BASE_3,
3912 EL_SP_HARDWARE_BASE_4,
3913 EL_SP_HARDWARE_BASE_5,
3914 EL_SP_HARDWARE_BASE_6,
3915 EL_INVISIBLE_STEELWALL,
3916 EL_INVISIBLE_STEELWALL_ACTIVE,
3917 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3918 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3919 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3920 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3921 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3922 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3923 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3924 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3925 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3926 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3930 EL_LIGHT_SWITCH_ACTIVE,
3931 EL_SIGN_EXCLAMATION,
3932 EL_SIGN_RADIOACTIVITY,
3939 EL_SIGN_ENTRY_FORBIDDEN,
3940 EL_SIGN_EMERGENCY_EXIT,
3948 EL_STEEL_EXIT_CLOSED,
3950 EL_STEEL_EXIT_OPENING,
3951 EL_STEEL_EXIT_CLOSING,
3952 EL_EM_STEEL_EXIT_CLOSED,
3953 EL_EM_STEEL_EXIT_OPEN,
3954 EL_EM_STEEL_EXIT_OPENING,
3955 EL_EM_STEEL_EXIT_CLOSING,
3956 EL_DC_STEELWALL_1_LEFT,
3957 EL_DC_STEELWALL_1_RIGHT,
3958 EL_DC_STEELWALL_1_TOP,
3959 EL_DC_STEELWALL_1_BOTTOM,
3960 EL_DC_STEELWALL_1_HORIZONTAL,
3961 EL_DC_STEELWALL_1_VERTICAL,
3962 EL_DC_STEELWALL_1_TOPLEFT,
3963 EL_DC_STEELWALL_1_TOPRIGHT,
3964 EL_DC_STEELWALL_1_BOTTOMLEFT,
3965 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3966 EL_DC_STEELWALL_1_TOPLEFT_2,
3967 EL_DC_STEELWALL_1_TOPRIGHT_2,
3968 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3969 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3970 EL_DC_STEELWALL_2_LEFT,
3971 EL_DC_STEELWALL_2_RIGHT,
3972 EL_DC_STEELWALL_2_TOP,
3973 EL_DC_STEELWALL_2_BOTTOM,
3974 EL_DC_STEELWALL_2_HORIZONTAL,
3975 EL_DC_STEELWALL_2_VERTICAL,
3976 EL_DC_STEELWALL_2_MIDDLE,
3977 EL_DC_STEELWALL_2_SINGLE,
3978 EL_STEELWALL_SLIPPERY,
3992 EL_GATE_1_GRAY_ACTIVE,
3993 EL_GATE_2_GRAY_ACTIVE,
3994 EL_GATE_3_GRAY_ACTIVE,
3995 EL_GATE_4_GRAY_ACTIVE,
4004 EL_EM_GATE_1_GRAY_ACTIVE,
4005 EL_EM_GATE_2_GRAY_ACTIVE,
4006 EL_EM_GATE_3_GRAY_ACTIVE,
4007 EL_EM_GATE_4_GRAY_ACTIVE,
4016 EL_EMC_GATE_5_GRAY_ACTIVE,
4017 EL_EMC_GATE_6_GRAY_ACTIVE,
4018 EL_EMC_GATE_7_GRAY_ACTIVE,
4019 EL_EMC_GATE_8_GRAY_ACTIVE,
4021 EL_DC_GATE_WHITE_GRAY,
4022 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4023 EL_DC_GATE_FAKE_GRAY,
4025 EL_SWITCHGATE_OPENING,
4026 EL_SWITCHGATE_CLOSED,
4027 EL_SWITCHGATE_CLOSING,
4028 EL_DC_SWITCHGATE_SWITCH_UP,
4029 EL_DC_SWITCHGATE_SWITCH_DOWN,
4031 EL_TIMEGATE_OPENING,
4033 EL_TIMEGATE_CLOSING,
4034 EL_DC_TIMEGATE_SWITCH,
4035 EL_DC_TIMEGATE_SWITCH_ACTIVE,
4039 EL_TUBE_VERTICAL_LEFT,
4040 EL_TUBE_VERTICAL_RIGHT,
4041 EL_TUBE_HORIZONTAL_UP,
4042 EL_TUBE_HORIZONTAL_DOWN,
4047 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4048 EL_EXPANDABLE_STEELWALL_VERTICAL,
4049 EL_EXPANDABLE_STEELWALL_ANY,
4054 static int ep_classic_enemy[] =
4071 static int ep_belt[] =
4073 EL_CONVEYOR_BELT_1_LEFT,
4074 EL_CONVEYOR_BELT_1_MIDDLE,
4075 EL_CONVEYOR_BELT_1_RIGHT,
4076 EL_CONVEYOR_BELT_2_LEFT,
4077 EL_CONVEYOR_BELT_2_MIDDLE,
4078 EL_CONVEYOR_BELT_2_RIGHT,
4079 EL_CONVEYOR_BELT_3_LEFT,
4080 EL_CONVEYOR_BELT_3_MIDDLE,
4081 EL_CONVEYOR_BELT_3_RIGHT,
4082 EL_CONVEYOR_BELT_4_LEFT,
4083 EL_CONVEYOR_BELT_4_MIDDLE,
4084 EL_CONVEYOR_BELT_4_RIGHT,
4089 static int ep_belt_active[] =
4091 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4092 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4093 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4094 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4095 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4096 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4097 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4098 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4099 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4100 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4101 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4102 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4107 static int ep_belt_switch[] =
4109 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4110 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4111 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4112 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4113 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4114 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4115 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4116 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4117 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4118 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4119 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4120 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4125 static int ep_tube[] =
4132 EL_TUBE_HORIZONTAL_UP,
4133 EL_TUBE_HORIZONTAL_DOWN,
4135 EL_TUBE_VERTICAL_LEFT,
4136 EL_TUBE_VERTICAL_RIGHT,
4142 static int ep_acid_pool[] =
4144 EL_ACID_POOL_TOPLEFT,
4145 EL_ACID_POOL_TOPRIGHT,
4146 EL_ACID_POOL_BOTTOMLEFT,
4147 EL_ACID_POOL_BOTTOM,
4148 EL_ACID_POOL_BOTTOMRIGHT,
4153 static int ep_keygate[] =
4163 EL_GATE_1_GRAY_ACTIVE,
4164 EL_GATE_2_GRAY_ACTIVE,
4165 EL_GATE_3_GRAY_ACTIVE,
4166 EL_GATE_4_GRAY_ACTIVE,
4175 EL_EM_GATE_1_GRAY_ACTIVE,
4176 EL_EM_GATE_2_GRAY_ACTIVE,
4177 EL_EM_GATE_3_GRAY_ACTIVE,
4178 EL_EM_GATE_4_GRAY_ACTIVE,
4187 EL_EMC_GATE_5_GRAY_ACTIVE,
4188 EL_EMC_GATE_6_GRAY_ACTIVE,
4189 EL_EMC_GATE_7_GRAY_ACTIVE,
4190 EL_EMC_GATE_8_GRAY_ACTIVE,
4192 EL_DC_GATE_WHITE_GRAY,
4193 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4198 static int ep_amoeboid[] =
4210 static int ep_amoebalive[] =
4221 static int ep_has_editor_content[] =
4227 EL_SOKOBAN_FIELD_PLAYER,
4244 static int ep_can_turn_each_move[] =
4246 // !!! do something with this one !!!
4250 static int ep_can_grow[] =
4264 static int ep_active_bomb[] =
4267 EL_EM_DYNAMITE_ACTIVE,
4268 EL_DYNABOMB_PLAYER_1_ACTIVE,
4269 EL_DYNABOMB_PLAYER_2_ACTIVE,
4270 EL_DYNABOMB_PLAYER_3_ACTIVE,
4271 EL_DYNABOMB_PLAYER_4_ACTIVE,
4272 EL_SP_DISK_RED_ACTIVE,
4277 static int ep_inactive[] =
4303 EL_QUICKSAND_FAST_EMPTY,
4326 EL_GATE_1_GRAY_ACTIVE,
4327 EL_GATE_2_GRAY_ACTIVE,
4328 EL_GATE_3_GRAY_ACTIVE,
4329 EL_GATE_4_GRAY_ACTIVE,
4338 EL_EM_GATE_1_GRAY_ACTIVE,
4339 EL_EM_GATE_2_GRAY_ACTIVE,
4340 EL_EM_GATE_3_GRAY_ACTIVE,
4341 EL_EM_GATE_4_GRAY_ACTIVE,
4350 EL_EMC_GATE_5_GRAY_ACTIVE,
4351 EL_EMC_GATE_6_GRAY_ACTIVE,
4352 EL_EMC_GATE_7_GRAY_ACTIVE,
4353 EL_EMC_GATE_8_GRAY_ACTIVE,
4355 EL_DC_GATE_WHITE_GRAY,
4356 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4357 EL_DC_GATE_FAKE_GRAY,
4360 EL_INVISIBLE_STEELWALL,
4368 EL_WALL_EMERALD_YELLOW,
4369 EL_DYNABOMB_INCREASE_NUMBER,
4370 EL_DYNABOMB_INCREASE_SIZE,
4371 EL_DYNABOMB_INCREASE_POWER,
4375 EL_SOKOBAN_FIELD_EMPTY,
4376 EL_SOKOBAN_FIELD_FULL,
4377 EL_WALL_EMERALD_RED,
4378 EL_WALL_EMERALD_PURPLE,
4379 EL_ACID_POOL_TOPLEFT,
4380 EL_ACID_POOL_TOPRIGHT,
4381 EL_ACID_POOL_BOTTOMLEFT,
4382 EL_ACID_POOL_BOTTOM,
4383 EL_ACID_POOL_BOTTOMRIGHT,
4387 EL_BD_MAGIC_WALL_DEAD,
4389 EL_DC_MAGIC_WALL_DEAD,
4390 EL_AMOEBA_TO_DIAMOND,
4398 EL_SP_GRAVITY_PORT_RIGHT,
4399 EL_SP_GRAVITY_PORT_DOWN,
4400 EL_SP_GRAVITY_PORT_LEFT,
4401 EL_SP_GRAVITY_PORT_UP,
4402 EL_SP_PORT_HORIZONTAL,
4403 EL_SP_PORT_VERTICAL,
4414 EL_SP_HARDWARE_GRAY,
4415 EL_SP_HARDWARE_GREEN,
4416 EL_SP_HARDWARE_BLUE,
4418 EL_SP_HARDWARE_YELLOW,
4419 EL_SP_HARDWARE_BASE_1,
4420 EL_SP_HARDWARE_BASE_2,
4421 EL_SP_HARDWARE_BASE_3,
4422 EL_SP_HARDWARE_BASE_4,
4423 EL_SP_HARDWARE_BASE_5,
4424 EL_SP_HARDWARE_BASE_6,
4425 EL_SP_GRAVITY_ON_PORT_LEFT,
4426 EL_SP_GRAVITY_ON_PORT_RIGHT,
4427 EL_SP_GRAVITY_ON_PORT_UP,
4428 EL_SP_GRAVITY_ON_PORT_DOWN,
4429 EL_SP_GRAVITY_OFF_PORT_LEFT,
4430 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4431 EL_SP_GRAVITY_OFF_PORT_UP,
4432 EL_SP_GRAVITY_OFF_PORT_DOWN,
4433 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4434 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4435 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4436 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4437 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4438 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4439 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4440 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4441 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4442 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4443 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4444 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4445 EL_SIGN_EXCLAMATION,
4446 EL_SIGN_RADIOACTIVITY,
4453 EL_SIGN_ENTRY_FORBIDDEN,
4454 EL_SIGN_EMERGENCY_EXIT,
4462 EL_DC_STEELWALL_1_LEFT,
4463 EL_DC_STEELWALL_1_RIGHT,
4464 EL_DC_STEELWALL_1_TOP,
4465 EL_DC_STEELWALL_1_BOTTOM,
4466 EL_DC_STEELWALL_1_HORIZONTAL,
4467 EL_DC_STEELWALL_1_VERTICAL,
4468 EL_DC_STEELWALL_1_TOPLEFT,
4469 EL_DC_STEELWALL_1_TOPRIGHT,
4470 EL_DC_STEELWALL_1_BOTTOMLEFT,
4471 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4472 EL_DC_STEELWALL_1_TOPLEFT_2,
4473 EL_DC_STEELWALL_1_TOPRIGHT_2,
4474 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4475 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4476 EL_DC_STEELWALL_2_LEFT,
4477 EL_DC_STEELWALL_2_RIGHT,
4478 EL_DC_STEELWALL_2_TOP,
4479 EL_DC_STEELWALL_2_BOTTOM,
4480 EL_DC_STEELWALL_2_HORIZONTAL,
4481 EL_DC_STEELWALL_2_VERTICAL,
4482 EL_DC_STEELWALL_2_MIDDLE,
4483 EL_DC_STEELWALL_2_SINGLE,
4484 EL_STEELWALL_SLIPPERY,
4489 EL_EMC_WALL_SLIPPERY_1,
4490 EL_EMC_WALL_SLIPPERY_2,
4491 EL_EMC_WALL_SLIPPERY_3,
4492 EL_EMC_WALL_SLIPPERY_4,
4513 static int ep_em_slippery_wall[] =
4518 static int ep_gfx_crumbled[] =
4529 static int ep_editor_cascade_active[] =
4531 EL_INTERNAL_CASCADE_BD_ACTIVE,
4532 EL_INTERNAL_CASCADE_EM_ACTIVE,
4533 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4534 EL_INTERNAL_CASCADE_RND_ACTIVE,
4535 EL_INTERNAL_CASCADE_SB_ACTIVE,
4536 EL_INTERNAL_CASCADE_SP_ACTIVE,
4537 EL_INTERNAL_CASCADE_DC_ACTIVE,
4538 EL_INTERNAL_CASCADE_DX_ACTIVE,
4539 EL_INTERNAL_CASCADE_MM_ACTIVE,
4540 EL_INTERNAL_CASCADE_DF_ACTIVE,
4541 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4542 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4543 EL_INTERNAL_CASCADE_CE_ACTIVE,
4544 EL_INTERNAL_CASCADE_GE_ACTIVE,
4545 EL_INTERNAL_CASCADE_ES_ACTIVE,
4546 EL_INTERNAL_CASCADE_REF_ACTIVE,
4547 EL_INTERNAL_CASCADE_USER_ACTIVE,
4548 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4553 static int ep_editor_cascade_inactive[] =
4555 EL_INTERNAL_CASCADE_BD,
4556 EL_INTERNAL_CASCADE_EM,
4557 EL_INTERNAL_CASCADE_EMC,
4558 EL_INTERNAL_CASCADE_RND,
4559 EL_INTERNAL_CASCADE_SB,
4560 EL_INTERNAL_CASCADE_SP,
4561 EL_INTERNAL_CASCADE_DC,
4562 EL_INTERNAL_CASCADE_DX,
4563 EL_INTERNAL_CASCADE_MM,
4564 EL_INTERNAL_CASCADE_DF,
4565 EL_INTERNAL_CASCADE_CHARS,
4566 EL_INTERNAL_CASCADE_STEEL_CHARS,
4567 EL_INTERNAL_CASCADE_CE,
4568 EL_INTERNAL_CASCADE_GE,
4569 EL_INTERNAL_CASCADE_ES,
4570 EL_INTERNAL_CASCADE_REF,
4571 EL_INTERNAL_CASCADE_USER,
4572 EL_INTERNAL_CASCADE_DYNAMIC,
4577 static int ep_obsolete[] =
4581 EL_EM_KEY_1_FILE_OBSOLETE,
4582 EL_EM_KEY_2_FILE_OBSOLETE,
4583 EL_EM_KEY_3_FILE_OBSOLETE,
4584 EL_EM_KEY_4_FILE_OBSOLETE,
4585 EL_ENVELOPE_OBSOLETE,
4594 } element_properties[] =
4596 { ep_diggable, EP_DIGGABLE },
4597 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4598 { ep_dont_run_into, EP_DONT_RUN_INTO },
4599 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4600 { ep_dont_touch, EP_DONT_TOUCH },
4601 { ep_indestructible, EP_INDESTRUCTIBLE },
4602 { ep_slippery, EP_SLIPPERY },
4603 { ep_can_change, EP_CAN_CHANGE },
4604 { ep_can_move, EP_CAN_MOVE },
4605 { ep_can_fall, EP_CAN_FALL },
4606 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4607 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4608 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4609 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4610 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4611 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4612 { ep_walkable_over, EP_WALKABLE_OVER },
4613 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4614 { ep_walkable_under, EP_WALKABLE_UNDER },
4615 { ep_passable_over, EP_PASSABLE_OVER },
4616 { ep_passable_inside, EP_PASSABLE_INSIDE },
4617 { ep_passable_under, EP_PASSABLE_UNDER },
4618 { ep_droppable, EP_DROPPABLE },
4619 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4620 { ep_pushable, EP_PUSHABLE },
4621 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4622 { ep_protected, EP_PROTECTED },
4623 { ep_throwable, EP_THROWABLE },
4624 { ep_can_explode, EP_CAN_EXPLODE },
4625 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4627 { ep_empty_space, EP_EMPTY_SPACE },
4628 { ep_player, EP_PLAYER },
4629 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4630 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4631 { ep_switchable, EP_SWITCHABLE },
4632 { ep_bd_element, EP_BD_ELEMENT },
4633 { ep_sp_element, EP_SP_ELEMENT },
4634 { ep_sb_element, EP_SB_ELEMENT },
4636 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4637 { ep_food_penguin, EP_FOOD_PENGUIN },
4638 { ep_food_pig, EP_FOOD_PIG },
4639 { ep_historic_wall, EP_HISTORIC_WALL },
4640 { ep_historic_solid, EP_HISTORIC_SOLID },
4641 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4642 { ep_belt, EP_BELT },
4643 { ep_belt_active, EP_BELT_ACTIVE },
4644 { ep_belt_switch, EP_BELT_SWITCH },
4645 { ep_tube, EP_TUBE },
4646 { ep_acid_pool, EP_ACID_POOL },
4647 { ep_keygate, EP_KEYGATE },
4648 { ep_amoeboid, EP_AMOEBOID },
4649 { ep_amoebalive, EP_AMOEBALIVE },
4650 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4651 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4652 { ep_can_grow, EP_CAN_GROW },
4653 { ep_active_bomb, EP_ACTIVE_BOMB },
4654 { ep_inactive, EP_INACTIVE },
4656 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4658 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4660 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4661 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4663 { ep_obsolete, EP_OBSOLETE },
4670 // always start with reliable default values (element has no properties)
4671 // (but never initialize clipboard elements after the very first time)
4672 // (to be able to use clipboard elements between several levels)
4673 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4674 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4675 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4676 SET_PROPERTY(i, j, FALSE);
4678 // set all base element properties from above array definitions
4679 for (i = 0; element_properties[i].elements != NULL; i++)
4680 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4681 SET_PROPERTY((element_properties[i].elements)[j],
4682 element_properties[i].property, TRUE);
4684 // copy properties to some elements that are only stored in level file
4685 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4686 for (j = 0; copy_properties[j][0] != -1; j++)
4687 if (HAS_PROPERTY(copy_properties[j][0], i))
4688 for (k = 1; k <= 4; k++)
4689 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4691 // set static element properties that are not listed in array definitions
4692 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4693 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4695 clipboard_elements_initialized = TRUE;
4698 void InitElementPropertiesEngine(int engine_version)
4700 static int no_wall_properties[] =
4703 EP_COLLECTIBLE_ONLY,
4705 EP_DONT_COLLIDE_WITH,
4708 EP_CAN_SMASH_PLAYER,
4709 EP_CAN_SMASH_ENEMIES,
4710 EP_CAN_SMASH_EVERYTHING,
4715 EP_FOOD_DARK_YAMYAM,
4731 /* important: after initialization in InitElementPropertiesStatic(), the
4732 elements are not again initialized to a default value; therefore all
4733 changes have to make sure that they leave the element with a defined
4734 property (which means that conditional property changes must be set to
4735 a reliable default value before) */
4737 // resolve group elements
4738 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4739 ResolveGroupElement(EL_GROUP_START + i);
4741 // set all special, combined or engine dependent element properties
4742 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4744 // do not change (already initialized) clipboard elements here
4745 if (IS_CLIPBOARD_ELEMENT(i))
4748 // ---------- INACTIVE ----------------------------------------------------
4749 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4750 i <= EL_CHAR_END) ||
4751 (i >= EL_STEEL_CHAR_START &&
4752 i <= EL_STEEL_CHAR_END)));
4754 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4755 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4756 IS_WALKABLE_INSIDE(i) ||
4757 IS_WALKABLE_UNDER(i)));
4759 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4760 IS_PASSABLE_INSIDE(i) ||
4761 IS_PASSABLE_UNDER(i)));
4763 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4764 IS_PASSABLE_OVER(i)));
4766 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4767 IS_PASSABLE_INSIDE(i)));
4769 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4770 IS_PASSABLE_UNDER(i)));
4772 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4775 // ---------- COLLECTIBLE -------------------------------------------------
4776 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4780 // ---------- SNAPPABLE ---------------------------------------------------
4781 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4782 IS_COLLECTIBLE(i) ||
4786 // ---------- WALL --------------------------------------------------------
4787 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4789 for (j = 0; no_wall_properties[j] != -1; j++)
4790 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4791 i >= EL_FIRST_RUNTIME_UNREAL)
4792 SET_PROPERTY(i, EP_WALL, FALSE);
4794 if (IS_HISTORIC_WALL(i))
4795 SET_PROPERTY(i, EP_WALL, TRUE);
4797 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4798 if (engine_version < VERSION_IDENT(2,2,0,0))
4799 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4801 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4803 !IS_COLLECTIBLE(i)));
4805 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4806 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4807 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4809 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4812 // ---------- EXPLOSION_PROOF ---------------------------------------------
4814 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4815 else if (engine_version < VERSION_IDENT(2,2,0,0))
4816 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4818 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4822 if (IS_CUSTOM_ELEMENT(i))
4824 // these are additional properties which are initially false when set
4826 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4828 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4829 if (DONT_COLLIDE_WITH(i))
4830 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4832 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4833 if (CAN_SMASH_EVERYTHING(i))
4834 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4835 if (CAN_SMASH_ENEMIES(i))
4836 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4839 // ---------- CAN_SMASH ---------------------------------------------------
4840 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4841 CAN_SMASH_ENEMIES(i) ||
4842 CAN_SMASH_EVERYTHING(i)));
4844 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4845 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4846 EXPLODES_BY_FIRE(i)));
4848 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4849 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4850 EXPLODES_SMASHED(i)));
4852 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4853 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4854 EXPLODES_IMPACT(i)));
4856 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4857 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4859 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4860 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4861 i == EL_BLACK_ORB));
4863 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4864 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4866 IS_CUSTOM_ELEMENT(i)));
4868 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4869 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4870 i == EL_SP_ELECTRON));
4872 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4873 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4874 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4875 getMoveIntoAcidProperty(&level, i));
4877 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4878 if (MAYBE_DONT_COLLIDE_WITH(i))
4879 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4880 getDontCollideWithProperty(&level, i));
4882 // ---------- SP_PORT -----------------------------------------------------
4883 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4884 IS_PASSABLE_INSIDE(i)));
4886 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4887 for (j = 0; j < level.num_android_clone_elements; j++)
4888 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4890 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4892 // ---------- CAN_CHANGE --------------------------------------------------
4893 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4894 for (j = 0; j < element_info[i].num_change_pages; j++)
4895 if (element_info[i].change_page[j].can_change)
4896 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4898 // ---------- HAS_ACTION --------------------------------------------------
4899 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4900 for (j = 0; j < element_info[i].num_change_pages; j++)
4901 if (element_info[i].change_page[j].has_action)
4902 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4904 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4905 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4908 // ---------- GFX_CRUMBLED ------------------------------------------------
4909 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4910 element_info[i].crumbled[ACTION_DEFAULT] !=
4911 element_info[i].graphic[ACTION_DEFAULT]);
4913 // ---------- EDITOR_CASCADE ----------------------------------------------
4914 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4915 IS_EDITOR_CASCADE_INACTIVE(i)));
4918 // dynamically adjust element properties according to game engine version
4920 static int ep_em_slippery_wall[] =
4925 EL_EXPANDABLE_WALL_HORIZONTAL,
4926 EL_EXPANDABLE_WALL_VERTICAL,
4927 EL_EXPANDABLE_WALL_ANY,
4928 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4929 EL_EXPANDABLE_STEELWALL_VERTICAL,
4930 EL_EXPANDABLE_STEELWALL_ANY,
4931 EL_EXPANDABLE_STEELWALL_GROWING,
4935 static int ep_em_explodes_by_fire[] =
4938 EL_EM_DYNAMITE_ACTIVE,
4943 // special EM style gems behaviour
4944 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4945 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4946 level.em_slippery_gems);
4948 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4949 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4950 (level.em_slippery_gems &&
4951 engine_version > VERSION_IDENT(2,0,1,0)));
4953 // special EM style explosion behaviour regarding chain reactions
4954 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4955 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4956 level.em_explodes_by_fire);
4959 // this is needed because some graphics depend on element properties
4960 if (game_status == GAME_MODE_PLAYING)
4961 InitElementGraphicInfo();
4964 void InitElementPropertiesGfxElement(void)
4968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4970 struct ElementInfo *ei = &element_info[i];
4972 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4976 static void InitGlobal(void)
4981 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4983 // check if element_name_info entry defined for each element in "main.h"
4984 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4985 Fail("undefined 'element_name_info' entry for element %d", i);
4987 element_info[i].token_name = element_name_info[i].token_name;
4988 element_info[i].class_name = element_name_info[i].class_name;
4989 element_info[i].editor_description= element_name_info[i].editor_description;
4992 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4994 // check if global_anim_name_info defined for each entry in "main.h"
4995 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4996 global_anim_name_info[i].token_name == NULL)
4997 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4999 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
5002 // create hash to store URLs for global animations
5003 anim_url_hash = newSetupFileHash();
5005 // create hash from image config list
5006 image_config_hash = newSetupFileHash();
5007 for (i = 0; image_config[i].token != NULL; i++)
5008 setHashEntry(image_config_hash,
5009 image_config[i].token,
5010 image_config[i].value);
5012 // create hash from element token list
5013 element_token_hash = newSetupFileHash();
5014 for (i = 0; element_name_info[i].token_name != NULL; i++)
5015 setHashEntry(element_token_hash,
5016 element_name_info[i].token_name,
5019 // create hash from graphic token list
5020 graphic_token_hash = newSetupFileHash();
5021 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5022 if (strSuffix(image_config[i].value, ".png") ||
5023 strSuffix(image_config[i].value, ".pcx") ||
5024 strSuffix(image_config[i].value, ".wav") ||
5025 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5026 setHashEntry(graphic_token_hash,
5027 image_config[i].token,
5028 int2str(graphic++, 0));
5030 // create hash from font token list
5031 font_token_hash = newSetupFileHash();
5032 for (i = 0; font_info[i].token_name != NULL; i++)
5033 setHashEntry(font_token_hash,
5034 font_info[i].token_name,
5037 // set default filenames for all cloned graphics in static configuration
5038 for (i = 0; image_config[i].token != NULL; i++)
5040 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5042 char *token = image_config[i].token;
5043 char *token_clone_from = getStringCat2(token, ".clone_from");
5044 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5046 if (token_cloned != NULL)
5048 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5050 if (value_cloned != NULL)
5052 // set default filename in static configuration
5053 image_config[i].value = value_cloned;
5055 // set default filename in image config hash
5056 setHashEntry(image_config_hash, token, value_cloned);
5060 free(token_clone_from);
5064 // always start with reliable default values (all elements)
5065 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5066 ActiveElement[i] = i;
5068 // now add all entries that have an active state (active elements)
5069 for (i = 0; element_with_active_state[i].element != -1; i++)
5071 int element = element_with_active_state[i].element;
5072 int element_active = element_with_active_state[i].element_active;
5074 ActiveElement[element] = element_active;
5077 // always start with reliable default values (all buttons)
5078 for (i = 0; i < NUM_IMAGE_FILES; i++)
5079 ActiveButton[i] = i;
5081 // now add all entries that have an active state (active buttons)
5082 for (i = 0; button_with_active_state[i].button != -1; i++)
5084 int button = button_with_active_state[i].button;
5085 int button_active = button_with_active_state[i].button_active;
5087 ActiveButton[button] = button_active;
5090 // always start with reliable default values (all fonts)
5091 for (i = 0; i < NUM_FONTS; i++)
5094 // now add all entries that have an active state (active fonts)
5095 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5097 int font = font_with_active_state[i].font_nr;
5098 int font_active = font_with_active_state[i].font_nr_active;
5100 ActiveFont[font] = font_active;
5103 global.autoplay_leveldir = NULL;
5104 global.patchtapes_leveldir = NULL;
5105 global.convert_leveldir = NULL;
5106 global.dumplevel_leveldir = NULL;
5107 global.dumptape_leveldir = NULL;
5108 global.create_sketch_images_dir = NULL;
5109 global.create_collect_images_dir = NULL;
5111 global.frames_per_second = 0;
5112 global.show_frames_per_second = FALSE;
5114 global.border_status = GAME_MODE_LOADING;
5115 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5117 global.use_envelope_request = FALSE;
5119 global.user_names = NULL;
5122 static void Execute_Command(char *command)
5126 if (strEqual(command, "print graphicsinfo.conf"))
5128 Print("# You can configure additional/alternative image files here.\n");
5129 Print("# (The entries below are default and therefore commented out.)\n");
5131 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5133 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5136 for (i = 0; image_config[i].token != NULL; i++)
5137 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5138 image_config[i].value));
5142 else if (strEqual(command, "print soundsinfo.conf"))
5144 Print("# You can configure additional/alternative sound files here.\n");
5145 Print("# (The entries below are default and therefore commented out.)\n");
5147 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5149 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5152 for (i = 0; sound_config[i].token != NULL; i++)
5153 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5154 sound_config[i].value));
5158 else if (strEqual(command, "print musicinfo.conf"))
5160 Print("# You can configure additional/alternative music files here.\n");
5161 Print("# (The entries below are default and therefore commented out.)\n");
5163 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5165 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5168 for (i = 0; music_config[i].token != NULL; i++)
5169 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5170 music_config[i].value));
5174 else if (strEqual(command, "print editorsetup.conf"))
5176 Print("# You can configure your personal editor element list here.\n");
5177 Print("# (The entries below are default and therefore commented out.)\n");
5180 // this is needed to be able to check element list for cascade elements
5181 InitElementPropertiesStatic();
5182 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5184 PrintEditorElementList();
5188 else if (strEqual(command, "print helpanim.conf"))
5190 Print("# You can configure different element help animations here.\n");
5191 Print("# (The entries below are default and therefore commented out.)\n");
5194 for (i = 0; helpanim_config[i].token != NULL; i++)
5196 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5197 helpanim_config[i].value));
5199 if (strEqual(helpanim_config[i].token, "end"))
5205 else if (strEqual(command, "print helptext.conf"))
5207 Print("# You can configure different element help text here.\n");
5208 Print("# (The entries below are default and therefore commented out.)\n");
5211 for (i = 0; helptext_config[i].token != NULL; i++)
5212 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5213 helptext_config[i].value));
5217 else if (strPrefix(command, "dump level "))
5219 char *filename = &command[11];
5221 if (fileExists(filename))
5223 LoadLevelFromFilename(&level, filename);
5229 char *leveldir = getStringCopy(filename); // read command parameters
5230 char *level_nr = strchr(leveldir, ' ');
5232 if (level_nr == NULL)
5233 Fail("cannot open file '%s'", filename);
5237 global.dumplevel_leveldir = leveldir;
5238 global.dumplevel_level_nr = atoi(level_nr);
5240 program.headless = TRUE;
5242 else if (strPrefix(command, "dump tape "))
5244 char *filename = &command[10];
5246 if (fileExists(filename))
5248 LoadTapeFromFilename(filename);
5254 char *leveldir = getStringCopy(filename); // read command parameters
5255 char *level_nr = strchr(leveldir, ' ');
5257 if (level_nr == NULL)
5258 Fail("cannot open file '%s'", filename);
5262 global.dumptape_leveldir = leveldir;
5263 global.dumptape_level_nr = atoi(level_nr);
5265 program.headless = TRUE;
5267 else if (strPrefix(command, "autoplay ") ||
5268 strPrefix(command, "autoffwd ") ||
5269 strPrefix(command, "autowarp ") ||
5270 strPrefix(command, "autotest ") ||
5271 strPrefix(command, "autosave ") ||
5272 strPrefix(command, "autoupload ") ||
5273 strPrefix(command, "autofix "))
5275 char *arg_ptr = strchr(command, ' ');
5276 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5278 global.autoplay_mode =
5279 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5280 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5281 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5282 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5283 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5284 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5285 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5286 AUTOPLAY_MODE_NONE);
5288 while (*str_ptr != '\0') // continue parsing string
5290 // cut leading whitespace from string, replace it by string terminator
5291 while (*str_ptr == ' ' || *str_ptr == '\t')
5294 if (*str_ptr == '\0') // end of string reached
5297 if (global.autoplay_leveldir == NULL) // read level set string
5299 global.autoplay_leveldir = str_ptr;
5300 global.autoplay_all = TRUE; // default: play all tapes
5302 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5303 global.autoplay_level[i] = FALSE;
5305 else // read level number string
5307 int level_nr = atoi(str_ptr); // get level_nr value
5309 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5310 global.autoplay_level[level_nr] = TRUE;
5312 global.autoplay_all = FALSE;
5315 // advance string pointer to the next whitespace (or end of string)
5316 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5320 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5321 program.headless = TRUE;
5323 else if (strPrefix(command, "patch tapes "))
5325 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5327 // skip leading whitespace
5328 while (*str_ptr == ' ' || *str_ptr == '\t')
5331 if (*str_ptr == '\0')
5332 Fail("cannot find MODE in command '%s'", command);
5334 global.patchtapes_mode = str_ptr; // store patch mode
5336 // advance to next whitespace (or end of string)
5337 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5340 while (*str_ptr != '\0') // continue parsing string
5342 // cut leading whitespace from string, replace it by string terminator
5343 while (*str_ptr == ' ' || *str_ptr == '\t')
5346 if (*str_ptr == '\0') // end of string reached
5349 if (global.patchtapes_leveldir == NULL) // read level set string
5351 global.patchtapes_leveldir = str_ptr;
5352 global.patchtapes_all = TRUE; // default: patch all tapes
5354 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5355 global.patchtapes_level[i] = FALSE;
5357 else // read level number string
5359 int level_nr = atoi(str_ptr); // get level_nr value
5361 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5362 global.patchtapes_level[level_nr] = TRUE;
5364 global.patchtapes_all = FALSE;
5367 // advance string pointer to the next whitespace (or end of string)
5368 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5372 if (global.patchtapes_leveldir == NULL)
5374 if (strEqual(global.patchtapes_mode, "help"))
5375 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5377 Fail("cannot find LEVELDIR in command '%s'", command);
5380 program.headless = TRUE;
5382 else if (strPrefix(command, "convert "))
5384 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5385 char *str_ptr = strchr(str_copy, ' ');
5387 global.convert_leveldir = str_copy;
5388 global.convert_level_nr = -1;
5390 if (str_ptr != NULL) // level number follows
5392 *str_ptr++ = '\0'; // terminate leveldir string
5393 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5396 program.headless = TRUE;
5398 else if (strPrefix(command, "create sketch images "))
5400 global.create_sketch_images_dir = getStringCopy(&command[21]);
5402 if (access(global.create_sketch_images_dir, W_OK) != 0)
5403 Fail("image target directory '%s' not found or not writable",
5404 global.create_sketch_images_dir);
5406 else if (strPrefix(command, "create collect image "))
5408 global.create_collect_images_dir = getStringCopy(&command[21]);
5410 if (access(global.create_collect_images_dir, W_OK) != 0)
5411 Fail("image target directory '%s' not found or not writable",
5412 global.create_collect_images_dir);
5414 else if (strPrefix(command, "create CE image "))
5416 CreateCustomElementImages(&command[16]);
5422 FailWithHelp("unrecognized command '%s'", command);
5425 // disable networking if any valid command was recognized
5426 options.network = setup.network_mode = FALSE;
5429 static void InitSetup(void)
5431 LoadUserNames(); // global user names
5432 LoadUserSetup(); // global user number
5434 LoadSetup(); // global setup info
5436 // set some options from setup file
5438 if (setup.options.verbose)
5439 options.verbose = TRUE;
5441 if (setup.debug.show_frames_per_second)
5442 global.show_frames_per_second = TRUE;
5445 static void InitGameInfo(void)
5447 game.restart_level = FALSE;
5448 game.restart_game_message = NULL;
5450 game.request_active = FALSE;
5451 game.request_active_or_moving = FALSE;
5453 game.use_masked_elements_initial = FALSE;
5456 static void InitPlayerInfo(void)
5460 // choose default local player
5461 local_player = &stored_player[0];
5463 for (i = 0; i < MAX_PLAYERS; i++)
5465 stored_player[i].connected_locally = FALSE;
5466 stored_player[i].connected_network = FALSE;
5469 local_player->connected_locally = TRUE;
5472 static void InitArtworkInfo(void)
5477 static char *get_string_in_brackets(char *string)
5479 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5481 sprintf(string_in_brackets, "[%s]", string);
5483 return string_in_brackets;
5486 static char *get_level_id_suffix(int id_nr)
5488 char *id_suffix = checked_malloc(1 + 3 + 1);
5490 if (id_nr < 0 || id_nr > 999)
5493 sprintf(id_suffix, ".%03d", id_nr);
5498 static void InitArtworkConfig(void)
5500 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5502 NUM_GLOBAL_ANIM_TOKENS + 1];
5503 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5504 NUM_GLOBAL_ANIM_TOKENS + 1];
5505 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5506 NUM_GLOBAL_ANIM_TOKENS + 1];
5507 static char *action_id_suffix[NUM_ACTIONS + 1];
5508 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5509 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5510 static char *level_id_suffix[MAX_LEVELS + 1];
5511 static char *dummy[1] = { NULL };
5512 static char *ignore_generic_tokens[] =
5517 "program_copyright",
5522 static char **ignore_image_tokens;
5523 static char **ignore_sound_tokens;
5524 static char **ignore_music_tokens;
5525 int num_ignore_generic_tokens;
5526 int num_ignore_image_tokens;
5527 int num_ignore_sound_tokens;
5528 int num_ignore_music_tokens;
5531 // dynamically determine list of generic tokens to be ignored
5532 num_ignore_generic_tokens = 0;
5533 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5534 num_ignore_generic_tokens++;
5536 // dynamically determine list of image tokens to be ignored
5537 num_ignore_image_tokens = num_ignore_generic_tokens;
5538 for (i = 0; image_config_vars[i].token != NULL; i++)
5539 num_ignore_image_tokens++;
5540 ignore_image_tokens =
5541 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5542 for (i = 0; i < num_ignore_generic_tokens; i++)
5543 ignore_image_tokens[i] = ignore_generic_tokens[i];
5544 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5545 ignore_image_tokens[num_ignore_generic_tokens + i] =
5546 image_config_vars[i].token;
5547 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5549 // dynamically determine list of sound tokens to be ignored
5550 num_ignore_sound_tokens = num_ignore_generic_tokens;
5551 ignore_sound_tokens =
5552 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5553 for (i = 0; i < num_ignore_generic_tokens; i++)
5554 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5555 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5557 // dynamically determine list of music tokens to be ignored
5558 num_ignore_music_tokens = num_ignore_generic_tokens;
5559 ignore_music_tokens =
5560 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5561 for (i = 0; i < num_ignore_generic_tokens; i++)
5562 ignore_music_tokens[i] = ignore_generic_tokens[i];
5563 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5565 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5566 image_id_prefix[i] = element_info[i].token_name;
5567 for (i = 0; i < NUM_FONTS; i++)
5568 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5569 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5570 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5571 global_anim_info[i].token_name;
5572 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5574 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5575 sound_id_prefix[i] = element_info[i].token_name;
5576 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5577 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5578 get_string_in_brackets(element_info[i].class_name);
5579 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5580 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5581 global_anim_info[i].token_name;
5582 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5584 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5585 music_id_prefix[i] = music_prefix_info[i].prefix;
5586 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5587 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5588 global_anim_info[i].token_name;
5589 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5591 for (i = 0; i < NUM_ACTIONS; i++)
5592 action_id_suffix[i] = element_action_info[i].suffix;
5593 action_id_suffix[NUM_ACTIONS] = NULL;
5595 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5596 direction_id_suffix[i] = element_direction_info[i].suffix;
5597 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5599 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5600 special_id_suffix[i] = special_suffix_info[i].suffix;
5601 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5603 for (i = 0; i < MAX_LEVELS; i++)
5604 level_id_suffix[i] = get_level_id_suffix(i);
5605 level_id_suffix[MAX_LEVELS] = NULL;
5607 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5608 image_id_prefix, action_id_suffix, direction_id_suffix,
5609 special_id_suffix, ignore_image_tokens);
5610 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5611 sound_id_prefix, action_id_suffix, dummy,
5612 special_id_suffix, ignore_sound_tokens);
5613 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5614 music_id_prefix, action_id_suffix, special_id_suffix,
5615 level_id_suffix, ignore_music_tokens);
5618 static void InitMixer(void)
5625 static void InitVideoOverlay(void)
5627 // if virtual buttons are not loaded from setup file, repeat initializing
5628 // virtual buttons grid with default values now that video is initialized
5629 if (!setup.touch.grid_initialized)
5632 InitTileCursorInfo();
5636 void InitGfxBuffers(void)
5638 static int win_xsize_last = -1;
5639 static int win_ysize_last = -1;
5641 // create additional image buffers for double-buffering and cross-fading
5643 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5645 // used to temporarily store the backbuffer -- only re-create if changed
5646 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5647 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5649 win_xsize_last = WIN_XSIZE;
5650 win_ysize_last = WIN_YSIZE;
5653 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5654 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5655 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5656 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5658 // initialize screen properties
5659 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5660 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5662 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5663 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5664 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5665 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5666 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5667 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5669 // required if door size definitions have changed
5670 InitGraphicCompatibilityInfo_Doors();
5672 InitGfxBuffers_EM();
5673 InitGfxBuffers_SP();
5676 static void InitGfx(void)
5678 struct GraphicInfo *graphic_info_last = graphic_info;
5679 char *filename_font_initial = NULL;
5680 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5681 char *image_token[NUM_INITIAL_IMAGES] =
5683 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5684 CONFIG_TOKEN_GLOBAL_BUSY,
5685 CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5686 CONFIG_TOKEN_BACKGROUND,
5687 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5688 CONFIG_TOKEN_BACKGROUND_LOADING
5690 struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5694 &init.busy_playfield
5696 Bitmap *bitmap_font_initial = NULL;
5697 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5700 // determine settings for initial font (for displaying startup messages)
5701 for (i = 0; image_config[i].token != NULL; i++)
5703 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5705 char font_token[128];
5708 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5709 len_font_token = strlen(font_token);
5711 if (strEqual(image_config[i].token, font_token))
5713 filename_font_initial = image_config[i].value;
5715 else if (strlen(image_config[i].token) > len_font_token &&
5716 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5718 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5719 font_initial[j].src_x = atoi(image_config[i].value);
5720 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5721 font_initial[j].src_y = atoi(image_config[i].value);
5722 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5723 font_initial[j].width = atoi(image_config[i].value);
5724 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5725 font_initial[j].height = atoi(image_config[i].value);
5730 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5732 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5733 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5736 if (filename_font_initial == NULL) // should not happen
5737 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5740 InitGfxCustomArtworkInfo();
5741 InitGfxOtherSettings();
5743 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5745 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5747 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5748 font_initial[j].bitmap = bitmap_font_initial;
5750 InitFontGraphicInfo();
5754 DrawInitTextHead("Loading graphics");
5756 InitMenuDesignSettings_Static();
5758 // initialize settings for initial images with default values
5759 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5760 for (j = 0; j < NUM_GFX_ARGS; j++)
5762 get_graphic_parameter_value(image_config_suffix[j].value,
5763 image_config_suffix[j].token,
5764 image_config_suffix[j].type);
5766 // read settings for initial images from default custom artwork config
5767 char *gfx_config_filename = getPath3(options.graphics_directory,
5769 GRAPHICSINFO_FILENAME);
5771 if (fileExists(gfx_config_filename))
5773 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5775 if (setup_file_hash)
5777 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5779 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5783 filename_image_initial[i] = getStringCopy(filename);
5785 for (j = 0; image_config_suffix[j].token != NULL; j++)
5787 int type = image_config_suffix[j].type;
5788 char *suffix = image_config_suffix[j].token;
5789 char *token = getStringCat2(image_token[i], suffix);
5790 char *value = getHashEntry(setup_file_hash, token);
5792 checked_free(token);
5796 get_graphic_parameter_value(value, suffix, type);
5801 // read values from custom graphics config file
5802 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5804 freeSetupFileHash(setup_file_hash);
5808 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5810 if (filename_image_initial[i] == NULL)
5812 int len_token = strlen(image_token[i]);
5814 // read settings for initial images from static default artwork config
5815 for (j = 0; image_config[j].token != NULL; j++)
5817 if (strEqual(image_config[j].token, image_token[i]))
5819 filename_image_initial[i] = getStringCopy(image_config[j].value);
5821 else if (strlen(image_config[j].token) > len_token &&
5822 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5824 for (k = 0; image_config_suffix[k].token != NULL; k++)
5826 if (strEqual(&image_config[j].token[len_token],
5827 image_config_suffix[k].token))
5829 get_graphic_parameter_value(image_config[j].value,
5830 image_config_suffix[k].token,
5831 image_config_suffix[k].type);
5838 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5840 if (filename_image_initial[i] == NULL) // should not happen
5841 Fail("cannot get filename for '%s'", image_token[i]);
5843 image_initial[i].bitmaps =
5844 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5846 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5847 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5848 LoadCustomImage(filename_image_initial[i]);
5850 checked_free(filename_image_initial[i]);
5853 graphic_info = image_initial; // graphic == 0 => image_initial
5855 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5856 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5858 graphic_info = graphic_info_last;
5860 for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5862 // set image size for busy animations
5863 init_busy[i]->width = image_initial[i].width;
5864 init_busy[i]->height = image_initial[i].height;
5867 SetLoadingBackgroundImage();
5869 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5871 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5872 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5873 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5874 InitGfxDrawTileCursorFunction(DrawTileCursor);
5876 gfx.fade_border_source_status = global.border_status;
5877 gfx.fade_border_target_status = global.border_status;
5878 gfx.masked_border_bitmap_ptr = backbuffer;
5880 // use copy of busy animation to prevent change while reloading artwork
5884 static void InitGfxBackground(void)
5886 fieldbuffer = bitmap_db_field;
5887 SetDrawtoField(DRAW_TO_BACKBUFFER);
5889 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5891 redraw_mask = REDRAW_ALL;
5894 static void InitLevelInfo(void)
5896 LoadLevelInfo(); // global level info
5897 LoadLevelSetup_LastSeries(); // last played series info
5898 LoadLevelSetup_SeriesInfo(); // last played level info
5900 if (global.autoplay_leveldir &&
5901 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5903 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5904 global.autoplay_leveldir);
5905 if (leveldir_current == NULL)
5906 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5909 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5912 static void InitLevelArtworkInfo(void)
5914 LoadLevelArtworkInfo();
5917 static void InitImages(void)
5919 print_timestamp_init("InitImages");
5922 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5923 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5924 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5925 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5926 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5927 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5928 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5929 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5932 setLevelArtworkDir(artwork.gfx_first);
5935 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5936 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5937 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5938 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5939 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5940 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5941 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5942 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5946 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5947 leveldir_current->identifier,
5948 artwork.gfx_current_identifier,
5949 artwork.gfx_current->identifier,
5950 leveldir_current->graphics_set,
5951 leveldir_current->graphics_path);
5954 UPDATE_BUSY_STATE();
5956 ReloadCustomImages();
5957 print_timestamp_time("ReloadCustomImages");
5959 UPDATE_BUSY_STATE();
5961 LoadCustomElementDescriptions();
5962 print_timestamp_time("LoadCustomElementDescriptions");
5964 UPDATE_BUSY_STATE();
5966 LoadMenuDesignSettings();
5967 print_timestamp_time("LoadMenuDesignSettings");
5969 UPDATE_BUSY_STATE();
5971 ReinitializeGraphics();
5972 print_timestamp_time("ReinitializeGraphics");
5974 LoadMenuDesignSettings_AfterGraphics();
5975 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5977 UPDATE_BUSY_STATE();
5979 print_timestamp_done("InitImages");
5982 static void InitSound(char *identifier)
5984 print_timestamp_init("InitSound");
5986 if (identifier == NULL)
5987 identifier = artwork.snd_current->identifier;
5989 // set artwork path to send it to the sound server process
5990 setLevelArtworkDir(artwork.snd_first);
5992 InitReloadCustomSounds(identifier);
5993 print_timestamp_time("InitReloadCustomSounds");
5995 ReinitializeSounds();
5996 print_timestamp_time("ReinitializeSounds");
5998 print_timestamp_done("InitSound");
6001 static void InitMusic(char *identifier)
6003 print_timestamp_init("InitMusic");
6005 if (identifier == NULL)
6006 identifier = artwork.mus_current->identifier;
6008 // set artwork path to send it to the sound server process
6009 setLevelArtworkDir(artwork.mus_first);
6011 InitReloadCustomMusic(identifier);
6012 print_timestamp_time("InitReloadCustomMusic");
6014 ReinitializeMusic();
6015 print_timestamp_time("ReinitializeMusic");
6017 print_timestamp_done("InitMusic");
6020 static void InitArtworkDone(void)
6022 if (program.headless)
6025 InitGlobalAnimations();
6028 static void InitNetworkSettings(void)
6030 boolean network_enabled = (options.network || setup.network_mode);
6031 char *network_server = (options.server_host != NULL ? options.server_host :
6032 setup.network_server_hostname);
6034 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6035 network_server = NULL;
6037 InitNetworkInfo(network_enabled,
6041 options.server_port);
6044 void InitNetworkServer(void)
6046 if (!network.enabled || network.connected)
6049 LimitScreenUpdates(FALSE);
6051 if (game_status == GAME_MODE_LOADING)
6054 if (!ConnectToServer(network.server_host, network.server_port))
6056 network.enabled = FALSE;
6058 setup.network_mode = FALSE;
6062 SendToServer_ProtocolVersion();
6063 SendToServer_PlayerName(setup.player_name);
6064 SendToServer_NrWanted(setup.network_player_nr + 1);
6066 network.connected = TRUE;
6069 // short time to recognize result of network initialization
6070 if (game_status == GAME_MODE_LOADING)
6071 Delay_WithScreenUpdates(1000);
6074 static boolean CheckArtworkConfigForCustomElements(char *filename)
6076 SetupFileHash *setup_file_hash;
6077 boolean redefined_ce_found = FALSE;
6079 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6081 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6083 BEGIN_HASH_ITERATION(setup_file_hash, itr)
6085 char *token = HASH_ITERATION_TOKEN(itr);
6087 if (strPrefix(token, "custom_"))
6089 redefined_ce_found = TRUE;
6094 END_HASH_ITERATION(setup_file_hash, itr)
6096 freeSetupFileHash(setup_file_hash);
6099 return redefined_ce_found;
6102 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6104 char *filename_base, *filename_local;
6105 boolean redefined_ce_found = FALSE;
6107 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6110 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6111 "leveldir_current->identifier == '%s'",
6112 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6113 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6114 "leveldir_current->graphics_path == '%s'",
6115 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6116 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6117 "leveldir_current->graphics_set == '%s'",
6118 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6119 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6120 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6121 leveldir_current == NULL ? "[NULL]" :
6122 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6125 // first look for special artwork configured in level series config
6126 filename_base = getCustomArtworkLevelConfigFilename(type);
6129 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6130 "filename_base == '%s'", filename_base);
6133 if (fileExists(filename_base))
6134 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6136 filename_local = getCustomArtworkConfigFilename(type);
6139 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6140 "filename_local == '%s'", filename_local);
6143 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6144 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6147 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6148 "redefined_ce_found == %d", redefined_ce_found);
6151 return redefined_ce_found;
6154 static void InitOverrideArtwork(void)
6156 boolean redefined_ce_found = FALSE;
6158 // to check if this level set redefines any CEs, do not use overriding
6159 gfx.override_level_graphics = FALSE;
6160 gfx.override_level_sounds = FALSE;
6161 gfx.override_level_music = FALSE;
6163 // now check if this level set has definitions for custom elements
6164 if (setup.override_level_graphics == AUTO ||
6165 setup.override_level_sounds == AUTO ||
6166 setup.override_level_music == AUTO)
6167 redefined_ce_found =
6168 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6169 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6170 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6173 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6174 redefined_ce_found);
6177 if (redefined_ce_found)
6179 // this level set has CE definitions: change "AUTO" to "FALSE"
6180 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6181 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6182 gfx.override_level_music = (setup.override_level_music == TRUE);
6186 // this level set has no CE definitions: change "AUTO" to "TRUE"
6187 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6188 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6189 gfx.override_level_music = (setup.override_level_music != FALSE);
6193 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6194 gfx.override_level_graphics,
6195 gfx.override_level_sounds,
6196 gfx.override_level_music);
6200 static char *setNewArtworkIdentifier(int type)
6202 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6203 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6204 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6205 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6206 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6207 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6208 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6209 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6210 char *leveldir_identifier = leveldir_current->identifier;
6211 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6212 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6213 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6214 TreeInfo *custom_artwork_set =
6215 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6216 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6217 char *artwork_current_identifier;
6218 char *artwork_new_identifier = NULL; // default: nothing has changed
6220 // leveldir_current may be invalid (level group, parent link)
6221 if (!validLevelSeries(leveldir_current))
6224 /* 1st step: determine artwork set to be activated in descending order:
6225 --------------------------------------------------------------------
6226 1. setup artwork (when configured to override everything else)
6227 2. artwork set configured in "levelinfo.conf" of current level set
6228 (artwork in level directory will have priority when loading later)
6229 3. artwork in level directory (stored in artwork sub-directory)
6230 4. setup artwork (currently configured in setup menu) */
6232 if (setup_override_artwork)
6233 artwork_current_identifier = setup_artwork_set;
6234 else if (has_level_artwork_set)
6235 artwork_current_identifier = leveldir_artwork_set;
6236 else if (has_custom_artwork_set)
6237 artwork_current_identifier = leveldir_identifier;
6239 artwork_current_identifier = setup_artwork_set;
6241 /* 2nd step: check if it is really needed to reload artwork set
6242 ------------------------------------------------------------ */
6244 // ---------- reload if level set and also artwork set has changed ----------
6245 if (last_leveldir_identifier[type] != leveldir_identifier &&
6246 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6247 artwork_new_identifier = artwork_current_identifier;
6249 last_leveldir_identifier[type] = leveldir_identifier;
6250 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6252 // ---------- reload if "override artwork" setting has changed --------------
6253 if (last_override_level_artwork[type] != setup_override_artwork)
6254 artwork_new_identifier = artwork_current_identifier;
6256 last_override_level_artwork[type] = setup_override_artwork;
6258 // ---------- reload if current artwork identifier has changed --------------
6259 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6260 artwork_new_identifier = artwork_current_identifier;
6262 // (we cannot compare string pointers here, so copy string content itself)
6263 setString(&last_artwork_identifier[type], artwork_current_identifier);
6265 // ---------- set new artwork identifier ----------
6266 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6268 // ---------- do not reload directly after starting -------------------------
6269 if (!initialized[type])
6270 artwork_new_identifier = NULL;
6272 initialized[type] = TRUE;
6274 return artwork_new_identifier;
6277 static void InitArtworkIdentifier(void)
6279 setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6280 setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6281 setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6284 void ReloadCustomArtwork(int force_reload)
6286 int last_game_status = game_status; // save current game status
6287 char *gfx_new_identifier;
6288 char *snd_new_identifier;
6289 char *mus_new_identifier;
6290 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6291 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6292 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6293 boolean reload_needed;
6295 InitOverrideArtwork();
6297 AdjustGraphicsForEMC();
6298 AdjustSoundsForEMC();
6300 gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6301 snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6302 mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6304 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6305 snd_new_identifier != NULL || force_reload_snd ||
6306 mus_new_identifier != NULL || force_reload_mus);
6311 print_timestamp_init("ReloadCustomArtwork");
6313 SetGameStatus(GAME_MODE_LOADING);
6315 FadeOut(REDRAW_ALL);
6317 SetLoadingBackgroundImage();
6319 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6320 print_timestamp_time("ClearRectangleOnBackground");
6324 UPDATE_BUSY_STATE();
6326 InitMissingFileHash();
6328 if (gfx_new_identifier != NULL || force_reload_gfx)
6331 Debug("init:ReloadCustomArtwork",
6332 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6333 artwork.gfx_current_identifier,
6335 artwork.gfx_current->identifier,
6336 leveldir_current->graphics_set);
6340 print_timestamp_time("InitImages");
6343 if (snd_new_identifier != NULL || force_reload_snd)
6345 InitSound(snd_new_identifier);
6346 print_timestamp_time("InitSound");
6349 if (mus_new_identifier != NULL || force_reload_mus)
6351 InitMusic(mus_new_identifier);
6352 print_timestamp_time("InitMusic");
6357 SetGameStatus(last_game_status); // restore current game status
6359 FadeOut(REDRAW_ALL);
6361 RedrawGlobalBorder();
6363 // force redraw of (open or closed) door graphics
6364 SetDoorState(DOOR_OPEN_ALL);
6365 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6367 FadeSetEnterScreen();
6368 FadeSkipNextFadeOut();
6370 print_timestamp_done("ReloadCustomArtwork");
6372 LimitScreenUpdates(FALSE);
6375 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6377 if (global.autoplay_leveldir == NULL)
6378 KeyboardAutoRepeatOff();
6381 void DisplayExitMessage(char *format, va_list ap)
6383 // also check for initialized video (headless flag may be temporarily unset)
6384 if (program.headless || !video.initialized)
6387 // check if draw buffer and fonts for exit message are already available
6388 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6391 int font_1 = FC_RED;
6392 int font_2 = FC_YELLOW;
6393 int font_3 = FC_BLUE;
6394 int font_width = getFontWidth(font_2);
6395 int font_height = getFontHeight(font_2);
6398 int sxsize = WIN_XSIZE - 2 * sx;
6399 int sysize = WIN_YSIZE - 2 * sy;
6400 int line_length = sxsize / font_width;
6401 int max_lines = sysize / font_height;
6402 int num_lines_printed;
6406 gfx.sxsize = sxsize;
6407 gfx.sysize = sysize;
6411 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6413 DrawTextSCentered(sy, font_1, "Fatal error:");
6414 sy += 3 * font_height;;
6417 DrawTextBufferVA(sx, sy, format, ap, font_2,
6418 line_length, line_length, max_lines,
6419 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6420 sy += (num_lines_printed + 3) * font_height;
6422 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6423 sy += 3 * font_height;
6426 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6427 line_length, line_length, max_lines,
6428 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6430 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6432 redraw_mask = REDRAW_ALL;
6434 // force drawing exit message even if screen updates are currently limited
6435 LimitScreenUpdates(FALSE);
6439 // deactivate toons on error message screen
6440 setup.toons = FALSE;
6442 WaitForEventToContinue();
6446 // ============================================================================
6448 // ============================================================================
6452 print_timestamp_init("OpenAll");
6454 SetGameStatus(GAME_MODE_LOADING);
6458 InitGlobal(); // initialize some global variables
6460 InitRND(NEW_RANDOMIZE);
6461 InitSimpleRandom(NEW_RANDOMIZE);
6462 InitBetterRandom(NEW_RANDOMIZE);
6464 InitMissingFileHash();
6466 print_timestamp_time("[init global stuff]");
6470 print_timestamp_time("[init setup/config stuff (1)]");
6472 if (options.execute_command)
6473 Execute_Command(options.execute_command);
6475 InitNetworkSettings();
6479 if (network.serveronly)
6481 #if defined(PLATFORM_UNIX)
6482 NetworkServer(network.server_port, TRUE);
6484 Warn("networking only supported in Unix version");
6487 exit(0); // never reached, server loops forever
6491 print_timestamp_time("[init setup/config stuff (2)]");
6493 print_timestamp_time("[init setup/config stuff (3)]");
6494 InitArtworkInfo(); // needed before loading gfx, sound & music
6495 print_timestamp_time("[init setup/config stuff (4)]");
6496 InitArtworkConfig(); // needed before forking sound child process
6497 print_timestamp_time("[init setup/config stuff (5)]");
6499 print_timestamp_time("[init setup/config stuff (6)]");
6503 print_timestamp_time("[init setup/config stuff]");
6505 InitVideoDefaults();
6507 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6510 InitEventFilter(FilterMouseMotionEvents);
6512 print_timestamp_time("[init video stuff]");
6514 InitElementPropertiesStatic();
6515 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6516 InitElementPropertiesGfxElement();
6518 print_timestamp_time("[init element properties stuff]");
6522 print_timestamp_time("InitGfx");
6525 print_timestamp_time("InitLevelInfo");
6527 InitLevelArtworkInfo();
6528 print_timestamp_time("InitLevelArtworkInfo");
6530 InitOverrideArtwork(); // needs to know current level directory
6531 print_timestamp_time("InitOverrideArtwork");
6533 InitArtworkIdentifier(); // needs to know current level directory
6534 print_timestamp_time("InitArtworkIdentifier");
6536 InitImages(); // needs to know current level directory
6537 print_timestamp_time("InitImages");
6539 InitSound(NULL); // needs to know current level directory
6540 print_timestamp_time("InitSound");
6542 InitMusic(NULL); // needs to know current level directory
6543 print_timestamp_time("InitMusic");
6547 InitGfxBackground();
6553 if (global.autoplay_leveldir)
6558 else if (global.patchtapes_leveldir)
6563 else if (global.convert_leveldir)
6568 else if (global.dumplevel_leveldir)
6573 else if (global.dumptape_leveldir)
6578 else if (global.create_sketch_images_dir)
6580 CreateLevelSketchImages();
6583 else if (global.create_collect_images_dir)
6585 CreateCollectElementImages();
6589 InitNetworkServer();
6591 SetGameStatus(GAME_MODE_MAIN);
6593 FadeSetEnterScreen();
6594 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6595 FadeSkipNextFadeOut();
6597 print_timestamp_time("[post-artwork]");
6599 print_timestamp_done("OpenAll");
6601 if (setup.ask_for_remaining_tapes)
6602 setup.ask_for_uploading_tapes = TRUE;
6607 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6609 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6610 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6611 #if defined(PLATFORM_ANDROID)
6612 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6613 SDL_AndroidGetInternalStoragePath());
6614 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6615 SDL_AndroidGetExternalStoragePath());
6616 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6617 (SDL_AndroidGetExternalStorageState() &
6618 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6619 SDL_AndroidGetExternalStorageState() &
6620 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6625 static boolean WaitForApiThreads(void)
6627 DelayCounter thread_delay = { 10000 };
6629 if (program.api_thread_count == 0)
6632 // deactivate global animations (not accessible in game state "loading")
6633 setup.toons = FALSE;
6635 // set game state to "loading" to be able to show busy animation
6636 SetGameStatus(GAME_MODE_LOADING);
6638 ResetDelayCounter(&thread_delay);
6640 // wait for threads to finish (and fail on timeout)
6641 while (program.api_thread_count > 0)
6643 if (DelayReached(&thread_delay))
6645 Error("failed waiting for threads - TIMEOUT");
6650 UPDATE_BUSY_STATE();
6658 void CloseAllAndExit(int exit_value)
6660 WaitForApiThreads();
6665 CloseAudio(); // called after freeing sounds (needed for SDL)
6673 // set a flag to tell the network server thread to quit and wait for it
6674 // using SDL_WaitThread()
6676 // Code used with SDL 1.2:
6677 // if (network.server_thread) // terminate network server
6678 // SDL_KillThread(network.server_thread);
6680 CloseVideoDisplay();
6681 ClosePlatformDependentStuff();
6683 if (exit_value != 0 && !options.execute_command)
6685 // fall back to default level set (current set may have caused an error)
6686 SaveLevelSetup_LastSeries_Deactivate();
6688 // tell user where to find error log file which may contain more details
6689 // (error notification now directly displayed on screen inside R'n'D
6690 // NotifyUserAboutErrorFile(); // currently only works for Windows