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_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
40 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
42 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL 0
43 #define INITIAL_IMG_GLOBAL_BUSY 1
44 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 2
45 #define INITIAL_IMG_BACKGROUND_LOADING 3
47 #define NUM_INITIAL_IMAGES 4
50 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
51 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
53 static int copy_properties[][5] =
57 EL_BUG_LEFT, EL_BUG_RIGHT,
58 EL_BUG_UP, EL_BUG_DOWN
62 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
63 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
67 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
68 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
72 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
73 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
77 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
78 EL_PACMAN_UP, EL_PACMAN_DOWN
82 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
83 EL_YAMYAM_UP, EL_YAMYAM_DOWN
87 EL_MOLE_LEFT, EL_MOLE_RIGHT,
88 EL_MOLE_UP, EL_MOLE_DOWN
92 EL_SPRING_LEFT, EL_SPRING_RIGHT,
93 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
102 // forward declaration for internal use
103 static int get_graphic_parameter_value(char *, char *, int);
106 static void SetLoadingBackgroundImage(void)
108 struct GraphicInfo *graphic_info_last = graphic_info;
109 int background_image = (game_status_last_screen == -1 ?
110 INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
111 INITIAL_IMG_BACKGROUND_LOADING);
113 graphic_info = image_initial;
115 SetDrawDeactivationMask(REDRAW_NONE);
116 SetDrawBackgroundMask(REDRAW_ALL);
118 SetWindowBackgroundImage(background_image);
120 graphic_info = graphic_info_last;
123 static void DrawInitAnim(void)
125 struct GraphicInfo *graphic_info_last = graphic_info;
126 int graphic = (game_status_last_screen == -1 ?
127 INITIAL_IMG_GLOBAL_BUSY_INITIAL :
128 INITIAL_IMG_GLOBAL_BUSY);
129 struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
130 &init_last.busy_initial :
132 static unsigned int action_delay = 0;
133 unsigned int action_delay_value = GameFrameDelay;
134 int sync_frame = FrameCounter;
138 // prevent OS (Windows) from complaining about program not responding
141 if (game_status != GAME_MODE_LOADING)
144 if (image_initial[graphic].bitmap == NULL || window == NULL)
147 if (!DelayReached(&action_delay, action_delay_value))
151 busy->x = WIN_XSIZE / 2;
153 busy->y = WIN_YSIZE / 2;
155 x = ALIGNED_TEXT_XPOS(busy);
156 y = ALIGNED_TEXT_YPOS(busy);
158 graphic_info = image_initial;
160 if (sync_frame % image_initial[graphic].anim_delay == 0)
164 int width = graphic_info[graphic].width;
165 int height = graphic_info[graphic].height;
166 int frame = getGraphicAnimationFrame(graphic, sync_frame);
168 ClearRectangleOnBackground(drawto, x, y, width, height);
170 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
171 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
173 BlitBitmap(drawto, window, x, y, width, height, x, y);
176 graphic_info = graphic_info_last;
181 static void DrawProgramInfo(void)
183 int font1_nr = FC_YELLOW;
184 int font2_nr = FC_RED;
185 int font2_height = getFontHeight(font2_nr);
188 int ypos3 = WIN_YSIZE - 20 - font2_height;
190 DrawInitText(getProgramInitString(), ypos1, font1_nr);
191 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
192 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
195 static void FreeGadgets(void)
197 FreeLevelEditorGadgets();
204 void InitGadgets(void)
206 static boolean gadgets_initialized = FALSE;
208 if (gadgets_initialized)
211 CreateLevelEditorGadgets();
215 CreateScreenGadgets();
217 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
219 gadgets_initialized = TRUE;
222 static void InitElementSmallImagesScaledUp(int graphic)
224 struct GraphicInfo *g = &graphic_info[graphic];
226 // create small and game tile sized bitmaps (and scale up, if needed)
227 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
230 static void InitElementSmallImages(void)
232 print_timestamp_init("InitElementSmallImages");
234 static int special_graphics[] =
248 IMG_EDITOR_ELEMENT_BORDER,
249 IMG_EDITOR_ELEMENT_BORDER_INPUT,
250 IMG_EDITOR_CASCADE_LIST,
251 IMG_EDITOR_CASCADE_LIST_ACTIVE,
254 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
255 int num_property_mappings = getImageListPropertyMappingSize();
258 print_timestamp_time("getImageListPropertyMapping/Size");
260 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
261 // initialize normal element images from static configuration
262 for (i = 0; element_to_graphic[i].element > -1; i++)
263 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
264 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
266 // initialize special element images from static configuration
267 for (i = 0; element_to_special_graphic[i].element > -1; i++)
268 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
269 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
271 // initialize element images from dynamic configuration
272 for (i = 0; i < num_property_mappings; i++)
273 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
274 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
275 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
277 // initialize special non-element images from above list
278 for (i = 0; special_graphics[i] > -1; i++)
279 InitElementSmallImagesScaledUp(special_graphics[i]);
280 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
282 print_timestamp_done("InitElementSmallImages");
285 static void InitScaledImagesScaledUp(int graphic)
287 struct GraphicInfo *g = &graphic_info[graphic];
289 ScaleImage(graphic, g->scale_up_factor);
292 static void InitScaledImages(void)
294 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
295 int num_property_mappings = getImageListPropertyMappingSize();
298 // scale normal images from static configuration, if not already scaled
299 for (i = 0; i < NUM_IMAGE_FILES; i++)
300 InitScaledImagesScaledUp(i);
302 // scale images from dynamic configuration, if not already scaled
303 for (i = 0; i < num_property_mappings; i++)
304 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
307 static void InitBitmapPointers(void)
309 int num_images = getImageListSize();
312 // standard size bitmap may have changed -- update default bitmap pointer
313 for (i = 0; i < num_images; i++)
314 if (graphic_info[i].bitmaps)
315 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
318 void InitImageTextures(void)
320 static int texture_graphics[] =
322 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
323 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
324 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
325 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
326 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
327 IMG_MENU_BUTTON_TOUCH_BACK,
328 IMG_MENU_BUTTON_TOUCH_NEXT,
329 IMG_MENU_BUTTON_TOUCH_BACK2,
330 IMG_MENU_BUTTON_TOUCH_NEXT2,
335 FreeAllImageTextures();
337 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
338 CreateImageTextures(i);
340 for (i = 0; i < MAX_NUM_TOONS; i++)
341 CreateImageTextures(IMG_TOON_1 + i);
343 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
345 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
347 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
349 int graphic = global_anim_info[i].graphic[j][k];
351 if (graphic == IMG_UNDEFINED)
354 CreateImageTextures(graphic);
359 for (i = 0; texture_graphics[i] > -1; i++)
360 CreateImageTextures(texture_graphics[i]);
363 static int getFontBitmapID(int font_nr)
367 // (special case: do not use special font for GAME_MODE_LOADING)
368 if (game_status >= GAME_MODE_TITLE_INITIAL &&
369 game_status <= GAME_MODE_PSEUDO_PREVIEW)
370 special = game_status;
371 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
372 special = GFX_SPECIAL_ARG_MAIN;
373 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
374 special = GFX_SPECIAL_ARG_NAMES;
377 return font_info[font_nr].special_bitmap_id[special];
382 static int getFontFromToken(char *token)
384 char *value = getHashEntry(font_token_hash, token);
389 // if font not found, use reliable default value
390 return FONT_INITIAL_1;
393 static void InitFontGraphicInfo(void)
395 static struct FontBitmapInfo *font_bitmap_info = NULL;
396 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
397 int num_property_mappings = getImageListPropertyMappingSize();
398 int num_font_bitmaps = NUM_FONTS;
401 if (graphic_info == NULL) // still at startup phase
403 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
404 getFontBitmapID, getFontFromToken);
409 // ---------- initialize font graphic definitions ----------
411 // always start with reliable default values (normal font graphics)
412 for (i = 0; i < NUM_FONTS; i++)
413 font_info[i].graphic = IMG_FONT_INITIAL_1;
415 // initialize normal font/graphic mapping from static configuration
416 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
418 int font_nr = font_to_graphic[i].font_nr;
419 int special = font_to_graphic[i].special;
420 int graphic = font_to_graphic[i].graphic;
425 font_info[font_nr].graphic = graphic;
428 // always start with reliable default values (special font graphics)
429 for (i = 0; i < NUM_FONTS; i++)
431 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
433 font_info[i].special_graphic[j] = font_info[i].graphic;
434 font_info[i].special_bitmap_id[j] = i;
438 // initialize special font/graphic mapping from static configuration
439 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
441 int font_nr = font_to_graphic[i].font_nr;
442 int special = font_to_graphic[i].special;
443 int graphic = font_to_graphic[i].graphic;
444 int base_graphic = font2baseimg(font_nr);
446 if (IS_SPECIAL_GFX_ARG(special))
448 boolean base_redefined =
449 getImageListEntryFromImageID(base_graphic)->redefined;
450 boolean special_redefined =
451 getImageListEntryFromImageID(graphic)->redefined;
452 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
454 /* if the base font ("font.title_1", for example) has been redefined,
455 but not the special font ("font.title_1.LEVELS", for example), do not
456 use an existing (in this case considered obsolete) special font
457 anymore, but use the automatically determined default font */
458 /* special case: cloned special fonts must be explicitly redefined,
459 but are not automatically redefined by redefining base font */
460 if (base_redefined && !special_redefined && !special_cloned)
463 font_info[font_nr].special_graphic[special] = graphic;
464 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
469 // initialize special font/graphic mapping from dynamic configuration
470 for (i = 0; i < num_property_mappings; i++)
472 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
473 int special = property_mapping[i].ext3_index;
474 int graphic = property_mapping[i].artwork_index;
476 if (font_nr < 0 || font_nr >= NUM_FONTS)
479 if (IS_SPECIAL_GFX_ARG(special))
481 font_info[font_nr].special_graphic[special] = graphic;
482 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
487 /* correct special font/graphic mapping for cloned fonts for downwards
488 compatibility of PREVIEW fonts -- this is only needed for implicit
489 redefinition of special font by redefined base font, and only if other
490 fonts are cloned from this special font (like in the "Zelda" level set) */
491 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
493 int font_nr = font_to_graphic[i].font_nr;
494 int special = font_to_graphic[i].special;
495 int graphic = font_to_graphic[i].graphic;
497 if (IS_SPECIAL_GFX_ARG(special))
499 boolean special_redefined =
500 getImageListEntryFromImageID(graphic)->redefined;
501 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
503 if (special_cloned && !special_redefined)
507 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
509 int font_nr2 = font_to_graphic[j].font_nr;
510 int special2 = font_to_graphic[j].special;
511 int graphic2 = font_to_graphic[j].graphic;
513 if (IS_SPECIAL_GFX_ARG(special2) &&
514 graphic2 == graphic_info[graphic].clone_from)
516 font_info[font_nr].special_graphic[special] =
517 font_info[font_nr2].special_graphic[special2];
518 font_info[font_nr].special_bitmap_id[special] =
519 font_info[font_nr2].special_bitmap_id[special2];
526 // reset non-redefined ".active" font graphics if normal font is redefined
527 // (this different treatment is needed because normal and active fonts are
528 // independently defined ("active" is not a property of font definitions!)
529 for (i = 0; i < NUM_FONTS; i++)
531 int font_nr_base = i;
532 int font_nr_active = FONT_ACTIVE(font_nr_base);
534 // check only those fonts with exist as normal and ".active" variant
535 if (font_nr_base != font_nr_active)
537 int base_graphic = font_info[font_nr_base].graphic;
538 int active_graphic = font_info[font_nr_active].graphic;
539 boolean base_redefined =
540 getImageListEntryFromImageID(base_graphic)->redefined;
541 boolean active_redefined =
542 getImageListEntryFromImageID(active_graphic)->redefined;
544 /* if the base font ("font.menu_1", for example) has been redefined,
545 but not the active font ("font.menu_1.active", for example), do not
546 use an existing (in this case considered obsolete) active font
547 anymore, but use the automatically determined default font */
548 if (base_redefined && !active_redefined)
549 font_info[font_nr_active].graphic = base_graphic;
551 // now also check each "special" font (which may be the same as above)
552 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
554 int base_graphic = font_info[font_nr_base].special_graphic[j];
555 int active_graphic = font_info[font_nr_active].special_graphic[j];
556 boolean base_redefined =
557 getImageListEntryFromImageID(base_graphic)->redefined;
558 boolean active_redefined =
559 getImageListEntryFromImageID(active_graphic)->redefined;
561 // same as above, but check special graphic definitions, for example:
562 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
563 if (base_redefined && !active_redefined)
565 font_info[font_nr_active].special_graphic[j] =
566 font_info[font_nr_base].special_graphic[j];
567 font_info[font_nr_active].special_bitmap_id[j] =
568 font_info[font_nr_base].special_bitmap_id[j];
574 // ---------- initialize font bitmap array ----------
576 if (font_bitmap_info != NULL)
577 FreeFontInfo(font_bitmap_info);
580 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
582 // ---------- initialize font bitmap definitions ----------
584 for (i = 0; i < NUM_FONTS; i++)
586 if (i < NUM_INITIAL_FONTS)
588 font_bitmap_info[i] = font_initial[i];
592 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
594 int font_bitmap_id = font_info[i].special_bitmap_id[j];
595 int graphic = font_info[i].special_graphic[j];
597 // set 'graphic_info' for font entries, if uninitialized (guessed)
598 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
600 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
601 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
604 // copy font relevant information from graphics information
605 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
606 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
607 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
608 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
609 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
611 font_bitmap_info[font_bitmap_id].offset_x =
612 graphic_info[graphic].offset_x;
613 font_bitmap_info[font_bitmap_id].offset_y =
614 graphic_info[graphic].offset_y;
616 font_bitmap_info[font_bitmap_id].draw_xoffset =
617 graphic_info[graphic].draw_xoffset;
618 font_bitmap_info[font_bitmap_id].draw_yoffset =
619 graphic_info[graphic].draw_yoffset;
621 font_bitmap_info[font_bitmap_id].num_chars =
622 graphic_info[graphic].anim_frames;
623 font_bitmap_info[font_bitmap_id].num_chars_per_line =
624 graphic_info[graphic].anim_frames_per_line;
628 InitFontInfo(font_bitmap_info, num_font_bitmaps,
629 getFontBitmapID, getFontFromToken);
632 static void InitGlobalAnimGraphicInfo(void)
634 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
635 int num_property_mappings = getImageListPropertyMappingSize();
638 if (graphic_info == NULL) // still at startup phase
641 // always start with reliable default values (no global animations)
642 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
643 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
644 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
645 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
647 // initialize global animation definitions from static configuration
648 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
650 int j = GLOBAL_ANIM_ID_PART_BASE;
651 int k = GFX_SPECIAL_ARG_DEFAULT;
653 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
656 // initialize global animation definitions from dynamic configuration
657 for (i = 0; i < num_property_mappings; i++)
659 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
660 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
661 int special = property_mapping[i].ext3_index;
662 int graphic = property_mapping[i].artwork_index;
664 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
667 // set animation part to base part, if not specified
668 if (!IS_GLOBAL_ANIM_PART(part_nr))
669 part_nr = GLOBAL_ANIM_ID_PART_BASE;
671 // set animation screen to default, if not specified
672 if (!IS_SPECIAL_GFX_ARG(special))
673 special = GFX_SPECIAL_ARG_DEFAULT;
675 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
677 // fix default value for ".draw_masked" (for backward compatibility)
678 struct GraphicInfo *g = &graphic_info[graphic];
679 struct FileInfo *image = getImageListEntryFromImageID(graphic);
680 char **parameter_raw = image->parameter;
681 int p = GFX_ARG_DRAW_MASKED;
682 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
683 image_config_suffix[p].token,
684 image_config_suffix[p].type);
686 // if ".draw_masked" parameter is undefined, use default value "TRUE"
687 if (draw_masked == ARG_UNDEFINED_VALUE)
688 g->draw_masked = TRUE;
692 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
693 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
694 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
695 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
696 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
697 Debug("init:InitGlobalAnimGraphicInfo",
698 "anim %d, part %d, mode %d => %d",
699 i, j, k, global_anim_info[i].graphic[j][k]);
703 static void InitGlobalAnimSoundInfo(void)
705 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
706 int num_property_mappings = getSoundListPropertyMappingSize();
709 // always start with reliable default values (no global animation sounds)
710 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
711 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
712 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
713 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
715 // initialize global animation sound definitions from dynamic configuration
716 for (i = 0; i < num_property_mappings; i++)
718 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
719 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
720 int special = property_mapping[i].ext3_index;
721 int sound = property_mapping[i].artwork_index;
723 // sound uses control definition; map it to position of graphic (artwork)
724 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
726 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
729 // set animation part to base part, if not specified
730 if (!IS_GLOBAL_ANIM_PART(part_nr))
731 part_nr = GLOBAL_ANIM_ID_PART_BASE;
733 // set animation screen to default, if not specified
734 if (!IS_SPECIAL_GFX_ARG(special))
735 special = GFX_SPECIAL_ARG_DEFAULT;
737 global_anim_info[anim_nr].sound[part_nr][special] = sound;
741 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
742 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
743 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
744 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
745 Debug("init:InitGlobalAnimSoundInfo",
746 "anim %d, part %d, mode %d => %d",
747 i, j, k, global_anim_info[i].sound[j][k]);
751 static void InitGlobalAnimMusicInfo(void)
753 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
754 int num_property_mappings = getMusicListPropertyMappingSize();
757 // always start with reliable default values (no global animation music)
758 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
759 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
760 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
761 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
763 // initialize global animation music definitions from dynamic configuration
764 for (i = 0; i < num_property_mappings; i++)
766 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
767 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
768 int special = property_mapping[i].ext2_index;
769 int music = property_mapping[i].artwork_index;
771 // music uses control definition; map it to position of graphic (artwork)
772 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
774 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
777 // set animation part to base part, if not specified
778 if (!IS_GLOBAL_ANIM_PART(part_nr))
779 part_nr = GLOBAL_ANIM_ID_PART_BASE;
781 // set animation screen to default, if not specified
782 if (!IS_SPECIAL_GFX_ARG(special))
783 special = GFX_SPECIAL_ARG_DEFAULT;
785 global_anim_info[anim_nr].music[part_nr][special] = music;
789 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
790 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
791 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
792 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
793 Debug("init:InitGlobalAnimMusicInfo",
794 "anim %d, part %d, mode %d => %d",
795 i, j, k, global_anim_info[i].music[j][k]);
799 static void InitElementGraphicInfo(void)
801 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
802 int num_property_mappings = getImageListPropertyMappingSize();
805 if (graphic_info == NULL) // still at startup phase
808 // set values to -1 to identify later as "uninitialized" values
809 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
811 for (act = 0; act < NUM_ACTIONS; act++)
813 element_info[i].graphic[act] = -1;
814 element_info[i].crumbled[act] = -1;
816 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
818 element_info[i].direction_graphic[act][dir] = -1;
819 element_info[i].direction_crumbled[act][dir] = -1;
826 // initialize normal element/graphic mapping from static configuration
827 for (i = 0; element_to_graphic[i].element > -1; i++)
829 int element = element_to_graphic[i].element;
830 int action = element_to_graphic[i].action;
831 int direction = element_to_graphic[i].direction;
832 boolean crumbled = element_to_graphic[i].crumbled;
833 int graphic = element_to_graphic[i].graphic;
834 int base_graphic = el2baseimg(element);
836 if (graphic_info[graphic].bitmap == NULL)
839 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
842 boolean base_redefined =
843 getImageListEntryFromImageID(base_graphic)->redefined;
844 boolean act_dir_redefined =
845 getImageListEntryFromImageID(graphic)->redefined;
847 /* if the base graphic ("emerald", for example) has been redefined,
848 but not the action graphic ("emerald.falling", for example), do not
849 use an existing (in this case considered obsolete) action graphic
850 anymore, but use the automatically determined default graphic */
851 if (base_redefined && !act_dir_redefined)
856 action = ACTION_DEFAULT;
861 element_info[element].direction_crumbled[action][direction] = graphic;
863 element_info[element].crumbled[action] = graphic;
868 element_info[element].direction_graphic[action][direction] = graphic;
870 element_info[element].graphic[action] = graphic;
874 // initialize normal element/graphic mapping from dynamic configuration
875 for (i = 0; i < num_property_mappings; i++)
877 int element = property_mapping[i].base_index;
878 int action = property_mapping[i].ext1_index;
879 int direction = property_mapping[i].ext2_index;
880 int special = property_mapping[i].ext3_index;
881 int graphic = property_mapping[i].artwork_index;
882 boolean crumbled = FALSE;
884 if (special == GFX_SPECIAL_ARG_CRUMBLED)
890 if (graphic_info[graphic].bitmap == NULL)
893 if (element >= MAX_NUM_ELEMENTS || special != -1)
897 action = ACTION_DEFAULT;
902 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
903 element_info[element].direction_crumbled[action][dir] = -1;
906 element_info[element].direction_crumbled[action][direction] = graphic;
908 element_info[element].crumbled[action] = graphic;
913 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
914 element_info[element].direction_graphic[action][dir] = -1;
917 element_info[element].direction_graphic[action][direction] = graphic;
919 element_info[element].graphic[action] = graphic;
923 // now copy all graphics that are defined to be cloned from other graphics
924 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
926 int graphic = element_info[i].graphic[ACTION_DEFAULT];
927 int crumbled_like, diggable_like;
932 crumbled_like = graphic_info[graphic].crumbled_like;
933 diggable_like = graphic_info[graphic].diggable_like;
935 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
937 for (act = 0; act < NUM_ACTIONS; act++)
938 element_info[i].crumbled[act] =
939 element_info[crumbled_like].crumbled[act];
940 for (act = 0; act < NUM_ACTIONS; act++)
941 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
942 element_info[i].direction_crumbled[act][dir] =
943 element_info[crumbled_like].direction_crumbled[act][dir];
946 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
948 element_info[i].graphic[ACTION_DIGGING] =
949 element_info[diggable_like].graphic[ACTION_DIGGING];
950 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
951 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
952 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
956 // set hardcoded definitions for some runtime elements without graphic
957 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
959 // set hardcoded definitions for some internal elements without graphic
960 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
962 if (IS_EDITOR_CASCADE_INACTIVE(i))
963 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
964 else if (IS_EDITOR_CASCADE_ACTIVE(i))
965 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
968 // now set all undefined/invalid graphics to -1 to set to default after it
969 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
971 for (act = 0; act < NUM_ACTIONS; act++)
975 graphic = element_info[i].graphic[act];
976 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
977 element_info[i].graphic[act] = -1;
979 graphic = element_info[i].crumbled[act];
980 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
981 element_info[i].crumbled[act] = -1;
983 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
985 graphic = element_info[i].direction_graphic[act][dir];
986 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
987 element_info[i].direction_graphic[act][dir] = -1;
989 graphic = element_info[i].direction_crumbled[act][dir];
990 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
991 element_info[i].direction_crumbled[act][dir] = -1;
998 // adjust graphics with 2nd tile for movement according to direction
999 // (do this before correcting '-1' values to minimize calculations)
1000 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1002 for (act = 0; act < NUM_ACTIONS; act++)
1004 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1006 int graphic = element_info[i].direction_graphic[act][dir];
1007 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1009 if (act == ACTION_FALLING) // special case
1010 graphic = element_info[i].graphic[act];
1012 if (graphic != -1 &&
1013 graphic_info[graphic].double_movement &&
1014 graphic_info[graphic].swap_double_tiles != 0)
1016 struct GraphicInfo *g = &graphic_info[graphic];
1017 int src_x_front = g->src_x;
1018 int src_y_front = g->src_y;
1019 int src_x_back = g->src_x + g->offset2_x;
1020 int src_y_back = g->src_y + g->offset2_y;
1021 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1023 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1024 src_y_front < src_y_back);
1025 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1026 boolean swap_movement_tiles_autodetected =
1027 (!frames_are_ordered_diagonally &&
1028 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1029 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1030 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1031 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1033 // swap frontside and backside graphic tile coordinates, if needed
1034 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1036 // get current (wrong) backside tile coordinates
1037 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1039 // set frontside tile coordinates to backside tile coordinates
1040 g->src_x = src_x_back;
1041 g->src_y = src_y_back;
1043 // invert tile offset to point to new backside tile coordinates
1047 // do not swap front and backside tiles again after correction
1048 g->swap_double_tiles = 0;
1055 UPDATE_BUSY_STATE();
1057 // now set all '-1' values to element specific default values
1058 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1060 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1061 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1062 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1063 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1065 if (default_graphic == -1)
1066 default_graphic = IMG_UNKNOWN;
1068 if (default_crumbled == -1)
1069 default_crumbled = default_graphic;
1071 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1073 default_direction_graphic[dir] =
1074 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1075 default_direction_crumbled[dir] =
1076 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1078 if (default_direction_graphic[dir] == -1)
1079 default_direction_graphic[dir] = default_graphic;
1081 if (default_direction_crumbled[dir] == -1)
1082 default_direction_crumbled[dir] = default_direction_graphic[dir];
1085 for (act = 0; act < NUM_ACTIONS; act++)
1087 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1088 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1089 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1090 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1091 act == ACTION_TURNING_FROM_RIGHT ||
1092 act == ACTION_TURNING_FROM_UP ||
1093 act == ACTION_TURNING_FROM_DOWN);
1095 // generic default action graphic (defined by "[default]" directive)
1096 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1097 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1098 int default_remove_graphic = IMG_EMPTY;
1100 if (act_remove && default_action_graphic != -1)
1101 default_remove_graphic = default_action_graphic;
1103 // look for special default action graphic (classic game specific)
1104 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1105 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1106 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1107 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1108 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1109 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1110 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1111 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1113 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1114 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1115 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1116 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1117 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1118 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1119 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1120 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1122 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1123 // !!! make this better !!!
1124 if (i == EL_EMPTY_SPACE)
1126 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1127 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1130 if (default_action_graphic == -1)
1131 default_action_graphic = default_graphic;
1133 if (default_action_crumbled == -1)
1134 default_action_crumbled = default_action_graphic;
1136 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1138 // use action graphic as the default direction graphic, if undefined
1139 int default_action_direction_graphic = element_info[i].graphic[act];
1140 int default_action_direction_crumbled = element_info[i].crumbled[act];
1142 // no graphic for current action -- use default direction graphic
1143 if (default_action_direction_graphic == -1)
1144 default_action_direction_graphic =
1145 (act_remove ? default_remove_graphic :
1147 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1148 default_action_graphic != default_graphic ?
1149 default_action_graphic :
1150 default_direction_graphic[dir]);
1152 if (element_info[i].direction_graphic[act][dir] == -1)
1153 element_info[i].direction_graphic[act][dir] =
1154 default_action_direction_graphic;
1156 if (default_action_direction_crumbled == -1)
1157 default_action_direction_crumbled =
1158 element_info[i].direction_graphic[act][dir];
1160 if (element_info[i].direction_crumbled[act][dir] == -1)
1161 element_info[i].direction_crumbled[act][dir] =
1162 default_action_direction_crumbled;
1165 // no graphic for this specific action -- use default action graphic
1166 if (element_info[i].graphic[act] == -1)
1167 element_info[i].graphic[act] =
1168 (act_remove ? default_remove_graphic :
1169 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1170 default_action_graphic);
1172 if (element_info[i].crumbled[act] == -1)
1173 element_info[i].crumbled[act] = element_info[i].graphic[act];
1177 UPDATE_BUSY_STATE();
1180 static void InitElementSpecialGraphicInfo(void)
1182 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1183 int num_property_mappings = getImageListPropertyMappingSize();
1186 // always start with reliable default values
1187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1188 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1189 element_info[i].special_graphic[j] =
1190 element_info[i].graphic[ACTION_DEFAULT];
1192 // initialize special element/graphic mapping from static configuration
1193 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1195 int element = element_to_special_graphic[i].element;
1196 int special = element_to_special_graphic[i].special;
1197 int graphic = element_to_special_graphic[i].graphic;
1198 int base_graphic = el2baseimg(element);
1199 boolean base_redefined =
1200 getImageListEntryFromImageID(base_graphic)->redefined;
1201 boolean special_redefined =
1202 getImageListEntryFromImageID(graphic)->redefined;
1204 /* if the base graphic ("emerald", for example) has been redefined,
1205 but not the special graphic ("emerald.EDITOR", for example), do not
1206 use an existing (in this case considered obsolete) special graphic
1207 anymore, but use the automatically created (down-scaled) graphic */
1208 if (base_redefined && !special_redefined)
1211 element_info[element].special_graphic[special] = graphic;
1214 // initialize special element/graphic mapping from dynamic configuration
1215 for (i = 0; i < num_property_mappings; i++)
1217 int element = property_mapping[i].base_index;
1218 int action = property_mapping[i].ext1_index;
1219 int direction = property_mapping[i].ext2_index;
1220 int special = property_mapping[i].ext3_index;
1221 int graphic = property_mapping[i].artwork_index;
1223 // for action ".active", replace element with active element, if exists
1224 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1226 element = ELEMENT_ACTIVE(element);
1230 if (element >= MAX_NUM_ELEMENTS)
1233 // do not change special graphic if action or direction was specified
1234 if (action != -1 || direction != -1)
1237 if (IS_SPECIAL_GFX_ARG(special))
1238 element_info[element].special_graphic[special] = graphic;
1241 // now set all undefined/invalid graphics to default
1242 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1243 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1244 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1245 element_info[i].special_graphic[j] =
1246 element_info[i].graphic[ACTION_DEFAULT];
1249 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1251 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1252 return get_parameter_value(value_raw, suffix, type);
1254 if (strEqual(value_raw, ARG_UNDEFINED))
1255 return ARG_UNDEFINED_VALUE;
1257 if (type == TYPE_ELEMENT)
1259 char *value = getHashEntry(element_token_hash, value_raw);
1264 Warn("error found in config file:");
1265 Warn("- config file: '%s'", getImageConfigFilename());
1266 Warn("error: invalid element token '%s'", value_raw);
1267 Warn("custom graphic rejected for this element/action");
1268 Warn("fallback done to undefined element for this graphic");
1272 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1274 else if (type == TYPE_GRAPHIC)
1276 char *value = getHashEntry(graphic_token_hash, value_raw);
1277 int fallback_graphic = IMG_CHAR_EXCLAM;
1282 Warn("error found in config file:");
1283 Warn("- config file: '%s'", getImageConfigFilename());
1284 Warn("error: invalid graphic token '%s'", value_raw);
1285 Warn("custom graphic rejected for this element/action");
1286 Warn("fallback done to 'char_exclam' for this graphic");
1290 return (value != NULL ? atoi(value) : fallback_graphic);
1296 static int get_scaled_graphic_width(int graphic)
1298 int original_width = getOriginalImageWidthFromImageID(graphic);
1299 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1301 return original_width * scale_up_factor;
1304 static int get_scaled_graphic_height(int graphic)
1306 int original_height = getOriginalImageHeightFromImageID(graphic);
1307 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1309 return original_height * scale_up_factor;
1312 static void set_graphic_parameters_ext(int graphic, int *parameter,
1313 Bitmap **src_bitmaps)
1315 struct GraphicInfo *g = &graphic_info[graphic];
1316 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1317 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1318 int anim_frames_per_line = 1;
1320 // always start with reliable default values
1321 g->src_image_width = 0;
1322 g->src_image_height = 0;
1325 g->width = TILEX; // default for element graphics
1326 g->height = TILEY; // default for element graphics
1327 g->offset_x = 0; // one or both of these values ...
1328 g->offset_y = 0; // ... will be corrected later
1329 g->offset2_x = 0; // one or both of these values ...
1330 g->offset2_y = 0; // ... will be corrected later
1331 g->swap_double_tiles = -1; // auto-detect tile swapping
1332 g->crumbled_like = -1; // do not use clone element
1333 g->diggable_like = -1; // do not use clone element
1334 g->border_size = TILEX / 8; // "CRUMBLED" border size
1335 g->scale_up_factor = 1; // default: no scaling up
1336 g->tile_size = TILESIZE; // default: standard tile size
1337 g->clone_from = -1; // do not use clone graphic
1338 g->init_delay_fixed = 0;
1339 g->init_delay_random = 0;
1340 g->init_delay_action = -1;
1341 g->anim_delay_fixed = 0;
1342 g->anim_delay_random = 0;
1343 g->anim_delay_action = -1;
1344 g->post_delay_fixed = 0;
1345 g->post_delay_random = 0;
1346 g->post_delay_action = -1;
1347 g->init_event = ANIM_EVENT_UNDEFINED;
1348 g->anim_event = ANIM_EVENT_UNDEFINED;
1349 g->init_event_action = -1;
1350 g->anim_event_action = -1;
1351 g->draw_masked = FALSE;
1353 g->fade_mode = FADE_MODE_DEFAULT;
1357 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1358 g->align = ALIGN_CENTER; // default for title screens
1359 g->valign = VALIGN_MIDDLE; // default for title screens
1360 g->sort_priority = 0; // default for title screens
1362 g->style = STYLE_DEFAULT;
1364 g->bitmaps = src_bitmaps;
1365 g->bitmap = src_bitmap;
1367 // optional zoom factor for scaling up the image to a larger size
1368 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1369 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1370 if (g->scale_up_factor < 1)
1371 g->scale_up_factor = 1; // no scaling
1373 // optional tile size for using non-standard image size
1374 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1376 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1379 // CHECK: should tile sizes less than standard tile size be allowed?
1380 if (g->tile_size < TILESIZE)
1381 g->tile_size = TILESIZE; // standard tile size
1384 // when setting tile size, also set width and height accordingly
1385 g->width = g->tile_size;
1386 g->height = g->tile_size;
1389 if (g->use_image_size)
1391 // set new default bitmap size (with scaling, but without small images)
1392 g->width = get_scaled_graphic_width(graphic);
1393 g->height = get_scaled_graphic_height(graphic);
1396 // optional width and height of each animation frame
1397 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1398 g->width = parameter[GFX_ARG_WIDTH];
1399 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1400 g->height = parameter[GFX_ARG_HEIGHT];
1402 // optional x and y tile position of animation frame sequence
1403 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1404 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1405 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1406 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1408 // optional x and y pixel position of animation frame sequence
1409 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1410 g->src_x = parameter[GFX_ARG_X];
1411 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1412 g->src_y = parameter[GFX_ARG_Y];
1419 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1420 g->width, getTokenFromImageID(graphic), TILEX);
1423 g->width = TILEX; // will be checked to be inside bitmap later
1429 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1430 g->height, getTokenFromImageID(graphic), TILEY);
1433 g->height = TILEY; // will be checked to be inside bitmap later
1439 // get final bitmap size (with scaling, but without small images)
1440 int src_image_width = get_scaled_graphic_width(graphic);
1441 int src_image_height = get_scaled_graphic_height(graphic);
1443 if (src_image_width == 0 || src_image_height == 0)
1445 // only happens when loaded outside artwork system (like "global.busy")
1446 src_image_width = src_bitmap->width;
1447 src_image_height = src_bitmap->height;
1450 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1452 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1453 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1457 anim_frames_per_row = MAX(1, src_image_width / g->width);
1458 anim_frames_per_col = MAX(1, src_image_height / g->height);
1461 g->src_image_width = src_image_width;
1462 g->src_image_height = src_image_height;
1465 // correct x or y offset dependent of vertical or horizontal frame order
1466 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1468 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1469 parameter[GFX_ARG_OFFSET] : g->height);
1470 anim_frames_per_line = anim_frames_per_col;
1472 else // frames are ordered horizontally
1474 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1475 parameter[GFX_ARG_OFFSET] : g->width);
1476 anim_frames_per_line = anim_frames_per_row;
1479 // optionally, the x and y offset of frames can be specified directly
1480 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1481 g->offset_x = parameter[GFX_ARG_XOFFSET];
1482 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1483 g->offset_y = parameter[GFX_ARG_YOFFSET];
1485 // optionally, moving animations may have separate start and end graphics
1486 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1488 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1489 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1491 // correct x or y offset2 dependent of vertical or horizontal frame order
1492 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1493 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1494 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1495 else // frames are ordered horizontally
1496 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1497 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1499 // optionally, the x and y offset of 2nd graphic can be specified directly
1500 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1501 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1502 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1503 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1505 // optionally, the second movement tile can be specified as start tile
1506 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1507 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1509 // automatically determine correct number of frames, if not defined
1510 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1511 g->anim_frames = parameter[GFX_ARG_FRAMES];
1512 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1513 g->anim_frames = anim_frames_per_row;
1514 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1515 g->anim_frames = anim_frames_per_col;
1519 if (g->anim_frames < 1) // frames must be at least 1
1522 g->anim_frames_per_line =
1523 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1524 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1526 g->anim_delay = parameter[GFX_ARG_DELAY];
1527 if (g->anim_delay < 1) // delay must be at least 1
1530 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1532 // automatically determine correct start frame, if not defined
1533 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1534 g->anim_start_frame = 0;
1535 else if (g->anim_mode & ANIM_REVERSE)
1536 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1538 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1540 // animation synchronized with global frame counter, not move position
1541 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1543 // optional element for cloning crumble graphics
1544 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1545 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1547 // optional element for cloning digging graphics
1548 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1549 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1551 // optional border size for "crumbling" diggable graphics
1552 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1553 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1555 // used for global animations and player "boring" and "sleeping" actions
1556 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1557 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1558 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1559 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1560 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1561 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1562 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1563 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1564 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1565 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1566 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1567 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1569 // used for global animations
1570 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1571 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1572 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1573 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1574 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1575 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1576 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1577 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1578 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1579 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1580 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1581 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1582 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1583 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1585 // used for toon animations and global animations
1586 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1587 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1588 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1589 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1590 g->direction = parameter[GFX_ARG_DIRECTION];
1591 g->position = parameter[GFX_ARG_POSITION];
1592 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1593 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1595 if (g->step_delay < 1) // delay must be at least 1
1598 // this is only used for drawing font characters
1599 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1600 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1602 // use a different default value for global animations and toons
1603 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1604 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1605 g->draw_masked = TRUE;
1607 // this is used for drawing envelopes, global animations and toons
1608 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1609 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1611 // used for toon animations and global animations
1612 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1613 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1615 // optional graphic for cloning all graphics settings
1616 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1617 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1619 // optional settings for drawing title screens and title messages
1620 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1621 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1622 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1623 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1624 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1625 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1626 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1627 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1628 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1629 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1630 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1631 g->align = parameter[GFX_ARG_ALIGN];
1632 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1633 g->valign = parameter[GFX_ARG_VALIGN];
1634 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1635 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1637 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1638 g->class = parameter[GFX_ARG_CLASS];
1639 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1640 g->style = parameter[GFX_ARG_STYLE];
1642 // this is only used for drawing menu buttons and text
1643 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1644 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1645 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1646 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1649 static void set_graphic_parameters(int graphic)
1651 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1652 char **parameter_raw = image->parameter;
1653 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1654 int parameter[NUM_GFX_ARGS];
1657 // if fallback to default artwork is done, also use the default parameters
1658 if (image->fallback_to_default)
1659 parameter_raw = image->default_parameter;
1661 // get integer values from string parameters
1662 for (i = 0; i < NUM_GFX_ARGS; i++)
1663 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1664 image_config_suffix[i].token,
1665 image_config_suffix[i].type);
1667 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1669 UPDATE_BUSY_STATE();
1672 static void set_cloned_graphic_parameters(int graphic)
1674 int fallback_graphic = IMG_CHAR_EXCLAM;
1675 int max_num_images = getImageListSize();
1676 int clone_graphic = graphic_info[graphic].clone_from;
1677 int num_references_followed = 1;
1679 while (graphic_info[clone_graphic].clone_from != -1 &&
1680 num_references_followed < max_num_images)
1682 clone_graphic = graphic_info[clone_graphic].clone_from;
1684 num_references_followed++;
1687 if (num_references_followed >= max_num_images)
1690 Warn("error found in config file:");
1691 Warn("- config file: '%s'", getImageConfigFilename());
1692 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1693 Warn("error: loop discovered when resolving cloned graphics");
1694 Warn("custom graphic rejected for this element/action");
1696 if (graphic == fallback_graphic)
1697 Fail("no fallback graphic available");
1699 Warn("fallback done to 'char_exclam' for this graphic");
1702 graphic_info[graphic] = graphic_info[fallback_graphic];
1706 graphic_info[graphic] = graphic_info[clone_graphic];
1707 graphic_info[graphic].clone_from = clone_graphic;
1711 static void InitGraphicInfo(void)
1713 int fallback_graphic = IMG_CHAR_EXCLAM;
1714 int num_images = getImageListSize();
1717 // use image size as default values for width and height for these images
1718 static int full_size_graphics[] =
1721 IMG_GLOBAL_BORDER_MAIN,
1722 IMG_GLOBAL_BORDER_SCORES,
1723 IMG_GLOBAL_BORDER_EDITOR,
1724 IMG_GLOBAL_BORDER_PLAYING,
1727 IMG_BACKGROUND_ENVELOPE_1,
1728 IMG_BACKGROUND_ENVELOPE_2,
1729 IMG_BACKGROUND_ENVELOPE_3,
1730 IMG_BACKGROUND_ENVELOPE_4,
1731 IMG_BACKGROUND_REQUEST,
1734 IMG_BACKGROUND_LOADING_INITIAL,
1735 IMG_BACKGROUND_LOADING,
1736 IMG_BACKGROUND_TITLE_INITIAL,
1737 IMG_BACKGROUND_TITLE,
1738 IMG_BACKGROUND_MAIN,
1739 IMG_BACKGROUND_NAMES,
1740 IMG_BACKGROUND_LEVELS,
1741 IMG_BACKGROUND_LEVELNR,
1742 IMG_BACKGROUND_SCORES,
1743 IMG_BACKGROUND_SCOREINFO,
1744 IMG_BACKGROUND_EDITOR,
1745 IMG_BACKGROUND_INFO,
1746 IMG_BACKGROUND_INFO_ELEMENTS,
1747 IMG_BACKGROUND_INFO_MUSIC,
1748 IMG_BACKGROUND_INFO_CREDITS,
1749 IMG_BACKGROUND_INFO_PROGRAM,
1750 IMG_BACKGROUND_INFO_VERSION,
1751 IMG_BACKGROUND_INFO_LEVELSET,
1752 IMG_BACKGROUND_SETUP,
1753 IMG_BACKGROUND_PLAYING,
1754 IMG_BACKGROUND_DOOR,
1755 IMG_BACKGROUND_TAPE,
1756 IMG_BACKGROUND_PANEL,
1757 IMG_BACKGROUND_PALETTE,
1758 IMG_BACKGROUND_TOOLBOX,
1760 IMG_TITLESCREEN_INITIAL_1,
1761 IMG_TITLESCREEN_INITIAL_2,
1762 IMG_TITLESCREEN_INITIAL_3,
1763 IMG_TITLESCREEN_INITIAL_4,
1764 IMG_TITLESCREEN_INITIAL_5,
1771 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1772 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1773 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1774 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1775 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1776 IMG_BACKGROUND_TITLEMESSAGE_1,
1777 IMG_BACKGROUND_TITLEMESSAGE_2,
1778 IMG_BACKGROUND_TITLEMESSAGE_3,
1779 IMG_BACKGROUND_TITLEMESSAGE_4,
1780 IMG_BACKGROUND_TITLEMESSAGE_5,
1785 FreeGlobalAnimEventInfo();
1787 checked_free(graphic_info);
1789 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1791 // initialize "use_image_size" flag with default value
1792 for (i = 0; i < num_images; i++)
1793 graphic_info[i].use_image_size = FALSE;
1795 // initialize "use_image_size" flag from static configuration above
1796 for (i = 0; full_size_graphics[i] != -1; i++)
1797 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1799 // first set all graphic paramaters ...
1800 for (i = 0; i < num_images; i++)
1801 set_graphic_parameters(i);
1803 // ... then copy these parameters for cloned graphics
1804 for (i = 0; i < num_images; i++)
1805 if (graphic_info[i].clone_from != -1)
1806 set_cloned_graphic_parameters(i);
1808 for (i = 0; i < num_images; i++)
1810 Bitmap *src_bitmap = graphic_info[i].bitmap;
1814 int src_bitmap_width, src_bitmap_height;
1816 // now check if no animation frames are outside of the loaded image
1818 if (graphic_info[i].bitmap == NULL)
1819 continue; // skip check for optional images that are undefined
1821 // get image size (this can differ from the standard element tile size!)
1822 width = graphic_info[i].width;
1823 height = graphic_info[i].height;
1825 // get final bitmap size (with scaling, but without small images)
1826 src_bitmap_width = graphic_info[i].src_image_width;
1827 src_bitmap_height = graphic_info[i].src_image_height;
1829 // check if first animation frame is inside specified bitmap
1831 // do not use getGraphicSourceXY() here to get position of first frame;
1832 // this avoids calculating wrong start position for out-of-bounds frame
1833 src_x = graphic_info[i].src_x;
1834 src_y = graphic_info[i].src_y;
1836 if (program.headless)
1839 if (src_x < 0 || src_y < 0 ||
1840 src_x + width > src_bitmap_width ||
1841 src_y + height > src_bitmap_height)
1844 Warn("error found in config file:");
1845 Warn("- config file: '%s'", getImageConfigFilename());
1846 Warn("- config token: '%s'", getTokenFromImageID(i));
1847 Warn("- image file: '%s'", src_bitmap->source_filename);
1848 Warn("- frame size: %d, %d", width, height);
1849 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1850 src_x, src_y, src_bitmap_width, src_bitmap_height);
1851 Warn("custom graphic rejected for this element/action");
1853 if (i == fallback_graphic)
1854 Fail("no fallback graphic available");
1856 Warn("fallback done to 'char_exclam' for this graphic");
1859 graphic_info[i] = graphic_info[fallback_graphic];
1861 // if first frame out of bounds, do not check last frame anymore
1865 // check if last animation frame is inside specified bitmap
1867 last_frame = graphic_info[i].anim_frames - 1;
1868 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1870 if (src_x < 0 || src_y < 0 ||
1871 src_x + width > src_bitmap_width ||
1872 src_y + height > src_bitmap_height)
1875 Warn("error found in config file:");
1876 Warn("- config file: '%s'", getImageConfigFilename());
1877 Warn("- config token: '%s'", getTokenFromImageID(i));
1878 Warn("- image file: '%s'", src_bitmap->source_filename);
1879 Warn("- frame size: %d, %d", width, height);
1880 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1881 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1882 Warn("custom graphic rejected for this element/action");
1884 if (i == fallback_graphic)
1885 Fail("no fallback graphic available");
1887 Warn("fallback done to 'char_exclam' for this graphic");
1890 graphic_info[i] = graphic_info[fallback_graphic];
1895 static void InitGraphicCompatibilityInfo(void)
1897 struct FileInfo *fi_global_door =
1898 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1899 int num_images = getImageListSize();
1902 /* the following compatibility handling is needed for the following case:
1903 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1904 graphics mainly used for door and panel graphics, like editor, tape and
1905 in-game buttons with hard-coded bitmap positions and button sizes; as
1906 these graphics now have individual definitions, redefining "global.door"
1907 to change all these graphics at once like before does not work anymore
1908 (because all those individual definitions still have their default values);
1909 to solve this, remap all those individual definitions that are not
1910 redefined to the new bitmap of "global.door" if it was redefined */
1912 // special compatibility handling if image "global.door" was redefined
1913 if (fi_global_door->redefined)
1915 for (i = 0; i < num_images; i++)
1917 struct FileInfo *fi = getImageListEntryFromImageID(i);
1919 // process only those images that still use the default settings
1922 // process all images which default to same image as "global.door"
1923 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1926 Debug("init:InitGraphicCompatibilityInfo",
1927 "special treatment needed for token '%s'", fi->token);
1930 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1931 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1937 InitGraphicCompatibilityInfo_Doors();
1940 static void InitElementSoundInfo(void)
1942 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1943 int num_property_mappings = getSoundListPropertyMappingSize();
1946 // set values to -1 to identify later as "uninitialized" values
1947 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1948 for (act = 0; act < NUM_ACTIONS; act++)
1949 element_info[i].sound[act] = -1;
1951 // initialize element/sound mapping from static configuration
1952 for (i = 0; element_to_sound[i].element > -1; i++)
1954 int element = element_to_sound[i].element;
1955 int action = element_to_sound[i].action;
1956 int sound = element_to_sound[i].sound;
1957 boolean is_class = element_to_sound[i].is_class;
1960 action = ACTION_DEFAULT;
1963 element_info[element].sound[action] = sound;
1965 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1966 if (strEqual(element_info[j].class_name,
1967 element_info[element].class_name))
1968 element_info[j].sound[action] = sound;
1971 // initialize element class/sound mapping from dynamic configuration
1972 for (i = 0; i < num_property_mappings; i++)
1974 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1975 int action = property_mapping[i].ext1_index;
1976 int sound = property_mapping[i].artwork_index;
1978 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1982 action = ACTION_DEFAULT;
1984 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1985 if (strEqual(element_info[j].class_name,
1986 element_info[element_class].class_name))
1987 element_info[j].sound[action] = sound;
1990 // initialize element/sound mapping from dynamic configuration
1991 for (i = 0; i < num_property_mappings; i++)
1993 int element = property_mapping[i].base_index;
1994 int action = property_mapping[i].ext1_index;
1995 int sound = property_mapping[i].artwork_index;
1997 if (element >= MAX_NUM_ELEMENTS)
2001 action = ACTION_DEFAULT;
2003 element_info[element].sound[action] = sound;
2006 // now set all '-1' values to element specific default values
2007 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2009 for (act = 0; act < NUM_ACTIONS; act++)
2011 // generic default action sound (defined by "[default]" directive)
2012 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2014 // look for special default action sound (classic game specific)
2015 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2016 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2017 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2018 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2019 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2020 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2021 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2022 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2024 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2025 // !!! make this better !!!
2026 if (i == EL_EMPTY_SPACE)
2027 default_action_sound = element_info[EL_DEFAULT].sound[act];
2029 // no sound for this specific action -- use default action sound
2030 if (element_info[i].sound[act] == -1)
2031 element_info[i].sound[act] = default_action_sound;
2035 // copy sound settings to some elements that are only stored in level file
2036 // in native R'n'D levels, but are used by game engine in native EM levels
2037 for (i = 0; copy_properties[i][0] != -1; i++)
2038 for (j = 1; j <= 4; j++)
2039 for (act = 0; act < NUM_ACTIONS; act++)
2040 element_info[copy_properties[i][j]].sound[act] =
2041 element_info[copy_properties[i][0]].sound[act];
2044 static void InitGameModeSoundInfo(void)
2048 // set values to -1 to identify later as "uninitialized" values
2049 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2052 // initialize gamemode/sound mapping from static configuration
2053 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2055 int gamemode = gamemode_to_sound[i].gamemode;
2056 int sound = gamemode_to_sound[i].sound;
2059 gamemode = GAME_MODE_DEFAULT;
2061 menu.sound[gamemode] = sound;
2064 // now set all '-1' values to levelset specific default values
2065 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2066 if (menu.sound[i] == -1)
2067 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2070 static void set_sound_parameters(int sound, char **parameter_raw)
2072 int parameter[NUM_SND_ARGS];
2075 // get integer values from string parameters
2076 for (i = 0; i < NUM_SND_ARGS; i++)
2078 get_parameter_value(parameter_raw[i],
2079 sound_config_suffix[i].token,
2080 sound_config_suffix[i].type);
2082 // explicit loop mode setting in configuration overrides default value
2083 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2084 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2086 // sound volume to change the original volume when loading the sound file
2087 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2089 // sound priority to give certain sounds a higher or lower priority
2090 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2093 static void InitSoundInfo(void)
2095 int *sound_effect_properties;
2096 int num_sounds = getSoundListSize();
2099 checked_free(sound_info);
2101 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2102 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2104 // initialize sound effect for all elements to "no sound"
2105 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2106 for (j = 0; j < NUM_ACTIONS; j++)
2107 element_info[i].sound[j] = SND_UNDEFINED;
2109 for (i = 0; i < num_sounds; i++)
2111 struct FileInfo *sound = getSoundListEntry(i);
2112 int len_effect_text = strlen(sound->token);
2114 sound_effect_properties[i] = ACTION_OTHER;
2115 sound_info[i].loop = FALSE; // default: play sound only once
2117 // determine all loop sounds and identify certain sound classes
2119 for (j = 0; element_action_info[j].suffix; j++)
2121 int len_action_text = strlen(element_action_info[j].suffix);
2123 if (len_action_text < len_effect_text &&
2124 strEqual(&sound->token[len_effect_text - len_action_text],
2125 element_action_info[j].suffix))
2127 sound_effect_properties[i] = element_action_info[j].value;
2128 sound_info[i].loop = element_action_info[j].is_loop_sound;
2134 // associate elements and some selected sound actions
2136 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2138 if (element_info[j].class_name)
2140 int len_class_text = strlen(element_info[j].class_name);
2142 if (len_class_text + 1 < len_effect_text &&
2143 strncmp(sound->token,
2144 element_info[j].class_name, len_class_text) == 0 &&
2145 sound->token[len_class_text] == '.')
2147 int sound_action_value = sound_effect_properties[i];
2149 element_info[j].sound[sound_action_value] = i;
2154 set_sound_parameters(i, sound->parameter);
2157 free(sound_effect_properties);
2160 static void InitGameModeMusicInfo(void)
2162 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2163 int num_property_mappings = getMusicListPropertyMappingSize();
2164 int default_levelset_music = -1;
2167 // set values to -1 to identify later as "uninitialized" values
2168 for (i = 0; i < MAX_LEVELS; i++)
2169 levelset.music[i] = -1;
2170 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2173 // initialize gamemode/music mapping from static configuration
2174 for (i = 0; gamemode_to_music[i].music > -1; i++)
2176 int gamemode = gamemode_to_music[i].gamemode;
2177 int music = gamemode_to_music[i].music;
2180 gamemode = GAME_MODE_DEFAULT;
2182 menu.music[gamemode] = music;
2185 // initialize gamemode/music mapping from dynamic configuration
2186 for (i = 0; i < num_property_mappings; i++)
2188 int prefix = property_mapping[i].base_index;
2189 int gamemode = property_mapping[i].ext2_index;
2190 int level = property_mapping[i].ext3_index;
2191 int music = property_mapping[i].artwork_index;
2193 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2197 gamemode = GAME_MODE_DEFAULT;
2199 // level specific music only allowed for in-game music
2200 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2201 gamemode = GAME_MODE_PLAYING;
2206 default_levelset_music = music;
2209 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2210 levelset.music[level] = music;
2211 if (gamemode != GAME_MODE_PLAYING)
2212 menu.music[gamemode] = music;
2215 // now set all '-1' values to menu specific default values
2216 // (undefined values of "levelset.music[]" might stay at "-1" to
2217 // allow dynamic selection of music files from music directory!)
2218 for (i = 0; i < MAX_LEVELS; i++)
2219 if (levelset.music[i] == -1)
2220 levelset.music[i] = default_levelset_music;
2221 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2222 if (menu.music[i] == -1)
2223 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2226 static void set_music_parameters(int music, char **parameter_raw)
2228 int parameter[NUM_MUS_ARGS];
2231 // get integer values from string parameters
2232 for (i = 0; i < NUM_MUS_ARGS; i++)
2234 get_parameter_value(parameter_raw[i],
2235 music_config_suffix[i].token,
2236 music_config_suffix[i].type);
2238 // explicit loop mode setting in configuration overrides default value
2239 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2240 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2243 static void InitMusicInfo(void)
2245 int num_music = getMusicListSize();
2248 checked_free(music_info);
2250 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2252 for (i = 0; i < num_music; i++)
2254 struct FileInfo *music = getMusicListEntry(i);
2255 int len_music_text = strlen(music->token);
2257 music_info[i].loop = TRUE; // default: play music in loop mode
2259 // determine all loop music
2261 for (j = 0; music_prefix_info[j].prefix; j++)
2263 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2265 if (len_prefix_text < len_music_text &&
2266 strncmp(music->token,
2267 music_prefix_info[j].prefix, len_prefix_text) == 0)
2269 music_info[i].loop = music_prefix_info[j].is_loop_music;
2275 set_music_parameters(i, music->parameter);
2280 static void InitGameInfoFromArtworkInfo(void)
2282 // special case: store initial value of custom artwork setting
2283 game.use_masked_elements_initial = game.use_masked_elements;
2286 static void ReinitializeGraphics(void)
2288 print_timestamp_init("ReinitializeGraphics");
2290 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2292 InitGraphicInfo(); // graphic properties mapping
2293 print_timestamp_time("InitGraphicInfo");
2294 InitElementGraphicInfo(); // element game graphic mapping
2295 print_timestamp_time("InitElementGraphicInfo");
2296 InitElementSpecialGraphicInfo(); // element special graphic mapping
2297 print_timestamp_time("InitElementSpecialGraphicInfo");
2299 InitElementSmallImages(); // scale elements to all needed sizes
2300 print_timestamp_time("InitElementSmallImages");
2301 InitScaledImages(); // scale all other images, if needed
2302 print_timestamp_time("InitScaledImages");
2303 InitBitmapPointers(); // set standard size bitmap pointers
2304 print_timestamp_time("InitBitmapPointers");
2305 InitFontGraphicInfo(); // initialize text drawing functions
2306 print_timestamp_time("InitFontGraphicInfo");
2307 InitGlobalAnimGraphicInfo(); // initialize global animation config
2308 print_timestamp_time("InitGlobalAnimGraphicInfo");
2310 InitImageTextures(); // create textures for certain images
2311 print_timestamp_time("InitImageTextures");
2313 InitGraphicInfo_EM(); // graphic mapping for EM engine
2314 print_timestamp_time("InitGraphicInfo_EM");
2316 InitGraphicCompatibilityInfo();
2317 print_timestamp_time("InitGraphicCompatibilityInfo");
2320 print_timestamp_time("InitGadgets");
2322 print_timestamp_time("InitDoors");
2324 InitGameInfoFromArtworkInfo();
2326 print_timestamp_done("ReinitializeGraphics");
2329 static void ReinitializeSounds(void)
2331 InitSoundInfo(); // sound properties mapping
2332 InitElementSoundInfo(); // element game sound mapping
2333 InitGameModeSoundInfo(); // game mode sound mapping
2334 InitGlobalAnimSoundInfo(); // global animation sound settings
2336 InitPlayLevelSound(); // internal game sound settings
2339 static void ReinitializeMusic(void)
2341 InitMusicInfo(); // music properties mapping
2342 InitGameModeMusicInfo(); // game mode music mapping
2343 InitGlobalAnimMusicInfo(); // global animation music settings
2346 static int get_special_property_bit(int element, int property_bit_nr)
2348 struct PropertyBitInfo
2354 static struct PropertyBitInfo pb_can_move_into_acid[] =
2356 // the player may be able fall into acid when gravity is activated
2361 { EL_SP_MURPHY, 0 },
2362 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2364 // all elements that can move may be able to also move into acid
2367 { EL_BUG_RIGHT, 1 },
2370 { EL_SPACESHIP, 2 },
2371 { EL_SPACESHIP_LEFT, 2 },
2372 { EL_SPACESHIP_RIGHT, 2 },
2373 { EL_SPACESHIP_UP, 2 },
2374 { EL_SPACESHIP_DOWN, 2 },
2375 { EL_BD_BUTTERFLY, 3 },
2376 { EL_BD_BUTTERFLY_LEFT, 3 },
2377 { EL_BD_BUTTERFLY_RIGHT, 3 },
2378 { EL_BD_BUTTERFLY_UP, 3 },
2379 { EL_BD_BUTTERFLY_DOWN, 3 },
2380 { EL_BD_FIREFLY, 4 },
2381 { EL_BD_FIREFLY_LEFT, 4 },
2382 { EL_BD_FIREFLY_RIGHT, 4 },
2383 { EL_BD_FIREFLY_UP, 4 },
2384 { EL_BD_FIREFLY_DOWN, 4 },
2386 { EL_YAMYAM_LEFT, 5 },
2387 { EL_YAMYAM_RIGHT, 5 },
2388 { EL_YAMYAM_UP, 5 },
2389 { EL_YAMYAM_DOWN, 5 },
2390 { EL_DARK_YAMYAM, 6 },
2393 { EL_PACMAN_LEFT, 8 },
2394 { EL_PACMAN_RIGHT, 8 },
2395 { EL_PACMAN_UP, 8 },
2396 { EL_PACMAN_DOWN, 8 },
2398 { EL_MOLE_LEFT, 9 },
2399 { EL_MOLE_RIGHT, 9 },
2401 { EL_MOLE_DOWN, 9 },
2405 { EL_SATELLITE, 13 },
2406 { EL_SP_SNIKSNAK, 14 },
2407 { EL_SP_ELECTRON, 15 },
2410 { EL_SPRING_LEFT, 17 },
2411 { EL_SPRING_RIGHT, 17 },
2412 { EL_EMC_ANDROID, 18 },
2417 static struct PropertyBitInfo pb_dont_collide_with[] =
2419 { EL_SP_SNIKSNAK, 0 },
2420 { EL_SP_ELECTRON, 1 },
2428 struct PropertyBitInfo *pb_info;
2431 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2432 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2437 struct PropertyBitInfo *pb_info = NULL;
2440 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2441 if (pb_definition[i].bit_nr == property_bit_nr)
2442 pb_info = pb_definition[i].pb_info;
2444 if (pb_info == NULL)
2447 for (i = 0; pb_info[i].element != -1; i++)
2448 if (pb_info[i].element == element)
2449 return pb_info[i].bit_nr;
2454 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2455 boolean property_value)
2457 int bit_nr = get_special_property_bit(element, property_bit_nr);
2462 *bitfield |= (1 << bit_nr);
2464 *bitfield &= ~(1 << bit_nr);
2468 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2470 int bit_nr = get_special_property_bit(element, property_bit_nr);
2473 return ((*bitfield & (1 << bit_nr)) != 0);
2478 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2480 static int group_nr;
2481 static struct ElementGroupInfo *group;
2482 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2485 if (actual_group == NULL) // not yet initialized
2488 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2490 Warn("recursion too deep when resolving group element %d",
2491 group_element - EL_GROUP_START + 1);
2493 // replace element which caused too deep recursion by question mark
2494 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2499 if (recursion_depth == 0) // initialization
2501 group = actual_group;
2502 group_nr = GROUP_NR(group_element);
2504 group->num_elements_resolved = 0;
2505 group->choice_pos = 0;
2507 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2508 element_info[i].in_group[group_nr] = FALSE;
2511 for (i = 0; i < actual_group->num_elements; i++)
2513 int element = actual_group->element[i];
2515 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2518 if (IS_GROUP_ELEMENT(element))
2519 ResolveGroupElementExt(element, recursion_depth + 1);
2522 group->element_resolved[group->num_elements_resolved++] = element;
2523 element_info[element].in_group[group_nr] = TRUE;
2528 void ResolveGroupElement(int group_element)
2530 ResolveGroupElementExt(group_element, 0);
2533 void InitElementPropertiesStatic(void)
2535 static boolean clipboard_elements_initialized = FALSE;
2537 static int ep_diggable[] =
2542 EL_SP_BUGGY_BASE_ACTIVATING,
2545 EL_INVISIBLE_SAND_ACTIVE,
2548 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2549 // (if amoeba can grow into anything diggable, maybe keep these out)
2554 EL_SP_BUGGY_BASE_ACTIVE,
2561 static int ep_collectible_only[] =
2583 EL_DYNABOMB_INCREASE_NUMBER,
2584 EL_DYNABOMB_INCREASE_SIZE,
2585 EL_DYNABOMB_INCREASE_POWER,
2603 // !!! handle separately !!!
2604 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2610 static int ep_dont_run_into[] =
2612 // same elements as in 'ep_dont_touch'
2618 // same elements as in 'ep_dont_collide_with'
2630 // !!! maybe this should better be handled by 'ep_diggable' !!!
2635 EL_SP_BUGGY_BASE_ACTIVE,
2642 static int ep_dont_collide_with[] =
2644 // same elements as in 'ep_dont_touch'
2661 static int ep_dont_touch[] =
2671 static int ep_indestructible[] =
2675 EL_ACID_POOL_TOPLEFT,
2676 EL_ACID_POOL_TOPRIGHT,
2677 EL_ACID_POOL_BOTTOMLEFT,
2678 EL_ACID_POOL_BOTTOM,
2679 EL_ACID_POOL_BOTTOMRIGHT,
2680 EL_SP_HARDWARE_GRAY,
2681 EL_SP_HARDWARE_GREEN,
2682 EL_SP_HARDWARE_BLUE,
2684 EL_SP_HARDWARE_YELLOW,
2685 EL_SP_HARDWARE_BASE_1,
2686 EL_SP_HARDWARE_BASE_2,
2687 EL_SP_HARDWARE_BASE_3,
2688 EL_SP_HARDWARE_BASE_4,
2689 EL_SP_HARDWARE_BASE_5,
2690 EL_SP_HARDWARE_BASE_6,
2691 EL_INVISIBLE_STEELWALL,
2692 EL_INVISIBLE_STEELWALL_ACTIVE,
2693 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2694 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2695 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2696 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2697 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2698 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2699 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2700 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2701 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2702 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2703 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2704 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2706 EL_LIGHT_SWITCH_ACTIVE,
2707 EL_SIGN_EXCLAMATION,
2708 EL_SIGN_RADIOACTIVITY,
2715 EL_SIGN_ENTRY_FORBIDDEN,
2716 EL_SIGN_EMERGENCY_EXIT,
2724 EL_STEEL_EXIT_CLOSED,
2726 EL_STEEL_EXIT_OPENING,
2727 EL_STEEL_EXIT_CLOSING,
2728 EL_EM_STEEL_EXIT_CLOSED,
2729 EL_EM_STEEL_EXIT_OPEN,
2730 EL_EM_STEEL_EXIT_OPENING,
2731 EL_EM_STEEL_EXIT_CLOSING,
2732 EL_DC_STEELWALL_1_LEFT,
2733 EL_DC_STEELWALL_1_RIGHT,
2734 EL_DC_STEELWALL_1_TOP,
2735 EL_DC_STEELWALL_1_BOTTOM,
2736 EL_DC_STEELWALL_1_HORIZONTAL,
2737 EL_DC_STEELWALL_1_VERTICAL,
2738 EL_DC_STEELWALL_1_TOPLEFT,
2739 EL_DC_STEELWALL_1_TOPRIGHT,
2740 EL_DC_STEELWALL_1_BOTTOMLEFT,
2741 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2742 EL_DC_STEELWALL_1_TOPLEFT_2,
2743 EL_DC_STEELWALL_1_TOPRIGHT_2,
2744 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2745 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2746 EL_DC_STEELWALL_2_LEFT,
2747 EL_DC_STEELWALL_2_RIGHT,
2748 EL_DC_STEELWALL_2_TOP,
2749 EL_DC_STEELWALL_2_BOTTOM,
2750 EL_DC_STEELWALL_2_HORIZONTAL,
2751 EL_DC_STEELWALL_2_VERTICAL,
2752 EL_DC_STEELWALL_2_MIDDLE,
2753 EL_DC_STEELWALL_2_SINGLE,
2754 EL_STEELWALL_SLIPPERY,
2768 EL_GATE_1_GRAY_ACTIVE,
2769 EL_GATE_2_GRAY_ACTIVE,
2770 EL_GATE_3_GRAY_ACTIVE,
2771 EL_GATE_4_GRAY_ACTIVE,
2780 EL_EM_GATE_1_GRAY_ACTIVE,
2781 EL_EM_GATE_2_GRAY_ACTIVE,
2782 EL_EM_GATE_3_GRAY_ACTIVE,
2783 EL_EM_GATE_4_GRAY_ACTIVE,
2792 EL_EMC_GATE_5_GRAY_ACTIVE,
2793 EL_EMC_GATE_6_GRAY_ACTIVE,
2794 EL_EMC_GATE_7_GRAY_ACTIVE,
2795 EL_EMC_GATE_8_GRAY_ACTIVE,
2797 EL_DC_GATE_WHITE_GRAY,
2798 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2799 EL_DC_GATE_FAKE_GRAY,
2801 EL_SWITCHGATE_OPENING,
2802 EL_SWITCHGATE_CLOSED,
2803 EL_SWITCHGATE_CLOSING,
2804 EL_DC_SWITCHGATE_SWITCH_UP,
2805 EL_DC_SWITCHGATE_SWITCH_DOWN,
2807 EL_TIMEGATE_OPENING,
2809 EL_TIMEGATE_CLOSING,
2810 EL_DC_TIMEGATE_SWITCH,
2811 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2815 EL_TUBE_VERTICAL_LEFT,
2816 EL_TUBE_VERTICAL_RIGHT,
2817 EL_TUBE_HORIZONTAL_UP,
2818 EL_TUBE_HORIZONTAL_DOWN,
2823 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2824 EL_EXPANDABLE_STEELWALL_VERTICAL,
2825 EL_EXPANDABLE_STEELWALL_ANY,
2830 static int ep_slippery[] =
2844 EL_ROBOT_WHEEL_ACTIVE,
2850 EL_ACID_POOL_TOPLEFT,
2851 EL_ACID_POOL_TOPRIGHT,
2861 EL_STEELWALL_SLIPPERY,
2864 EL_EMC_WALL_SLIPPERY_1,
2865 EL_EMC_WALL_SLIPPERY_2,
2866 EL_EMC_WALL_SLIPPERY_3,
2867 EL_EMC_WALL_SLIPPERY_4,
2869 EL_EMC_MAGIC_BALL_ACTIVE,
2874 static int ep_can_change[] =
2879 static int ep_can_move[] =
2881 // same elements as in 'pb_can_move_into_acid'
2904 static int ep_can_fall[] =
2919 EL_QUICKSAND_FAST_FULL,
2921 EL_BD_MAGIC_WALL_FULL,
2922 EL_DC_MAGIC_WALL_FULL,
2936 static int ep_can_smash_player[] =
2962 static int ep_can_smash_enemies[] =
2971 static int ep_can_smash_everything[] =
2980 static int ep_explodes_by_fire[] =
2982 // same elements as in 'ep_explodes_impact'
2987 // same elements as in 'ep_explodes_smashed'
2997 EL_EM_DYNAMITE_ACTIVE,
2998 EL_DYNABOMB_PLAYER_1_ACTIVE,
2999 EL_DYNABOMB_PLAYER_2_ACTIVE,
3000 EL_DYNABOMB_PLAYER_3_ACTIVE,
3001 EL_DYNABOMB_PLAYER_4_ACTIVE,
3002 EL_DYNABOMB_INCREASE_NUMBER,
3003 EL_DYNABOMB_INCREASE_SIZE,
3004 EL_DYNABOMB_INCREASE_POWER,
3005 EL_SP_DISK_RED_ACTIVE,
3019 static int ep_explodes_smashed[] =
3021 // same elements as in 'ep_explodes_impact'
3035 static int ep_explodes_impact[] =
3044 static int ep_walkable_over[] =
3064 EL_SOKOBAN_FIELD_EMPTY,
3071 EL_EM_STEEL_EXIT_OPEN,
3072 EL_EM_STEEL_EXIT_OPENING,
3081 EL_GATE_1_GRAY_ACTIVE,
3082 EL_GATE_2_GRAY_ACTIVE,
3083 EL_GATE_3_GRAY_ACTIVE,
3084 EL_GATE_4_GRAY_ACTIVE,
3092 static int ep_walkable_inside[] =
3097 EL_TUBE_VERTICAL_LEFT,
3098 EL_TUBE_VERTICAL_RIGHT,
3099 EL_TUBE_HORIZONTAL_UP,
3100 EL_TUBE_HORIZONTAL_DOWN,
3109 static int ep_walkable_under[] =
3114 static int ep_passable_over[] =
3124 EL_EM_GATE_1_GRAY_ACTIVE,
3125 EL_EM_GATE_2_GRAY_ACTIVE,
3126 EL_EM_GATE_3_GRAY_ACTIVE,
3127 EL_EM_GATE_4_GRAY_ACTIVE,
3136 EL_EMC_GATE_5_GRAY_ACTIVE,
3137 EL_EMC_GATE_6_GRAY_ACTIVE,
3138 EL_EMC_GATE_7_GRAY_ACTIVE,
3139 EL_EMC_GATE_8_GRAY_ACTIVE,
3141 EL_DC_GATE_WHITE_GRAY,
3142 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3149 static int ep_passable_inside[] =
3155 EL_SP_PORT_HORIZONTAL,
3156 EL_SP_PORT_VERTICAL,
3158 EL_SP_GRAVITY_PORT_LEFT,
3159 EL_SP_GRAVITY_PORT_RIGHT,
3160 EL_SP_GRAVITY_PORT_UP,
3161 EL_SP_GRAVITY_PORT_DOWN,
3162 EL_SP_GRAVITY_ON_PORT_LEFT,
3163 EL_SP_GRAVITY_ON_PORT_RIGHT,
3164 EL_SP_GRAVITY_ON_PORT_UP,
3165 EL_SP_GRAVITY_ON_PORT_DOWN,
3166 EL_SP_GRAVITY_OFF_PORT_LEFT,
3167 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3168 EL_SP_GRAVITY_OFF_PORT_UP,
3169 EL_SP_GRAVITY_OFF_PORT_DOWN,
3174 static int ep_passable_under[] =
3179 static int ep_droppable[] =
3184 static int ep_explodes_1x1_old[] =
3189 static int ep_pushable[] =
3201 EL_SOKOBAN_FIELD_FULL,
3210 static int ep_explodes_cross_old[] =
3215 static int ep_protected[] =
3217 // same elements as in 'ep_walkable_inside'
3221 EL_TUBE_VERTICAL_LEFT,
3222 EL_TUBE_VERTICAL_RIGHT,
3223 EL_TUBE_HORIZONTAL_UP,
3224 EL_TUBE_HORIZONTAL_DOWN,
3230 // same elements as in 'ep_passable_over'
3239 EL_EM_GATE_1_GRAY_ACTIVE,
3240 EL_EM_GATE_2_GRAY_ACTIVE,
3241 EL_EM_GATE_3_GRAY_ACTIVE,
3242 EL_EM_GATE_4_GRAY_ACTIVE,
3251 EL_EMC_GATE_5_GRAY_ACTIVE,
3252 EL_EMC_GATE_6_GRAY_ACTIVE,
3253 EL_EMC_GATE_7_GRAY_ACTIVE,
3254 EL_EMC_GATE_8_GRAY_ACTIVE,
3256 EL_DC_GATE_WHITE_GRAY,
3257 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3261 // same elements as in 'ep_passable_inside'
3266 EL_SP_PORT_HORIZONTAL,
3267 EL_SP_PORT_VERTICAL,
3269 EL_SP_GRAVITY_PORT_LEFT,
3270 EL_SP_GRAVITY_PORT_RIGHT,
3271 EL_SP_GRAVITY_PORT_UP,
3272 EL_SP_GRAVITY_PORT_DOWN,
3273 EL_SP_GRAVITY_ON_PORT_LEFT,
3274 EL_SP_GRAVITY_ON_PORT_RIGHT,
3275 EL_SP_GRAVITY_ON_PORT_UP,
3276 EL_SP_GRAVITY_ON_PORT_DOWN,
3277 EL_SP_GRAVITY_OFF_PORT_LEFT,
3278 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3279 EL_SP_GRAVITY_OFF_PORT_UP,
3280 EL_SP_GRAVITY_OFF_PORT_DOWN,
3285 static int ep_throwable[] =
3290 static int ep_can_explode[] =
3292 // same elements as in 'ep_explodes_impact'
3297 // same elements as in 'ep_explodes_smashed'
3303 // elements that can explode by explosion or by dragonfire
3307 EL_EM_DYNAMITE_ACTIVE,
3308 EL_DYNABOMB_PLAYER_1_ACTIVE,
3309 EL_DYNABOMB_PLAYER_2_ACTIVE,
3310 EL_DYNABOMB_PLAYER_3_ACTIVE,
3311 EL_DYNABOMB_PLAYER_4_ACTIVE,
3312 EL_DYNABOMB_INCREASE_NUMBER,
3313 EL_DYNABOMB_INCREASE_SIZE,
3314 EL_DYNABOMB_INCREASE_POWER,
3315 EL_SP_DISK_RED_ACTIVE,
3323 // elements that can explode only by explosion
3329 static int ep_gravity_reachable[] =
3335 EL_INVISIBLE_SAND_ACTIVE,
3340 EL_SP_PORT_HORIZONTAL,
3341 EL_SP_PORT_VERTICAL,
3343 EL_SP_GRAVITY_PORT_LEFT,
3344 EL_SP_GRAVITY_PORT_RIGHT,
3345 EL_SP_GRAVITY_PORT_UP,
3346 EL_SP_GRAVITY_PORT_DOWN,
3347 EL_SP_GRAVITY_ON_PORT_LEFT,
3348 EL_SP_GRAVITY_ON_PORT_RIGHT,
3349 EL_SP_GRAVITY_ON_PORT_UP,
3350 EL_SP_GRAVITY_ON_PORT_DOWN,
3351 EL_SP_GRAVITY_OFF_PORT_LEFT,
3352 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3353 EL_SP_GRAVITY_OFF_PORT_UP,
3354 EL_SP_GRAVITY_OFF_PORT_DOWN,
3360 static int ep_empty_space[] =
3383 static int ep_player[] =
3390 EL_SOKOBAN_FIELD_PLAYER,
3396 static int ep_can_pass_magic_wall[] =
3410 static int ep_can_pass_dc_magic_wall[] =
3426 static int ep_switchable[] =
3430 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3431 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3432 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3433 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3434 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3435 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3436 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3437 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3438 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3439 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3440 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3441 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3442 EL_SWITCHGATE_SWITCH_UP,
3443 EL_SWITCHGATE_SWITCH_DOWN,
3444 EL_DC_SWITCHGATE_SWITCH_UP,
3445 EL_DC_SWITCHGATE_SWITCH_DOWN,
3447 EL_LIGHT_SWITCH_ACTIVE,
3449 EL_DC_TIMEGATE_SWITCH,
3450 EL_BALLOON_SWITCH_LEFT,
3451 EL_BALLOON_SWITCH_RIGHT,
3452 EL_BALLOON_SWITCH_UP,
3453 EL_BALLOON_SWITCH_DOWN,
3454 EL_BALLOON_SWITCH_ANY,
3455 EL_BALLOON_SWITCH_NONE,
3458 EL_EMC_MAGIC_BALL_SWITCH,
3459 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3464 static int ep_bd_element[] =
3498 static int ep_sp_element[] =
3500 // should always be valid
3503 // standard classic Supaplex elements
3510 EL_SP_HARDWARE_GRAY,
3518 EL_SP_GRAVITY_PORT_RIGHT,
3519 EL_SP_GRAVITY_PORT_DOWN,
3520 EL_SP_GRAVITY_PORT_LEFT,
3521 EL_SP_GRAVITY_PORT_UP,
3526 EL_SP_PORT_VERTICAL,
3527 EL_SP_PORT_HORIZONTAL,
3533 EL_SP_HARDWARE_BASE_1,
3534 EL_SP_HARDWARE_GREEN,
3535 EL_SP_HARDWARE_BLUE,
3537 EL_SP_HARDWARE_YELLOW,
3538 EL_SP_HARDWARE_BASE_2,
3539 EL_SP_HARDWARE_BASE_3,
3540 EL_SP_HARDWARE_BASE_4,
3541 EL_SP_HARDWARE_BASE_5,
3542 EL_SP_HARDWARE_BASE_6,
3546 // additional elements that appeared in newer Supaplex levels
3549 // additional gravity port elements (not switching, but setting gravity)
3550 EL_SP_GRAVITY_ON_PORT_LEFT,
3551 EL_SP_GRAVITY_ON_PORT_RIGHT,
3552 EL_SP_GRAVITY_ON_PORT_UP,
3553 EL_SP_GRAVITY_ON_PORT_DOWN,
3554 EL_SP_GRAVITY_OFF_PORT_LEFT,
3555 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3556 EL_SP_GRAVITY_OFF_PORT_UP,
3557 EL_SP_GRAVITY_OFF_PORT_DOWN,
3559 // more than one Murphy in a level results in an inactive clone
3562 // runtime Supaplex elements
3563 EL_SP_DISK_RED_ACTIVE,
3564 EL_SP_TERMINAL_ACTIVE,
3565 EL_SP_BUGGY_BASE_ACTIVATING,
3566 EL_SP_BUGGY_BASE_ACTIVE,
3573 static int ep_sb_element[] =
3578 EL_SOKOBAN_FIELD_EMPTY,
3579 EL_SOKOBAN_FIELD_FULL,
3580 EL_SOKOBAN_FIELD_PLAYER,
3585 EL_INVISIBLE_STEELWALL,
3590 static int ep_gem[] =
3602 static int ep_food_dark_yamyam[] =
3630 static int ep_food_penguin[] =
3644 static int ep_food_pig[] =
3656 static int ep_historic_wall[] =
3667 EL_GATE_1_GRAY_ACTIVE,
3668 EL_GATE_2_GRAY_ACTIVE,
3669 EL_GATE_3_GRAY_ACTIVE,
3670 EL_GATE_4_GRAY_ACTIVE,
3679 EL_EM_GATE_1_GRAY_ACTIVE,
3680 EL_EM_GATE_2_GRAY_ACTIVE,
3681 EL_EM_GATE_3_GRAY_ACTIVE,
3682 EL_EM_GATE_4_GRAY_ACTIVE,
3689 EL_EXPANDABLE_WALL_HORIZONTAL,
3690 EL_EXPANDABLE_WALL_VERTICAL,
3691 EL_EXPANDABLE_WALL_ANY,
3692 EL_EXPANDABLE_WALL_GROWING,
3693 EL_BD_EXPANDABLE_WALL,
3700 EL_SP_HARDWARE_GRAY,
3701 EL_SP_HARDWARE_GREEN,
3702 EL_SP_HARDWARE_BLUE,
3704 EL_SP_HARDWARE_YELLOW,
3705 EL_SP_HARDWARE_BASE_1,
3706 EL_SP_HARDWARE_BASE_2,
3707 EL_SP_HARDWARE_BASE_3,
3708 EL_SP_HARDWARE_BASE_4,
3709 EL_SP_HARDWARE_BASE_5,
3710 EL_SP_HARDWARE_BASE_6,
3712 EL_SP_TERMINAL_ACTIVE,
3715 EL_INVISIBLE_STEELWALL,
3716 EL_INVISIBLE_STEELWALL_ACTIVE,
3718 EL_INVISIBLE_WALL_ACTIVE,
3719 EL_STEELWALL_SLIPPERY,
3736 static int ep_historic_solid[] =
3740 EL_EXPANDABLE_WALL_HORIZONTAL,
3741 EL_EXPANDABLE_WALL_VERTICAL,
3742 EL_EXPANDABLE_WALL_ANY,
3743 EL_BD_EXPANDABLE_WALL,
3756 EL_QUICKSAND_FILLING,
3757 EL_QUICKSAND_EMPTYING,
3759 EL_MAGIC_WALL_ACTIVE,
3760 EL_MAGIC_WALL_EMPTYING,
3761 EL_MAGIC_WALL_FILLING,
3765 EL_BD_MAGIC_WALL_ACTIVE,
3766 EL_BD_MAGIC_WALL_EMPTYING,
3767 EL_BD_MAGIC_WALL_FULL,
3768 EL_BD_MAGIC_WALL_FILLING,
3769 EL_BD_MAGIC_WALL_DEAD,
3778 EL_SP_TERMINAL_ACTIVE,
3782 EL_INVISIBLE_WALL_ACTIVE,
3783 EL_SWITCHGATE_SWITCH_UP,
3784 EL_SWITCHGATE_SWITCH_DOWN,
3786 EL_TIMEGATE_SWITCH_ACTIVE,
3798 // the following elements are a direct copy of "indestructible" elements,
3799 // except "EL_ACID", which is "indestructible", but not "solid"!
3804 EL_ACID_POOL_TOPLEFT,
3805 EL_ACID_POOL_TOPRIGHT,
3806 EL_ACID_POOL_BOTTOMLEFT,
3807 EL_ACID_POOL_BOTTOM,
3808 EL_ACID_POOL_BOTTOMRIGHT,
3809 EL_SP_HARDWARE_GRAY,
3810 EL_SP_HARDWARE_GREEN,
3811 EL_SP_HARDWARE_BLUE,
3813 EL_SP_HARDWARE_YELLOW,
3814 EL_SP_HARDWARE_BASE_1,
3815 EL_SP_HARDWARE_BASE_2,
3816 EL_SP_HARDWARE_BASE_3,
3817 EL_SP_HARDWARE_BASE_4,
3818 EL_SP_HARDWARE_BASE_5,
3819 EL_SP_HARDWARE_BASE_6,
3820 EL_INVISIBLE_STEELWALL,
3821 EL_INVISIBLE_STEELWALL_ACTIVE,
3822 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3823 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3824 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3825 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3826 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3827 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3828 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3829 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3830 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3831 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3832 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3833 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3835 EL_LIGHT_SWITCH_ACTIVE,
3836 EL_SIGN_EXCLAMATION,
3837 EL_SIGN_RADIOACTIVITY,
3844 EL_SIGN_ENTRY_FORBIDDEN,
3845 EL_SIGN_EMERGENCY_EXIT,
3853 EL_STEEL_EXIT_CLOSED,
3855 EL_STEEL_EXIT_OPENING,
3856 EL_STEEL_EXIT_CLOSING,
3857 EL_EM_STEEL_EXIT_CLOSED,
3858 EL_EM_STEEL_EXIT_OPEN,
3859 EL_EM_STEEL_EXIT_OPENING,
3860 EL_EM_STEEL_EXIT_CLOSING,
3861 EL_DC_STEELWALL_1_LEFT,
3862 EL_DC_STEELWALL_1_RIGHT,
3863 EL_DC_STEELWALL_1_TOP,
3864 EL_DC_STEELWALL_1_BOTTOM,
3865 EL_DC_STEELWALL_1_HORIZONTAL,
3866 EL_DC_STEELWALL_1_VERTICAL,
3867 EL_DC_STEELWALL_1_TOPLEFT,
3868 EL_DC_STEELWALL_1_TOPRIGHT,
3869 EL_DC_STEELWALL_1_BOTTOMLEFT,
3870 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3871 EL_DC_STEELWALL_1_TOPLEFT_2,
3872 EL_DC_STEELWALL_1_TOPRIGHT_2,
3873 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3874 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3875 EL_DC_STEELWALL_2_LEFT,
3876 EL_DC_STEELWALL_2_RIGHT,
3877 EL_DC_STEELWALL_2_TOP,
3878 EL_DC_STEELWALL_2_BOTTOM,
3879 EL_DC_STEELWALL_2_HORIZONTAL,
3880 EL_DC_STEELWALL_2_VERTICAL,
3881 EL_DC_STEELWALL_2_MIDDLE,
3882 EL_DC_STEELWALL_2_SINGLE,
3883 EL_STEELWALL_SLIPPERY,
3897 EL_GATE_1_GRAY_ACTIVE,
3898 EL_GATE_2_GRAY_ACTIVE,
3899 EL_GATE_3_GRAY_ACTIVE,
3900 EL_GATE_4_GRAY_ACTIVE,
3909 EL_EM_GATE_1_GRAY_ACTIVE,
3910 EL_EM_GATE_2_GRAY_ACTIVE,
3911 EL_EM_GATE_3_GRAY_ACTIVE,
3912 EL_EM_GATE_4_GRAY_ACTIVE,
3921 EL_EMC_GATE_5_GRAY_ACTIVE,
3922 EL_EMC_GATE_6_GRAY_ACTIVE,
3923 EL_EMC_GATE_7_GRAY_ACTIVE,
3924 EL_EMC_GATE_8_GRAY_ACTIVE,
3926 EL_DC_GATE_WHITE_GRAY,
3927 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3928 EL_DC_GATE_FAKE_GRAY,
3930 EL_SWITCHGATE_OPENING,
3931 EL_SWITCHGATE_CLOSED,
3932 EL_SWITCHGATE_CLOSING,
3933 EL_DC_SWITCHGATE_SWITCH_UP,
3934 EL_DC_SWITCHGATE_SWITCH_DOWN,
3936 EL_TIMEGATE_OPENING,
3938 EL_TIMEGATE_CLOSING,
3939 EL_DC_TIMEGATE_SWITCH,
3940 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3944 EL_TUBE_VERTICAL_LEFT,
3945 EL_TUBE_VERTICAL_RIGHT,
3946 EL_TUBE_HORIZONTAL_UP,
3947 EL_TUBE_HORIZONTAL_DOWN,
3952 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3953 EL_EXPANDABLE_STEELWALL_VERTICAL,
3954 EL_EXPANDABLE_STEELWALL_ANY,
3959 static int ep_classic_enemy[] =
3976 static int ep_belt[] =
3978 EL_CONVEYOR_BELT_1_LEFT,
3979 EL_CONVEYOR_BELT_1_MIDDLE,
3980 EL_CONVEYOR_BELT_1_RIGHT,
3981 EL_CONVEYOR_BELT_2_LEFT,
3982 EL_CONVEYOR_BELT_2_MIDDLE,
3983 EL_CONVEYOR_BELT_2_RIGHT,
3984 EL_CONVEYOR_BELT_3_LEFT,
3985 EL_CONVEYOR_BELT_3_MIDDLE,
3986 EL_CONVEYOR_BELT_3_RIGHT,
3987 EL_CONVEYOR_BELT_4_LEFT,
3988 EL_CONVEYOR_BELT_4_MIDDLE,
3989 EL_CONVEYOR_BELT_4_RIGHT,
3994 static int ep_belt_active[] =
3996 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3997 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3998 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3999 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4000 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4001 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4002 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4003 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4004 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4005 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4006 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4007 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4012 static int ep_belt_switch[] =
4014 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4015 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4016 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4017 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4018 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4019 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4020 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4021 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4022 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4023 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4024 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4025 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4030 static int ep_tube[] =
4037 EL_TUBE_HORIZONTAL_UP,
4038 EL_TUBE_HORIZONTAL_DOWN,
4040 EL_TUBE_VERTICAL_LEFT,
4041 EL_TUBE_VERTICAL_RIGHT,
4047 static int ep_acid_pool[] =
4049 EL_ACID_POOL_TOPLEFT,
4050 EL_ACID_POOL_TOPRIGHT,
4051 EL_ACID_POOL_BOTTOMLEFT,
4052 EL_ACID_POOL_BOTTOM,
4053 EL_ACID_POOL_BOTTOMRIGHT,
4058 static int ep_keygate[] =
4068 EL_GATE_1_GRAY_ACTIVE,
4069 EL_GATE_2_GRAY_ACTIVE,
4070 EL_GATE_3_GRAY_ACTIVE,
4071 EL_GATE_4_GRAY_ACTIVE,
4080 EL_EM_GATE_1_GRAY_ACTIVE,
4081 EL_EM_GATE_2_GRAY_ACTIVE,
4082 EL_EM_GATE_3_GRAY_ACTIVE,
4083 EL_EM_GATE_4_GRAY_ACTIVE,
4092 EL_EMC_GATE_5_GRAY_ACTIVE,
4093 EL_EMC_GATE_6_GRAY_ACTIVE,
4094 EL_EMC_GATE_7_GRAY_ACTIVE,
4095 EL_EMC_GATE_8_GRAY_ACTIVE,
4097 EL_DC_GATE_WHITE_GRAY,
4098 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4103 static int ep_amoeboid[] =
4115 static int ep_amoebalive[] =
4126 static int ep_has_editor_content[] =
4132 EL_SOKOBAN_FIELD_PLAYER,
4149 static int ep_can_turn_each_move[] =
4151 // !!! do something with this one !!!
4155 static int ep_can_grow[] =
4169 static int ep_active_bomb[] =
4172 EL_EM_DYNAMITE_ACTIVE,
4173 EL_DYNABOMB_PLAYER_1_ACTIVE,
4174 EL_DYNABOMB_PLAYER_2_ACTIVE,
4175 EL_DYNABOMB_PLAYER_3_ACTIVE,
4176 EL_DYNABOMB_PLAYER_4_ACTIVE,
4177 EL_SP_DISK_RED_ACTIVE,
4182 static int ep_inactive[] =
4208 EL_QUICKSAND_FAST_EMPTY,
4231 EL_GATE_1_GRAY_ACTIVE,
4232 EL_GATE_2_GRAY_ACTIVE,
4233 EL_GATE_3_GRAY_ACTIVE,
4234 EL_GATE_4_GRAY_ACTIVE,
4243 EL_EM_GATE_1_GRAY_ACTIVE,
4244 EL_EM_GATE_2_GRAY_ACTIVE,
4245 EL_EM_GATE_3_GRAY_ACTIVE,
4246 EL_EM_GATE_4_GRAY_ACTIVE,
4255 EL_EMC_GATE_5_GRAY_ACTIVE,
4256 EL_EMC_GATE_6_GRAY_ACTIVE,
4257 EL_EMC_GATE_7_GRAY_ACTIVE,
4258 EL_EMC_GATE_8_GRAY_ACTIVE,
4260 EL_DC_GATE_WHITE_GRAY,
4261 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4262 EL_DC_GATE_FAKE_GRAY,
4265 EL_INVISIBLE_STEELWALL,
4273 EL_WALL_EMERALD_YELLOW,
4274 EL_DYNABOMB_INCREASE_NUMBER,
4275 EL_DYNABOMB_INCREASE_SIZE,
4276 EL_DYNABOMB_INCREASE_POWER,
4280 EL_SOKOBAN_FIELD_EMPTY,
4281 EL_SOKOBAN_FIELD_FULL,
4282 EL_WALL_EMERALD_RED,
4283 EL_WALL_EMERALD_PURPLE,
4284 EL_ACID_POOL_TOPLEFT,
4285 EL_ACID_POOL_TOPRIGHT,
4286 EL_ACID_POOL_BOTTOMLEFT,
4287 EL_ACID_POOL_BOTTOM,
4288 EL_ACID_POOL_BOTTOMRIGHT,
4292 EL_BD_MAGIC_WALL_DEAD,
4294 EL_DC_MAGIC_WALL_DEAD,
4295 EL_AMOEBA_TO_DIAMOND,
4303 EL_SP_GRAVITY_PORT_RIGHT,
4304 EL_SP_GRAVITY_PORT_DOWN,
4305 EL_SP_GRAVITY_PORT_LEFT,
4306 EL_SP_GRAVITY_PORT_UP,
4307 EL_SP_PORT_HORIZONTAL,
4308 EL_SP_PORT_VERTICAL,
4319 EL_SP_HARDWARE_GRAY,
4320 EL_SP_HARDWARE_GREEN,
4321 EL_SP_HARDWARE_BLUE,
4323 EL_SP_HARDWARE_YELLOW,
4324 EL_SP_HARDWARE_BASE_1,
4325 EL_SP_HARDWARE_BASE_2,
4326 EL_SP_HARDWARE_BASE_3,
4327 EL_SP_HARDWARE_BASE_4,
4328 EL_SP_HARDWARE_BASE_5,
4329 EL_SP_HARDWARE_BASE_6,
4330 EL_SP_GRAVITY_ON_PORT_LEFT,
4331 EL_SP_GRAVITY_ON_PORT_RIGHT,
4332 EL_SP_GRAVITY_ON_PORT_UP,
4333 EL_SP_GRAVITY_ON_PORT_DOWN,
4334 EL_SP_GRAVITY_OFF_PORT_LEFT,
4335 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4336 EL_SP_GRAVITY_OFF_PORT_UP,
4337 EL_SP_GRAVITY_OFF_PORT_DOWN,
4338 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4339 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4340 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4341 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4342 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4343 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4344 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4345 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4346 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4347 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4348 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4349 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4350 EL_SIGN_EXCLAMATION,
4351 EL_SIGN_RADIOACTIVITY,
4358 EL_SIGN_ENTRY_FORBIDDEN,
4359 EL_SIGN_EMERGENCY_EXIT,
4367 EL_DC_STEELWALL_1_LEFT,
4368 EL_DC_STEELWALL_1_RIGHT,
4369 EL_DC_STEELWALL_1_TOP,
4370 EL_DC_STEELWALL_1_BOTTOM,
4371 EL_DC_STEELWALL_1_HORIZONTAL,
4372 EL_DC_STEELWALL_1_VERTICAL,
4373 EL_DC_STEELWALL_1_TOPLEFT,
4374 EL_DC_STEELWALL_1_TOPRIGHT,
4375 EL_DC_STEELWALL_1_BOTTOMLEFT,
4376 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4377 EL_DC_STEELWALL_1_TOPLEFT_2,
4378 EL_DC_STEELWALL_1_TOPRIGHT_2,
4379 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4380 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4381 EL_DC_STEELWALL_2_LEFT,
4382 EL_DC_STEELWALL_2_RIGHT,
4383 EL_DC_STEELWALL_2_TOP,
4384 EL_DC_STEELWALL_2_BOTTOM,
4385 EL_DC_STEELWALL_2_HORIZONTAL,
4386 EL_DC_STEELWALL_2_VERTICAL,
4387 EL_DC_STEELWALL_2_MIDDLE,
4388 EL_DC_STEELWALL_2_SINGLE,
4389 EL_STEELWALL_SLIPPERY,
4394 EL_EMC_WALL_SLIPPERY_1,
4395 EL_EMC_WALL_SLIPPERY_2,
4396 EL_EMC_WALL_SLIPPERY_3,
4397 EL_EMC_WALL_SLIPPERY_4,
4418 static int ep_em_slippery_wall[] =
4423 static int ep_gfx_crumbled[] =
4434 static int ep_editor_cascade_active[] =
4436 EL_INTERNAL_CASCADE_BD_ACTIVE,
4437 EL_INTERNAL_CASCADE_EM_ACTIVE,
4438 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4439 EL_INTERNAL_CASCADE_RND_ACTIVE,
4440 EL_INTERNAL_CASCADE_SB_ACTIVE,
4441 EL_INTERNAL_CASCADE_SP_ACTIVE,
4442 EL_INTERNAL_CASCADE_DC_ACTIVE,
4443 EL_INTERNAL_CASCADE_DX_ACTIVE,
4444 EL_INTERNAL_CASCADE_MM_ACTIVE,
4445 EL_INTERNAL_CASCADE_DF_ACTIVE,
4446 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4447 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4448 EL_INTERNAL_CASCADE_CE_ACTIVE,
4449 EL_INTERNAL_CASCADE_GE_ACTIVE,
4450 EL_INTERNAL_CASCADE_ES_ACTIVE,
4451 EL_INTERNAL_CASCADE_REF_ACTIVE,
4452 EL_INTERNAL_CASCADE_USER_ACTIVE,
4453 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4458 static int ep_editor_cascade_inactive[] =
4460 EL_INTERNAL_CASCADE_BD,
4461 EL_INTERNAL_CASCADE_EM,
4462 EL_INTERNAL_CASCADE_EMC,
4463 EL_INTERNAL_CASCADE_RND,
4464 EL_INTERNAL_CASCADE_SB,
4465 EL_INTERNAL_CASCADE_SP,
4466 EL_INTERNAL_CASCADE_DC,
4467 EL_INTERNAL_CASCADE_DX,
4468 EL_INTERNAL_CASCADE_MM,
4469 EL_INTERNAL_CASCADE_DF,
4470 EL_INTERNAL_CASCADE_CHARS,
4471 EL_INTERNAL_CASCADE_STEEL_CHARS,
4472 EL_INTERNAL_CASCADE_CE,
4473 EL_INTERNAL_CASCADE_GE,
4474 EL_INTERNAL_CASCADE_ES,
4475 EL_INTERNAL_CASCADE_REF,
4476 EL_INTERNAL_CASCADE_USER,
4477 EL_INTERNAL_CASCADE_DYNAMIC,
4482 static int ep_obsolete[] =
4486 EL_EM_KEY_1_FILE_OBSOLETE,
4487 EL_EM_KEY_2_FILE_OBSOLETE,
4488 EL_EM_KEY_3_FILE_OBSOLETE,
4489 EL_EM_KEY_4_FILE_OBSOLETE,
4490 EL_ENVELOPE_OBSOLETE,
4499 } element_properties[] =
4501 { ep_diggable, EP_DIGGABLE },
4502 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4503 { ep_dont_run_into, EP_DONT_RUN_INTO },
4504 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4505 { ep_dont_touch, EP_DONT_TOUCH },
4506 { ep_indestructible, EP_INDESTRUCTIBLE },
4507 { ep_slippery, EP_SLIPPERY },
4508 { ep_can_change, EP_CAN_CHANGE },
4509 { ep_can_move, EP_CAN_MOVE },
4510 { ep_can_fall, EP_CAN_FALL },
4511 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4512 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4513 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4514 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4515 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4516 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4517 { ep_walkable_over, EP_WALKABLE_OVER },
4518 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4519 { ep_walkable_under, EP_WALKABLE_UNDER },
4520 { ep_passable_over, EP_PASSABLE_OVER },
4521 { ep_passable_inside, EP_PASSABLE_INSIDE },
4522 { ep_passable_under, EP_PASSABLE_UNDER },
4523 { ep_droppable, EP_DROPPABLE },
4524 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4525 { ep_pushable, EP_PUSHABLE },
4526 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4527 { ep_protected, EP_PROTECTED },
4528 { ep_throwable, EP_THROWABLE },
4529 { ep_can_explode, EP_CAN_EXPLODE },
4530 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4532 { ep_empty_space, EP_EMPTY_SPACE },
4533 { ep_player, EP_PLAYER },
4534 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4535 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4536 { ep_switchable, EP_SWITCHABLE },
4537 { ep_bd_element, EP_BD_ELEMENT },
4538 { ep_sp_element, EP_SP_ELEMENT },
4539 { ep_sb_element, EP_SB_ELEMENT },
4541 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4542 { ep_food_penguin, EP_FOOD_PENGUIN },
4543 { ep_food_pig, EP_FOOD_PIG },
4544 { ep_historic_wall, EP_HISTORIC_WALL },
4545 { ep_historic_solid, EP_HISTORIC_SOLID },
4546 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4547 { ep_belt, EP_BELT },
4548 { ep_belt_active, EP_BELT_ACTIVE },
4549 { ep_belt_switch, EP_BELT_SWITCH },
4550 { ep_tube, EP_TUBE },
4551 { ep_acid_pool, EP_ACID_POOL },
4552 { ep_keygate, EP_KEYGATE },
4553 { ep_amoeboid, EP_AMOEBOID },
4554 { ep_amoebalive, EP_AMOEBALIVE },
4555 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4556 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4557 { ep_can_grow, EP_CAN_GROW },
4558 { ep_active_bomb, EP_ACTIVE_BOMB },
4559 { ep_inactive, EP_INACTIVE },
4561 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4563 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4565 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4566 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4568 { ep_obsolete, EP_OBSOLETE },
4575 // always start with reliable default values (element has no properties)
4576 // (but never initialize clipboard elements after the very first time)
4577 // (to be able to use clipboard elements between several levels)
4578 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4579 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4580 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4581 SET_PROPERTY(i, j, FALSE);
4583 // set all base element properties from above array definitions
4584 for (i = 0; element_properties[i].elements != NULL; i++)
4585 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4586 SET_PROPERTY((element_properties[i].elements)[j],
4587 element_properties[i].property, TRUE);
4589 // copy properties to some elements that are only stored in level file
4590 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4591 for (j = 0; copy_properties[j][0] != -1; j++)
4592 if (HAS_PROPERTY(copy_properties[j][0], i))
4593 for (k = 1; k <= 4; k++)
4594 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4596 // set static element properties that are not listed in array definitions
4597 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4598 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4600 clipboard_elements_initialized = TRUE;
4603 void InitElementPropertiesEngine(int engine_version)
4605 static int no_wall_properties[] =
4608 EP_COLLECTIBLE_ONLY,
4610 EP_DONT_COLLIDE_WITH,
4613 EP_CAN_SMASH_PLAYER,
4614 EP_CAN_SMASH_ENEMIES,
4615 EP_CAN_SMASH_EVERYTHING,
4620 EP_FOOD_DARK_YAMYAM,
4636 /* important: after initialization in InitElementPropertiesStatic(), the
4637 elements are not again initialized to a default value; therefore all
4638 changes have to make sure that they leave the element with a defined
4639 property (which means that conditional property changes must be set to
4640 a reliable default value before) */
4642 // resolve group elements
4643 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4644 ResolveGroupElement(EL_GROUP_START + i);
4646 // set all special, combined or engine dependent element properties
4647 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4649 // do not change (already initialized) clipboard elements here
4650 if (IS_CLIPBOARD_ELEMENT(i))
4653 // ---------- INACTIVE ----------------------------------------------------
4654 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4655 i <= EL_CHAR_END) ||
4656 (i >= EL_STEEL_CHAR_START &&
4657 i <= EL_STEEL_CHAR_END)));
4659 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4660 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4661 IS_WALKABLE_INSIDE(i) ||
4662 IS_WALKABLE_UNDER(i)));
4664 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4665 IS_PASSABLE_INSIDE(i) ||
4666 IS_PASSABLE_UNDER(i)));
4668 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4669 IS_PASSABLE_OVER(i)));
4671 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4672 IS_PASSABLE_INSIDE(i)));
4674 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4675 IS_PASSABLE_UNDER(i)));
4677 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4680 // ---------- COLLECTIBLE -------------------------------------------------
4681 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4685 // ---------- SNAPPABLE ---------------------------------------------------
4686 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4687 IS_COLLECTIBLE(i) ||
4691 // ---------- WALL --------------------------------------------------------
4692 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4694 for (j = 0; no_wall_properties[j] != -1; j++)
4695 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4696 i >= EL_FIRST_RUNTIME_UNREAL)
4697 SET_PROPERTY(i, EP_WALL, FALSE);
4699 if (IS_HISTORIC_WALL(i))
4700 SET_PROPERTY(i, EP_WALL, TRUE);
4702 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4703 if (engine_version < VERSION_IDENT(2,2,0,0))
4704 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4706 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4708 !IS_COLLECTIBLE(i)));
4710 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4711 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4712 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4714 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4717 // ---------- EXPLOSION_PROOF ---------------------------------------------
4719 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4720 else if (engine_version < VERSION_IDENT(2,2,0,0))
4721 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4723 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4727 if (IS_CUSTOM_ELEMENT(i))
4729 // these are additional properties which are initially false when set
4731 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4733 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4734 if (DONT_COLLIDE_WITH(i))
4735 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4737 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4738 if (CAN_SMASH_EVERYTHING(i))
4739 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4740 if (CAN_SMASH_ENEMIES(i))
4741 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4744 // ---------- CAN_SMASH ---------------------------------------------------
4745 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4746 CAN_SMASH_ENEMIES(i) ||
4747 CAN_SMASH_EVERYTHING(i)));
4749 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4750 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4751 EXPLODES_BY_FIRE(i)));
4753 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4754 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4755 EXPLODES_SMASHED(i)));
4757 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4758 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4759 EXPLODES_IMPACT(i)));
4761 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4762 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4764 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4765 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4766 i == EL_BLACK_ORB));
4768 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4769 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4771 IS_CUSTOM_ELEMENT(i)));
4773 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4774 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4775 i == EL_SP_ELECTRON));
4777 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4778 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4779 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4780 getMoveIntoAcidProperty(&level, i));
4782 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4783 if (MAYBE_DONT_COLLIDE_WITH(i))
4784 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4785 getDontCollideWithProperty(&level, i));
4787 // ---------- SP_PORT -----------------------------------------------------
4788 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4789 IS_PASSABLE_INSIDE(i)));
4791 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4792 for (j = 0; j < level.num_android_clone_elements; j++)
4793 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4795 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4797 // ---------- CAN_CHANGE --------------------------------------------------
4798 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4799 for (j = 0; j < element_info[i].num_change_pages; j++)
4800 if (element_info[i].change_page[j].can_change)
4801 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4803 // ---------- HAS_ACTION --------------------------------------------------
4804 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4805 for (j = 0; j < element_info[i].num_change_pages; j++)
4806 if (element_info[i].change_page[j].has_action)
4807 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4809 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4810 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4813 // ---------- GFX_CRUMBLED ------------------------------------------------
4814 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4815 element_info[i].crumbled[ACTION_DEFAULT] !=
4816 element_info[i].graphic[ACTION_DEFAULT]);
4818 // ---------- EDITOR_CASCADE ----------------------------------------------
4819 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4820 IS_EDITOR_CASCADE_INACTIVE(i)));
4823 // dynamically adjust element properties according to game engine version
4825 static int ep_em_slippery_wall[] =
4830 EL_EXPANDABLE_WALL_HORIZONTAL,
4831 EL_EXPANDABLE_WALL_VERTICAL,
4832 EL_EXPANDABLE_WALL_ANY,
4833 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4834 EL_EXPANDABLE_STEELWALL_VERTICAL,
4835 EL_EXPANDABLE_STEELWALL_ANY,
4836 EL_EXPANDABLE_STEELWALL_GROWING,
4840 static int ep_em_explodes_by_fire[] =
4843 EL_EM_DYNAMITE_ACTIVE,
4848 // special EM style gems behaviour
4849 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4850 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4851 level.em_slippery_gems);
4853 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4854 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4855 (level.em_slippery_gems &&
4856 engine_version > VERSION_IDENT(2,0,1,0)));
4858 // special EM style explosion behaviour regarding chain reactions
4859 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4860 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4861 level.em_explodes_by_fire);
4864 // this is needed because some graphics depend on element properties
4865 if (game_status == GAME_MODE_PLAYING)
4866 InitElementGraphicInfo();
4869 void InitElementPropertiesGfxElement(void)
4873 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4875 struct ElementInfo *ei = &element_info[i];
4877 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4881 static void InitGlobal(void)
4886 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4888 // check if element_name_info entry defined for each element in "main.h"
4889 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4890 Fail("undefined 'element_name_info' entry for element %d", i);
4892 element_info[i].token_name = element_name_info[i].token_name;
4893 element_info[i].class_name = element_name_info[i].class_name;
4894 element_info[i].editor_description= element_name_info[i].editor_description;
4897 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4899 // check if global_anim_name_info defined for each entry in "main.h"
4900 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4901 global_anim_name_info[i].token_name == NULL)
4902 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4904 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4907 // create hash from image config list
4908 image_config_hash = newSetupFileHash();
4909 for (i = 0; image_config[i].token != NULL; i++)
4910 setHashEntry(image_config_hash,
4911 image_config[i].token,
4912 image_config[i].value);
4914 // create hash from element token list
4915 element_token_hash = newSetupFileHash();
4916 for (i = 0; element_name_info[i].token_name != NULL; i++)
4917 setHashEntry(element_token_hash,
4918 element_name_info[i].token_name,
4921 // create hash from graphic token list
4922 graphic_token_hash = newSetupFileHash();
4923 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4924 if (strSuffix(image_config[i].value, ".png") ||
4925 strSuffix(image_config[i].value, ".pcx") ||
4926 strSuffix(image_config[i].value, ".wav") ||
4927 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4928 setHashEntry(graphic_token_hash,
4929 image_config[i].token,
4930 int2str(graphic++, 0));
4932 // create hash from font token list
4933 font_token_hash = newSetupFileHash();
4934 for (i = 0; font_info[i].token_name != NULL; i++)
4935 setHashEntry(font_token_hash,
4936 font_info[i].token_name,
4939 // set default filenames for all cloned graphics in static configuration
4940 for (i = 0; image_config[i].token != NULL; i++)
4942 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4944 char *token = image_config[i].token;
4945 char *token_clone_from = getStringCat2(token, ".clone_from");
4946 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4948 if (token_cloned != NULL)
4950 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4952 if (value_cloned != NULL)
4954 // set default filename in static configuration
4955 image_config[i].value = value_cloned;
4957 // set default filename in image config hash
4958 setHashEntry(image_config_hash, token, value_cloned);
4962 free(token_clone_from);
4966 // always start with reliable default values (all elements)
4967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4968 ActiveElement[i] = i;
4970 // now add all entries that have an active state (active elements)
4971 for (i = 0; element_with_active_state[i].element != -1; i++)
4973 int element = element_with_active_state[i].element;
4974 int element_active = element_with_active_state[i].element_active;
4976 ActiveElement[element] = element_active;
4979 // always start with reliable default values (all buttons)
4980 for (i = 0; i < NUM_IMAGE_FILES; i++)
4981 ActiveButton[i] = i;
4983 // now add all entries that have an active state (active buttons)
4984 for (i = 0; button_with_active_state[i].button != -1; i++)
4986 int button = button_with_active_state[i].button;
4987 int button_active = button_with_active_state[i].button_active;
4989 ActiveButton[button] = button_active;
4992 // always start with reliable default values (all fonts)
4993 for (i = 0; i < NUM_FONTS; i++)
4996 // now add all entries that have an active state (active fonts)
4997 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4999 int font = font_with_active_state[i].font_nr;
5000 int font_active = font_with_active_state[i].font_nr_active;
5002 ActiveFont[font] = font_active;
5005 global.autoplay_leveldir = NULL;
5006 global.patchtapes_leveldir = NULL;
5007 global.convert_leveldir = NULL;
5008 global.dumplevel_leveldir = NULL;
5009 global.dumptape_leveldir = NULL;
5010 global.create_sketch_images_dir = NULL;
5011 global.create_collect_images_dir = NULL;
5013 global.frames_per_second = 0;
5014 global.show_frames_per_second = FALSE;
5016 global.border_status = GAME_MODE_LOADING;
5017 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5019 global.use_envelope_request = FALSE;
5021 global.user_names = NULL;
5024 static void Execute_Command(char *command)
5028 if (strEqual(command, "print graphicsinfo.conf"))
5030 Print("# You can configure additional/alternative image files here.\n");
5031 Print("# (The entries below are default and therefore commented out.)\n");
5033 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5035 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5038 for (i = 0; image_config[i].token != NULL; i++)
5039 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5040 image_config[i].value));
5044 else if (strEqual(command, "print soundsinfo.conf"))
5046 Print("# You can configure additional/alternative sound files here.\n");
5047 Print("# (The entries below are default and therefore commented out.)\n");
5049 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5051 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5054 for (i = 0; sound_config[i].token != NULL; i++)
5055 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5056 sound_config[i].value));
5060 else if (strEqual(command, "print musicinfo.conf"))
5062 Print("# You can configure additional/alternative music files here.\n");
5063 Print("# (The entries below are default and therefore commented out.)\n");
5065 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5067 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5070 for (i = 0; music_config[i].token != NULL; i++)
5071 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5072 music_config[i].value));
5076 else if (strEqual(command, "print editorsetup.conf"))
5078 Print("# You can configure your personal editor element list here.\n");
5079 Print("# (The entries below are default and therefore commented out.)\n");
5082 // this is needed to be able to check element list for cascade elements
5083 InitElementPropertiesStatic();
5084 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5086 PrintEditorElementList();
5090 else if (strEqual(command, "print helpanim.conf"))
5092 Print("# You can configure different element help animations here.\n");
5093 Print("# (The entries below are default and therefore commented out.)\n");
5096 for (i = 0; helpanim_config[i].token != NULL; i++)
5098 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5099 helpanim_config[i].value));
5101 if (strEqual(helpanim_config[i].token, "end"))
5107 else if (strEqual(command, "print helptext.conf"))
5109 Print("# You can configure different element help text here.\n");
5110 Print("# (The entries below are default and therefore commented out.)\n");
5113 for (i = 0; helptext_config[i].token != NULL; i++)
5114 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5115 helptext_config[i].value));
5119 else if (strPrefix(command, "dump level "))
5121 char *filename = &command[11];
5123 if (fileExists(filename))
5125 LoadLevelFromFilename(&level, filename);
5131 char *leveldir = getStringCopy(filename); // read command parameters
5132 char *level_nr = strchr(leveldir, ' ');
5134 if (level_nr == NULL)
5135 Fail("cannot open file '%s'", filename);
5139 global.dumplevel_leveldir = leveldir;
5140 global.dumplevel_level_nr = atoi(level_nr);
5142 program.headless = TRUE;
5144 else if (strPrefix(command, "dump tape "))
5146 char *filename = &command[10];
5148 if (fileExists(filename))
5150 LoadTapeFromFilename(filename);
5156 char *leveldir = getStringCopy(filename); // read command parameters
5157 char *level_nr = strchr(leveldir, ' ');
5159 if (level_nr == NULL)
5160 Fail("cannot open file '%s'", filename);
5164 global.dumptape_leveldir = leveldir;
5165 global.dumptape_level_nr = atoi(level_nr);
5167 program.headless = TRUE;
5169 else if (strPrefix(command, "autoplay ") ||
5170 strPrefix(command, "autoffwd ") ||
5171 strPrefix(command, "autowarp ") ||
5172 strPrefix(command, "autotest ") ||
5173 strPrefix(command, "autosave ") ||
5174 strPrefix(command, "autoupload ") ||
5175 strPrefix(command, "autofix "))
5177 char *arg_ptr = strchr(command, ' ');
5178 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5180 global.autoplay_mode =
5181 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5182 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5183 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5184 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5185 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5186 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5187 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5188 AUTOPLAY_MODE_NONE);
5190 while (*str_ptr != '\0') // continue parsing string
5192 // cut leading whitespace from string, replace it by string terminator
5193 while (*str_ptr == ' ' || *str_ptr == '\t')
5196 if (*str_ptr == '\0') // end of string reached
5199 if (global.autoplay_leveldir == NULL) // read level set string
5201 global.autoplay_leveldir = str_ptr;
5202 global.autoplay_all = TRUE; // default: play all tapes
5204 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5205 global.autoplay_level[i] = FALSE;
5207 else // read level number string
5209 int level_nr = atoi(str_ptr); // get level_nr value
5211 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5212 global.autoplay_level[level_nr] = TRUE;
5214 global.autoplay_all = FALSE;
5217 // advance string pointer to the next whitespace (or end of string)
5218 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5222 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5223 program.headless = TRUE;
5225 else if (strPrefix(command, "patch tapes "))
5227 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5229 // skip leading whitespace
5230 while (*str_ptr == ' ' || *str_ptr == '\t')
5233 if (*str_ptr == '\0')
5234 Fail("cannot find MODE in command '%s'", command);
5236 global.patchtapes_mode = str_ptr; // store patch mode
5238 // advance to next whitespace (or end of string)
5239 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5242 while (*str_ptr != '\0') // continue parsing string
5244 // cut leading whitespace from string, replace it by string terminator
5245 while (*str_ptr == ' ' || *str_ptr == '\t')
5248 if (*str_ptr == '\0') // end of string reached
5251 if (global.patchtapes_leveldir == NULL) // read level set string
5253 global.patchtapes_leveldir = str_ptr;
5254 global.patchtapes_all = TRUE; // default: patch all tapes
5256 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5257 global.patchtapes_level[i] = FALSE;
5259 else // read level number string
5261 int level_nr = atoi(str_ptr); // get level_nr value
5263 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5264 global.patchtapes_level[level_nr] = TRUE;
5266 global.patchtapes_all = FALSE;
5269 // advance string pointer to the next whitespace (or end of string)
5270 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5274 if (global.patchtapes_leveldir == NULL)
5276 if (strEqual(global.patchtapes_mode, "help"))
5277 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5279 Fail("cannot find LEVELDIR in command '%s'", command);
5282 program.headless = TRUE;
5284 else if (strPrefix(command, "convert "))
5286 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5287 char *str_ptr = strchr(str_copy, ' ');
5289 global.convert_leveldir = str_copy;
5290 global.convert_level_nr = -1;
5292 if (str_ptr != NULL) // level number follows
5294 *str_ptr++ = '\0'; // terminate leveldir string
5295 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5298 program.headless = TRUE;
5300 else if (strPrefix(command, "create sketch images "))
5302 global.create_sketch_images_dir = getStringCopy(&command[21]);
5304 if (access(global.create_sketch_images_dir, W_OK) != 0)
5305 Fail("image target directory '%s' not found or not writable",
5306 global.create_sketch_images_dir);
5308 else if (strPrefix(command, "create collect image "))
5310 global.create_collect_images_dir = getStringCopy(&command[21]);
5312 if (access(global.create_collect_images_dir, W_OK) != 0)
5313 Fail("image target directory '%s' not found or not writable",
5314 global.create_collect_images_dir);
5316 else if (strPrefix(command, "create CE image "))
5318 CreateCustomElementImages(&command[16]);
5324 FailWithHelp("unrecognized command '%s'", command);
5327 // disable networking if any valid command was recognized
5328 options.network = setup.network_mode = FALSE;
5331 static void InitSetup(void)
5333 LoadUserNames(); // global user names
5334 LoadUserSetup(); // global user number
5336 LoadSetup(); // global setup info
5338 // set some options from setup file
5340 if (setup.options.verbose)
5341 options.verbose = TRUE;
5343 if (setup.debug.show_frames_per_second)
5344 global.show_frames_per_second = TRUE;
5347 static void InitGameInfo(void)
5349 game.restart_level = FALSE;
5350 game.restart_game_message = NULL;
5352 game.request_active = FALSE;
5353 game.request_active_or_moving = FALSE;
5355 game.use_masked_elements_initial = FALSE;
5358 static void InitPlayerInfo(void)
5362 // choose default local player
5363 local_player = &stored_player[0];
5365 for (i = 0; i < MAX_PLAYERS; i++)
5367 stored_player[i].connected_locally = FALSE;
5368 stored_player[i].connected_network = FALSE;
5371 local_player->connected_locally = TRUE;
5374 static void InitArtworkInfo(void)
5379 static char *get_string_in_brackets(char *string)
5381 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5383 sprintf(string_in_brackets, "[%s]", string);
5385 return string_in_brackets;
5388 static char *get_level_id_suffix(int id_nr)
5390 char *id_suffix = checked_malloc(1 + 3 + 1);
5392 if (id_nr < 0 || id_nr > 999)
5395 sprintf(id_suffix, ".%03d", id_nr);
5400 static void InitArtworkConfig(void)
5402 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5404 NUM_GLOBAL_ANIM_TOKENS + 1];
5405 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5406 NUM_GLOBAL_ANIM_TOKENS + 1];
5407 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5408 NUM_GLOBAL_ANIM_TOKENS + 1];
5409 static char *action_id_suffix[NUM_ACTIONS + 1];
5410 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5411 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5412 static char *level_id_suffix[MAX_LEVELS + 1];
5413 static char *dummy[1] = { NULL };
5414 static char *ignore_generic_tokens[] =
5419 "program_copyright",
5424 static char **ignore_image_tokens;
5425 static char **ignore_sound_tokens;
5426 static char **ignore_music_tokens;
5427 int num_ignore_generic_tokens;
5428 int num_ignore_image_tokens;
5429 int num_ignore_sound_tokens;
5430 int num_ignore_music_tokens;
5433 // dynamically determine list of generic tokens to be ignored
5434 num_ignore_generic_tokens = 0;
5435 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5436 num_ignore_generic_tokens++;
5438 // dynamically determine list of image tokens to be ignored
5439 num_ignore_image_tokens = num_ignore_generic_tokens;
5440 for (i = 0; image_config_vars[i].token != NULL; i++)
5441 num_ignore_image_tokens++;
5442 ignore_image_tokens =
5443 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5444 for (i = 0; i < num_ignore_generic_tokens; i++)
5445 ignore_image_tokens[i] = ignore_generic_tokens[i];
5446 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5447 ignore_image_tokens[num_ignore_generic_tokens + i] =
5448 image_config_vars[i].token;
5449 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5451 // dynamically determine list of sound tokens to be ignored
5452 num_ignore_sound_tokens = num_ignore_generic_tokens;
5453 ignore_sound_tokens =
5454 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5455 for (i = 0; i < num_ignore_generic_tokens; i++)
5456 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5457 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5459 // dynamically determine list of music tokens to be ignored
5460 num_ignore_music_tokens = num_ignore_generic_tokens;
5461 ignore_music_tokens =
5462 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5463 for (i = 0; i < num_ignore_generic_tokens; i++)
5464 ignore_music_tokens[i] = ignore_generic_tokens[i];
5465 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5467 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5468 image_id_prefix[i] = element_info[i].token_name;
5469 for (i = 0; i < NUM_FONTS; i++)
5470 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5471 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5472 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5473 global_anim_info[i].token_name;
5474 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5476 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5477 sound_id_prefix[i] = element_info[i].token_name;
5478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5479 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5480 get_string_in_brackets(element_info[i].class_name);
5481 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5482 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5483 global_anim_info[i].token_name;
5484 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5486 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5487 music_id_prefix[i] = music_prefix_info[i].prefix;
5488 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5489 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5490 global_anim_info[i].token_name;
5491 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5493 for (i = 0; i < NUM_ACTIONS; i++)
5494 action_id_suffix[i] = element_action_info[i].suffix;
5495 action_id_suffix[NUM_ACTIONS] = NULL;
5497 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5498 direction_id_suffix[i] = element_direction_info[i].suffix;
5499 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5501 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5502 special_id_suffix[i] = special_suffix_info[i].suffix;
5503 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5505 for (i = 0; i < MAX_LEVELS; i++)
5506 level_id_suffix[i] = get_level_id_suffix(i);
5507 level_id_suffix[MAX_LEVELS] = NULL;
5509 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5510 image_id_prefix, action_id_suffix, direction_id_suffix,
5511 special_id_suffix, ignore_image_tokens);
5512 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5513 sound_id_prefix, action_id_suffix, dummy,
5514 special_id_suffix, ignore_sound_tokens);
5515 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5516 music_id_prefix, action_id_suffix, special_id_suffix,
5517 level_id_suffix, ignore_music_tokens);
5520 static void InitMixer(void)
5527 static void InitVideoOverlay(void)
5529 // if virtual buttons are not loaded from setup file, repeat initializing
5530 // virtual buttons grid with default values now that video is initialized
5531 if (!setup.touch.grid_initialized)
5534 InitTileCursorInfo();
5538 void InitGfxBuffers(void)
5540 static int win_xsize_last = -1;
5541 static int win_ysize_last = -1;
5543 // create additional image buffers for double-buffering and cross-fading
5545 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5547 // used to temporarily store the backbuffer -- only re-create if changed
5548 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5549 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5551 win_xsize_last = WIN_XSIZE;
5552 win_ysize_last = WIN_YSIZE;
5555 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5556 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5557 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5558 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5560 // initialize screen properties
5561 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5562 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5564 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5565 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5566 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5567 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5568 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5569 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5571 // required if door size definitions have changed
5572 InitGraphicCompatibilityInfo_Doors();
5574 InitGfxBuffers_EM();
5575 InitGfxBuffers_SP();
5578 static void InitGfx(void)
5580 struct GraphicInfo *graphic_info_last = graphic_info;
5581 char *filename_font_initial = NULL;
5582 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5583 char *image_token[NUM_INITIAL_IMAGES] =
5585 CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5586 CONFIG_TOKEN_GLOBAL_BUSY,
5587 CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5588 CONFIG_TOKEN_BACKGROUND_LOADING
5590 Bitmap *bitmap_font_initial = NULL;
5591 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5594 // determine settings for initial font (for displaying startup messages)
5595 for (i = 0; image_config[i].token != NULL; i++)
5597 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5599 char font_token[128];
5602 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5603 len_font_token = strlen(font_token);
5605 if (strEqual(image_config[i].token, font_token))
5607 filename_font_initial = image_config[i].value;
5609 else if (strlen(image_config[i].token) > len_font_token &&
5610 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5612 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5613 font_initial[j].src_x = atoi(image_config[i].value);
5614 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5615 font_initial[j].src_y = atoi(image_config[i].value);
5616 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5617 font_initial[j].width = atoi(image_config[i].value);
5618 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5619 font_initial[j].height = atoi(image_config[i].value);
5624 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5626 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5627 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5630 if (filename_font_initial == NULL) // should not happen
5631 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5634 InitGfxCustomArtworkInfo();
5635 InitGfxOtherSettings();
5637 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5639 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5641 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5642 font_initial[j].bitmap = bitmap_font_initial;
5644 InitFontGraphicInfo();
5648 DrawInitTextHead("Loading graphics");
5650 InitMenuDesignSettings_Static();
5652 // initialize settings for initial images with default values
5653 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5654 for (j = 0; j < NUM_GFX_ARGS; j++)
5656 get_graphic_parameter_value(image_config_suffix[j].value,
5657 image_config_suffix[j].token,
5658 image_config_suffix[j].type);
5660 // read settings for initial images from default custom artwork config
5661 char *gfx_config_filename = getPath3(options.graphics_directory,
5663 GRAPHICSINFO_FILENAME);
5665 if (fileExists(gfx_config_filename))
5667 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5669 if (setup_file_hash)
5671 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5673 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5677 filename_image_initial[i] = getStringCopy(filename);
5679 for (j = 0; image_config_suffix[j].token != NULL; j++)
5681 int type = image_config_suffix[j].type;
5682 char *suffix = image_config_suffix[j].token;
5683 char *token = getStringCat2(image_token[i], suffix);
5684 char *value = getHashEntry(setup_file_hash, token);
5686 checked_free(token);
5690 get_graphic_parameter_value(value, suffix, type);
5695 // read values from custom graphics config file
5696 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5698 freeSetupFileHash(setup_file_hash);
5702 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5704 if (filename_image_initial[i] == NULL)
5706 int len_token = strlen(image_token[i]);
5708 // read settings for initial images from static default artwork config
5709 for (j = 0; image_config[j].token != NULL; j++)
5711 if (strEqual(image_config[j].token, image_token[i]))
5713 filename_image_initial[i] = getStringCopy(image_config[j].value);
5715 else if (strlen(image_config[j].token) > len_token &&
5716 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5718 for (k = 0; image_config_suffix[k].token != NULL; k++)
5720 if (strEqual(&image_config[j].token[len_token],
5721 image_config_suffix[k].token))
5723 get_graphic_parameter_value(image_config[j].value,
5724 image_config_suffix[k].token,
5725 image_config_suffix[k].type);
5732 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5734 if (filename_image_initial[i] == NULL) // should not happen
5735 Fail("cannot get filename for '%s'", image_token[i]);
5737 image_initial[i].bitmaps =
5738 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5740 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5741 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5742 LoadCustomImage(filename_image_initial[i]);
5744 checked_free(filename_image_initial[i]);
5747 graphic_info = image_initial; // graphic == 0 => image_initial
5749 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5750 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5752 graphic_info = graphic_info_last;
5754 SetLoadingBackgroundImage();
5756 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5758 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5759 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5760 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5761 InitGfxDrawTileCursorFunction(DrawTileCursor);
5763 gfx.fade_border_source_status = global.border_status;
5764 gfx.fade_border_target_status = global.border_status;
5765 gfx.masked_border_bitmap_ptr = backbuffer;
5767 // use copy of busy animation to prevent change while reloading artwork
5771 static void InitGfxBackground(void)
5773 fieldbuffer = bitmap_db_field;
5774 SetDrawtoField(DRAW_TO_BACKBUFFER);
5776 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5778 redraw_mask = REDRAW_ALL;
5781 static void InitLevelInfo(void)
5783 LoadLevelInfo(); // global level info
5784 LoadLevelSetup_LastSeries(); // last played series info
5785 LoadLevelSetup_SeriesInfo(); // last played level info
5787 if (global.autoplay_leveldir &&
5788 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5790 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5791 global.autoplay_leveldir);
5792 if (leveldir_current == NULL)
5793 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5796 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5799 static void InitLevelArtworkInfo(void)
5801 LoadLevelArtworkInfo();
5804 static void InitImages(void)
5806 print_timestamp_init("InitImages");
5809 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5810 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5811 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5812 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5813 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5814 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5815 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5816 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5819 setLevelArtworkDir(artwork.gfx_first);
5822 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5823 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5824 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5825 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5826 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5827 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5828 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5829 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5833 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5834 leveldir_current->identifier,
5835 artwork.gfx_current_identifier,
5836 artwork.gfx_current->identifier,
5837 leveldir_current->graphics_set,
5838 leveldir_current->graphics_path);
5841 UPDATE_BUSY_STATE();
5843 ReloadCustomImages();
5844 print_timestamp_time("ReloadCustomImages");
5846 UPDATE_BUSY_STATE();
5848 LoadCustomElementDescriptions();
5849 print_timestamp_time("LoadCustomElementDescriptions");
5851 UPDATE_BUSY_STATE();
5853 LoadMenuDesignSettings();
5854 print_timestamp_time("LoadMenuDesignSettings");
5856 UPDATE_BUSY_STATE();
5858 ReinitializeGraphics();
5859 print_timestamp_time("ReinitializeGraphics");
5861 LoadMenuDesignSettings_AfterGraphics();
5862 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5864 UPDATE_BUSY_STATE();
5866 print_timestamp_done("InitImages");
5869 static void InitSound(char *identifier)
5871 print_timestamp_init("InitSound");
5873 if (identifier == NULL)
5874 identifier = artwork.snd_current->identifier;
5876 // set artwork path to send it to the sound server process
5877 setLevelArtworkDir(artwork.snd_first);
5879 InitReloadCustomSounds(identifier);
5880 print_timestamp_time("InitReloadCustomSounds");
5882 ReinitializeSounds();
5883 print_timestamp_time("ReinitializeSounds");
5885 print_timestamp_done("InitSound");
5888 static void InitMusic(char *identifier)
5890 print_timestamp_init("InitMusic");
5892 if (identifier == NULL)
5893 identifier = artwork.mus_current->identifier;
5895 // set artwork path to send it to the sound server process
5896 setLevelArtworkDir(artwork.mus_first);
5898 InitReloadCustomMusic(identifier);
5899 print_timestamp_time("InitReloadCustomMusic");
5901 ReinitializeMusic();
5902 print_timestamp_time("ReinitializeMusic");
5904 print_timestamp_done("InitMusic");
5907 static void InitArtworkDone(void)
5909 if (program.headless)
5912 InitGlobalAnimations();
5915 static void InitNetworkSettings(void)
5917 boolean network_enabled = (options.network || setup.network_mode);
5918 char *network_server = (options.server_host != NULL ? options.server_host :
5919 setup.network_server_hostname);
5921 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5922 network_server = NULL;
5924 InitNetworkInfo(network_enabled,
5928 options.server_port);
5931 void InitNetworkServer(void)
5933 if (!network.enabled || network.connected)
5936 LimitScreenUpdates(FALSE);
5938 if (game_status == GAME_MODE_LOADING)
5941 if (!ConnectToServer(network.server_host, network.server_port))
5943 network.enabled = FALSE;
5945 setup.network_mode = FALSE;
5949 SendToServer_ProtocolVersion();
5950 SendToServer_PlayerName(setup.player_name);
5951 SendToServer_NrWanted(setup.network_player_nr + 1);
5953 network.connected = TRUE;
5956 // short time to recognize result of network initialization
5957 if (game_status == GAME_MODE_LOADING)
5958 Delay_WithScreenUpdates(1000);
5961 static boolean CheckArtworkConfigForCustomElements(char *filename)
5963 SetupFileHash *setup_file_hash;
5964 boolean redefined_ce_found = FALSE;
5966 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5968 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5970 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5972 char *token = HASH_ITERATION_TOKEN(itr);
5974 if (strPrefix(token, "custom_"))
5976 redefined_ce_found = TRUE;
5981 END_HASH_ITERATION(setup_file_hash, itr)
5983 freeSetupFileHash(setup_file_hash);
5986 return redefined_ce_found;
5989 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5991 char *filename_base, *filename_local;
5992 boolean redefined_ce_found = FALSE;
5994 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5997 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5998 "leveldir_current->identifier == '%s'",
5999 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6000 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6001 "leveldir_current->graphics_path == '%s'",
6002 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6003 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6004 "leveldir_current->graphics_set == '%s'",
6005 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6006 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6007 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6008 leveldir_current == NULL ? "[NULL]" :
6009 LEVELDIR_ARTWORK_SET(leveldir_current, type));
6012 // first look for special artwork configured in level series config
6013 filename_base = getCustomArtworkLevelConfigFilename(type);
6016 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6017 "filename_base == '%s'", filename_base);
6020 if (fileExists(filename_base))
6021 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6023 filename_local = getCustomArtworkConfigFilename(type);
6026 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6027 "filename_local == '%s'", filename_local);
6030 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6031 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6034 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6035 "redefined_ce_found == %d", redefined_ce_found);
6038 return redefined_ce_found;
6041 static void InitOverrideArtwork(void)
6043 boolean redefined_ce_found = FALSE;
6045 // to check if this level set redefines any CEs, do not use overriding
6046 gfx.override_level_graphics = FALSE;
6047 gfx.override_level_sounds = FALSE;
6048 gfx.override_level_music = FALSE;
6050 // now check if this level set has definitions for custom elements
6051 if (setup.override_level_graphics == AUTO ||
6052 setup.override_level_sounds == AUTO ||
6053 setup.override_level_music == AUTO)
6054 redefined_ce_found =
6055 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6056 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6057 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6060 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6061 redefined_ce_found);
6064 if (redefined_ce_found)
6066 // this level set has CE definitions: change "AUTO" to "FALSE"
6067 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6068 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6069 gfx.override_level_music = (setup.override_level_music == TRUE);
6073 // this level set has no CE definitions: change "AUTO" to "TRUE"
6074 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6075 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6076 gfx.override_level_music = (setup.override_level_music != FALSE);
6080 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6081 gfx.override_level_graphics,
6082 gfx.override_level_sounds,
6083 gfx.override_level_music);
6087 static char *getNewArtworkIdentifier(int type)
6089 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6090 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6091 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6092 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6093 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6094 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6095 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6096 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6097 char *leveldir_identifier = leveldir_current->identifier;
6098 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6099 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6100 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6101 TreeInfo *custom_artwork_set =
6102 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6103 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6104 char *artwork_current_identifier;
6105 char *artwork_new_identifier = NULL; // default: nothing has changed
6107 // leveldir_current may be invalid (level group, parent link)
6108 if (!validLevelSeries(leveldir_current))
6111 /* 1st step: determine artwork set to be activated in descending order:
6112 --------------------------------------------------------------------
6113 1. setup artwork (when configured to override everything else)
6114 2. artwork set configured in "levelinfo.conf" of current level set
6115 (artwork in level directory will have priority when loading later)
6116 3. artwork in level directory (stored in artwork sub-directory)
6117 4. setup artwork (currently configured in setup menu) */
6119 if (setup_override_artwork)
6120 artwork_current_identifier = setup_artwork_set;
6121 else if (has_level_artwork_set)
6122 artwork_current_identifier = leveldir_artwork_set;
6123 else if (has_custom_artwork_set)
6124 artwork_current_identifier = leveldir_identifier;
6126 artwork_current_identifier = setup_artwork_set;
6128 /* 2nd step: check if it is really needed to reload artwork set
6129 ------------------------------------------------------------ */
6131 // ---------- reload if level set and also artwork set has changed ----------
6132 if (last_leveldir_identifier[type] != leveldir_identifier &&
6133 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6134 artwork_new_identifier = artwork_current_identifier;
6136 last_leveldir_identifier[type] = leveldir_identifier;
6137 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6139 // ---------- reload if "override artwork" setting has changed --------------
6140 if (last_override_level_artwork[type] != setup_override_artwork)
6141 artwork_new_identifier = artwork_current_identifier;
6143 last_override_level_artwork[type] = setup_override_artwork;
6145 // ---------- reload if current artwork identifier has changed --------------
6146 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6147 artwork_new_identifier = artwork_current_identifier;
6149 // (we cannot compare string pointers here, so copy string content itself)
6150 setString(&last_artwork_identifier[type], artwork_current_identifier);
6152 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6154 // ---------- do not reload directly after starting -------------------------
6155 if (!initialized[type])
6156 artwork_new_identifier = NULL;
6158 initialized[type] = TRUE;
6160 return artwork_new_identifier;
6163 void ReloadCustomArtwork(int force_reload)
6165 int last_game_status = game_status; // save current game status
6166 char *gfx_new_identifier;
6167 char *snd_new_identifier;
6168 char *mus_new_identifier;
6169 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6170 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6171 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6172 boolean reload_needed;
6174 InitOverrideArtwork();
6176 AdjustGraphicsForEMC();
6177 AdjustSoundsForEMC();
6179 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6180 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6181 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6183 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6184 snd_new_identifier != NULL || force_reload_snd ||
6185 mus_new_identifier != NULL || force_reload_mus);
6190 print_timestamp_init("ReloadCustomArtwork");
6192 SetGameStatus(GAME_MODE_LOADING);
6194 FadeOut(REDRAW_ALL);
6196 SetLoadingBackgroundImage();
6198 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6199 print_timestamp_time("ClearRectangleOnBackground");
6203 UPDATE_BUSY_STATE();
6205 if (gfx_new_identifier != NULL || force_reload_gfx)
6208 Debug("init:ReloadCustomArtwork",
6209 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6210 artwork.gfx_current_identifier,
6212 artwork.gfx_current->identifier,
6213 leveldir_current->graphics_set);
6217 print_timestamp_time("InitImages");
6220 if (snd_new_identifier != NULL || force_reload_snd)
6222 InitSound(snd_new_identifier);
6223 print_timestamp_time("InitSound");
6226 if (mus_new_identifier != NULL || force_reload_mus)
6228 InitMusic(mus_new_identifier);
6229 print_timestamp_time("InitMusic");
6234 SetGameStatus(last_game_status); // restore current game status
6236 FadeOut(REDRAW_ALL);
6238 RedrawGlobalBorder();
6240 // force redraw of (open or closed) door graphics
6241 SetDoorState(DOOR_OPEN_ALL);
6242 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6244 FadeSetEnterScreen();
6245 FadeSkipNextFadeOut();
6247 print_timestamp_done("ReloadCustomArtwork");
6249 LimitScreenUpdates(FALSE);
6252 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6254 if (global.autoplay_leveldir == NULL)
6255 KeyboardAutoRepeatOff();
6258 void DisplayExitMessage(char *format, va_list ap)
6260 // also check for initialized video (headless flag may be temporarily unset)
6261 if (program.headless || !video.initialized)
6264 // check if draw buffer and fonts for exit message are already available
6265 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6268 int font_1 = FC_RED;
6269 int font_2 = FC_YELLOW;
6270 int font_3 = FC_BLUE;
6271 int font_width = getFontWidth(font_2);
6272 int font_height = getFontHeight(font_2);
6275 int sxsize = WIN_XSIZE - 2 * sx;
6276 int sysize = WIN_YSIZE - 2 * sy;
6277 int line_length = sxsize / font_width;
6278 int max_lines = sysize / font_height;
6279 int num_lines_printed;
6283 gfx.sxsize = sxsize;
6284 gfx.sysize = sysize;
6288 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6290 DrawTextSCentered(sy, font_1, "Fatal error:");
6291 sy += 3 * font_height;;
6294 DrawTextBufferVA(sx, sy, format, ap, font_2,
6295 line_length, line_length, max_lines,
6296 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6297 sy += (num_lines_printed + 3) * font_height;
6299 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6300 sy += 3 * font_height;
6303 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6304 line_length, line_length, max_lines,
6305 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6307 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6309 redraw_mask = REDRAW_ALL;
6311 // force drawing exit message even if screen updates are currently limited
6312 LimitScreenUpdates(FALSE);
6316 // deactivate toons on error message screen
6317 setup.toons = FALSE;
6319 WaitForEventToContinue();
6323 // ============================================================================
6325 // ============================================================================
6329 print_timestamp_init("OpenAll");
6331 SetGameStatus(GAME_MODE_LOADING);
6335 InitGlobal(); // initialize some global variables
6337 InitRND(NEW_RANDOMIZE);
6338 InitSimpleRandom(NEW_RANDOMIZE);
6339 InitBetterRandom(NEW_RANDOMIZE);
6341 print_timestamp_time("[init global stuff]");
6345 print_timestamp_time("[init setup/config stuff (1)]");
6347 if (options.execute_command)
6348 Execute_Command(options.execute_command);
6350 InitNetworkSettings();
6354 if (network.serveronly)
6356 #if defined(PLATFORM_UNIX)
6357 NetworkServer(network.server_port, TRUE);
6359 Warn("networking only supported in Unix version");
6362 exit(0); // never reached, server loops forever
6366 print_timestamp_time("[init setup/config stuff (2)]");
6368 print_timestamp_time("[init setup/config stuff (3)]");
6369 InitArtworkInfo(); // needed before loading gfx, sound & music
6370 print_timestamp_time("[init setup/config stuff (4)]");
6371 InitArtworkConfig(); // needed before forking sound child process
6372 print_timestamp_time("[init setup/config stuff (5)]");
6374 print_timestamp_time("[init setup/config stuff (6)]");
6378 print_timestamp_time("[init setup/config stuff]");
6380 InitVideoDefaults();
6382 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6385 InitEventFilter(FilterMouseMotionEvents);
6387 print_timestamp_time("[init video stuff]");
6389 InitElementPropertiesStatic();
6390 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6391 InitElementPropertiesGfxElement();
6393 print_timestamp_time("[init element properties stuff]");
6397 print_timestamp_time("InitGfx");
6400 print_timestamp_time("InitLevelInfo");
6402 InitLevelArtworkInfo();
6403 print_timestamp_time("InitLevelArtworkInfo");
6405 InitOverrideArtwork(); // needs to know current level directory
6406 print_timestamp_time("InitOverrideArtwork");
6408 InitImages(); // needs to know current level directory
6409 print_timestamp_time("InitImages");
6411 InitSound(NULL); // needs to know current level directory
6412 print_timestamp_time("InitSound");
6414 InitMusic(NULL); // needs to know current level directory
6415 print_timestamp_time("InitMusic");
6419 InitGfxBackground();
6425 if (global.autoplay_leveldir)
6430 else if (global.patchtapes_leveldir)
6435 else if (global.convert_leveldir)
6440 else if (global.dumplevel_leveldir)
6445 else if (global.dumptape_leveldir)
6450 else if (global.create_sketch_images_dir)
6452 CreateLevelSketchImages();
6455 else if (global.create_collect_images_dir)
6457 CreateCollectElementImages();
6461 InitNetworkServer();
6463 SetGameStatus(GAME_MODE_MAIN);
6465 FadeSetEnterScreen();
6466 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6467 FadeSkipNextFadeOut();
6469 print_timestamp_time("[post-artwork]");
6471 print_timestamp_done("OpenAll");
6473 if (setup.ask_for_remaining_tapes)
6474 setup.ask_for_uploading_tapes = TRUE;
6479 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6481 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6482 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6483 #if defined(PLATFORM_ANDROID)
6484 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6485 SDL_AndroidGetInternalStoragePath());
6486 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6487 SDL_AndroidGetExternalStoragePath());
6488 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6489 (SDL_AndroidGetExternalStorageState() &
6490 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6491 SDL_AndroidGetExternalStorageState() &
6492 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6497 static boolean WaitForApiThreads(void)
6499 unsigned int thread_delay = 0;
6500 unsigned int thread_delay_value = 10000;
6502 if (program.api_thread_count == 0)
6505 // deactivate global animations (not accessible in game state "loading")
6506 setup.toons = FALSE;
6508 // set game state to "loading" to be able to show busy animation
6509 SetGameStatus(GAME_MODE_LOADING);
6511 ResetDelayCounter(&thread_delay);
6513 // wait for threads to finish (and fail on timeout)
6514 while (program.api_thread_count > 0)
6516 if (DelayReached(&thread_delay, thread_delay_value))
6518 Error("failed waiting for threads - TIMEOUT");
6523 UPDATE_BUSY_STATE();
6531 void CloseAllAndExit(int exit_value)
6533 WaitForApiThreads();
6538 CloseAudio(); // called after freeing sounds (needed for SDL)
6546 // set a flag to tell the network server thread to quit and wait for it
6547 // using SDL_WaitThread()
6549 // Code used with SDL 1.2:
6550 // if (network.server_thread) // terminate network server
6551 // SDL_KillThread(network.server_thread);
6553 CloseVideoDisplay();
6554 ClosePlatformDependentStuff();
6556 if (exit_value != 0 && !options.execute_command)
6558 // fall back to default level set (current set may have caused an error)
6559 SaveLevelSetup_LastSeries_Deactivate();
6561 // tell user where to find error log file which may contain more details
6562 // (error notification now directly displayed on screen inside R'n'D
6563 // NotifyUserAboutErrorFile(); // currently only works for Windows