1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://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 "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
87 // forward declaration for internal use
88 static int get_graphic_parameter_value(char *, char *, int);
91 static void DrawInitAnim(void)
93 struct GraphicInfo *graphic_info_last = graphic_info;
95 static unsigned int action_delay = 0;
96 unsigned int action_delay_value = GameFrameDelay;
97 int sync_frame = FrameCounter;
100 // prevent OS (Windows) from complaining about program not responding
103 if (game_status != GAME_MODE_LOADING)
106 if (anim_initial.bitmap == NULL || window == NULL)
109 if (!DelayReached(&action_delay, action_delay_value))
112 if (init_last.busy.x == -1)
113 init_last.busy.x = WIN_XSIZE / 2;
114 if (init_last.busy.y == -1)
115 init_last.busy.y = WIN_YSIZE / 2;
117 x = ALIGNED_TEXT_XPOS(&init_last.busy);
118 y = ALIGNED_TEXT_YPOS(&init_last.busy);
120 graphic_info = &anim_initial; // graphic == 0 => anim_initial
122 if (sync_frame % anim_initial.anim_delay == 0)
126 int width = graphic_info[graphic].width;
127 int height = graphic_info[graphic].height;
128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
130 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
131 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
134 graphic_info = graphic_info_last;
139 static void DrawProgramInfo(void)
141 int font1_nr = FC_YELLOW;
142 int font2_nr = FC_RED;
143 int font2_height = getFontHeight(font2_nr);
146 int ypos3 = WIN_YSIZE - 20 - font2_height;
148 DrawInitText(getProgramInitString(), ypos1, font1_nr);
149 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
150 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
153 static void FreeGadgets(void)
155 FreeLevelEditorGadgets();
162 void InitGadgets(void)
164 static boolean gadgets_initialized = FALSE;
166 if (gadgets_initialized)
169 CreateLevelEditorGadgets();
173 CreateScreenGadgets();
175 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
177 gadgets_initialized = TRUE;
180 static void InitElementSmallImagesScaledUp(int graphic)
182 struct GraphicInfo *g = &graphic_info[graphic];
184 // create small and game tile sized bitmaps (and scale up, if needed)
185 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
188 static void InitElementSmallImages(void)
190 print_timestamp_init("InitElementSmallImages");
192 static int special_graphics[] =
206 IMG_EDITOR_ELEMENT_BORDER,
207 IMG_EDITOR_ELEMENT_BORDER_INPUT,
208 IMG_EDITOR_CASCADE_LIST,
209 IMG_EDITOR_CASCADE_LIST_ACTIVE,
212 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
213 int num_property_mappings = getImageListPropertyMappingSize();
216 print_timestamp_time("getImageListPropertyMapping/Size");
218 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
219 // initialize normal element images from static configuration
220 for (i = 0; element_to_graphic[i].element > -1; i++)
221 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
222 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
224 // initialize special element images from static configuration
225 for (i = 0; element_to_special_graphic[i].element > -1; i++)
226 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
227 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
229 // initialize element images from dynamic configuration
230 for (i = 0; i < num_property_mappings; i++)
231 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
232 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
233 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
235 // initialize special non-element images from above list
236 for (i = 0; special_graphics[i] > -1; i++)
237 InitElementSmallImagesScaledUp(special_graphics[i]);
238 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
240 print_timestamp_done("InitElementSmallImages");
243 static void InitScaledImagesScaledUp(int graphic)
245 struct GraphicInfo *g = &graphic_info[graphic];
247 ScaleImage(graphic, g->scale_up_factor);
250 static void InitScaledImages(void)
252 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
253 int num_property_mappings = getImageListPropertyMappingSize();
256 // scale normal images from static configuration, if not already scaled
257 for (i = 0; i < NUM_IMAGE_FILES; i++)
258 InitScaledImagesScaledUp(i);
260 // scale images from dynamic configuration, if not already scaled
261 for (i = 0; i < num_property_mappings; i++)
262 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
265 static void InitBitmapPointers(void)
267 int num_images = getImageListSize();
270 // standard size bitmap may have changed -- update default bitmap pointer
271 for (i = 0; i < num_images; i++)
272 if (graphic_info[i].bitmaps)
273 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
276 void InitImageTextures(void)
278 static int texture_graphics[] =
280 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
281 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
282 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
283 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
284 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
285 IMG_MENU_BUTTON_TOUCH_BACK,
286 IMG_MENU_BUTTON_TOUCH_NEXT,
287 IMG_MENU_BUTTON_TOUCH_BACK2,
288 IMG_MENU_BUTTON_TOUCH_NEXT2,
293 FreeAllImageTextures();
295 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
296 CreateImageTextures(i);
298 for (i = 0; i < MAX_NUM_TOONS; i++)
299 CreateImageTextures(IMG_TOON_1 + i);
301 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
303 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
305 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
307 int graphic = global_anim_info[i].graphic[j][k];
309 if (graphic == IMG_UNDEFINED)
312 CreateImageTextures(graphic);
317 for (i = 0; texture_graphics[i] > -1; i++)
318 CreateImageTextures(texture_graphics[i]);
322 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
323 void SetBitmaps_EM(Bitmap **em_bitmap)
325 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
326 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
331 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
332 void SetBitmaps_SP(Bitmap **sp_bitmap)
334 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
338 static int getFontBitmapID(int font_nr)
342 // (special case: do not use special font for GAME_MODE_LOADING)
343 if (game_status >= GAME_MODE_TITLE_INITIAL &&
344 game_status <= GAME_MODE_PSEUDO_PREVIEW)
345 special = game_status;
346 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
347 special = GFX_SPECIAL_ARG_MAIN;
350 return font_info[font_nr].special_bitmap_id[special];
355 static int getFontFromToken(char *token)
357 char *value = getHashEntry(font_token_hash, token);
362 // if font not found, use reliable default value
363 return FONT_INITIAL_1;
366 static void InitFontGraphicInfo(void)
368 static struct FontBitmapInfo *font_bitmap_info = NULL;
369 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
370 int num_property_mappings = getImageListPropertyMappingSize();
371 int num_font_bitmaps = NUM_FONTS;
374 if (graphic_info == NULL) // still at startup phase
376 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
377 getFontBitmapID, getFontFromToken);
382 // ---------- initialize font graphic definitions ----------
384 // always start with reliable default values (normal font graphics)
385 for (i = 0; i < NUM_FONTS; i++)
386 font_info[i].graphic = IMG_FONT_INITIAL_1;
388 // initialize normal font/graphic mapping from static configuration
389 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
391 int font_nr = font_to_graphic[i].font_nr;
392 int special = font_to_graphic[i].special;
393 int graphic = font_to_graphic[i].graphic;
398 font_info[font_nr].graphic = graphic;
401 // always start with reliable default values (special font graphics)
402 for (i = 0; i < NUM_FONTS; i++)
404 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
406 font_info[i].special_graphic[j] = font_info[i].graphic;
407 font_info[i].special_bitmap_id[j] = i;
411 // initialize special font/graphic mapping from static configuration
412 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
414 int font_nr = font_to_graphic[i].font_nr;
415 int special = font_to_graphic[i].special;
416 int graphic = font_to_graphic[i].graphic;
417 int base_graphic = font2baseimg(font_nr);
419 if (IS_SPECIAL_GFX_ARG(special))
421 boolean base_redefined =
422 getImageListEntryFromImageID(base_graphic)->redefined;
423 boolean special_redefined =
424 getImageListEntryFromImageID(graphic)->redefined;
425 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
427 /* if the base font ("font.title_1", for example) has been redefined,
428 but not the special font ("font.title_1.LEVELS", for example), do not
429 use an existing (in this case considered obsolete) special font
430 anymore, but use the automatically determined default font */
431 /* special case: cloned special fonts must be explicitly redefined,
432 but are not automatically redefined by redefining base font */
433 if (base_redefined && !special_redefined && !special_cloned)
436 font_info[font_nr].special_graphic[special] = graphic;
437 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
442 // initialize special font/graphic mapping from dynamic configuration
443 for (i = 0; i < num_property_mappings; i++)
445 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
446 int special = property_mapping[i].ext3_index;
447 int graphic = property_mapping[i].artwork_index;
449 if (font_nr < 0 || font_nr >= NUM_FONTS)
452 if (IS_SPECIAL_GFX_ARG(special))
454 font_info[font_nr].special_graphic[special] = graphic;
455 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
460 /* correct special font/graphic mapping for cloned fonts for downwards
461 compatibility of PREVIEW fonts -- this is only needed for implicit
462 redefinition of special font by redefined base font, and only if other
463 fonts are cloned from this special font (like in the "Zelda" level set) */
464 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
466 int font_nr = font_to_graphic[i].font_nr;
467 int special = font_to_graphic[i].special;
468 int graphic = font_to_graphic[i].graphic;
470 if (IS_SPECIAL_GFX_ARG(special))
472 boolean special_redefined =
473 getImageListEntryFromImageID(graphic)->redefined;
474 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
476 if (special_cloned && !special_redefined)
480 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
482 int font_nr2 = font_to_graphic[j].font_nr;
483 int special2 = font_to_graphic[j].special;
484 int graphic2 = font_to_graphic[j].graphic;
486 if (IS_SPECIAL_GFX_ARG(special2) &&
487 graphic2 == graphic_info[graphic].clone_from)
489 font_info[font_nr].special_graphic[special] =
490 font_info[font_nr2].special_graphic[special2];
491 font_info[font_nr].special_bitmap_id[special] =
492 font_info[font_nr2].special_bitmap_id[special2];
499 // reset non-redefined ".active" font graphics if normal font is redefined
500 // (this different treatment is needed because normal and active fonts are
501 // independently defined ("active" is not a property of font definitions!)
502 for (i = 0; i < NUM_FONTS; i++)
504 int font_nr_base = i;
505 int font_nr_active = FONT_ACTIVE(font_nr_base);
507 // check only those fonts with exist as normal and ".active" variant
508 if (font_nr_base != font_nr_active)
510 int base_graphic = font_info[font_nr_base].graphic;
511 int active_graphic = font_info[font_nr_active].graphic;
512 boolean base_redefined =
513 getImageListEntryFromImageID(base_graphic)->redefined;
514 boolean active_redefined =
515 getImageListEntryFromImageID(active_graphic)->redefined;
517 /* if the base font ("font.menu_1", for example) has been redefined,
518 but not the active font ("font.menu_1.active", for example), do not
519 use an existing (in this case considered obsolete) active font
520 anymore, but use the automatically determined default font */
521 if (base_redefined && !active_redefined)
522 font_info[font_nr_active].graphic = base_graphic;
524 // now also check each "special" font (which may be the same as above)
525 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
527 int base_graphic = font_info[font_nr_base].special_graphic[j];
528 int active_graphic = font_info[font_nr_active].special_graphic[j];
529 boolean base_redefined =
530 getImageListEntryFromImageID(base_graphic)->redefined;
531 boolean active_redefined =
532 getImageListEntryFromImageID(active_graphic)->redefined;
534 // same as above, but check special graphic definitions, for example:
535 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
536 if (base_redefined && !active_redefined)
538 font_info[font_nr_active].special_graphic[j] =
539 font_info[font_nr_base].special_graphic[j];
540 font_info[font_nr_active].special_bitmap_id[j] =
541 font_info[font_nr_base].special_bitmap_id[j];
547 // ---------- initialize font bitmap array ----------
549 if (font_bitmap_info != NULL)
550 FreeFontInfo(font_bitmap_info);
553 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
555 // ---------- initialize font bitmap definitions ----------
557 for (i = 0; i < NUM_FONTS; i++)
559 if (i < NUM_INITIAL_FONTS)
561 font_bitmap_info[i] = font_initial[i];
565 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
567 int font_bitmap_id = font_info[i].special_bitmap_id[j];
568 int graphic = font_info[i].special_graphic[j];
570 // set 'graphic_info' for font entries, if uninitialized (guessed)
571 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
573 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
574 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
577 // copy font relevant information from graphics information
578 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
579 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
580 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
581 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
582 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
584 font_bitmap_info[font_bitmap_id].offset_x =
585 graphic_info[graphic].offset_x;
586 font_bitmap_info[font_bitmap_id].offset_y =
587 graphic_info[graphic].offset_y;
589 font_bitmap_info[font_bitmap_id].draw_xoffset =
590 graphic_info[graphic].draw_xoffset;
591 font_bitmap_info[font_bitmap_id].draw_yoffset =
592 graphic_info[graphic].draw_yoffset;
594 font_bitmap_info[font_bitmap_id].num_chars =
595 graphic_info[graphic].anim_frames;
596 font_bitmap_info[font_bitmap_id].num_chars_per_line =
597 graphic_info[graphic].anim_frames_per_line;
601 InitFontInfo(font_bitmap_info, num_font_bitmaps,
602 getFontBitmapID, getFontFromToken);
605 static void InitGlobalAnimGraphicInfo(void)
607 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
608 int num_property_mappings = getImageListPropertyMappingSize();
611 if (graphic_info == NULL) // still at startup phase
614 // always start with reliable default values (no global animations)
615 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
616 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
617 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
618 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
620 // initialize global animation definitions from static configuration
621 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
623 int j = GLOBAL_ANIM_ID_PART_BASE;
624 int k = GFX_SPECIAL_ARG_DEFAULT;
626 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
629 // initialize global animation definitions from dynamic configuration
630 for (i = 0; i < num_property_mappings; i++)
632 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
633 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
634 int special = property_mapping[i].ext3_index;
635 int graphic = property_mapping[i].artwork_index;
637 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
640 // set animation part to base part, if not specified
641 if (!IS_GLOBAL_ANIM_PART(part_nr))
642 part_nr = GLOBAL_ANIM_ID_PART_BASE;
644 // set animation screen to default, if not specified
645 if (!IS_SPECIAL_GFX_ARG(special))
646 special = GFX_SPECIAL_ARG_DEFAULT;
648 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
650 // fix default value for ".draw_masked" (for backward compatibility)
651 struct GraphicInfo *g = &graphic_info[graphic];
652 struct FileInfo *image = getImageListEntryFromImageID(graphic);
653 char **parameter_raw = image->parameter;
654 int p = GFX_ARG_DRAW_MASKED;
655 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
656 image_config_suffix[p].token,
657 image_config_suffix[p].type);
659 // if ".draw_masked" parameter is undefined, use default value "TRUE"
660 if (draw_masked == ARG_UNDEFINED_VALUE)
661 g->draw_masked = TRUE;
665 printf("::: InitGlobalAnimGraphicInfo\n");
667 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
668 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
669 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
670 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
671 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
672 printf("::: - anim %d, part %d, mode %d => %d\n",
673 i, j, k, global_anim_info[i].graphic[j][k]);
677 static void InitGlobalAnimSoundInfo(void)
679 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
680 int num_property_mappings = getSoundListPropertyMappingSize();
683 // always start with reliable default values (no global animation sounds)
684 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
685 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
686 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
687 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
689 // initialize global animation sound definitions from dynamic configuration
690 for (i = 0; i < num_property_mappings; i++)
692 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
693 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
694 int special = property_mapping[i].ext3_index;
695 int sound = property_mapping[i].artwork_index;
697 // sound uses control definition; map it to position of graphic (artwork)
698 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
700 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
703 // set animation part to base part, if not specified
704 if (!IS_GLOBAL_ANIM_PART(part_nr))
705 part_nr = GLOBAL_ANIM_ID_PART_BASE;
707 // set animation screen to default, if not specified
708 if (!IS_SPECIAL_GFX_ARG(special))
709 special = GFX_SPECIAL_ARG_DEFAULT;
711 global_anim_info[anim_nr].sound[part_nr][special] = sound;
715 printf("::: InitGlobalAnimSoundInfo\n");
717 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
718 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
719 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
720 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
721 printf("::: - anim %d, part %d, mode %d => %d\n",
722 i, j, k, global_anim_info[i].sound[j][k]);
726 static void InitGlobalAnimMusicInfo(void)
728 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
729 int num_property_mappings = getMusicListPropertyMappingSize();
732 // always start with reliable default values (no global animation music)
733 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
734 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
735 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
736 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
738 // initialize global animation music definitions from dynamic configuration
739 for (i = 0; i < num_property_mappings; i++)
741 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
742 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
743 int special = property_mapping[i].ext2_index;
744 int music = property_mapping[i].artwork_index;
746 // music uses control definition; map it to position of graphic (artwork)
747 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
749 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
752 // set animation part to base part, if not specified
753 if (!IS_GLOBAL_ANIM_PART(part_nr))
754 part_nr = GLOBAL_ANIM_ID_PART_BASE;
756 // set animation screen to default, if not specified
757 if (!IS_SPECIAL_GFX_ARG(special))
758 special = GFX_SPECIAL_ARG_DEFAULT;
760 global_anim_info[anim_nr].music[part_nr][special] = music;
764 printf("::: InitGlobalAnimMusicInfo\n");
766 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
767 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
768 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
769 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
770 printf("::: - anim %d, part %d, mode %d => %d\n",
771 i, j, k, global_anim_info[i].music[j][k]);
775 static void InitElementGraphicInfo(void)
777 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
778 int num_property_mappings = getImageListPropertyMappingSize();
781 if (graphic_info == NULL) // still at startup phase
784 // set values to -1 to identify later as "uninitialized" values
785 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
787 for (act = 0; act < NUM_ACTIONS; act++)
789 element_info[i].graphic[act] = -1;
790 element_info[i].crumbled[act] = -1;
792 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
794 element_info[i].direction_graphic[act][dir] = -1;
795 element_info[i].direction_crumbled[act][dir] = -1;
802 // initialize normal element/graphic mapping from static configuration
803 for (i = 0; element_to_graphic[i].element > -1; i++)
805 int element = element_to_graphic[i].element;
806 int action = element_to_graphic[i].action;
807 int direction = element_to_graphic[i].direction;
808 boolean crumbled = element_to_graphic[i].crumbled;
809 int graphic = element_to_graphic[i].graphic;
810 int base_graphic = el2baseimg(element);
812 if (graphic_info[graphic].bitmap == NULL)
815 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
818 boolean base_redefined =
819 getImageListEntryFromImageID(base_graphic)->redefined;
820 boolean act_dir_redefined =
821 getImageListEntryFromImageID(graphic)->redefined;
823 /* if the base graphic ("emerald", for example) has been redefined,
824 but not the action graphic ("emerald.falling", for example), do not
825 use an existing (in this case considered obsolete) action graphic
826 anymore, but use the automatically determined default graphic */
827 if (base_redefined && !act_dir_redefined)
832 action = ACTION_DEFAULT;
837 element_info[element].direction_crumbled[action][direction] = graphic;
839 element_info[element].crumbled[action] = graphic;
844 element_info[element].direction_graphic[action][direction] = graphic;
846 element_info[element].graphic[action] = graphic;
850 // initialize normal element/graphic mapping from dynamic configuration
851 for (i = 0; i < num_property_mappings; i++)
853 int element = property_mapping[i].base_index;
854 int action = property_mapping[i].ext1_index;
855 int direction = property_mapping[i].ext2_index;
856 int special = property_mapping[i].ext3_index;
857 int graphic = property_mapping[i].artwork_index;
858 boolean crumbled = FALSE;
860 if (special == GFX_SPECIAL_ARG_CRUMBLED)
866 if (graphic_info[graphic].bitmap == NULL)
869 if (element >= MAX_NUM_ELEMENTS || special != -1)
873 action = ACTION_DEFAULT;
878 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
879 element_info[element].direction_crumbled[action][dir] = -1;
882 element_info[element].direction_crumbled[action][direction] = graphic;
884 element_info[element].crumbled[action] = graphic;
889 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
890 element_info[element].direction_graphic[action][dir] = -1;
893 element_info[element].direction_graphic[action][direction] = graphic;
895 element_info[element].graphic[action] = graphic;
899 // now copy all graphics that are defined to be cloned from other graphics
900 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
902 int graphic = element_info[i].graphic[ACTION_DEFAULT];
903 int crumbled_like, diggable_like;
908 crumbled_like = graphic_info[graphic].crumbled_like;
909 diggable_like = graphic_info[graphic].diggable_like;
911 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
913 for (act = 0; act < NUM_ACTIONS; act++)
914 element_info[i].crumbled[act] =
915 element_info[crumbled_like].crumbled[act];
916 for (act = 0; act < NUM_ACTIONS; act++)
917 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
918 element_info[i].direction_crumbled[act][dir] =
919 element_info[crumbled_like].direction_crumbled[act][dir];
922 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
924 element_info[i].graphic[ACTION_DIGGING] =
925 element_info[diggable_like].graphic[ACTION_DIGGING];
926 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
927 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
928 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
932 // set hardcoded definitions for some runtime elements without graphic
933 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
935 // set hardcoded definitions for some internal elements without graphic
936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 if (IS_EDITOR_CASCADE_INACTIVE(i))
939 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
940 else if (IS_EDITOR_CASCADE_ACTIVE(i))
941 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
944 // now set all undefined/invalid graphics to -1 to set to default after it
945 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
947 for (act = 0; act < NUM_ACTIONS; act++)
951 graphic = element_info[i].graphic[act];
952 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
953 element_info[i].graphic[act] = -1;
955 graphic = element_info[i].crumbled[act];
956 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
957 element_info[i].crumbled[act] = -1;
959 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
961 graphic = element_info[i].direction_graphic[act][dir];
962 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
963 element_info[i].direction_graphic[act][dir] = -1;
965 graphic = element_info[i].direction_crumbled[act][dir];
966 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
967 element_info[i].direction_crumbled[act][dir] = -1;
974 // adjust graphics with 2nd tile for movement according to direction
975 // (do this before correcting '-1' values to minimize calculations)
976 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
978 for (act = 0; act < NUM_ACTIONS; act++)
980 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
982 int graphic = element_info[i].direction_graphic[act][dir];
983 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
985 if (act == ACTION_FALLING) // special case
986 graphic = element_info[i].graphic[act];
989 graphic_info[graphic].double_movement &&
990 graphic_info[graphic].swap_double_tiles != 0)
992 struct GraphicInfo *g = &graphic_info[graphic];
993 int src_x_front = g->src_x;
994 int src_y_front = g->src_y;
995 int src_x_back = g->src_x + g->offset2_x;
996 int src_y_back = g->src_y + g->offset2_y;
997 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
999 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1000 src_y_front < src_y_back);
1001 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1002 boolean swap_movement_tiles_autodetected =
1003 (!frames_are_ordered_diagonally &&
1004 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1005 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1006 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1007 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1009 // swap frontside and backside graphic tile coordinates, if needed
1010 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1012 // get current (wrong) backside tile coordinates
1013 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1015 // set frontside tile coordinates to backside tile coordinates
1016 g->src_x = src_x_back;
1017 g->src_y = src_y_back;
1019 // invert tile offset to point to new backside tile coordinates
1023 // do not swap front and backside tiles again after correction
1024 g->swap_double_tiles = 0;
1031 UPDATE_BUSY_STATE();
1033 // now set all '-1' values to element specific default values
1034 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1036 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1037 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1038 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1039 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1041 if (default_graphic == -1)
1042 default_graphic = IMG_UNKNOWN;
1044 if (default_crumbled == -1)
1045 default_crumbled = default_graphic;
1047 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1049 default_direction_graphic[dir] =
1050 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1051 default_direction_crumbled[dir] =
1052 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1054 if (default_direction_graphic[dir] == -1)
1055 default_direction_graphic[dir] = default_graphic;
1057 if (default_direction_crumbled[dir] == -1)
1058 default_direction_crumbled[dir] = default_direction_graphic[dir];
1061 for (act = 0; act < NUM_ACTIONS; act++)
1063 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1064 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1065 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1066 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1067 act == ACTION_TURNING_FROM_RIGHT ||
1068 act == ACTION_TURNING_FROM_UP ||
1069 act == ACTION_TURNING_FROM_DOWN);
1071 // generic default action graphic (defined by "[default]" directive)
1072 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1073 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1074 int default_remove_graphic = IMG_EMPTY;
1076 if (act_remove && default_action_graphic != -1)
1077 default_remove_graphic = default_action_graphic;
1079 // look for special default action graphic (classic game specific)
1080 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1081 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1082 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1083 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1084 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1085 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1086 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1087 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1089 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1090 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1091 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1092 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1093 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1094 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1095 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1096 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1098 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1099 // !!! make this better !!!
1100 if (i == EL_EMPTY_SPACE)
1102 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1103 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1106 if (default_action_graphic == -1)
1107 default_action_graphic = default_graphic;
1109 if (default_action_crumbled == -1)
1110 default_action_crumbled = default_action_graphic;
1112 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1114 // use action graphic as the default direction graphic, if undefined
1115 int default_action_direction_graphic = element_info[i].graphic[act];
1116 int default_action_direction_crumbled = element_info[i].crumbled[act];
1118 // no graphic for current action -- use default direction graphic
1119 if (default_action_direction_graphic == -1)
1120 default_action_direction_graphic =
1121 (act_remove ? default_remove_graphic :
1123 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1124 default_action_graphic != default_graphic ?
1125 default_action_graphic :
1126 default_direction_graphic[dir]);
1128 if (element_info[i].direction_graphic[act][dir] == -1)
1129 element_info[i].direction_graphic[act][dir] =
1130 default_action_direction_graphic;
1132 if (default_action_direction_crumbled == -1)
1133 default_action_direction_crumbled =
1134 element_info[i].direction_graphic[act][dir];
1136 if (element_info[i].direction_crumbled[act][dir] == -1)
1137 element_info[i].direction_crumbled[act][dir] =
1138 default_action_direction_crumbled;
1141 // no graphic for this specific action -- use default action graphic
1142 if (element_info[i].graphic[act] == -1)
1143 element_info[i].graphic[act] =
1144 (act_remove ? default_remove_graphic :
1145 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1146 default_action_graphic);
1148 if (element_info[i].crumbled[act] == -1)
1149 element_info[i].crumbled[act] = element_info[i].graphic[act];
1153 UPDATE_BUSY_STATE();
1156 static void InitElementSpecialGraphicInfo(void)
1158 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1159 int num_property_mappings = getImageListPropertyMappingSize();
1162 // always start with reliable default values
1163 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1164 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1165 element_info[i].special_graphic[j] =
1166 element_info[i].graphic[ACTION_DEFAULT];
1168 // initialize special element/graphic mapping from static configuration
1169 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1171 int element = element_to_special_graphic[i].element;
1172 int special = element_to_special_graphic[i].special;
1173 int graphic = element_to_special_graphic[i].graphic;
1174 int base_graphic = el2baseimg(element);
1175 boolean base_redefined =
1176 getImageListEntryFromImageID(base_graphic)->redefined;
1177 boolean special_redefined =
1178 getImageListEntryFromImageID(graphic)->redefined;
1180 /* if the base graphic ("emerald", for example) has been redefined,
1181 but not the special graphic ("emerald.EDITOR", for example), do not
1182 use an existing (in this case considered obsolete) special graphic
1183 anymore, but use the automatically created (down-scaled) graphic */
1184 if (base_redefined && !special_redefined)
1187 element_info[element].special_graphic[special] = graphic;
1190 // initialize special element/graphic mapping from dynamic configuration
1191 for (i = 0; i < num_property_mappings; i++)
1193 int element = property_mapping[i].base_index;
1194 int action = property_mapping[i].ext1_index;
1195 int direction = property_mapping[i].ext2_index;
1196 int special = property_mapping[i].ext3_index;
1197 int graphic = property_mapping[i].artwork_index;
1199 // for action ".active", replace element with active element, if exists
1200 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1202 element = ELEMENT_ACTIVE(element);
1206 if (element >= MAX_NUM_ELEMENTS)
1209 // do not change special graphic if action or direction was specified
1210 if (action != -1 || direction != -1)
1213 if (IS_SPECIAL_GFX_ARG(special))
1214 element_info[element].special_graphic[special] = graphic;
1217 // now set all undefined/invalid graphics to default
1218 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1219 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1220 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1221 element_info[i].special_graphic[j] =
1222 element_info[i].graphic[ACTION_DEFAULT];
1225 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1227 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1228 return get_parameter_value(value_raw, suffix, type);
1230 if (strEqual(value_raw, ARG_UNDEFINED))
1231 return ARG_UNDEFINED_VALUE;
1233 if (type == TYPE_ELEMENT)
1235 char *value = getHashEntry(element_token_hash, value_raw);
1239 Error(ERR_INFO_LINE, "-");
1240 Error(ERR_INFO, "warning: error found in config file:");
1241 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1242 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1243 Error(ERR_INFO, "custom graphic rejected for this element/action");
1244 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1245 Error(ERR_INFO_LINE, "-");
1248 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1250 else if (type == TYPE_GRAPHIC)
1252 char *value = getHashEntry(graphic_token_hash, value_raw);
1253 int fallback_graphic = IMG_CHAR_EXCLAM;
1257 Error(ERR_INFO_LINE, "-");
1258 Error(ERR_INFO, "warning: error found in config file:");
1259 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1260 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1261 Error(ERR_INFO, "custom graphic rejected for this element/action");
1262 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1263 Error(ERR_INFO_LINE, "-");
1266 return (value != NULL ? atoi(value) : fallback_graphic);
1272 static int get_scaled_graphic_width(int graphic)
1274 int original_width = getOriginalImageWidthFromImageID(graphic);
1275 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1277 return original_width * scale_up_factor;
1280 static int get_scaled_graphic_height(int graphic)
1282 int original_height = getOriginalImageHeightFromImageID(graphic);
1283 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1285 return original_height * scale_up_factor;
1288 static void set_graphic_parameters_ext(int graphic, int *parameter,
1289 Bitmap **src_bitmaps)
1291 struct GraphicInfo *g = &graphic_info[graphic];
1292 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1293 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1294 int anim_frames_per_line = 1;
1296 // always start with reliable default values
1297 g->src_image_width = 0;
1298 g->src_image_height = 0;
1301 g->width = TILEX; // default for element graphics
1302 g->height = TILEY; // default for element graphics
1303 g->offset_x = 0; // one or both of these values ...
1304 g->offset_y = 0; // ... will be corrected later
1305 g->offset2_x = 0; // one or both of these values ...
1306 g->offset2_y = 0; // ... will be corrected later
1307 g->swap_double_tiles = -1; // auto-detect tile swapping
1308 g->crumbled_like = -1; // do not use clone element
1309 g->diggable_like = -1; // do not use clone element
1310 g->border_size = TILEX / 8; // "CRUMBLED" border size
1311 g->scale_up_factor = 1; // default: no scaling up
1312 g->tile_size = TILESIZE; // default: standard tile size
1313 g->clone_from = -1; // do not use clone graphic
1314 g->init_delay_fixed = 0;
1315 g->init_delay_random = 0;
1316 g->init_delay_action = -1;
1317 g->anim_delay_fixed = 0;
1318 g->anim_delay_random = 0;
1319 g->anim_delay_action = -1;
1320 g->post_delay_fixed = 0;
1321 g->post_delay_random = 0;
1322 g->post_delay_action = -1;
1323 g->init_event = ANIM_EVENT_UNDEFINED;
1324 g->anim_event = ANIM_EVENT_UNDEFINED;
1325 g->init_event_action = -1;
1326 g->anim_event_action = -1;
1327 g->draw_masked = FALSE;
1329 g->fade_mode = FADE_MODE_DEFAULT;
1333 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1334 g->align = ALIGN_CENTER; // default for title screens
1335 g->valign = VALIGN_MIDDLE; // default for title screens
1336 g->sort_priority = 0; // default for title screens
1338 g->style = STYLE_DEFAULT;
1340 g->bitmaps = src_bitmaps;
1341 g->bitmap = src_bitmap;
1343 // optional zoom factor for scaling up the image to a larger size
1344 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1345 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1346 if (g->scale_up_factor < 1)
1347 g->scale_up_factor = 1; // no scaling
1349 // optional tile size for using non-standard image size
1350 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1352 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1355 // CHECK: should tile sizes less than standard tile size be allowed?
1356 if (g->tile_size < TILESIZE)
1357 g->tile_size = TILESIZE; // standard tile size
1360 // when setting tile size, also set width and height accordingly
1361 g->width = g->tile_size;
1362 g->height = g->tile_size;
1365 if (g->use_image_size)
1367 // set new default bitmap size (with scaling, but without small images)
1368 g->width = get_scaled_graphic_width(graphic);
1369 g->height = get_scaled_graphic_height(graphic);
1372 // optional width and height of each animation frame
1373 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1374 g->width = parameter[GFX_ARG_WIDTH];
1375 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1376 g->height = parameter[GFX_ARG_HEIGHT];
1378 // optional x and y tile position of animation frame sequence
1379 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1380 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1381 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1382 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1384 // optional x and y pixel position of animation frame sequence
1385 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1386 g->src_x = parameter[GFX_ARG_X];
1387 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1388 g->src_y = parameter[GFX_ARG_Y];
1394 Error(ERR_INFO_LINE, "-");
1395 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1396 g->width, getTokenFromImageID(graphic), TILEX);
1397 Error(ERR_INFO_LINE, "-");
1399 g->width = TILEX; // will be checked to be inside bitmap later
1404 Error(ERR_INFO_LINE, "-");
1405 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1406 g->height, getTokenFromImageID(graphic), TILEY);
1407 Error(ERR_INFO_LINE, "-");
1409 g->height = TILEY; // will be checked to be inside bitmap later
1415 // get final bitmap size (with scaling, but without small images)
1416 int src_image_width = get_scaled_graphic_width(graphic);
1417 int src_image_height = get_scaled_graphic_height(graphic);
1419 if (src_image_width == 0 || src_image_height == 0)
1421 // only happens when loaded outside artwork system (like "global.busy")
1422 src_image_width = src_bitmap->width;
1423 src_image_height = src_bitmap->height;
1426 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1428 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1429 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1433 anim_frames_per_row = MAX(1, src_image_width / g->width);
1434 anim_frames_per_col = MAX(1, src_image_height / g->height);
1437 g->src_image_width = src_image_width;
1438 g->src_image_height = src_image_height;
1441 // correct x or y offset dependent of vertical or horizontal frame order
1442 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1444 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1445 parameter[GFX_ARG_OFFSET] : g->height);
1446 anim_frames_per_line = anim_frames_per_col;
1448 else // frames are ordered horizontally
1450 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1451 parameter[GFX_ARG_OFFSET] : g->width);
1452 anim_frames_per_line = anim_frames_per_row;
1455 // optionally, the x and y offset of frames can be specified directly
1456 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1457 g->offset_x = parameter[GFX_ARG_XOFFSET];
1458 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1459 g->offset_y = parameter[GFX_ARG_YOFFSET];
1461 // optionally, moving animations may have separate start and end graphics
1462 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1464 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1465 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1467 // correct x or y offset2 dependent of vertical or horizontal frame order
1468 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1469 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1470 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1471 else // frames are ordered horizontally
1472 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1473 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1475 // optionally, the x and y offset of 2nd graphic can be specified directly
1476 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1477 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1478 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1479 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1481 // optionally, the second movement tile can be specified as start tile
1482 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1483 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1485 // automatically determine correct number of frames, if not defined
1486 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1487 g->anim_frames = parameter[GFX_ARG_FRAMES];
1488 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1489 g->anim_frames = anim_frames_per_row;
1490 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1491 g->anim_frames = anim_frames_per_col;
1495 if (g->anim_frames < 1) // frames must be at least 1
1498 g->anim_frames_per_line =
1499 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1500 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1502 g->anim_delay = parameter[GFX_ARG_DELAY];
1503 if (g->anim_delay < 1) // delay must be at least 1
1506 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1508 // automatically determine correct start frame, if not defined
1509 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1510 g->anim_start_frame = 0;
1511 else if (g->anim_mode & ANIM_REVERSE)
1512 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1514 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1516 // animation synchronized with global frame counter, not move position
1517 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1519 // optional element for cloning crumble graphics
1520 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1521 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1523 // optional element for cloning digging graphics
1524 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1525 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1527 // optional border size for "crumbling" diggable graphics
1528 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1529 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1531 // used for global animations and player "boring" and "sleeping" actions
1532 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1533 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1534 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1535 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1536 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1537 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1538 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1539 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1540 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1541 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1542 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1543 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1545 // used for global animations
1546 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1547 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1548 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1549 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1550 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1551 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1552 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1553 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1554 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1555 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1556 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1557 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1558 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1559 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1561 // used for toon animations and global animations
1562 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1563 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1564 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1565 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1566 g->direction = parameter[GFX_ARG_DIRECTION];
1567 g->position = parameter[GFX_ARG_POSITION];
1568 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1569 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1571 if (g->step_delay < 1) // delay must be at least 1
1574 // this is only used for drawing font characters
1575 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1576 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1578 // use a different default value for global animations and toons
1579 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1580 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1581 g->draw_masked = TRUE;
1583 // this is used for drawing envelopes, global animations and toons
1584 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1585 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1587 // used for toon animations and global animations
1588 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1589 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1591 // optional graphic for cloning all graphics settings
1592 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1593 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1595 // optional settings for drawing title screens and title messages
1596 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1597 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1598 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1599 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1600 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1601 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1602 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1603 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1604 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1605 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1606 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1607 g->align = parameter[GFX_ARG_ALIGN];
1608 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1609 g->valign = parameter[GFX_ARG_VALIGN];
1610 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1611 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1613 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1614 g->class = parameter[GFX_ARG_CLASS];
1615 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1616 g->style = parameter[GFX_ARG_STYLE];
1618 // this is only used for drawing menu buttons and text
1619 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1620 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1621 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1622 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1625 static void set_graphic_parameters(int graphic)
1627 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1628 char **parameter_raw = image->parameter;
1629 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1630 int parameter[NUM_GFX_ARGS];
1633 // if fallback to default artwork is done, also use the default parameters
1634 if (image->fallback_to_default)
1635 parameter_raw = image->default_parameter;
1637 // get integer values from string parameters
1638 for (i = 0; i < NUM_GFX_ARGS; i++)
1639 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1640 image_config_suffix[i].token,
1641 image_config_suffix[i].type);
1643 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1645 UPDATE_BUSY_STATE();
1648 static void set_cloned_graphic_parameters(int graphic)
1650 int fallback_graphic = IMG_CHAR_EXCLAM;
1651 int max_num_images = getImageListSize();
1652 int clone_graphic = graphic_info[graphic].clone_from;
1653 int num_references_followed = 1;
1655 while (graphic_info[clone_graphic].clone_from != -1 &&
1656 num_references_followed < max_num_images)
1658 clone_graphic = graphic_info[clone_graphic].clone_from;
1660 num_references_followed++;
1663 if (num_references_followed >= max_num_images)
1665 Error(ERR_INFO_LINE, "-");
1666 Error(ERR_INFO, "warning: error found in config file:");
1667 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1668 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1669 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1670 Error(ERR_INFO, "custom graphic rejected for this element/action");
1672 if (graphic == fallback_graphic)
1673 Error(ERR_EXIT, "no fallback graphic available");
1675 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1676 Error(ERR_INFO_LINE, "-");
1678 graphic_info[graphic] = graphic_info[fallback_graphic];
1682 graphic_info[graphic] = graphic_info[clone_graphic];
1683 graphic_info[graphic].clone_from = clone_graphic;
1687 static void InitGraphicInfo(void)
1689 int fallback_graphic = IMG_CHAR_EXCLAM;
1690 int num_images = getImageListSize();
1693 // use image size as default values for width and height for these images
1694 static int full_size_graphics[] =
1697 IMG_GLOBAL_BORDER_MAIN,
1698 IMG_GLOBAL_BORDER_SCORES,
1699 IMG_GLOBAL_BORDER_EDITOR,
1700 IMG_GLOBAL_BORDER_PLAYING,
1703 IMG_BACKGROUND_ENVELOPE_1,
1704 IMG_BACKGROUND_ENVELOPE_2,
1705 IMG_BACKGROUND_ENVELOPE_3,
1706 IMG_BACKGROUND_ENVELOPE_4,
1707 IMG_BACKGROUND_REQUEST,
1710 IMG_BACKGROUND_TITLE_INITIAL,
1711 IMG_BACKGROUND_TITLE,
1712 IMG_BACKGROUND_MAIN,
1713 IMG_BACKGROUND_LEVELS,
1714 IMG_BACKGROUND_LEVELNR,
1715 IMG_BACKGROUND_SCORES,
1716 IMG_BACKGROUND_EDITOR,
1717 IMG_BACKGROUND_INFO,
1718 IMG_BACKGROUND_INFO_ELEMENTS,
1719 IMG_BACKGROUND_INFO_MUSIC,
1720 IMG_BACKGROUND_INFO_CREDITS,
1721 IMG_BACKGROUND_INFO_PROGRAM,
1722 IMG_BACKGROUND_INFO_VERSION,
1723 IMG_BACKGROUND_INFO_LEVELSET,
1724 IMG_BACKGROUND_SETUP,
1725 IMG_BACKGROUND_PLAYING,
1726 IMG_BACKGROUND_DOOR,
1727 IMG_BACKGROUND_TAPE,
1728 IMG_BACKGROUND_PANEL,
1729 IMG_BACKGROUND_PALETTE,
1730 IMG_BACKGROUND_TOOLBOX,
1732 IMG_TITLESCREEN_INITIAL_1,
1733 IMG_TITLESCREEN_INITIAL_2,
1734 IMG_TITLESCREEN_INITIAL_3,
1735 IMG_TITLESCREEN_INITIAL_4,
1736 IMG_TITLESCREEN_INITIAL_5,
1743 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1744 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1745 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1746 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1747 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1748 IMG_BACKGROUND_TITLEMESSAGE_1,
1749 IMG_BACKGROUND_TITLEMESSAGE_2,
1750 IMG_BACKGROUND_TITLEMESSAGE_3,
1751 IMG_BACKGROUND_TITLEMESSAGE_4,
1752 IMG_BACKGROUND_TITLEMESSAGE_5,
1757 FreeGlobalAnimEventInfo();
1759 checked_free(graphic_info);
1761 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1763 // initialize "use_image_size" flag with default value
1764 for (i = 0; i < num_images; i++)
1765 graphic_info[i].use_image_size = FALSE;
1767 // initialize "use_image_size" flag from static configuration above
1768 for (i = 0; full_size_graphics[i] != -1; i++)
1769 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1771 // first set all graphic paramaters ...
1772 for (i = 0; i < num_images; i++)
1773 set_graphic_parameters(i);
1775 // ... then copy these parameters for cloned graphics
1776 for (i = 0; i < num_images; i++)
1777 if (graphic_info[i].clone_from != -1)
1778 set_cloned_graphic_parameters(i);
1780 for (i = 0; i < num_images; i++)
1782 Bitmap *src_bitmap = graphic_info[i].bitmap;
1786 int src_bitmap_width, src_bitmap_height;
1788 // now check if no animation frames are outside of the loaded image
1790 if (graphic_info[i].bitmap == NULL)
1791 continue; // skip check for optional images that are undefined
1793 // get image size (this can differ from the standard element tile size!)
1794 width = graphic_info[i].width;
1795 height = graphic_info[i].height;
1797 // get final bitmap size (with scaling, but without small images)
1798 src_bitmap_width = graphic_info[i].src_image_width;
1799 src_bitmap_height = graphic_info[i].src_image_height;
1801 // check if first animation frame is inside specified bitmap
1803 // do not use getGraphicSourceXY() here to get position of first frame;
1804 // this avoids calculating wrong start position for out-of-bounds frame
1805 src_x = graphic_info[i].src_x;
1806 src_y = graphic_info[i].src_y;
1808 if (program.headless)
1811 if (src_x < 0 || src_y < 0 ||
1812 src_x + width > src_bitmap_width ||
1813 src_y + height > src_bitmap_height)
1815 Error(ERR_INFO_LINE, "-");
1816 Error(ERR_INFO, "warning: error found in config file:");
1817 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1818 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1819 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1820 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1822 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1823 src_x, src_y, src_bitmap_width, src_bitmap_height);
1824 Error(ERR_INFO, "custom graphic rejected for this element/action");
1826 if (i == fallback_graphic)
1827 Error(ERR_EXIT, "no fallback graphic available");
1829 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1830 Error(ERR_INFO_LINE, "-");
1832 graphic_info[i] = graphic_info[fallback_graphic];
1834 // if first frame out of bounds, do not check last frame anymore
1838 // check if last animation frame is inside specified bitmap
1840 last_frame = graphic_info[i].anim_frames - 1;
1841 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1843 if (src_x < 0 || src_y < 0 ||
1844 src_x + width > src_bitmap_width ||
1845 src_y + height > src_bitmap_height)
1847 Error(ERR_INFO_LINE, "-");
1848 Error(ERR_INFO, "warning: error found in config file:");
1849 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1850 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1851 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1852 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1854 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1855 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1856 Error(ERR_INFO, "custom graphic rejected for this element/action");
1858 if (i == fallback_graphic)
1859 Error(ERR_EXIT, "no fallback graphic available");
1861 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1862 Error(ERR_INFO_LINE, "-");
1864 graphic_info[i] = graphic_info[fallback_graphic];
1869 static void InitGraphicCompatibilityInfo(void)
1871 struct FileInfo *fi_global_door =
1872 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1873 int num_images = getImageListSize();
1876 /* the following compatibility handling is needed for the following case:
1877 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1878 graphics mainly used for door and panel graphics, like editor, tape and
1879 in-game buttons with hard-coded bitmap positions and button sizes; as
1880 these graphics now have individual definitions, redefining "global.door"
1881 to change all these graphics at once like before does not work anymore
1882 (because all those individual definitions still have their default values);
1883 to solve this, remap all those individual definitions that are not
1884 redefined to the new bitmap of "global.door" if it was redefined */
1886 // special compatibility handling if image "global.door" was redefined
1887 if (fi_global_door->redefined)
1889 for (i = 0; i < num_images; i++)
1891 struct FileInfo *fi = getImageListEntryFromImageID(i);
1893 // process only those images that still use the default settings
1896 // process all images which default to same image as "global.door"
1897 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1899 // printf("::: special treatment needed for token '%s'\n", fi->token);
1901 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1902 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1908 InitGraphicCompatibilityInfo_Doors();
1911 static void InitElementSoundInfo(void)
1913 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1914 int num_property_mappings = getSoundListPropertyMappingSize();
1917 // set values to -1 to identify later as "uninitialized" values
1918 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1919 for (act = 0; act < NUM_ACTIONS; act++)
1920 element_info[i].sound[act] = -1;
1922 // initialize element/sound mapping from static configuration
1923 for (i = 0; element_to_sound[i].element > -1; i++)
1925 int element = element_to_sound[i].element;
1926 int action = element_to_sound[i].action;
1927 int sound = element_to_sound[i].sound;
1928 boolean is_class = element_to_sound[i].is_class;
1931 action = ACTION_DEFAULT;
1934 element_info[element].sound[action] = sound;
1936 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1937 if (strEqual(element_info[j].class_name,
1938 element_info[element].class_name))
1939 element_info[j].sound[action] = sound;
1942 // initialize element class/sound mapping from dynamic configuration
1943 for (i = 0; i < num_property_mappings; i++)
1945 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1946 int action = property_mapping[i].ext1_index;
1947 int sound = property_mapping[i].artwork_index;
1949 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1953 action = ACTION_DEFAULT;
1955 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1956 if (strEqual(element_info[j].class_name,
1957 element_info[element_class].class_name))
1958 element_info[j].sound[action] = sound;
1961 // initialize element/sound mapping from dynamic configuration
1962 for (i = 0; i < num_property_mappings; i++)
1964 int element = property_mapping[i].base_index;
1965 int action = property_mapping[i].ext1_index;
1966 int sound = property_mapping[i].artwork_index;
1968 if (element >= MAX_NUM_ELEMENTS)
1972 action = ACTION_DEFAULT;
1974 element_info[element].sound[action] = sound;
1977 // now set all '-1' values to element specific default values
1978 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1980 for (act = 0; act < NUM_ACTIONS; act++)
1982 // generic default action sound (defined by "[default]" directive)
1983 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1985 // look for special default action sound (classic game specific)
1986 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1987 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1988 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1989 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1990 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1991 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1992 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1993 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1995 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1996 // !!! make this better !!!
1997 if (i == EL_EMPTY_SPACE)
1998 default_action_sound = element_info[EL_DEFAULT].sound[act];
2000 // no sound for this specific action -- use default action sound
2001 if (element_info[i].sound[act] == -1)
2002 element_info[i].sound[act] = default_action_sound;
2006 // copy sound settings to some elements that are only stored in level file
2007 // in native R'n'D levels, but are used by game engine in native EM levels
2008 for (i = 0; copy_properties[i][0] != -1; i++)
2009 for (j = 1; j <= 4; j++)
2010 for (act = 0; act < NUM_ACTIONS; act++)
2011 element_info[copy_properties[i][j]].sound[act] =
2012 element_info[copy_properties[i][0]].sound[act];
2015 static void InitGameModeSoundInfo(void)
2019 // set values to -1 to identify later as "uninitialized" values
2020 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2023 // initialize gamemode/sound mapping from static configuration
2024 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2026 int gamemode = gamemode_to_sound[i].gamemode;
2027 int sound = gamemode_to_sound[i].sound;
2030 gamemode = GAME_MODE_DEFAULT;
2032 menu.sound[gamemode] = sound;
2035 // now set all '-1' values to levelset specific default values
2036 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2037 if (menu.sound[i] == -1)
2038 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2041 static void set_sound_parameters(int sound, char **parameter_raw)
2043 int parameter[NUM_SND_ARGS];
2046 // get integer values from string parameters
2047 for (i = 0; i < NUM_SND_ARGS; i++)
2049 get_parameter_value(parameter_raw[i],
2050 sound_config_suffix[i].token,
2051 sound_config_suffix[i].type);
2053 // explicit loop mode setting in configuration overrides default value
2054 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2055 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2057 // sound volume to change the original volume when loading the sound file
2058 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2060 // sound priority to give certain sounds a higher or lower priority
2061 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2064 static void InitSoundInfo(void)
2066 int *sound_effect_properties;
2067 int num_sounds = getSoundListSize();
2070 checked_free(sound_info);
2072 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2073 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2075 // initialize sound effect for all elements to "no sound"
2076 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2077 for (j = 0; j < NUM_ACTIONS; j++)
2078 element_info[i].sound[j] = SND_UNDEFINED;
2080 for (i = 0; i < num_sounds; i++)
2082 struct FileInfo *sound = getSoundListEntry(i);
2083 int len_effect_text = strlen(sound->token);
2085 sound_effect_properties[i] = ACTION_OTHER;
2086 sound_info[i].loop = FALSE; // default: play sound only once
2088 // determine all loop sounds and identify certain sound classes
2090 for (j = 0; element_action_info[j].suffix; j++)
2092 int len_action_text = strlen(element_action_info[j].suffix);
2094 if (len_action_text < len_effect_text &&
2095 strEqual(&sound->token[len_effect_text - len_action_text],
2096 element_action_info[j].suffix))
2098 sound_effect_properties[i] = element_action_info[j].value;
2099 sound_info[i].loop = element_action_info[j].is_loop_sound;
2105 // associate elements and some selected sound actions
2107 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2109 if (element_info[j].class_name)
2111 int len_class_text = strlen(element_info[j].class_name);
2113 if (len_class_text + 1 < len_effect_text &&
2114 strncmp(sound->token,
2115 element_info[j].class_name, len_class_text) == 0 &&
2116 sound->token[len_class_text] == '.')
2118 int sound_action_value = sound_effect_properties[i];
2120 element_info[j].sound[sound_action_value] = i;
2125 set_sound_parameters(i, sound->parameter);
2128 free(sound_effect_properties);
2131 static void InitGameModeMusicInfo(void)
2133 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2134 int num_property_mappings = getMusicListPropertyMappingSize();
2135 int default_levelset_music = -1;
2138 // set values to -1 to identify later as "uninitialized" values
2139 for (i = 0; i < MAX_LEVELS; i++)
2140 levelset.music[i] = -1;
2141 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2144 // initialize gamemode/music mapping from static configuration
2145 for (i = 0; gamemode_to_music[i].music > -1; i++)
2147 int gamemode = gamemode_to_music[i].gamemode;
2148 int music = gamemode_to_music[i].music;
2151 gamemode = GAME_MODE_DEFAULT;
2153 menu.music[gamemode] = music;
2156 // initialize gamemode/music mapping from dynamic configuration
2157 for (i = 0; i < num_property_mappings; i++)
2159 int prefix = property_mapping[i].base_index;
2160 int gamemode = property_mapping[i].ext2_index;
2161 int level = property_mapping[i].ext3_index;
2162 int music = property_mapping[i].artwork_index;
2164 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2168 gamemode = GAME_MODE_DEFAULT;
2170 // level specific music only allowed for in-game music
2171 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2172 gamemode = GAME_MODE_PLAYING;
2177 default_levelset_music = music;
2180 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2181 levelset.music[level] = music;
2182 if (gamemode != GAME_MODE_PLAYING)
2183 menu.music[gamemode] = music;
2186 // now set all '-1' values to menu specific default values
2187 // (undefined values of "levelset.music[]" might stay at "-1" to
2188 // allow dynamic selection of music files from music directory!)
2189 for (i = 0; i < MAX_LEVELS; i++)
2190 if (levelset.music[i] == -1)
2191 levelset.music[i] = default_levelset_music;
2192 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2193 if (menu.music[i] == -1)
2194 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2197 static void set_music_parameters(int music, char **parameter_raw)
2199 int parameter[NUM_MUS_ARGS];
2202 // get integer values from string parameters
2203 for (i = 0; i < NUM_MUS_ARGS; i++)
2205 get_parameter_value(parameter_raw[i],
2206 music_config_suffix[i].token,
2207 music_config_suffix[i].type);
2209 // explicit loop mode setting in configuration overrides default value
2210 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2211 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2214 static void InitMusicInfo(void)
2216 int num_music = getMusicListSize();
2219 checked_free(music_info);
2221 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2223 for (i = 0; i < num_music; i++)
2225 struct FileInfo *music = getMusicListEntry(i);
2226 int len_music_text = strlen(music->token);
2228 music_info[i].loop = TRUE; // default: play music in loop mode
2230 // determine all loop music
2232 for (j = 0; music_prefix_info[j].prefix; j++)
2234 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2236 if (len_prefix_text < len_music_text &&
2237 strncmp(music->token,
2238 music_prefix_info[j].prefix, len_prefix_text) == 0)
2240 music_info[i].loop = music_prefix_info[j].is_loop_music;
2246 set_music_parameters(i, music->parameter);
2250 static void ReinitializeGraphics(void)
2252 print_timestamp_init("ReinitializeGraphics");
2254 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2256 InitGraphicInfo(); // graphic properties mapping
2257 print_timestamp_time("InitGraphicInfo");
2258 InitElementGraphicInfo(); // element game graphic mapping
2259 print_timestamp_time("InitElementGraphicInfo");
2260 InitElementSpecialGraphicInfo(); // element special graphic mapping
2261 print_timestamp_time("InitElementSpecialGraphicInfo");
2263 InitElementSmallImages(); // scale elements to all needed sizes
2264 print_timestamp_time("InitElementSmallImages");
2265 InitScaledImages(); // scale all other images, if needed
2266 print_timestamp_time("InitScaledImages");
2267 InitBitmapPointers(); // set standard size bitmap pointers
2268 print_timestamp_time("InitBitmapPointers");
2269 InitFontGraphicInfo(); // initialize text drawing functions
2270 print_timestamp_time("InitFontGraphicInfo");
2271 InitGlobalAnimGraphicInfo(); // initialize global animation config
2272 print_timestamp_time("InitGlobalAnimGraphicInfo");
2274 InitImageTextures(); // create textures for certain images
2275 print_timestamp_time("InitImageTextures");
2277 InitGraphicInfo_EM(); // graphic mapping for EM engine
2278 print_timestamp_time("InitGraphicInfo_EM");
2280 InitGraphicCompatibilityInfo();
2281 print_timestamp_time("InitGraphicCompatibilityInfo");
2283 SetMainBackgroundImage(IMG_BACKGROUND);
2284 print_timestamp_time("SetMainBackgroundImage");
2285 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2286 print_timestamp_time("SetDoorBackgroundImage");
2289 print_timestamp_time("InitGadgets");
2291 print_timestamp_time("InitDoors");
2293 print_timestamp_done("ReinitializeGraphics");
2296 static void ReinitializeSounds(void)
2298 InitSoundInfo(); // sound properties mapping
2299 InitElementSoundInfo(); // element game sound mapping
2300 InitGameModeSoundInfo(); // game mode sound mapping
2301 InitGlobalAnimSoundInfo(); // global animation sound settings
2303 InitPlayLevelSound(); // internal game sound settings
2306 static void ReinitializeMusic(void)
2308 InitMusicInfo(); // music properties mapping
2309 InitGameModeMusicInfo(); // game mode music mapping
2310 InitGlobalAnimMusicInfo(); // global animation music settings
2313 static int get_special_property_bit(int element, int property_bit_nr)
2315 struct PropertyBitInfo
2321 static struct PropertyBitInfo pb_can_move_into_acid[] =
2323 // the player may be able fall into acid when gravity is activated
2328 { EL_SP_MURPHY, 0 },
2329 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2331 // all elements that can move may be able to also move into acid
2334 { EL_BUG_RIGHT, 1 },
2337 { EL_SPACESHIP, 2 },
2338 { EL_SPACESHIP_LEFT, 2 },
2339 { EL_SPACESHIP_RIGHT, 2 },
2340 { EL_SPACESHIP_UP, 2 },
2341 { EL_SPACESHIP_DOWN, 2 },
2342 { EL_BD_BUTTERFLY, 3 },
2343 { EL_BD_BUTTERFLY_LEFT, 3 },
2344 { EL_BD_BUTTERFLY_RIGHT, 3 },
2345 { EL_BD_BUTTERFLY_UP, 3 },
2346 { EL_BD_BUTTERFLY_DOWN, 3 },
2347 { EL_BD_FIREFLY, 4 },
2348 { EL_BD_FIREFLY_LEFT, 4 },
2349 { EL_BD_FIREFLY_RIGHT, 4 },
2350 { EL_BD_FIREFLY_UP, 4 },
2351 { EL_BD_FIREFLY_DOWN, 4 },
2353 { EL_YAMYAM_LEFT, 5 },
2354 { EL_YAMYAM_RIGHT, 5 },
2355 { EL_YAMYAM_UP, 5 },
2356 { EL_YAMYAM_DOWN, 5 },
2357 { EL_DARK_YAMYAM, 6 },
2360 { EL_PACMAN_LEFT, 8 },
2361 { EL_PACMAN_RIGHT, 8 },
2362 { EL_PACMAN_UP, 8 },
2363 { EL_PACMAN_DOWN, 8 },
2365 { EL_MOLE_LEFT, 9 },
2366 { EL_MOLE_RIGHT, 9 },
2368 { EL_MOLE_DOWN, 9 },
2372 { EL_SATELLITE, 13 },
2373 { EL_SP_SNIKSNAK, 14 },
2374 { EL_SP_ELECTRON, 15 },
2377 { EL_EMC_ANDROID, 18 },
2382 static struct PropertyBitInfo pb_dont_collide_with[] =
2384 { EL_SP_SNIKSNAK, 0 },
2385 { EL_SP_ELECTRON, 1 },
2393 struct PropertyBitInfo *pb_info;
2396 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2397 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2402 struct PropertyBitInfo *pb_info = NULL;
2405 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2406 if (pb_definition[i].bit_nr == property_bit_nr)
2407 pb_info = pb_definition[i].pb_info;
2409 if (pb_info == NULL)
2412 for (i = 0; pb_info[i].element != -1; i++)
2413 if (pb_info[i].element == element)
2414 return pb_info[i].bit_nr;
2419 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2420 boolean property_value)
2422 int bit_nr = get_special_property_bit(element, property_bit_nr);
2427 *bitfield |= (1 << bit_nr);
2429 *bitfield &= ~(1 << bit_nr);
2433 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2435 int bit_nr = get_special_property_bit(element, property_bit_nr);
2438 return ((*bitfield & (1 << bit_nr)) != 0);
2443 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2445 static int group_nr;
2446 static struct ElementGroupInfo *group;
2447 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2450 if (actual_group == NULL) // not yet initialized
2453 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2455 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2456 group_element - EL_GROUP_START + 1);
2458 // replace element which caused too deep recursion by question mark
2459 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2464 if (recursion_depth == 0) // initialization
2466 group = actual_group;
2467 group_nr = GROUP_NR(group_element);
2469 group->num_elements_resolved = 0;
2470 group->choice_pos = 0;
2472 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2473 element_info[i].in_group[group_nr] = FALSE;
2476 for (i = 0; i < actual_group->num_elements; i++)
2478 int element = actual_group->element[i];
2480 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2483 if (IS_GROUP_ELEMENT(element))
2484 ResolveGroupElementExt(element, recursion_depth + 1);
2487 group->element_resolved[group->num_elements_resolved++] = element;
2488 element_info[element].in_group[group_nr] = TRUE;
2493 void ResolveGroupElement(int group_element)
2495 ResolveGroupElementExt(group_element, 0);
2498 void InitElementPropertiesStatic(void)
2500 static boolean clipboard_elements_initialized = FALSE;
2502 static int ep_diggable[] =
2507 EL_SP_BUGGY_BASE_ACTIVATING,
2510 EL_INVISIBLE_SAND_ACTIVE,
2513 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2514 // (if amoeba can grow into anything diggable, maybe keep these out)
2519 EL_SP_BUGGY_BASE_ACTIVE,
2526 static int ep_collectible_only[] =
2548 EL_DYNABOMB_INCREASE_NUMBER,
2549 EL_DYNABOMB_INCREASE_SIZE,
2550 EL_DYNABOMB_INCREASE_POWER,
2568 // !!! handle separately !!!
2569 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2575 static int ep_dont_run_into[] =
2577 // same elements as in 'ep_dont_touch'
2583 // same elements as in 'ep_dont_collide_with'
2595 // !!! maybe this should better be handled by 'ep_diggable' !!!
2600 EL_SP_BUGGY_BASE_ACTIVE,
2607 static int ep_dont_collide_with[] =
2609 // same elements as in 'ep_dont_touch'
2626 static int ep_dont_touch[] =
2636 static int ep_indestructible[] =
2640 EL_ACID_POOL_TOPLEFT,
2641 EL_ACID_POOL_TOPRIGHT,
2642 EL_ACID_POOL_BOTTOMLEFT,
2643 EL_ACID_POOL_BOTTOM,
2644 EL_ACID_POOL_BOTTOMRIGHT,
2645 EL_SP_HARDWARE_GRAY,
2646 EL_SP_HARDWARE_GREEN,
2647 EL_SP_HARDWARE_BLUE,
2649 EL_SP_HARDWARE_YELLOW,
2650 EL_SP_HARDWARE_BASE_1,
2651 EL_SP_HARDWARE_BASE_2,
2652 EL_SP_HARDWARE_BASE_3,
2653 EL_SP_HARDWARE_BASE_4,
2654 EL_SP_HARDWARE_BASE_5,
2655 EL_SP_HARDWARE_BASE_6,
2656 EL_INVISIBLE_STEELWALL,
2657 EL_INVISIBLE_STEELWALL_ACTIVE,
2658 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2659 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2660 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2661 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2662 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2663 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2664 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2665 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2666 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2667 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2668 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2669 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2671 EL_LIGHT_SWITCH_ACTIVE,
2672 EL_SIGN_EXCLAMATION,
2673 EL_SIGN_RADIOACTIVITY,
2680 EL_SIGN_ENTRY_FORBIDDEN,
2681 EL_SIGN_EMERGENCY_EXIT,
2689 EL_STEEL_EXIT_CLOSED,
2691 EL_STEEL_EXIT_OPENING,
2692 EL_STEEL_EXIT_CLOSING,
2693 EL_EM_STEEL_EXIT_CLOSED,
2694 EL_EM_STEEL_EXIT_OPEN,
2695 EL_EM_STEEL_EXIT_OPENING,
2696 EL_EM_STEEL_EXIT_CLOSING,
2697 EL_DC_STEELWALL_1_LEFT,
2698 EL_DC_STEELWALL_1_RIGHT,
2699 EL_DC_STEELWALL_1_TOP,
2700 EL_DC_STEELWALL_1_BOTTOM,
2701 EL_DC_STEELWALL_1_HORIZONTAL,
2702 EL_DC_STEELWALL_1_VERTICAL,
2703 EL_DC_STEELWALL_1_TOPLEFT,
2704 EL_DC_STEELWALL_1_TOPRIGHT,
2705 EL_DC_STEELWALL_1_BOTTOMLEFT,
2706 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2707 EL_DC_STEELWALL_1_TOPLEFT_2,
2708 EL_DC_STEELWALL_1_TOPRIGHT_2,
2709 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2710 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2711 EL_DC_STEELWALL_2_LEFT,
2712 EL_DC_STEELWALL_2_RIGHT,
2713 EL_DC_STEELWALL_2_TOP,
2714 EL_DC_STEELWALL_2_BOTTOM,
2715 EL_DC_STEELWALL_2_HORIZONTAL,
2716 EL_DC_STEELWALL_2_VERTICAL,
2717 EL_DC_STEELWALL_2_MIDDLE,
2718 EL_DC_STEELWALL_2_SINGLE,
2719 EL_STEELWALL_SLIPPERY,
2733 EL_GATE_1_GRAY_ACTIVE,
2734 EL_GATE_2_GRAY_ACTIVE,
2735 EL_GATE_3_GRAY_ACTIVE,
2736 EL_GATE_4_GRAY_ACTIVE,
2745 EL_EM_GATE_1_GRAY_ACTIVE,
2746 EL_EM_GATE_2_GRAY_ACTIVE,
2747 EL_EM_GATE_3_GRAY_ACTIVE,
2748 EL_EM_GATE_4_GRAY_ACTIVE,
2757 EL_EMC_GATE_5_GRAY_ACTIVE,
2758 EL_EMC_GATE_6_GRAY_ACTIVE,
2759 EL_EMC_GATE_7_GRAY_ACTIVE,
2760 EL_EMC_GATE_8_GRAY_ACTIVE,
2762 EL_DC_GATE_WHITE_GRAY,
2763 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2764 EL_DC_GATE_FAKE_GRAY,
2766 EL_SWITCHGATE_OPENING,
2767 EL_SWITCHGATE_CLOSED,
2768 EL_SWITCHGATE_CLOSING,
2769 EL_DC_SWITCHGATE_SWITCH_UP,
2770 EL_DC_SWITCHGATE_SWITCH_DOWN,
2772 EL_TIMEGATE_OPENING,
2774 EL_TIMEGATE_CLOSING,
2775 EL_DC_TIMEGATE_SWITCH,
2776 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2780 EL_TUBE_VERTICAL_LEFT,
2781 EL_TUBE_VERTICAL_RIGHT,
2782 EL_TUBE_HORIZONTAL_UP,
2783 EL_TUBE_HORIZONTAL_DOWN,
2788 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2789 EL_EXPANDABLE_STEELWALL_VERTICAL,
2790 EL_EXPANDABLE_STEELWALL_ANY,
2795 static int ep_slippery[] =
2809 EL_ROBOT_WHEEL_ACTIVE,
2815 EL_ACID_POOL_TOPLEFT,
2816 EL_ACID_POOL_TOPRIGHT,
2826 EL_STEELWALL_SLIPPERY,
2829 EL_EMC_WALL_SLIPPERY_1,
2830 EL_EMC_WALL_SLIPPERY_2,
2831 EL_EMC_WALL_SLIPPERY_3,
2832 EL_EMC_WALL_SLIPPERY_4,
2834 EL_EMC_MAGIC_BALL_ACTIVE,
2839 static int ep_can_change[] =
2844 static int ep_can_move[] =
2846 // same elements as in 'pb_can_move_into_acid'
2869 static int ep_can_fall[] =
2883 EL_QUICKSAND_FAST_FULL,
2885 EL_BD_MAGIC_WALL_FULL,
2886 EL_DC_MAGIC_WALL_FULL,
2900 static int ep_can_smash_player[] =
2926 static int ep_can_smash_enemies[] =
2935 static int ep_can_smash_everything[] =
2944 static int ep_explodes_by_fire[] =
2946 // same elements as in 'ep_explodes_impact'
2951 // same elements as in 'ep_explodes_smashed'
2961 EL_EM_DYNAMITE_ACTIVE,
2962 EL_DYNABOMB_PLAYER_1_ACTIVE,
2963 EL_DYNABOMB_PLAYER_2_ACTIVE,
2964 EL_DYNABOMB_PLAYER_3_ACTIVE,
2965 EL_DYNABOMB_PLAYER_4_ACTIVE,
2966 EL_DYNABOMB_INCREASE_NUMBER,
2967 EL_DYNABOMB_INCREASE_SIZE,
2968 EL_DYNABOMB_INCREASE_POWER,
2969 EL_SP_DISK_RED_ACTIVE,
2983 static int ep_explodes_smashed[] =
2985 // same elements as in 'ep_explodes_impact'
2999 static int ep_explodes_impact[] =
3008 static int ep_walkable_over[] =
3012 EL_SOKOBAN_FIELD_EMPTY,
3019 EL_EM_STEEL_EXIT_OPEN,
3020 EL_EM_STEEL_EXIT_OPENING,
3029 EL_GATE_1_GRAY_ACTIVE,
3030 EL_GATE_2_GRAY_ACTIVE,
3031 EL_GATE_3_GRAY_ACTIVE,
3032 EL_GATE_4_GRAY_ACTIVE,
3040 static int ep_walkable_inside[] =
3045 EL_TUBE_VERTICAL_LEFT,
3046 EL_TUBE_VERTICAL_RIGHT,
3047 EL_TUBE_HORIZONTAL_UP,
3048 EL_TUBE_HORIZONTAL_DOWN,
3057 static int ep_walkable_under[] =
3062 static int ep_passable_over[] =
3072 EL_EM_GATE_1_GRAY_ACTIVE,
3073 EL_EM_GATE_2_GRAY_ACTIVE,
3074 EL_EM_GATE_3_GRAY_ACTIVE,
3075 EL_EM_GATE_4_GRAY_ACTIVE,
3084 EL_EMC_GATE_5_GRAY_ACTIVE,
3085 EL_EMC_GATE_6_GRAY_ACTIVE,
3086 EL_EMC_GATE_7_GRAY_ACTIVE,
3087 EL_EMC_GATE_8_GRAY_ACTIVE,
3089 EL_DC_GATE_WHITE_GRAY,
3090 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3097 static int ep_passable_inside[] =
3103 EL_SP_PORT_HORIZONTAL,
3104 EL_SP_PORT_VERTICAL,
3106 EL_SP_GRAVITY_PORT_LEFT,
3107 EL_SP_GRAVITY_PORT_RIGHT,
3108 EL_SP_GRAVITY_PORT_UP,
3109 EL_SP_GRAVITY_PORT_DOWN,
3110 EL_SP_GRAVITY_ON_PORT_LEFT,
3111 EL_SP_GRAVITY_ON_PORT_RIGHT,
3112 EL_SP_GRAVITY_ON_PORT_UP,
3113 EL_SP_GRAVITY_ON_PORT_DOWN,
3114 EL_SP_GRAVITY_OFF_PORT_LEFT,
3115 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3116 EL_SP_GRAVITY_OFF_PORT_UP,
3117 EL_SP_GRAVITY_OFF_PORT_DOWN,
3122 static int ep_passable_under[] =
3127 static int ep_droppable[] =
3132 static int ep_explodes_1x1_old[] =
3137 static int ep_pushable[] =
3149 EL_SOKOBAN_FIELD_FULL,
3158 static int ep_explodes_cross_old[] =
3163 static int ep_protected[] =
3165 // same elements as in 'ep_walkable_inside'
3169 EL_TUBE_VERTICAL_LEFT,
3170 EL_TUBE_VERTICAL_RIGHT,
3171 EL_TUBE_HORIZONTAL_UP,
3172 EL_TUBE_HORIZONTAL_DOWN,
3178 // same elements as in 'ep_passable_over'
3187 EL_EM_GATE_1_GRAY_ACTIVE,
3188 EL_EM_GATE_2_GRAY_ACTIVE,
3189 EL_EM_GATE_3_GRAY_ACTIVE,
3190 EL_EM_GATE_4_GRAY_ACTIVE,
3199 EL_EMC_GATE_5_GRAY_ACTIVE,
3200 EL_EMC_GATE_6_GRAY_ACTIVE,
3201 EL_EMC_GATE_7_GRAY_ACTIVE,
3202 EL_EMC_GATE_8_GRAY_ACTIVE,
3204 EL_DC_GATE_WHITE_GRAY,
3205 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3209 // same elements as in 'ep_passable_inside'
3214 EL_SP_PORT_HORIZONTAL,
3215 EL_SP_PORT_VERTICAL,
3217 EL_SP_GRAVITY_PORT_LEFT,
3218 EL_SP_GRAVITY_PORT_RIGHT,
3219 EL_SP_GRAVITY_PORT_UP,
3220 EL_SP_GRAVITY_PORT_DOWN,
3221 EL_SP_GRAVITY_ON_PORT_LEFT,
3222 EL_SP_GRAVITY_ON_PORT_RIGHT,
3223 EL_SP_GRAVITY_ON_PORT_UP,
3224 EL_SP_GRAVITY_ON_PORT_DOWN,
3225 EL_SP_GRAVITY_OFF_PORT_LEFT,
3226 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3227 EL_SP_GRAVITY_OFF_PORT_UP,
3228 EL_SP_GRAVITY_OFF_PORT_DOWN,
3233 static int ep_throwable[] =
3238 static int ep_can_explode[] =
3240 // same elements as in 'ep_explodes_impact'
3245 // same elements as in 'ep_explodes_smashed'
3251 // elements that can explode by explosion or by dragonfire
3255 EL_EM_DYNAMITE_ACTIVE,
3256 EL_DYNABOMB_PLAYER_1_ACTIVE,
3257 EL_DYNABOMB_PLAYER_2_ACTIVE,
3258 EL_DYNABOMB_PLAYER_3_ACTIVE,
3259 EL_DYNABOMB_PLAYER_4_ACTIVE,
3260 EL_DYNABOMB_INCREASE_NUMBER,
3261 EL_DYNABOMB_INCREASE_SIZE,
3262 EL_DYNABOMB_INCREASE_POWER,
3263 EL_SP_DISK_RED_ACTIVE,
3271 // elements that can explode only by explosion
3277 static int ep_gravity_reachable[] =
3283 EL_INVISIBLE_SAND_ACTIVE,
3288 EL_SP_PORT_HORIZONTAL,
3289 EL_SP_PORT_VERTICAL,
3291 EL_SP_GRAVITY_PORT_LEFT,
3292 EL_SP_GRAVITY_PORT_RIGHT,
3293 EL_SP_GRAVITY_PORT_UP,
3294 EL_SP_GRAVITY_PORT_DOWN,
3295 EL_SP_GRAVITY_ON_PORT_LEFT,
3296 EL_SP_GRAVITY_ON_PORT_RIGHT,
3297 EL_SP_GRAVITY_ON_PORT_UP,
3298 EL_SP_GRAVITY_ON_PORT_DOWN,
3299 EL_SP_GRAVITY_OFF_PORT_LEFT,
3300 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3301 EL_SP_GRAVITY_OFF_PORT_UP,
3302 EL_SP_GRAVITY_OFF_PORT_DOWN,
3308 static int ep_player[] =
3315 EL_SOKOBAN_FIELD_PLAYER,
3321 static int ep_can_pass_magic_wall[] =
3335 static int ep_can_pass_dc_magic_wall[] =
3351 static int ep_switchable[] =
3355 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3356 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3357 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3358 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3359 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3360 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3361 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3362 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3363 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3364 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3365 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3366 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3367 EL_SWITCHGATE_SWITCH_UP,
3368 EL_SWITCHGATE_SWITCH_DOWN,
3369 EL_DC_SWITCHGATE_SWITCH_UP,
3370 EL_DC_SWITCHGATE_SWITCH_DOWN,
3372 EL_LIGHT_SWITCH_ACTIVE,
3374 EL_DC_TIMEGATE_SWITCH,
3375 EL_BALLOON_SWITCH_LEFT,
3376 EL_BALLOON_SWITCH_RIGHT,
3377 EL_BALLOON_SWITCH_UP,
3378 EL_BALLOON_SWITCH_DOWN,
3379 EL_BALLOON_SWITCH_ANY,
3380 EL_BALLOON_SWITCH_NONE,
3383 EL_EMC_MAGIC_BALL_SWITCH,
3384 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3389 static int ep_bd_element[] =
3423 static int ep_sp_element[] =
3425 // should always be valid
3428 // standard classic Supaplex elements
3435 EL_SP_HARDWARE_GRAY,
3443 EL_SP_GRAVITY_PORT_RIGHT,
3444 EL_SP_GRAVITY_PORT_DOWN,
3445 EL_SP_GRAVITY_PORT_LEFT,
3446 EL_SP_GRAVITY_PORT_UP,
3451 EL_SP_PORT_VERTICAL,
3452 EL_SP_PORT_HORIZONTAL,
3458 EL_SP_HARDWARE_BASE_1,
3459 EL_SP_HARDWARE_GREEN,
3460 EL_SP_HARDWARE_BLUE,
3462 EL_SP_HARDWARE_YELLOW,
3463 EL_SP_HARDWARE_BASE_2,
3464 EL_SP_HARDWARE_BASE_3,
3465 EL_SP_HARDWARE_BASE_4,
3466 EL_SP_HARDWARE_BASE_5,
3467 EL_SP_HARDWARE_BASE_6,
3471 // additional elements that appeared in newer Supaplex levels
3474 // additional gravity port elements (not switching, but setting gravity)
3475 EL_SP_GRAVITY_ON_PORT_LEFT,
3476 EL_SP_GRAVITY_ON_PORT_RIGHT,
3477 EL_SP_GRAVITY_ON_PORT_UP,
3478 EL_SP_GRAVITY_ON_PORT_DOWN,
3479 EL_SP_GRAVITY_OFF_PORT_LEFT,
3480 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3481 EL_SP_GRAVITY_OFF_PORT_UP,
3482 EL_SP_GRAVITY_OFF_PORT_DOWN,
3484 // more than one Murphy in a level results in an inactive clone
3487 // runtime Supaplex elements
3488 EL_SP_DISK_RED_ACTIVE,
3489 EL_SP_TERMINAL_ACTIVE,
3490 EL_SP_BUGGY_BASE_ACTIVATING,
3491 EL_SP_BUGGY_BASE_ACTIVE,
3498 static int ep_sb_element[] =
3503 EL_SOKOBAN_FIELD_EMPTY,
3504 EL_SOKOBAN_FIELD_FULL,
3505 EL_SOKOBAN_FIELD_PLAYER,
3510 EL_INVISIBLE_STEELWALL,
3515 static int ep_gem[] =
3527 static int ep_food_dark_yamyam[] =
3555 static int ep_food_penguin[] =
3569 static int ep_food_pig[] =
3581 static int ep_historic_wall[] =
3592 EL_GATE_1_GRAY_ACTIVE,
3593 EL_GATE_2_GRAY_ACTIVE,
3594 EL_GATE_3_GRAY_ACTIVE,
3595 EL_GATE_4_GRAY_ACTIVE,
3604 EL_EM_GATE_1_GRAY_ACTIVE,
3605 EL_EM_GATE_2_GRAY_ACTIVE,
3606 EL_EM_GATE_3_GRAY_ACTIVE,
3607 EL_EM_GATE_4_GRAY_ACTIVE,
3614 EL_EXPANDABLE_WALL_HORIZONTAL,
3615 EL_EXPANDABLE_WALL_VERTICAL,
3616 EL_EXPANDABLE_WALL_ANY,
3617 EL_EXPANDABLE_WALL_GROWING,
3618 EL_BD_EXPANDABLE_WALL,
3625 EL_SP_HARDWARE_GRAY,
3626 EL_SP_HARDWARE_GREEN,
3627 EL_SP_HARDWARE_BLUE,
3629 EL_SP_HARDWARE_YELLOW,
3630 EL_SP_HARDWARE_BASE_1,
3631 EL_SP_HARDWARE_BASE_2,
3632 EL_SP_HARDWARE_BASE_3,
3633 EL_SP_HARDWARE_BASE_4,
3634 EL_SP_HARDWARE_BASE_5,
3635 EL_SP_HARDWARE_BASE_6,
3637 EL_SP_TERMINAL_ACTIVE,
3640 EL_INVISIBLE_STEELWALL,
3641 EL_INVISIBLE_STEELWALL_ACTIVE,
3643 EL_INVISIBLE_WALL_ACTIVE,
3644 EL_STEELWALL_SLIPPERY,
3661 static int ep_historic_solid[] =
3665 EL_EXPANDABLE_WALL_HORIZONTAL,
3666 EL_EXPANDABLE_WALL_VERTICAL,
3667 EL_EXPANDABLE_WALL_ANY,
3668 EL_BD_EXPANDABLE_WALL,
3681 EL_QUICKSAND_FILLING,
3682 EL_QUICKSAND_EMPTYING,
3684 EL_MAGIC_WALL_ACTIVE,
3685 EL_MAGIC_WALL_EMPTYING,
3686 EL_MAGIC_WALL_FILLING,
3690 EL_BD_MAGIC_WALL_ACTIVE,
3691 EL_BD_MAGIC_WALL_EMPTYING,
3692 EL_BD_MAGIC_WALL_FULL,
3693 EL_BD_MAGIC_WALL_FILLING,
3694 EL_BD_MAGIC_WALL_DEAD,
3703 EL_SP_TERMINAL_ACTIVE,
3707 EL_INVISIBLE_WALL_ACTIVE,
3708 EL_SWITCHGATE_SWITCH_UP,
3709 EL_SWITCHGATE_SWITCH_DOWN,
3711 EL_TIMEGATE_SWITCH_ACTIVE,
3723 // the following elements are a direct copy of "indestructible" elements,
3724 // except "EL_ACID", which is "indestructible", but not "solid"!
3729 EL_ACID_POOL_TOPLEFT,
3730 EL_ACID_POOL_TOPRIGHT,
3731 EL_ACID_POOL_BOTTOMLEFT,
3732 EL_ACID_POOL_BOTTOM,
3733 EL_ACID_POOL_BOTTOMRIGHT,
3734 EL_SP_HARDWARE_GRAY,
3735 EL_SP_HARDWARE_GREEN,
3736 EL_SP_HARDWARE_BLUE,
3738 EL_SP_HARDWARE_YELLOW,
3739 EL_SP_HARDWARE_BASE_1,
3740 EL_SP_HARDWARE_BASE_2,
3741 EL_SP_HARDWARE_BASE_3,
3742 EL_SP_HARDWARE_BASE_4,
3743 EL_SP_HARDWARE_BASE_5,
3744 EL_SP_HARDWARE_BASE_6,
3745 EL_INVISIBLE_STEELWALL,
3746 EL_INVISIBLE_STEELWALL_ACTIVE,
3747 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3748 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3749 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3750 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3751 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3752 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3753 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3754 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3755 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3756 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3757 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3758 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3760 EL_LIGHT_SWITCH_ACTIVE,
3761 EL_SIGN_EXCLAMATION,
3762 EL_SIGN_RADIOACTIVITY,
3769 EL_SIGN_ENTRY_FORBIDDEN,
3770 EL_SIGN_EMERGENCY_EXIT,
3778 EL_STEEL_EXIT_CLOSED,
3780 EL_STEEL_EXIT_OPENING,
3781 EL_STEEL_EXIT_CLOSING,
3782 EL_EM_STEEL_EXIT_CLOSED,
3783 EL_EM_STEEL_EXIT_OPEN,
3784 EL_EM_STEEL_EXIT_OPENING,
3785 EL_EM_STEEL_EXIT_CLOSING,
3786 EL_DC_STEELWALL_1_LEFT,
3787 EL_DC_STEELWALL_1_RIGHT,
3788 EL_DC_STEELWALL_1_TOP,
3789 EL_DC_STEELWALL_1_BOTTOM,
3790 EL_DC_STEELWALL_1_HORIZONTAL,
3791 EL_DC_STEELWALL_1_VERTICAL,
3792 EL_DC_STEELWALL_1_TOPLEFT,
3793 EL_DC_STEELWALL_1_TOPRIGHT,
3794 EL_DC_STEELWALL_1_BOTTOMLEFT,
3795 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3796 EL_DC_STEELWALL_1_TOPLEFT_2,
3797 EL_DC_STEELWALL_1_TOPRIGHT_2,
3798 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3799 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3800 EL_DC_STEELWALL_2_LEFT,
3801 EL_DC_STEELWALL_2_RIGHT,
3802 EL_DC_STEELWALL_2_TOP,
3803 EL_DC_STEELWALL_2_BOTTOM,
3804 EL_DC_STEELWALL_2_HORIZONTAL,
3805 EL_DC_STEELWALL_2_VERTICAL,
3806 EL_DC_STEELWALL_2_MIDDLE,
3807 EL_DC_STEELWALL_2_SINGLE,
3808 EL_STEELWALL_SLIPPERY,
3822 EL_GATE_1_GRAY_ACTIVE,
3823 EL_GATE_2_GRAY_ACTIVE,
3824 EL_GATE_3_GRAY_ACTIVE,
3825 EL_GATE_4_GRAY_ACTIVE,
3834 EL_EM_GATE_1_GRAY_ACTIVE,
3835 EL_EM_GATE_2_GRAY_ACTIVE,
3836 EL_EM_GATE_3_GRAY_ACTIVE,
3837 EL_EM_GATE_4_GRAY_ACTIVE,
3846 EL_EMC_GATE_5_GRAY_ACTIVE,
3847 EL_EMC_GATE_6_GRAY_ACTIVE,
3848 EL_EMC_GATE_7_GRAY_ACTIVE,
3849 EL_EMC_GATE_8_GRAY_ACTIVE,
3851 EL_DC_GATE_WHITE_GRAY,
3852 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3853 EL_DC_GATE_FAKE_GRAY,
3855 EL_SWITCHGATE_OPENING,
3856 EL_SWITCHGATE_CLOSED,
3857 EL_SWITCHGATE_CLOSING,
3858 EL_DC_SWITCHGATE_SWITCH_UP,
3859 EL_DC_SWITCHGATE_SWITCH_DOWN,
3861 EL_TIMEGATE_OPENING,
3863 EL_TIMEGATE_CLOSING,
3864 EL_DC_TIMEGATE_SWITCH,
3865 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3869 EL_TUBE_VERTICAL_LEFT,
3870 EL_TUBE_VERTICAL_RIGHT,
3871 EL_TUBE_HORIZONTAL_UP,
3872 EL_TUBE_HORIZONTAL_DOWN,
3877 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3878 EL_EXPANDABLE_STEELWALL_VERTICAL,
3879 EL_EXPANDABLE_STEELWALL_ANY,
3884 static int ep_classic_enemy[] =
3901 static int ep_belt[] =
3903 EL_CONVEYOR_BELT_1_LEFT,
3904 EL_CONVEYOR_BELT_1_MIDDLE,
3905 EL_CONVEYOR_BELT_1_RIGHT,
3906 EL_CONVEYOR_BELT_2_LEFT,
3907 EL_CONVEYOR_BELT_2_MIDDLE,
3908 EL_CONVEYOR_BELT_2_RIGHT,
3909 EL_CONVEYOR_BELT_3_LEFT,
3910 EL_CONVEYOR_BELT_3_MIDDLE,
3911 EL_CONVEYOR_BELT_3_RIGHT,
3912 EL_CONVEYOR_BELT_4_LEFT,
3913 EL_CONVEYOR_BELT_4_MIDDLE,
3914 EL_CONVEYOR_BELT_4_RIGHT,
3919 static int ep_belt_active[] =
3921 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3922 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3923 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3924 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3925 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3926 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3927 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3928 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3929 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3930 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3931 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3932 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3937 static int ep_belt_switch[] =
3939 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3940 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3941 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3942 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3943 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3944 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3945 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3946 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3947 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3948 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3949 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3950 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3955 static int ep_tube[] =
3962 EL_TUBE_HORIZONTAL_UP,
3963 EL_TUBE_HORIZONTAL_DOWN,
3965 EL_TUBE_VERTICAL_LEFT,
3966 EL_TUBE_VERTICAL_RIGHT,
3972 static int ep_acid_pool[] =
3974 EL_ACID_POOL_TOPLEFT,
3975 EL_ACID_POOL_TOPRIGHT,
3976 EL_ACID_POOL_BOTTOMLEFT,
3977 EL_ACID_POOL_BOTTOM,
3978 EL_ACID_POOL_BOTTOMRIGHT,
3983 static int ep_keygate[] =
3993 EL_GATE_1_GRAY_ACTIVE,
3994 EL_GATE_2_GRAY_ACTIVE,
3995 EL_GATE_3_GRAY_ACTIVE,
3996 EL_GATE_4_GRAY_ACTIVE,
4005 EL_EM_GATE_1_GRAY_ACTIVE,
4006 EL_EM_GATE_2_GRAY_ACTIVE,
4007 EL_EM_GATE_3_GRAY_ACTIVE,
4008 EL_EM_GATE_4_GRAY_ACTIVE,
4017 EL_EMC_GATE_5_GRAY_ACTIVE,
4018 EL_EMC_GATE_6_GRAY_ACTIVE,
4019 EL_EMC_GATE_7_GRAY_ACTIVE,
4020 EL_EMC_GATE_8_GRAY_ACTIVE,
4022 EL_DC_GATE_WHITE_GRAY,
4023 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4028 static int ep_amoeboid[] =
4040 static int ep_amoebalive[] =
4051 static int ep_has_editor_content[] =
4057 EL_SOKOBAN_FIELD_PLAYER,
4074 static int ep_can_turn_each_move[] =
4076 // !!! do something with this one !!!
4080 static int ep_can_grow[] =
4094 static int ep_active_bomb[] =
4097 EL_EM_DYNAMITE_ACTIVE,
4098 EL_DYNABOMB_PLAYER_1_ACTIVE,
4099 EL_DYNABOMB_PLAYER_2_ACTIVE,
4100 EL_DYNABOMB_PLAYER_3_ACTIVE,
4101 EL_DYNABOMB_PLAYER_4_ACTIVE,
4102 EL_SP_DISK_RED_ACTIVE,
4107 static int ep_inactive[] =
4117 EL_QUICKSAND_FAST_EMPTY,
4140 EL_GATE_1_GRAY_ACTIVE,
4141 EL_GATE_2_GRAY_ACTIVE,
4142 EL_GATE_3_GRAY_ACTIVE,
4143 EL_GATE_4_GRAY_ACTIVE,
4152 EL_EM_GATE_1_GRAY_ACTIVE,
4153 EL_EM_GATE_2_GRAY_ACTIVE,
4154 EL_EM_GATE_3_GRAY_ACTIVE,
4155 EL_EM_GATE_4_GRAY_ACTIVE,
4164 EL_EMC_GATE_5_GRAY_ACTIVE,
4165 EL_EMC_GATE_6_GRAY_ACTIVE,
4166 EL_EMC_GATE_7_GRAY_ACTIVE,
4167 EL_EMC_GATE_8_GRAY_ACTIVE,
4169 EL_DC_GATE_WHITE_GRAY,
4170 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4171 EL_DC_GATE_FAKE_GRAY,
4174 EL_INVISIBLE_STEELWALL,
4182 EL_WALL_EMERALD_YELLOW,
4183 EL_DYNABOMB_INCREASE_NUMBER,
4184 EL_DYNABOMB_INCREASE_SIZE,
4185 EL_DYNABOMB_INCREASE_POWER,
4189 EL_SOKOBAN_FIELD_EMPTY,
4190 EL_SOKOBAN_FIELD_FULL,
4191 EL_WALL_EMERALD_RED,
4192 EL_WALL_EMERALD_PURPLE,
4193 EL_ACID_POOL_TOPLEFT,
4194 EL_ACID_POOL_TOPRIGHT,
4195 EL_ACID_POOL_BOTTOMLEFT,
4196 EL_ACID_POOL_BOTTOM,
4197 EL_ACID_POOL_BOTTOMRIGHT,
4201 EL_BD_MAGIC_WALL_DEAD,
4203 EL_DC_MAGIC_WALL_DEAD,
4204 EL_AMOEBA_TO_DIAMOND,
4212 EL_SP_GRAVITY_PORT_RIGHT,
4213 EL_SP_GRAVITY_PORT_DOWN,
4214 EL_SP_GRAVITY_PORT_LEFT,
4215 EL_SP_GRAVITY_PORT_UP,
4216 EL_SP_PORT_HORIZONTAL,
4217 EL_SP_PORT_VERTICAL,
4228 EL_SP_HARDWARE_GRAY,
4229 EL_SP_HARDWARE_GREEN,
4230 EL_SP_HARDWARE_BLUE,
4232 EL_SP_HARDWARE_YELLOW,
4233 EL_SP_HARDWARE_BASE_1,
4234 EL_SP_HARDWARE_BASE_2,
4235 EL_SP_HARDWARE_BASE_3,
4236 EL_SP_HARDWARE_BASE_4,
4237 EL_SP_HARDWARE_BASE_5,
4238 EL_SP_HARDWARE_BASE_6,
4239 EL_SP_GRAVITY_ON_PORT_LEFT,
4240 EL_SP_GRAVITY_ON_PORT_RIGHT,
4241 EL_SP_GRAVITY_ON_PORT_UP,
4242 EL_SP_GRAVITY_ON_PORT_DOWN,
4243 EL_SP_GRAVITY_OFF_PORT_LEFT,
4244 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4245 EL_SP_GRAVITY_OFF_PORT_UP,
4246 EL_SP_GRAVITY_OFF_PORT_DOWN,
4247 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4248 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4249 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4250 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4251 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4252 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4253 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4254 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4255 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4256 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4257 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4258 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4259 EL_SIGN_EXCLAMATION,
4260 EL_SIGN_RADIOACTIVITY,
4267 EL_SIGN_ENTRY_FORBIDDEN,
4268 EL_SIGN_EMERGENCY_EXIT,
4276 EL_DC_STEELWALL_1_LEFT,
4277 EL_DC_STEELWALL_1_RIGHT,
4278 EL_DC_STEELWALL_1_TOP,
4279 EL_DC_STEELWALL_1_BOTTOM,
4280 EL_DC_STEELWALL_1_HORIZONTAL,
4281 EL_DC_STEELWALL_1_VERTICAL,
4282 EL_DC_STEELWALL_1_TOPLEFT,
4283 EL_DC_STEELWALL_1_TOPRIGHT,
4284 EL_DC_STEELWALL_1_BOTTOMLEFT,
4285 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4286 EL_DC_STEELWALL_1_TOPLEFT_2,
4287 EL_DC_STEELWALL_1_TOPRIGHT_2,
4288 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4289 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4290 EL_DC_STEELWALL_2_LEFT,
4291 EL_DC_STEELWALL_2_RIGHT,
4292 EL_DC_STEELWALL_2_TOP,
4293 EL_DC_STEELWALL_2_BOTTOM,
4294 EL_DC_STEELWALL_2_HORIZONTAL,
4295 EL_DC_STEELWALL_2_VERTICAL,
4296 EL_DC_STEELWALL_2_MIDDLE,
4297 EL_DC_STEELWALL_2_SINGLE,
4298 EL_STEELWALL_SLIPPERY,
4303 EL_EMC_WALL_SLIPPERY_1,
4304 EL_EMC_WALL_SLIPPERY_2,
4305 EL_EMC_WALL_SLIPPERY_3,
4306 EL_EMC_WALL_SLIPPERY_4,
4327 static int ep_em_slippery_wall[] =
4332 static int ep_gfx_crumbled[] =
4343 static int ep_editor_cascade_active[] =
4345 EL_INTERNAL_CASCADE_BD_ACTIVE,
4346 EL_INTERNAL_CASCADE_EM_ACTIVE,
4347 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4348 EL_INTERNAL_CASCADE_RND_ACTIVE,
4349 EL_INTERNAL_CASCADE_SB_ACTIVE,
4350 EL_INTERNAL_CASCADE_SP_ACTIVE,
4351 EL_INTERNAL_CASCADE_DC_ACTIVE,
4352 EL_INTERNAL_CASCADE_DX_ACTIVE,
4353 EL_INTERNAL_CASCADE_MM_ACTIVE,
4354 EL_INTERNAL_CASCADE_DF_ACTIVE,
4355 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4356 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4357 EL_INTERNAL_CASCADE_CE_ACTIVE,
4358 EL_INTERNAL_CASCADE_GE_ACTIVE,
4359 EL_INTERNAL_CASCADE_REF_ACTIVE,
4360 EL_INTERNAL_CASCADE_USER_ACTIVE,
4361 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4366 static int ep_editor_cascade_inactive[] =
4368 EL_INTERNAL_CASCADE_BD,
4369 EL_INTERNAL_CASCADE_EM,
4370 EL_INTERNAL_CASCADE_EMC,
4371 EL_INTERNAL_CASCADE_RND,
4372 EL_INTERNAL_CASCADE_SB,
4373 EL_INTERNAL_CASCADE_SP,
4374 EL_INTERNAL_CASCADE_DC,
4375 EL_INTERNAL_CASCADE_DX,
4376 EL_INTERNAL_CASCADE_MM,
4377 EL_INTERNAL_CASCADE_DF,
4378 EL_INTERNAL_CASCADE_CHARS,
4379 EL_INTERNAL_CASCADE_STEEL_CHARS,
4380 EL_INTERNAL_CASCADE_CE,
4381 EL_INTERNAL_CASCADE_GE,
4382 EL_INTERNAL_CASCADE_REF,
4383 EL_INTERNAL_CASCADE_USER,
4384 EL_INTERNAL_CASCADE_DYNAMIC,
4389 static int ep_obsolete[] =
4393 EL_EM_KEY_1_FILE_OBSOLETE,
4394 EL_EM_KEY_2_FILE_OBSOLETE,
4395 EL_EM_KEY_3_FILE_OBSOLETE,
4396 EL_EM_KEY_4_FILE_OBSOLETE,
4397 EL_ENVELOPE_OBSOLETE,
4406 } element_properties[] =
4408 { ep_diggable, EP_DIGGABLE },
4409 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4410 { ep_dont_run_into, EP_DONT_RUN_INTO },
4411 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4412 { ep_dont_touch, EP_DONT_TOUCH },
4413 { ep_indestructible, EP_INDESTRUCTIBLE },
4414 { ep_slippery, EP_SLIPPERY },
4415 { ep_can_change, EP_CAN_CHANGE },
4416 { ep_can_move, EP_CAN_MOVE },
4417 { ep_can_fall, EP_CAN_FALL },
4418 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4419 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4420 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4421 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4422 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4423 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4424 { ep_walkable_over, EP_WALKABLE_OVER },
4425 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4426 { ep_walkable_under, EP_WALKABLE_UNDER },
4427 { ep_passable_over, EP_PASSABLE_OVER },
4428 { ep_passable_inside, EP_PASSABLE_INSIDE },
4429 { ep_passable_under, EP_PASSABLE_UNDER },
4430 { ep_droppable, EP_DROPPABLE },
4431 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4432 { ep_pushable, EP_PUSHABLE },
4433 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4434 { ep_protected, EP_PROTECTED },
4435 { ep_throwable, EP_THROWABLE },
4436 { ep_can_explode, EP_CAN_EXPLODE },
4437 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4439 { ep_player, EP_PLAYER },
4440 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4441 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4442 { ep_switchable, EP_SWITCHABLE },
4443 { ep_bd_element, EP_BD_ELEMENT },
4444 { ep_sp_element, EP_SP_ELEMENT },
4445 { ep_sb_element, EP_SB_ELEMENT },
4447 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4448 { ep_food_penguin, EP_FOOD_PENGUIN },
4449 { ep_food_pig, EP_FOOD_PIG },
4450 { ep_historic_wall, EP_HISTORIC_WALL },
4451 { ep_historic_solid, EP_HISTORIC_SOLID },
4452 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4453 { ep_belt, EP_BELT },
4454 { ep_belt_active, EP_BELT_ACTIVE },
4455 { ep_belt_switch, EP_BELT_SWITCH },
4456 { ep_tube, EP_TUBE },
4457 { ep_acid_pool, EP_ACID_POOL },
4458 { ep_keygate, EP_KEYGATE },
4459 { ep_amoeboid, EP_AMOEBOID },
4460 { ep_amoebalive, EP_AMOEBALIVE },
4461 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4462 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4463 { ep_can_grow, EP_CAN_GROW },
4464 { ep_active_bomb, EP_ACTIVE_BOMB },
4465 { ep_inactive, EP_INACTIVE },
4467 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4469 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4471 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4472 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4474 { ep_obsolete, EP_OBSOLETE },
4481 // always start with reliable default values (element has no properties)
4482 // (but never initialize clipboard elements after the very first time)
4483 // (to be able to use clipboard elements between several levels)
4484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4485 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4486 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4487 SET_PROPERTY(i, j, FALSE);
4489 // set all base element properties from above array definitions
4490 for (i = 0; element_properties[i].elements != NULL; i++)
4491 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4492 SET_PROPERTY((element_properties[i].elements)[j],
4493 element_properties[i].property, TRUE);
4495 // copy properties to some elements that are only stored in level file
4496 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4497 for (j = 0; copy_properties[j][0] != -1; j++)
4498 if (HAS_PROPERTY(copy_properties[j][0], i))
4499 for (k = 1; k <= 4; k++)
4500 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4502 // set static element properties that are not listed in array definitions
4503 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4504 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4506 clipboard_elements_initialized = TRUE;
4509 void InitElementPropertiesEngine(int engine_version)
4511 static int no_wall_properties[] =
4514 EP_COLLECTIBLE_ONLY,
4516 EP_DONT_COLLIDE_WITH,
4519 EP_CAN_SMASH_PLAYER,
4520 EP_CAN_SMASH_ENEMIES,
4521 EP_CAN_SMASH_EVERYTHING,
4526 EP_FOOD_DARK_YAMYAM,
4542 /* important: after initialization in InitElementPropertiesStatic(), the
4543 elements are not again initialized to a default value; therefore all
4544 changes have to make sure that they leave the element with a defined
4545 property (which means that conditional property changes must be set to
4546 a reliable default value before) */
4548 // resolve group elements
4549 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4550 ResolveGroupElement(EL_GROUP_START + i);
4552 // set all special, combined or engine dependent element properties
4553 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4555 // do not change (already initialized) clipboard elements here
4556 if (IS_CLIPBOARD_ELEMENT(i))
4559 // ---------- INACTIVE ----------------------------------------------------
4560 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4561 i <= EL_CHAR_END) ||
4562 (i >= EL_STEEL_CHAR_START &&
4563 i <= EL_STEEL_CHAR_END)));
4565 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4566 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4567 IS_WALKABLE_INSIDE(i) ||
4568 IS_WALKABLE_UNDER(i)));
4570 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4571 IS_PASSABLE_INSIDE(i) ||
4572 IS_PASSABLE_UNDER(i)));
4574 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4575 IS_PASSABLE_OVER(i)));
4577 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4578 IS_PASSABLE_INSIDE(i)));
4580 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4581 IS_PASSABLE_UNDER(i)));
4583 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4586 // ---------- COLLECTIBLE -------------------------------------------------
4587 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4591 // ---------- SNAPPABLE ---------------------------------------------------
4592 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4593 IS_COLLECTIBLE(i) ||
4597 // ---------- WALL --------------------------------------------------------
4598 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4600 for (j = 0; no_wall_properties[j] != -1; j++)
4601 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4602 i >= EL_FIRST_RUNTIME_UNREAL)
4603 SET_PROPERTY(i, EP_WALL, FALSE);
4605 if (IS_HISTORIC_WALL(i))
4606 SET_PROPERTY(i, EP_WALL, TRUE);
4608 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4609 if (engine_version < VERSION_IDENT(2,2,0,0))
4610 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4612 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4614 !IS_COLLECTIBLE(i)));
4616 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4617 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4618 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4620 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4623 // ---------- EXPLOSION_PROOF ---------------------------------------------
4625 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4626 else if (engine_version < VERSION_IDENT(2,2,0,0))
4627 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4629 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4633 if (IS_CUSTOM_ELEMENT(i))
4635 // these are additional properties which are initially false when set
4637 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4639 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4640 if (DONT_COLLIDE_WITH(i))
4641 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4643 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4644 if (CAN_SMASH_EVERYTHING(i))
4645 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4646 if (CAN_SMASH_ENEMIES(i))
4647 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4650 // ---------- CAN_SMASH ---------------------------------------------------
4651 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4652 CAN_SMASH_ENEMIES(i) ||
4653 CAN_SMASH_EVERYTHING(i)));
4655 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4656 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4657 EXPLODES_BY_FIRE(i)));
4659 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4660 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4661 EXPLODES_SMASHED(i)));
4663 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4664 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4665 EXPLODES_IMPACT(i)));
4667 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4668 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4670 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4671 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4672 i == EL_BLACK_ORB));
4674 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4675 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4677 IS_CUSTOM_ELEMENT(i)));
4679 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4680 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4681 i == EL_SP_ELECTRON));
4683 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4684 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4685 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4686 getMoveIntoAcidProperty(&level, i));
4688 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4689 if (MAYBE_DONT_COLLIDE_WITH(i))
4690 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4691 getDontCollideWithProperty(&level, i));
4693 // ---------- SP_PORT -----------------------------------------------------
4694 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4695 IS_PASSABLE_INSIDE(i)));
4697 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4698 for (j = 0; j < level.num_android_clone_elements; j++)
4699 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4701 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4703 // ---------- CAN_CHANGE --------------------------------------------------
4704 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4705 for (j = 0; j < element_info[i].num_change_pages; j++)
4706 if (element_info[i].change_page[j].can_change)
4707 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4709 // ---------- HAS_ACTION --------------------------------------------------
4710 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4711 for (j = 0; j < element_info[i].num_change_pages; j++)
4712 if (element_info[i].change_page[j].has_action)
4713 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4715 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4716 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4719 // ---------- GFX_CRUMBLED ------------------------------------------------
4720 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4721 element_info[i].crumbled[ACTION_DEFAULT] !=
4722 element_info[i].graphic[ACTION_DEFAULT]);
4724 // ---------- EDITOR_CASCADE ----------------------------------------------
4725 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4726 IS_EDITOR_CASCADE_INACTIVE(i)));
4729 // dynamically adjust element properties according to game engine version
4731 static int ep_em_slippery_wall[] =
4736 EL_EXPANDABLE_WALL_HORIZONTAL,
4737 EL_EXPANDABLE_WALL_VERTICAL,
4738 EL_EXPANDABLE_WALL_ANY,
4739 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4740 EL_EXPANDABLE_STEELWALL_VERTICAL,
4741 EL_EXPANDABLE_STEELWALL_ANY,
4742 EL_EXPANDABLE_STEELWALL_GROWING,
4746 static int ep_em_explodes_by_fire[] =
4749 EL_EM_DYNAMITE_ACTIVE,
4754 // special EM style gems behaviour
4755 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4756 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4757 level.em_slippery_gems);
4759 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4760 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4761 (level.em_slippery_gems &&
4762 engine_version > VERSION_IDENT(2,0,1,0)));
4764 // special EM style explosion behaviour regarding chain reactions
4765 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4766 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4767 level.em_explodes_by_fire);
4770 // this is needed because some graphics depend on element properties
4771 if (game_status == GAME_MODE_PLAYING)
4772 InitElementGraphicInfo();
4775 void InitElementPropertiesGfxElement(void)
4779 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4781 struct ElementInfo *ei = &element_info[i];
4783 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4787 static void InitGlobal(void)
4792 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4794 // check if element_name_info entry defined for each element in "main.h"
4795 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4796 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4798 element_info[i].token_name = element_name_info[i].token_name;
4799 element_info[i].class_name = element_name_info[i].class_name;
4800 element_info[i].editor_description= element_name_info[i].editor_description;
4803 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4805 // check if global_anim_name_info defined for each entry in "main.h"
4806 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4807 global_anim_name_info[i].token_name == NULL)
4808 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4810 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4813 // create hash from image config list
4814 image_config_hash = newSetupFileHash();
4815 for (i = 0; image_config[i].token != NULL; i++)
4816 setHashEntry(image_config_hash,
4817 image_config[i].token,
4818 image_config[i].value);
4820 // create hash from element token list
4821 element_token_hash = newSetupFileHash();
4822 for (i = 0; element_name_info[i].token_name != NULL; i++)
4823 setHashEntry(element_token_hash,
4824 element_name_info[i].token_name,
4827 // create hash from graphic token list
4828 graphic_token_hash = newSetupFileHash();
4829 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4830 if (strSuffix(image_config[i].value, ".png") ||
4831 strSuffix(image_config[i].value, ".pcx") ||
4832 strSuffix(image_config[i].value, ".wav") ||
4833 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4834 setHashEntry(graphic_token_hash,
4835 image_config[i].token,
4836 int2str(graphic++, 0));
4838 // create hash from font token list
4839 font_token_hash = newSetupFileHash();
4840 for (i = 0; font_info[i].token_name != NULL; i++)
4841 setHashEntry(font_token_hash,
4842 font_info[i].token_name,
4845 // set default filenames for all cloned graphics in static configuration
4846 for (i = 0; image_config[i].token != NULL; i++)
4848 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4850 char *token = image_config[i].token;
4851 char *token_clone_from = getStringCat2(token, ".clone_from");
4852 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4854 if (token_cloned != NULL)
4856 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4858 if (value_cloned != NULL)
4860 // set default filename in static configuration
4861 image_config[i].value = value_cloned;
4863 // set default filename in image config hash
4864 setHashEntry(image_config_hash, token, value_cloned);
4868 free(token_clone_from);
4872 // always start with reliable default values (all elements)
4873 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4874 ActiveElement[i] = i;
4876 // now add all entries that have an active state (active elements)
4877 for (i = 0; element_with_active_state[i].element != -1; i++)
4879 int element = element_with_active_state[i].element;
4880 int element_active = element_with_active_state[i].element_active;
4882 ActiveElement[element] = element_active;
4885 // always start with reliable default values (all buttons)
4886 for (i = 0; i < NUM_IMAGE_FILES; i++)
4887 ActiveButton[i] = i;
4889 // now add all entries that have an active state (active buttons)
4890 for (i = 0; button_with_active_state[i].button != -1; i++)
4892 int button = button_with_active_state[i].button;
4893 int button_active = button_with_active_state[i].button_active;
4895 ActiveButton[button] = button_active;
4898 // always start with reliable default values (all fonts)
4899 for (i = 0; i < NUM_FONTS; i++)
4902 // now add all entries that have an active state (active fonts)
4903 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4905 int font = font_with_active_state[i].font_nr;
4906 int font_active = font_with_active_state[i].font_nr_active;
4908 ActiveFont[font] = font_active;
4911 global.autoplay_leveldir = NULL;
4912 global.convert_leveldir = NULL;
4913 global.create_images_dir = NULL;
4915 global.frames_per_second = 0;
4916 global.show_frames_per_second = FALSE;
4918 global.border_status = GAME_MODE_LOADING;
4919 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4921 global.use_envelope_request = FALSE;
4924 static void Execute_Command(char *command)
4928 if (strEqual(command, "print graphicsinfo.conf"))
4930 Print("# You can configure additional/alternative image files here.\n");
4931 Print("# (The entries below are default and therefore commented out.)\n");
4933 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4935 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4938 for (i = 0; image_config[i].token != NULL; i++)
4939 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4940 image_config[i].value));
4944 else if (strEqual(command, "print soundsinfo.conf"))
4946 Print("# You can configure additional/alternative sound files here.\n");
4947 Print("# (The entries below are default and therefore commented out.)\n");
4949 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4951 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4954 for (i = 0; sound_config[i].token != NULL; i++)
4955 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4956 sound_config[i].value));
4960 else if (strEqual(command, "print musicinfo.conf"))
4962 Print("# You can configure additional/alternative music files here.\n");
4963 Print("# (The entries below are default and therefore commented out.)\n");
4965 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4967 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4970 for (i = 0; music_config[i].token != NULL; i++)
4971 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4972 music_config[i].value));
4976 else if (strEqual(command, "print editorsetup.conf"))
4978 Print("# You can configure your personal editor element list here.\n");
4979 Print("# (The entries below are default and therefore commented out.)\n");
4982 // this is needed to be able to check element list for cascade elements
4983 InitElementPropertiesStatic();
4984 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4986 PrintEditorElementList();
4990 else if (strEqual(command, "print helpanim.conf"))
4992 Print("# You can configure different element help animations here.\n");
4993 Print("# (The entries below are default and therefore commented out.)\n");
4996 for (i = 0; helpanim_config[i].token != NULL; i++)
4998 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4999 helpanim_config[i].value));
5001 if (strEqual(helpanim_config[i].token, "end"))
5007 else if (strEqual(command, "print helptext.conf"))
5009 Print("# You can configure different element help text here.\n");
5010 Print("# (The entries below are default and therefore commented out.)\n");
5013 for (i = 0; helptext_config[i].token != NULL; i++)
5014 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5015 helptext_config[i].value));
5019 else if (strPrefix(command, "dump level "))
5021 char *filename = &command[11];
5023 if (!fileExists(filename))
5024 Error(ERR_EXIT, "cannot open file '%s'", filename);
5026 LoadLevelFromFilename(&level, filename);
5031 else if (strPrefix(command, "dump tape "))
5033 char *filename = &command[10];
5035 if (!fileExists(filename))
5036 Error(ERR_EXIT, "cannot open file '%s'", filename);
5038 LoadTapeFromFilename(filename);
5043 else if (strPrefix(command, "autotest ") ||
5044 strPrefix(command, "autoplay ") ||
5045 strPrefix(command, "autoffwd ") ||
5046 strPrefix(command, "autowarp "))
5048 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5050 global.autoplay_mode =
5051 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5052 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5053 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5054 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5055 AUTOPLAY_MODE_NONE);
5057 while (*str_ptr != '\0') // continue parsing string
5059 // cut leading whitespace from string, replace it by string terminator
5060 while (*str_ptr == ' ' || *str_ptr == '\t')
5063 if (*str_ptr == '\0') // end of string reached
5066 if (global.autoplay_leveldir == NULL) // read level set string
5068 global.autoplay_leveldir = str_ptr;
5069 global.autoplay_all = TRUE; // default: play all tapes
5071 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5072 global.autoplay_level[i] = FALSE;
5074 else // read level number string
5076 int level_nr = atoi(str_ptr); // get level_nr value
5078 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5079 global.autoplay_level[level_nr] = TRUE;
5081 global.autoplay_all = FALSE;
5084 // advance string pointer to the next whitespace (or end of string)
5085 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5089 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5090 program.headless = TRUE;
5092 else if (strPrefix(command, "convert "))
5094 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5095 char *str_ptr = strchr(str_copy, ' ');
5097 global.convert_leveldir = str_copy;
5098 global.convert_level_nr = -1;
5100 if (str_ptr != NULL) // level number follows
5102 *str_ptr++ = '\0'; // terminate leveldir string
5103 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5106 program.headless = TRUE;
5108 else if (strPrefix(command, "create images "))
5110 global.create_images_dir = getStringCopy(&command[14]);
5112 if (access(global.create_images_dir, W_OK) != 0)
5113 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5114 global.create_images_dir);
5116 else if (strPrefix(command, "create CE image "))
5118 CreateCustomElementImages(&command[16]);
5124 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5127 // disable networking if any valid command was recognized
5128 options.network = setup.network_mode = FALSE;
5131 static void InitSetup(void)
5133 LoadSetup(); // global setup info
5134 LoadSetup_AutoSetup(); // global auto setup info
5136 // set some options from setup file
5138 if (setup.options.verbose)
5139 options.verbose = TRUE;
5141 if (setup.debug.show_frames_per_second)
5142 global.show_frames_per_second = TRUE;
5145 static void InitGameInfo(void)
5147 game.restart_level = FALSE;
5148 game.restart_game_message = NULL;
5149 game.request_active = FALSE;
5152 static void InitPlayerInfo(void)
5156 // choose default local player
5157 local_player = &stored_player[0];
5159 for (i = 0; i < MAX_PLAYERS; i++)
5161 stored_player[i].connected_locally = FALSE;
5162 stored_player[i].connected_network = FALSE;
5165 local_player->connected_locally = TRUE;
5168 static void InitArtworkInfo(void)
5173 static char *get_string_in_brackets(char *string)
5175 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5177 sprintf(string_in_brackets, "[%s]", string);
5179 return string_in_brackets;
5182 static char *get_level_id_suffix(int id_nr)
5184 char *id_suffix = checked_malloc(1 + 3 + 1);
5186 if (id_nr < 0 || id_nr > 999)
5189 sprintf(id_suffix, ".%03d", id_nr);
5194 static void InitArtworkConfig(void)
5196 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5198 NUM_GLOBAL_ANIM_TOKENS + 1];
5199 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5200 NUM_GLOBAL_ANIM_TOKENS + 1];
5201 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5202 NUM_GLOBAL_ANIM_TOKENS + 1];
5203 static char *action_id_suffix[NUM_ACTIONS + 1];
5204 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5205 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5206 static char *level_id_suffix[MAX_LEVELS + 1];
5207 static char *dummy[1] = { NULL };
5208 static char *ignore_generic_tokens[] =
5213 "program_copyright",
5218 static char **ignore_image_tokens;
5219 static char **ignore_sound_tokens;
5220 static char **ignore_music_tokens;
5221 int num_ignore_generic_tokens;
5222 int num_ignore_image_tokens;
5223 int num_ignore_sound_tokens;
5224 int num_ignore_music_tokens;
5227 // dynamically determine list of generic tokens to be ignored
5228 num_ignore_generic_tokens = 0;
5229 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5230 num_ignore_generic_tokens++;
5232 // dynamically determine list of image tokens to be ignored
5233 num_ignore_image_tokens = num_ignore_generic_tokens;
5234 for (i = 0; image_config_vars[i].token != NULL; i++)
5235 num_ignore_image_tokens++;
5236 ignore_image_tokens =
5237 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5238 for (i = 0; i < num_ignore_generic_tokens; i++)
5239 ignore_image_tokens[i] = ignore_generic_tokens[i];
5240 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5241 ignore_image_tokens[num_ignore_generic_tokens + i] =
5242 image_config_vars[i].token;
5243 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5245 // dynamically determine list of sound tokens to be ignored
5246 num_ignore_sound_tokens = num_ignore_generic_tokens;
5247 ignore_sound_tokens =
5248 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5249 for (i = 0; i < num_ignore_generic_tokens; i++)
5250 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5251 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5253 // dynamically determine list of music tokens to be ignored
5254 num_ignore_music_tokens = num_ignore_generic_tokens;
5255 ignore_music_tokens =
5256 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5257 for (i = 0; i < num_ignore_generic_tokens; i++)
5258 ignore_music_tokens[i] = ignore_generic_tokens[i];
5259 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5261 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5262 image_id_prefix[i] = element_info[i].token_name;
5263 for (i = 0; i < NUM_FONTS; i++)
5264 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5265 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5266 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5267 global_anim_info[i].token_name;
5268 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5270 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5271 sound_id_prefix[i] = element_info[i].token_name;
5272 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5273 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5274 get_string_in_brackets(element_info[i].class_name);
5275 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5276 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5277 global_anim_info[i].token_name;
5278 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5280 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5281 music_id_prefix[i] = music_prefix_info[i].prefix;
5282 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5283 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5284 global_anim_info[i].token_name;
5285 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5287 for (i = 0; i < NUM_ACTIONS; i++)
5288 action_id_suffix[i] = element_action_info[i].suffix;
5289 action_id_suffix[NUM_ACTIONS] = NULL;
5291 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5292 direction_id_suffix[i] = element_direction_info[i].suffix;
5293 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5295 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5296 special_id_suffix[i] = special_suffix_info[i].suffix;
5297 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5299 for (i = 0; i < MAX_LEVELS; i++)
5300 level_id_suffix[i] = get_level_id_suffix(i);
5301 level_id_suffix[MAX_LEVELS] = NULL;
5303 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5304 image_id_prefix, action_id_suffix, direction_id_suffix,
5305 special_id_suffix, ignore_image_tokens);
5306 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5307 sound_id_prefix, action_id_suffix, dummy,
5308 special_id_suffix, ignore_sound_tokens);
5309 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5310 music_id_prefix, action_id_suffix, special_id_suffix,
5311 level_id_suffix, ignore_music_tokens);
5314 static void InitMixer(void)
5321 static void InitVideoOverlay(void)
5323 // if virtual buttons are not loaded from setup file, repeat initializing
5324 // virtual buttons grid with default values now that video is initialized
5325 if (!setup.touch.grid_initialized)
5328 InitTileCursorInfo();
5332 void InitGfxBuffers(void)
5334 static int win_xsize_last = -1;
5335 static int win_ysize_last = -1;
5337 // create additional image buffers for double-buffering and cross-fading
5339 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5341 // used to temporarily store the backbuffer -- only re-create if changed
5342 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5343 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5345 win_xsize_last = WIN_XSIZE;
5346 win_ysize_last = WIN_YSIZE;
5349 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5350 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5351 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5352 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5354 // initialize screen properties
5355 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5356 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5358 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5359 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5360 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5361 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5362 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5363 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5365 // required if door size definitions have changed
5366 InitGraphicCompatibilityInfo_Doors();
5368 InitGfxBuffers_EM();
5369 InitGfxBuffers_SP();
5372 static void InitGfx(void)
5374 struct GraphicInfo *graphic_info_last = graphic_info;
5375 char *filename_font_initial = NULL;
5376 char *filename_anim_initial = NULL;
5377 Bitmap *bitmap_font_initial = NULL;
5380 // determine settings for initial font (for displaying startup messages)
5381 for (i = 0; image_config[i].token != NULL; i++)
5383 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5385 char font_token[128];
5388 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5389 len_font_token = strlen(font_token);
5391 if (strEqual(image_config[i].token, font_token))
5392 filename_font_initial = image_config[i].value;
5393 else if (strlen(image_config[i].token) > len_font_token &&
5394 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5396 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5397 font_initial[j].src_x = atoi(image_config[i].value);
5398 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5399 font_initial[j].src_y = atoi(image_config[i].value);
5400 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5401 font_initial[j].width = atoi(image_config[i].value);
5402 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5403 font_initial[j].height = atoi(image_config[i].value);
5408 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5410 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5411 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5414 if (filename_font_initial == NULL) // should not happen
5415 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5418 InitGfxCustomArtworkInfo();
5419 InitGfxOtherSettings();
5421 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5423 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5424 font_initial[j].bitmap = bitmap_font_initial;
5426 InitFontGraphicInfo();
5430 DrawInitText("Loading graphics", 120, FC_GREEN);
5432 // initialize settings for busy animation with default values
5433 int parameter[NUM_GFX_ARGS];
5434 for (i = 0; i < NUM_GFX_ARGS; i++)
5435 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5436 image_config_suffix[i].token,
5437 image_config_suffix[i].type);
5439 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5440 int len_anim_token = strlen(anim_token);
5442 // read settings for busy animation from default custom artwork config
5443 char *gfx_config_filename = getPath3(options.graphics_directory,
5445 GRAPHICSINFO_FILENAME);
5447 if (fileExists(gfx_config_filename))
5449 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5451 if (setup_file_hash)
5453 char *filename = getHashEntry(setup_file_hash, anim_token);
5457 filename_anim_initial = getStringCopy(filename);
5459 for (j = 0; image_config_suffix[j].token != NULL; j++)
5461 int type = image_config_suffix[j].type;
5462 char *suffix = image_config_suffix[j].token;
5463 char *token = getStringCat2(anim_token, suffix);
5464 char *value = getHashEntry(setup_file_hash, token);
5466 checked_free(token);
5469 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5473 freeSetupFileHash(setup_file_hash);
5477 if (filename_anim_initial == NULL)
5479 // read settings for busy animation from static default artwork config
5480 for (i = 0; image_config[i].token != NULL; i++)
5482 if (strEqual(image_config[i].token, anim_token))
5483 filename_anim_initial = getStringCopy(image_config[i].value);
5484 else if (strlen(image_config[i].token) > len_anim_token &&
5485 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5487 for (j = 0; image_config_suffix[j].token != NULL; j++)
5489 if (strEqual(&image_config[i].token[len_anim_token],
5490 image_config_suffix[j].token))
5492 get_graphic_parameter_value(image_config[i].value,
5493 image_config_suffix[j].token,
5494 image_config_suffix[j].type);
5500 if (filename_anim_initial == NULL) // should not happen
5501 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5503 anim_initial.bitmaps =
5504 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5506 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5507 LoadCustomImage(filename_anim_initial);
5509 checked_free(filename_anim_initial);
5511 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5513 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5515 graphic_info = graphic_info_last;
5517 init.busy.width = anim_initial.width;
5518 init.busy.height = anim_initial.height;
5520 InitMenuDesignSettings_Static();
5522 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5523 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5524 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5525 InitGfxDrawTileCursorFunction(DrawTileCursor);
5527 gfx.fade_border_source_status = global.border_status;
5528 gfx.fade_border_target_status = global.border_status;
5529 gfx.masked_border_bitmap_ptr = backbuffer;
5531 // use copy of busy animation to prevent change while reloading artwork
5535 static void InitGfxBackground(void)
5537 fieldbuffer = bitmap_db_field;
5538 SetDrawtoField(DRAW_TO_BACKBUFFER);
5540 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5542 redraw_mask = REDRAW_ALL;
5545 static void InitLevelInfo(void)
5547 LoadLevelInfo(); // global level info
5548 LoadLevelSetup_LastSeries(); // last played series info
5549 LoadLevelSetup_SeriesInfo(); // last played level info
5551 if (global.autoplay_leveldir &&
5552 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5554 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5555 global.autoplay_leveldir);
5556 if (leveldir_current == NULL)
5557 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5560 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5563 static void InitLevelArtworkInfo(void)
5565 LoadLevelArtworkInfo();
5568 static void InitImages(void)
5570 print_timestamp_init("InitImages");
5573 printf("::: leveldir_current->identifier == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5575 printf("::: leveldir_current->graphics_path == '%s'\n",
5576 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5577 printf("::: leveldir_current->graphics_set == '%s'\n",
5578 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5579 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5580 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5583 setLevelArtworkDir(artwork.gfx_first);
5586 printf("::: leveldir_current->identifier == '%s'\n",
5587 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5588 printf("::: leveldir_current->graphics_path == '%s'\n",
5589 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5590 printf("::: leveldir_current->graphics_set == '%s'\n",
5591 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5592 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5593 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5597 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5598 leveldir_current->identifier,
5599 artwork.gfx_current_identifier,
5600 artwork.gfx_current->identifier,
5601 leveldir_current->graphics_set,
5602 leveldir_current->graphics_path);
5605 UPDATE_BUSY_STATE();
5607 ReloadCustomImages();
5608 print_timestamp_time("ReloadCustomImages");
5610 UPDATE_BUSY_STATE();
5612 LoadCustomElementDescriptions();
5613 print_timestamp_time("LoadCustomElementDescriptions");
5615 UPDATE_BUSY_STATE();
5617 LoadMenuDesignSettings();
5618 print_timestamp_time("LoadMenuDesignSettings");
5620 UPDATE_BUSY_STATE();
5622 ReinitializeGraphics();
5623 print_timestamp_time("ReinitializeGraphics");
5625 LoadMenuDesignSettings_AfterGraphics();
5626 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5628 UPDATE_BUSY_STATE();
5630 print_timestamp_done("InitImages");
5633 static void InitSound(char *identifier)
5635 print_timestamp_init("InitSound");
5637 if (identifier == NULL)
5638 identifier = artwork.snd_current->identifier;
5640 // set artwork path to send it to the sound server process
5641 setLevelArtworkDir(artwork.snd_first);
5643 InitReloadCustomSounds(identifier);
5644 print_timestamp_time("InitReloadCustomSounds");
5646 ReinitializeSounds();
5647 print_timestamp_time("ReinitializeSounds");
5649 print_timestamp_done("InitSound");
5652 static void InitMusic(char *identifier)
5654 print_timestamp_init("InitMusic");
5656 if (identifier == NULL)
5657 identifier = artwork.mus_current->identifier;
5659 // set artwork path to send it to the sound server process
5660 setLevelArtworkDir(artwork.mus_first);
5662 InitReloadCustomMusic(identifier);
5663 print_timestamp_time("InitReloadCustomMusic");
5665 ReinitializeMusic();
5666 print_timestamp_time("ReinitializeMusic");
5668 print_timestamp_done("InitMusic");
5671 static void InitArtworkDone(void)
5673 if (program.headless)
5676 InitGlobalAnimations();
5679 static void InitNetworkSettings(void)
5681 boolean network_enabled = (options.network || setup.network_mode);
5682 char *network_server = (options.server_host != NULL ? options.server_host :
5683 setup.network_server_hostname);
5685 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5686 network_server = NULL;
5688 InitNetworkInfo(network_enabled,
5692 options.server_port);
5695 void InitNetworkServer(void)
5697 if (!network.enabled || network.connected)
5700 LimitScreenUpdates(FALSE);
5702 if (game_status == GAME_MODE_LOADING)
5705 if (!ConnectToServer(network.server_host, network.server_port))
5707 network.enabled = FALSE;
5709 setup.network_mode = FALSE;
5713 SendToServer_ProtocolVersion();
5714 SendToServer_PlayerName(setup.player_name);
5715 SendToServer_NrWanted(setup.network_player_nr + 1);
5717 network.connected = TRUE;
5720 // short time to recognize result of network initialization
5721 if (game_status == GAME_MODE_LOADING)
5722 Delay_WithScreenUpdates(1000);
5725 static boolean CheckArtworkConfigForCustomElements(char *filename)
5727 SetupFileHash *setup_file_hash;
5728 boolean redefined_ce_found = FALSE;
5730 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5732 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5734 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5736 char *token = HASH_ITERATION_TOKEN(itr);
5738 if (strPrefix(token, "custom_"))
5740 redefined_ce_found = TRUE;
5745 END_HASH_ITERATION(setup_file_hash, itr)
5747 freeSetupFileHash(setup_file_hash);
5750 return redefined_ce_found;
5753 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5755 char *filename_base, *filename_local;
5756 boolean redefined_ce_found = FALSE;
5758 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5761 printf("::: leveldir_current->identifier == '%s'\n",
5762 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5763 printf("::: leveldir_current->graphics_path == '%s'\n",
5764 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5765 printf("::: leveldir_current->graphics_set == '%s'\n",
5766 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5767 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5768 leveldir_current == NULL ? "[NULL]" :
5769 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5772 // first look for special artwork configured in level series config
5773 filename_base = getCustomArtworkLevelConfigFilename(type);
5776 printf("::: filename_base == '%s'\n", filename_base);
5779 if (fileExists(filename_base))
5780 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5782 filename_local = getCustomArtworkConfigFilename(type);
5785 printf("::: filename_local == '%s'\n", filename_local);
5788 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5789 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5792 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5795 return redefined_ce_found;
5798 static void InitOverrideArtwork(void)
5800 boolean redefined_ce_found = FALSE;
5802 // to check if this level set redefines any CEs, do not use overriding
5803 gfx.override_level_graphics = FALSE;
5804 gfx.override_level_sounds = FALSE;
5805 gfx.override_level_music = FALSE;
5807 // now check if this level set has definitions for custom elements
5808 if (setup.override_level_graphics == AUTO ||
5809 setup.override_level_sounds == AUTO ||
5810 setup.override_level_music == AUTO)
5811 redefined_ce_found =
5812 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5813 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5814 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5817 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5820 if (redefined_ce_found)
5822 // this level set has CE definitions: change "AUTO" to "FALSE"
5823 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5824 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5825 gfx.override_level_music = (setup.override_level_music == TRUE);
5829 // this level set has no CE definitions: change "AUTO" to "TRUE"
5830 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5831 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5832 gfx.override_level_music = (setup.override_level_music != FALSE);
5836 printf("::: => %d, %d, %d\n",
5837 gfx.override_level_graphics,
5838 gfx.override_level_sounds,
5839 gfx.override_level_music);
5843 static char *getNewArtworkIdentifier(int type)
5845 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5846 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5847 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5848 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5849 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5850 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5851 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5852 char *leveldir_identifier = leveldir_current->identifier;
5853 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5854 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5855 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5856 char *artwork_current_identifier;
5857 char *artwork_new_identifier = NULL; // default: nothing has changed
5859 // leveldir_current may be invalid (level group, parent link)
5860 if (!validLevelSeries(leveldir_current))
5863 /* 1st step: determine artwork set to be activated in descending order:
5864 --------------------------------------------------------------------
5865 1. setup artwork (when configured to override everything else)
5866 2. artwork set configured in "levelinfo.conf" of current level set
5867 (artwork in level directory will have priority when loading later)
5868 3. artwork in level directory (stored in artwork sub-directory)
5869 4. setup artwork (currently configured in setup menu) */
5871 if (setup_override_artwork)
5872 artwork_current_identifier = setup_artwork_set;
5873 else if (leveldir_artwork_set != NULL)
5874 artwork_current_identifier = leveldir_artwork_set;
5875 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5876 artwork_current_identifier = leveldir_identifier;
5878 artwork_current_identifier = setup_artwork_set;
5881 /* 2nd step: check if it is really needed to reload artwork set
5882 ------------------------------------------------------------ */
5884 // ---------- reload if level set and also artwork set has changed ----------
5885 if (leveldir_current_identifier[type] != leveldir_identifier &&
5886 (last_has_level_artwork_set[type] || has_level_artwork_set))
5887 artwork_new_identifier = artwork_current_identifier;
5889 leveldir_current_identifier[type] = leveldir_identifier;
5890 last_has_level_artwork_set[type] = has_level_artwork_set;
5892 // ---------- reload if "override artwork" setting has changed --------------
5893 if (last_override_level_artwork[type] != setup_override_artwork)
5894 artwork_new_identifier = artwork_current_identifier;
5896 last_override_level_artwork[type] = setup_override_artwork;
5898 // ---------- reload if current artwork identifier has changed --------------
5899 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5900 artwork_current_identifier))
5901 artwork_new_identifier = artwork_current_identifier;
5903 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5905 // ---------- do not reload directly after starting -------------------------
5906 if (!initialized[type])
5907 artwork_new_identifier = NULL;
5909 initialized[type] = TRUE;
5911 return artwork_new_identifier;
5914 void ReloadCustomArtwork(int force_reload)
5916 int last_game_status = game_status; // save current game status
5917 char *gfx_new_identifier;
5918 char *snd_new_identifier;
5919 char *mus_new_identifier;
5920 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5921 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5922 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5923 boolean reload_needed;
5925 InitOverrideArtwork();
5927 force_reload_gfx |= AdjustGraphicsForEMC();
5929 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5930 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5931 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5933 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5934 snd_new_identifier != NULL || force_reload_snd ||
5935 mus_new_identifier != NULL || force_reload_mus);
5940 print_timestamp_init("ReloadCustomArtwork");
5942 SetGameStatus(GAME_MODE_LOADING);
5944 FadeOut(REDRAW_ALL);
5946 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5947 print_timestamp_time("ClearRectangle");
5951 if (gfx_new_identifier != NULL || force_reload_gfx)
5954 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5955 artwork.gfx_current_identifier,
5957 artwork.gfx_current->identifier,
5958 leveldir_current->graphics_set);
5962 print_timestamp_time("InitImages");
5965 if (snd_new_identifier != NULL || force_reload_snd)
5967 InitSound(snd_new_identifier);
5968 print_timestamp_time("InitSound");
5971 if (mus_new_identifier != NULL || force_reload_mus)
5973 InitMusic(mus_new_identifier);
5974 print_timestamp_time("InitMusic");
5979 SetGameStatus(last_game_status); // restore current game status
5981 init_last = init; // switch to new busy animation
5983 FadeOut(REDRAW_ALL);
5985 RedrawGlobalBorder();
5987 // force redraw of (open or closed) door graphics
5988 SetDoorState(DOOR_OPEN_ALL);
5989 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5991 FadeSetEnterScreen();
5992 FadeSkipNextFadeOut();
5994 print_timestamp_done("ReloadCustomArtwork");
5996 LimitScreenUpdates(FALSE);
5999 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6001 if (global.autoplay_leveldir == NULL)
6002 KeyboardAutoRepeatOff();
6005 void DisplayExitMessage(char *format, va_list ap)
6007 // also check for initialized video (headless flag may be temporarily unset)
6008 if (program.headless || !video.initialized)
6011 // check if draw buffer and fonts for exit message are already available
6012 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6015 int font_1 = FC_RED;
6016 int font_2 = FC_YELLOW;
6017 int font_3 = FC_BLUE;
6018 int font_width = getFontWidth(font_2);
6019 int font_height = getFontHeight(font_2);
6022 int sxsize = WIN_XSIZE - 2 * sx;
6023 int sysize = WIN_YSIZE - 2 * sy;
6024 int line_length = sxsize / font_width;
6025 int max_lines = sysize / font_height;
6026 int num_lines_printed;
6030 gfx.sxsize = sxsize;
6031 gfx.sysize = sysize;
6035 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6037 DrawTextSCentered(sy, font_1, "Fatal error:");
6038 sy += 3 * font_height;;
6041 DrawTextBufferVA(sx, sy, format, ap, font_2,
6042 line_length, line_length, max_lines,
6043 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6044 sy += (num_lines_printed + 3) * font_height;
6046 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6047 sy += 3 * font_height;
6050 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6051 line_length, line_length, max_lines,
6052 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6054 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6056 redraw_mask = REDRAW_ALL;
6058 // force drawing exit message even if screen updates are currently limited
6059 LimitScreenUpdates(FALSE);
6063 // deactivate toons on error message screen
6064 setup.toons = FALSE;
6066 WaitForEventToContinue();
6070 // ============================================================================
6072 // ============================================================================
6076 print_timestamp_init("OpenAll");
6078 SetGameStatus(GAME_MODE_LOADING);
6082 InitGlobal(); // initialize some global variables
6084 print_timestamp_time("[init global stuff]");
6088 print_timestamp_time("[init setup/config stuff (1)]");
6092 if (options.execute_command)
6093 Execute_Command(options.execute_command);
6095 InitNetworkSettings();
6099 if (network.serveronly)
6101 #if defined(PLATFORM_UNIX)
6102 NetworkServer(network.server_port, TRUE);
6104 Error(ERR_WARN, "networking only supported in Unix version");
6107 exit(0); // never reached, server loops forever
6111 print_timestamp_time("[init setup/config stuff (2)]");
6113 print_timestamp_time("[init setup/config stuff (3)]");
6114 InitArtworkInfo(); // needed before loading gfx, sound & music
6115 print_timestamp_time("[init setup/config stuff (4)]");
6116 InitArtworkConfig(); // needed before forking sound child process
6117 print_timestamp_time("[init setup/config stuff (5)]");
6119 print_timestamp_time("[init setup/config stuff (6)]");
6121 InitRND(NEW_RANDOMIZE);
6122 InitSimpleRandom(NEW_RANDOMIZE);
6126 print_timestamp_time("[init setup/config stuff]");
6128 InitVideoDefaults();
6130 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6133 InitEventFilter(FilterMouseMotionEvents);
6135 print_timestamp_time("[init video stuff]");
6137 InitElementPropertiesStatic();
6138 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6139 InitElementPropertiesGfxElement();
6141 print_timestamp_time("[init element properties stuff]");
6145 print_timestamp_time("InitGfx");
6148 print_timestamp_time("InitLevelInfo");
6150 InitLevelArtworkInfo();
6151 print_timestamp_time("InitLevelArtworkInfo");
6153 InitOverrideArtwork(); // needs to know current level directory
6154 print_timestamp_time("InitOverrideArtwork");
6156 InitImages(); // needs to know current level directory
6157 print_timestamp_time("InitImages");
6159 InitSound(NULL); // needs to know current level directory
6160 print_timestamp_time("InitSound");
6162 InitMusic(NULL); // needs to know current level directory
6163 print_timestamp_time("InitMusic");
6167 InitGfxBackground();
6173 if (global.autoplay_leveldir)
6178 else if (global.convert_leveldir)
6183 else if (global.create_images_dir)
6185 CreateLevelSketchImages();
6189 InitNetworkServer();
6191 SetGameStatus(GAME_MODE_MAIN);
6193 FadeSetEnterScreen();
6194 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6195 FadeSkipNextFadeOut();
6197 print_timestamp_time("[post-artwork]");
6199 print_timestamp_done("OpenAll");
6204 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6206 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6207 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6208 #if defined(PLATFORM_ANDROID)
6209 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6210 SDL_AndroidGetInternalStoragePath());
6211 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6212 SDL_AndroidGetExternalStoragePath());
6213 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6214 (SDL_AndroidGetExternalStorageState() &
6215 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6216 SDL_AndroidGetExternalStorageState() &
6217 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6222 void CloseAllAndExit(int exit_value)
6227 CloseAudio(); // called after freeing sounds (needed for SDL)
6235 // set a flag to tell the network server thread to quit and wait for it
6236 // using SDL_WaitThread()
6238 // Code used with SDL 1.2:
6239 // if (network_server) // terminate network server
6240 // SDL_KillThread(server_thread);
6242 CloseVideoDisplay();
6243 ClosePlatformDependentStuff();
6245 if (exit_value != 0 && !options.execute_command)
6247 // fall back to default level set (current set may have caused an error)
6248 SaveLevelSetup_LastSeries_Deactivate();
6250 // tell user where to find error log file which may contain more details
6251 // (error notification now directly displayed on screen inside R'n'D
6252 // NotifyUserAboutErrorFile(); // currently only works for Windows