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,
289 FreeAllImageTextures();
291 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
292 CreateImageTextures(i);
294 for (i = 0; i < MAX_NUM_TOONS; i++)
295 CreateImageTextures(IMG_TOON_1 + i);
297 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
299 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
301 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
303 int graphic = global_anim_info[i].graphic[j][k];
305 if (graphic == IMG_UNDEFINED)
308 CreateImageTextures(graphic);
313 for (i = 0; texture_graphics[i] > -1; i++)
314 CreateImageTextures(texture_graphics[i]);
318 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
319 void SetBitmaps_EM(Bitmap **em_bitmap)
321 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
322 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
327 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
328 void SetBitmaps_SP(Bitmap **sp_bitmap)
330 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
334 static int getFontBitmapID(int font_nr)
338 // (special case: do not use special font for GAME_MODE_LOADING)
339 if (game_status >= GAME_MODE_TITLE_INITIAL &&
340 game_status <= GAME_MODE_PSEUDO_PREVIEW)
341 special = game_status;
342 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
343 special = GFX_SPECIAL_ARG_MAIN;
346 return font_info[font_nr].special_bitmap_id[special];
351 static int getFontFromToken(char *token)
353 char *value = getHashEntry(font_token_hash, token);
358 // if font not found, use reliable default value
359 return FONT_INITIAL_1;
362 static void InitFontGraphicInfo(void)
364 static struct FontBitmapInfo *font_bitmap_info = NULL;
365 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
366 int num_property_mappings = getImageListPropertyMappingSize();
367 int num_font_bitmaps = NUM_FONTS;
370 if (graphic_info == NULL) // still at startup phase
372 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
373 getFontBitmapID, getFontFromToken);
378 // ---------- initialize font graphic definitions ----------
380 // always start with reliable default values (normal font graphics)
381 for (i = 0; i < NUM_FONTS; i++)
382 font_info[i].graphic = IMG_FONT_INITIAL_1;
384 // initialize normal font/graphic mapping from static configuration
385 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
387 int font_nr = font_to_graphic[i].font_nr;
388 int special = font_to_graphic[i].special;
389 int graphic = font_to_graphic[i].graphic;
394 font_info[font_nr].graphic = graphic;
397 // always start with reliable default values (special font graphics)
398 for (i = 0; i < NUM_FONTS; i++)
400 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
402 font_info[i].special_graphic[j] = font_info[i].graphic;
403 font_info[i].special_bitmap_id[j] = i;
407 // initialize special font/graphic mapping from static configuration
408 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
410 int font_nr = font_to_graphic[i].font_nr;
411 int special = font_to_graphic[i].special;
412 int graphic = font_to_graphic[i].graphic;
413 int base_graphic = font2baseimg(font_nr);
415 if (IS_SPECIAL_GFX_ARG(special))
417 boolean base_redefined =
418 getImageListEntryFromImageID(base_graphic)->redefined;
419 boolean special_redefined =
420 getImageListEntryFromImageID(graphic)->redefined;
421 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
423 /* if the base font ("font.title_1", for example) has been redefined,
424 but not the special font ("font.title_1.LEVELS", for example), do not
425 use an existing (in this case considered obsolete) special font
426 anymore, but use the automatically determined default font */
427 /* special case: cloned special fonts must be explicitly redefined,
428 but are not automatically redefined by redefining base font */
429 if (base_redefined && !special_redefined && !special_cloned)
432 font_info[font_nr].special_graphic[special] = graphic;
433 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
438 // initialize special font/graphic mapping from dynamic configuration
439 for (i = 0; i < num_property_mappings; i++)
441 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
442 int special = property_mapping[i].ext3_index;
443 int graphic = property_mapping[i].artwork_index;
445 if (font_nr < 0 || font_nr >= NUM_FONTS)
448 if (IS_SPECIAL_GFX_ARG(special))
450 font_info[font_nr].special_graphic[special] = graphic;
451 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
456 /* correct special font/graphic mapping for cloned fonts for downwards
457 compatibility of PREVIEW fonts -- this is only needed for implicit
458 redefinition of special font by redefined base font, and only if other
459 fonts are cloned from this special font (like in the "Zelda" level set) */
460 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
462 int font_nr = font_to_graphic[i].font_nr;
463 int special = font_to_graphic[i].special;
464 int graphic = font_to_graphic[i].graphic;
466 if (IS_SPECIAL_GFX_ARG(special))
468 boolean special_redefined =
469 getImageListEntryFromImageID(graphic)->redefined;
470 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
472 if (special_cloned && !special_redefined)
476 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
478 int font_nr2 = font_to_graphic[j].font_nr;
479 int special2 = font_to_graphic[j].special;
480 int graphic2 = font_to_graphic[j].graphic;
482 if (IS_SPECIAL_GFX_ARG(special2) &&
483 graphic2 == graphic_info[graphic].clone_from)
485 font_info[font_nr].special_graphic[special] =
486 font_info[font_nr2].special_graphic[special2];
487 font_info[font_nr].special_bitmap_id[special] =
488 font_info[font_nr2].special_bitmap_id[special2];
495 // reset non-redefined ".active" font graphics if normal font is redefined
496 // (this different treatment is needed because normal and active fonts are
497 // independently defined ("active" is not a property of font definitions!)
498 for (i = 0; i < NUM_FONTS; i++)
500 int font_nr_base = i;
501 int font_nr_active = FONT_ACTIVE(font_nr_base);
503 // check only those fonts with exist as normal and ".active" variant
504 if (font_nr_base != font_nr_active)
506 int base_graphic = font_info[font_nr_base].graphic;
507 int active_graphic = font_info[font_nr_active].graphic;
508 boolean base_redefined =
509 getImageListEntryFromImageID(base_graphic)->redefined;
510 boolean active_redefined =
511 getImageListEntryFromImageID(active_graphic)->redefined;
513 /* if the base font ("font.menu_1", for example) has been redefined,
514 but not the active font ("font.menu_1.active", for example), do not
515 use an existing (in this case considered obsolete) active font
516 anymore, but use the automatically determined default font */
517 if (base_redefined && !active_redefined)
518 font_info[font_nr_active].graphic = base_graphic;
520 // now also check each "special" font (which may be the same as above)
521 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
523 int base_graphic = font_info[font_nr_base].special_graphic[j];
524 int active_graphic = font_info[font_nr_active].special_graphic[j];
525 boolean base_redefined =
526 getImageListEntryFromImageID(base_graphic)->redefined;
527 boolean active_redefined =
528 getImageListEntryFromImageID(active_graphic)->redefined;
530 // same as above, but check special graphic definitions, for example:
531 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
532 if (base_redefined && !active_redefined)
534 font_info[font_nr_active].special_graphic[j] =
535 font_info[font_nr_base].special_graphic[j];
536 font_info[font_nr_active].special_bitmap_id[j] =
537 font_info[font_nr_base].special_bitmap_id[j];
543 // ---------- initialize font bitmap array ----------
545 if (font_bitmap_info != NULL)
546 FreeFontInfo(font_bitmap_info);
549 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
551 // ---------- initialize font bitmap definitions ----------
553 for (i = 0; i < NUM_FONTS; i++)
555 if (i < NUM_INITIAL_FONTS)
557 font_bitmap_info[i] = font_initial[i];
561 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
563 int font_bitmap_id = font_info[i].special_bitmap_id[j];
564 int graphic = font_info[i].special_graphic[j];
566 // set 'graphic_info' for font entries, if uninitialized (guessed)
567 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
569 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
570 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
573 // copy font relevant information from graphics information
574 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
575 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
576 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
577 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
578 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
580 font_bitmap_info[font_bitmap_id].offset_x =
581 graphic_info[graphic].offset_x;
582 font_bitmap_info[font_bitmap_id].offset_y =
583 graphic_info[graphic].offset_y;
585 font_bitmap_info[font_bitmap_id].draw_xoffset =
586 graphic_info[graphic].draw_xoffset;
587 font_bitmap_info[font_bitmap_id].draw_yoffset =
588 graphic_info[graphic].draw_yoffset;
590 font_bitmap_info[font_bitmap_id].num_chars =
591 graphic_info[graphic].anim_frames;
592 font_bitmap_info[font_bitmap_id].num_chars_per_line =
593 graphic_info[graphic].anim_frames_per_line;
597 InitFontInfo(font_bitmap_info, num_font_bitmaps,
598 getFontBitmapID, getFontFromToken);
601 static void InitGlobalAnimGraphicInfo(void)
603 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
604 int num_property_mappings = getImageListPropertyMappingSize();
607 if (graphic_info == NULL) // still at startup phase
610 // always start with reliable default values (no global animations)
611 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
612 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
613 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
614 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
616 // initialize global animation definitions from static configuration
617 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
619 int j = GLOBAL_ANIM_ID_PART_BASE;
620 int k = GFX_SPECIAL_ARG_DEFAULT;
622 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
625 // initialize global animation definitions from dynamic configuration
626 for (i = 0; i < num_property_mappings; i++)
628 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
629 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
630 int special = property_mapping[i].ext3_index;
631 int graphic = property_mapping[i].artwork_index;
633 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
636 // set animation part to base part, if not specified
637 if (!IS_GLOBAL_ANIM_PART(part_nr))
638 part_nr = GLOBAL_ANIM_ID_PART_BASE;
640 // set animation screen to default, if not specified
641 if (!IS_SPECIAL_GFX_ARG(special))
642 special = GFX_SPECIAL_ARG_DEFAULT;
644 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
646 // fix default value for ".draw_masked" (for backward compatibility)
647 struct GraphicInfo *g = &graphic_info[graphic];
648 struct FileInfo *image = getImageListEntryFromImageID(graphic);
649 char **parameter_raw = image->parameter;
650 int p = GFX_ARG_DRAW_MASKED;
651 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
652 image_config_suffix[p].token,
653 image_config_suffix[p].type);
655 // if ".draw_masked" parameter is undefined, use default value "TRUE"
656 if (draw_masked == ARG_UNDEFINED_VALUE)
657 g->draw_masked = TRUE;
661 printf("::: InitGlobalAnimGraphicInfo\n");
663 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
664 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
665 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
666 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
667 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
668 printf("::: - anim %d, part %d, mode %d => %d\n",
669 i, j, k, global_anim_info[i].graphic[j][k]);
673 static void InitGlobalAnimSoundInfo(void)
675 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
676 int num_property_mappings = getSoundListPropertyMappingSize();
679 // always start with reliable default values (no global animation sounds)
680 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
681 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
682 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
683 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
685 // initialize global animation sound definitions from dynamic configuration
686 for (i = 0; i < num_property_mappings; i++)
688 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
689 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
690 int special = property_mapping[i].ext3_index;
691 int sound = property_mapping[i].artwork_index;
693 // sound uses control definition; map it to position of graphic (artwork)
694 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
696 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
699 // set animation part to base part, if not specified
700 if (!IS_GLOBAL_ANIM_PART(part_nr))
701 part_nr = GLOBAL_ANIM_ID_PART_BASE;
703 // set animation screen to default, if not specified
704 if (!IS_SPECIAL_GFX_ARG(special))
705 special = GFX_SPECIAL_ARG_DEFAULT;
707 global_anim_info[anim_nr].sound[part_nr][special] = sound;
711 printf("::: InitGlobalAnimSoundInfo\n");
713 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
714 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
715 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
716 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
717 printf("::: - anim %d, part %d, mode %d => %d\n",
718 i, j, k, global_anim_info[i].sound[j][k]);
722 static void InitGlobalAnimMusicInfo(void)
724 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
725 int num_property_mappings = getMusicListPropertyMappingSize();
728 // always start with reliable default values (no global animation music)
729 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
730 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
731 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
732 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
734 // initialize global animation music definitions from dynamic configuration
735 for (i = 0; i < num_property_mappings; i++)
737 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
738 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
739 int special = property_mapping[i].ext2_index;
740 int music = property_mapping[i].artwork_index;
742 // music uses control definition; map it to position of graphic (artwork)
743 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
745 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
748 // set animation part to base part, if not specified
749 if (!IS_GLOBAL_ANIM_PART(part_nr))
750 part_nr = GLOBAL_ANIM_ID_PART_BASE;
752 // set animation screen to default, if not specified
753 if (!IS_SPECIAL_GFX_ARG(special))
754 special = GFX_SPECIAL_ARG_DEFAULT;
756 global_anim_info[anim_nr].music[part_nr][special] = music;
760 printf("::: InitGlobalAnimMusicInfo\n");
762 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
763 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
764 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
765 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
766 printf("::: - anim %d, part %d, mode %d => %d\n",
767 i, j, k, global_anim_info[i].music[j][k]);
771 static void InitElementGraphicInfo(void)
773 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
774 int num_property_mappings = getImageListPropertyMappingSize();
777 if (graphic_info == NULL) // still at startup phase
780 // set values to -1 to identify later as "uninitialized" values
781 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
783 for (act = 0; act < NUM_ACTIONS; act++)
785 element_info[i].graphic[act] = -1;
786 element_info[i].crumbled[act] = -1;
788 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
790 element_info[i].direction_graphic[act][dir] = -1;
791 element_info[i].direction_crumbled[act][dir] = -1;
798 // initialize normal element/graphic mapping from static configuration
799 for (i = 0; element_to_graphic[i].element > -1; i++)
801 int element = element_to_graphic[i].element;
802 int action = element_to_graphic[i].action;
803 int direction = element_to_graphic[i].direction;
804 boolean crumbled = element_to_graphic[i].crumbled;
805 int graphic = element_to_graphic[i].graphic;
806 int base_graphic = el2baseimg(element);
808 if (graphic_info[graphic].bitmap == NULL)
811 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
814 boolean base_redefined =
815 getImageListEntryFromImageID(base_graphic)->redefined;
816 boolean act_dir_redefined =
817 getImageListEntryFromImageID(graphic)->redefined;
819 /* if the base graphic ("emerald", for example) has been redefined,
820 but not the action graphic ("emerald.falling", for example), do not
821 use an existing (in this case considered obsolete) action graphic
822 anymore, but use the automatically determined default graphic */
823 if (base_redefined && !act_dir_redefined)
828 action = ACTION_DEFAULT;
833 element_info[element].direction_crumbled[action][direction] = graphic;
835 element_info[element].crumbled[action] = graphic;
840 element_info[element].direction_graphic[action][direction] = graphic;
842 element_info[element].graphic[action] = graphic;
846 // initialize normal element/graphic mapping from dynamic configuration
847 for (i = 0; i < num_property_mappings; i++)
849 int element = property_mapping[i].base_index;
850 int action = property_mapping[i].ext1_index;
851 int direction = property_mapping[i].ext2_index;
852 int special = property_mapping[i].ext3_index;
853 int graphic = property_mapping[i].artwork_index;
854 boolean crumbled = FALSE;
856 if (special == GFX_SPECIAL_ARG_CRUMBLED)
862 if (graphic_info[graphic].bitmap == NULL)
865 if (element >= MAX_NUM_ELEMENTS || special != -1)
869 action = ACTION_DEFAULT;
874 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
875 element_info[element].direction_crumbled[action][dir] = -1;
878 element_info[element].direction_crumbled[action][direction] = graphic;
880 element_info[element].crumbled[action] = graphic;
885 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
886 element_info[element].direction_graphic[action][dir] = -1;
889 element_info[element].direction_graphic[action][direction] = graphic;
891 element_info[element].graphic[action] = graphic;
895 // now copy all graphics that are defined to be cloned from other graphics
896 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
898 int graphic = element_info[i].graphic[ACTION_DEFAULT];
899 int crumbled_like, diggable_like;
904 crumbled_like = graphic_info[graphic].crumbled_like;
905 diggable_like = graphic_info[graphic].diggable_like;
907 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
909 for (act = 0; act < NUM_ACTIONS; act++)
910 element_info[i].crumbled[act] =
911 element_info[crumbled_like].crumbled[act];
912 for (act = 0; act < NUM_ACTIONS; act++)
913 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
914 element_info[i].direction_crumbled[act][dir] =
915 element_info[crumbled_like].direction_crumbled[act][dir];
918 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
920 element_info[i].graphic[ACTION_DIGGING] =
921 element_info[diggable_like].graphic[ACTION_DIGGING];
922 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
923 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
924 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
928 // set hardcoded definitions for some runtime elements without graphic
929 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
931 // set hardcoded definitions for some internal elements without graphic
932 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
934 if (IS_EDITOR_CASCADE_INACTIVE(i))
935 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
936 else if (IS_EDITOR_CASCADE_ACTIVE(i))
937 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
940 // now set all undefined/invalid graphics to -1 to set to default after it
941 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
943 for (act = 0; act < NUM_ACTIONS; act++)
947 graphic = element_info[i].graphic[act];
948 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
949 element_info[i].graphic[act] = -1;
951 graphic = element_info[i].crumbled[act];
952 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
953 element_info[i].crumbled[act] = -1;
955 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
957 graphic = element_info[i].direction_graphic[act][dir];
958 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
959 element_info[i].direction_graphic[act][dir] = -1;
961 graphic = element_info[i].direction_crumbled[act][dir];
962 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
963 element_info[i].direction_crumbled[act][dir] = -1;
970 // adjust graphics with 2nd tile for movement according to direction
971 // (do this before correcting '-1' values to minimize calculations)
972 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
974 for (act = 0; act < NUM_ACTIONS; act++)
976 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
978 int graphic = element_info[i].direction_graphic[act][dir];
979 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
981 if (act == ACTION_FALLING) // special case
982 graphic = element_info[i].graphic[act];
985 graphic_info[graphic].double_movement &&
986 graphic_info[graphic].swap_double_tiles != 0)
988 struct GraphicInfo *g = &graphic_info[graphic];
989 int src_x_front = g->src_x;
990 int src_y_front = g->src_y;
991 int src_x_back = g->src_x + g->offset2_x;
992 int src_y_back = g->src_y + g->offset2_y;
993 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
995 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
996 src_y_front < src_y_back);
997 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
998 boolean swap_movement_tiles_autodetected =
999 (!frames_are_ordered_diagonally &&
1000 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1001 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1002 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1003 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1005 // swap frontside and backside graphic tile coordinates, if needed
1006 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1008 // get current (wrong) backside tile coordinates
1009 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1011 // set frontside tile coordinates to backside tile coordinates
1012 g->src_x = src_x_back;
1013 g->src_y = src_y_back;
1015 // invert tile offset to point to new backside tile coordinates
1019 // do not swap front and backside tiles again after correction
1020 g->swap_double_tiles = 0;
1027 UPDATE_BUSY_STATE();
1029 // now set all '-1' values to element specific default values
1030 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1032 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1033 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1034 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1035 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1037 if (default_graphic == -1)
1038 default_graphic = IMG_UNKNOWN;
1040 if (default_crumbled == -1)
1041 default_crumbled = default_graphic;
1043 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1045 default_direction_graphic[dir] =
1046 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1047 default_direction_crumbled[dir] =
1048 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1050 if (default_direction_graphic[dir] == -1)
1051 default_direction_graphic[dir] = default_graphic;
1053 if (default_direction_crumbled[dir] == -1)
1054 default_direction_crumbled[dir] = default_direction_graphic[dir];
1057 for (act = 0; act < NUM_ACTIONS; act++)
1059 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1060 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1061 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1062 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1063 act == ACTION_TURNING_FROM_RIGHT ||
1064 act == ACTION_TURNING_FROM_UP ||
1065 act == ACTION_TURNING_FROM_DOWN);
1067 // generic default action graphic (defined by "[default]" directive)
1068 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1069 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1070 int default_remove_graphic = IMG_EMPTY;
1072 if (act_remove && default_action_graphic != -1)
1073 default_remove_graphic = default_action_graphic;
1075 // look for special default action graphic (classic game specific)
1076 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1077 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1078 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1079 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1080 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1081 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1082 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1083 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1085 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1086 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1087 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1088 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1089 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1090 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1091 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1092 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1094 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1095 // !!! make this better !!!
1096 if (i == EL_EMPTY_SPACE)
1098 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1099 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1102 if (default_action_graphic == -1)
1103 default_action_graphic = default_graphic;
1105 if (default_action_crumbled == -1)
1106 default_action_crumbled = default_action_graphic;
1108 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1110 // use action graphic as the default direction graphic, if undefined
1111 int default_action_direction_graphic = element_info[i].graphic[act];
1112 int default_action_direction_crumbled = element_info[i].crumbled[act];
1114 // no graphic for current action -- use default direction graphic
1115 if (default_action_direction_graphic == -1)
1116 default_action_direction_graphic =
1117 (act_remove ? default_remove_graphic :
1119 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1120 default_action_graphic != default_graphic ?
1121 default_action_graphic :
1122 default_direction_graphic[dir]);
1124 if (element_info[i].direction_graphic[act][dir] == -1)
1125 element_info[i].direction_graphic[act][dir] =
1126 default_action_direction_graphic;
1128 if (default_action_direction_crumbled == -1)
1129 default_action_direction_crumbled =
1130 element_info[i].direction_graphic[act][dir];
1132 if (element_info[i].direction_crumbled[act][dir] == -1)
1133 element_info[i].direction_crumbled[act][dir] =
1134 default_action_direction_crumbled;
1137 // no graphic for this specific action -- use default action graphic
1138 if (element_info[i].graphic[act] == -1)
1139 element_info[i].graphic[act] =
1140 (act_remove ? default_remove_graphic :
1141 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1142 default_action_graphic);
1144 if (element_info[i].crumbled[act] == -1)
1145 element_info[i].crumbled[act] = element_info[i].graphic[act];
1149 UPDATE_BUSY_STATE();
1152 static void InitElementSpecialGraphicInfo(void)
1154 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1155 int num_property_mappings = getImageListPropertyMappingSize();
1158 // always start with reliable default values
1159 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1160 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1161 element_info[i].special_graphic[j] =
1162 element_info[i].graphic[ACTION_DEFAULT];
1164 // initialize special element/graphic mapping from static configuration
1165 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1167 int element = element_to_special_graphic[i].element;
1168 int special = element_to_special_graphic[i].special;
1169 int graphic = element_to_special_graphic[i].graphic;
1170 int base_graphic = el2baseimg(element);
1171 boolean base_redefined =
1172 getImageListEntryFromImageID(base_graphic)->redefined;
1173 boolean special_redefined =
1174 getImageListEntryFromImageID(graphic)->redefined;
1176 /* if the base graphic ("emerald", for example) has been redefined,
1177 but not the special graphic ("emerald.EDITOR", for example), do not
1178 use an existing (in this case considered obsolete) special graphic
1179 anymore, but use the automatically created (down-scaled) graphic */
1180 if (base_redefined && !special_redefined)
1183 element_info[element].special_graphic[special] = graphic;
1186 // initialize special element/graphic mapping from dynamic configuration
1187 for (i = 0; i < num_property_mappings; i++)
1189 int element = property_mapping[i].base_index;
1190 int action = property_mapping[i].ext1_index;
1191 int direction = property_mapping[i].ext2_index;
1192 int special = property_mapping[i].ext3_index;
1193 int graphic = property_mapping[i].artwork_index;
1195 // for action ".active", replace element with active element, if exists
1196 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1198 element = ELEMENT_ACTIVE(element);
1202 if (element >= MAX_NUM_ELEMENTS)
1205 // do not change special graphic if action or direction was specified
1206 if (action != -1 || direction != -1)
1209 if (IS_SPECIAL_GFX_ARG(special))
1210 element_info[element].special_graphic[special] = graphic;
1213 // now set all undefined/invalid graphics to default
1214 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1215 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1216 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1217 element_info[i].special_graphic[j] =
1218 element_info[i].graphic[ACTION_DEFAULT];
1221 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1223 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1224 return get_parameter_value(value_raw, suffix, type);
1226 if (strEqual(value_raw, ARG_UNDEFINED))
1227 return ARG_UNDEFINED_VALUE;
1229 if (type == TYPE_ELEMENT)
1231 char *value = getHashEntry(element_token_hash, value_raw);
1235 Error(ERR_INFO_LINE, "-");
1236 Error(ERR_INFO, "warning: error found in config file:");
1237 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1238 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1239 Error(ERR_INFO, "custom graphic rejected for this element/action");
1240 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1241 Error(ERR_INFO_LINE, "-");
1244 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1246 else if (type == TYPE_GRAPHIC)
1248 char *value = getHashEntry(graphic_token_hash, value_raw);
1249 int fallback_graphic = IMG_CHAR_EXCLAM;
1253 Error(ERR_INFO_LINE, "-");
1254 Error(ERR_INFO, "warning: error found in config file:");
1255 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1256 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1257 Error(ERR_INFO, "custom graphic rejected for this element/action");
1258 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1259 Error(ERR_INFO_LINE, "-");
1262 return (value != NULL ? atoi(value) : fallback_graphic);
1268 static int get_scaled_graphic_width(int graphic)
1270 int original_width = getOriginalImageWidthFromImageID(graphic);
1271 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1273 return original_width * scale_up_factor;
1276 static int get_scaled_graphic_height(int graphic)
1278 int original_height = getOriginalImageHeightFromImageID(graphic);
1279 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1281 return original_height * scale_up_factor;
1284 static void set_graphic_parameters_ext(int graphic, int *parameter,
1285 Bitmap **src_bitmaps)
1287 struct GraphicInfo *g = &graphic_info[graphic];
1288 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1289 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1290 int anim_frames_per_line = 1;
1292 // always start with reliable default values
1293 g->src_image_width = 0;
1294 g->src_image_height = 0;
1297 g->width = TILEX; // default for element graphics
1298 g->height = TILEY; // default for element graphics
1299 g->offset_x = 0; // one or both of these values ...
1300 g->offset_y = 0; // ... will be corrected later
1301 g->offset2_x = 0; // one or both of these values ...
1302 g->offset2_y = 0; // ... will be corrected later
1303 g->swap_double_tiles = -1; // auto-detect tile swapping
1304 g->crumbled_like = -1; // do not use clone element
1305 g->diggable_like = -1; // do not use clone element
1306 g->border_size = TILEX / 8; // "CRUMBLED" border size
1307 g->scale_up_factor = 1; // default: no scaling up
1308 g->tile_size = TILESIZE; // default: standard tile size
1309 g->clone_from = -1; // do not use clone graphic
1310 g->init_delay_fixed = 0;
1311 g->init_delay_random = 0;
1312 g->init_delay_action = -1;
1313 g->anim_delay_fixed = 0;
1314 g->anim_delay_random = 0;
1315 g->anim_delay_action = -1;
1316 g->post_delay_fixed = 0;
1317 g->post_delay_random = 0;
1318 g->post_delay_action = -1;
1319 g->init_event = ANIM_EVENT_UNDEFINED;
1320 g->anim_event = ANIM_EVENT_UNDEFINED;
1321 g->init_event_action = -1;
1322 g->anim_event_action = -1;
1323 g->draw_masked = FALSE;
1325 g->fade_mode = FADE_MODE_DEFAULT;
1329 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1330 g->align = ALIGN_CENTER; // default for title screens
1331 g->valign = VALIGN_MIDDLE; // default for title screens
1332 g->sort_priority = 0; // default for title screens
1334 g->style = STYLE_DEFAULT;
1336 g->bitmaps = src_bitmaps;
1337 g->bitmap = src_bitmap;
1339 // optional zoom factor for scaling up the image to a larger size
1340 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1341 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1342 if (g->scale_up_factor < 1)
1343 g->scale_up_factor = 1; // no scaling
1345 // optional tile size for using non-standard image size
1346 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1348 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1351 // CHECK: should tile sizes less than standard tile size be allowed?
1352 if (g->tile_size < TILESIZE)
1353 g->tile_size = TILESIZE; // standard tile size
1356 // when setting tile size, also set width and height accordingly
1357 g->width = g->tile_size;
1358 g->height = g->tile_size;
1361 if (g->use_image_size)
1363 // set new default bitmap size (with scaling, but without small images)
1364 g->width = get_scaled_graphic_width(graphic);
1365 g->height = get_scaled_graphic_height(graphic);
1368 // optional width and height of each animation frame
1369 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1370 g->width = parameter[GFX_ARG_WIDTH];
1371 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1372 g->height = parameter[GFX_ARG_HEIGHT];
1374 // optional x and y tile position of animation frame sequence
1375 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1376 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1377 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1378 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1380 // optional x and y pixel position of animation frame sequence
1381 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1382 g->src_x = parameter[GFX_ARG_X];
1383 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1384 g->src_y = parameter[GFX_ARG_Y];
1390 Error(ERR_INFO_LINE, "-");
1391 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1392 g->width, getTokenFromImageID(graphic), TILEX);
1393 Error(ERR_INFO_LINE, "-");
1395 g->width = TILEX; // will be checked to be inside bitmap later
1400 Error(ERR_INFO_LINE, "-");
1401 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1402 g->height, getTokenFromImageID(graphic), TILEY);
1403 Error(ERR_INFO_LINE, "-");
1405 g->height = TILEY; // will be checked to be inside bitmap later
1411 // get final bitmap size (with scaling, but without small images)
1412 int src_image_width = get_scaled_graphic_width(graphic);
1413 int src_image_height = get_scaled_graphic_height(graphic);
1415 if (src_image_width == 0 || src_image_height == 0)
1417 // only happens when loaded outside artwork system (like "global.busy")
1418 src_image_width = src_bitmap->width;
1419 src_image_height = src_bitmap->height;
1422 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1424 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1425 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1429 anim_frames_per_row = MAX(1, src_image_width / g->width);
1430 anim_frames_per_col = MAX(1, src_image_height / g->height);
1433 g->src_image_width = src_image_width;
1434 g->src_image_height = src_image_height;
1437 // correct x or y offset dependent of vertical or horizontal frame order
1438 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1440 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1441 parameter[GFX_ARG_OFFSET] : g->height);
1442 anim_frames_per_line = anim_frames_per_col;
1444 else // frames are ordered horizontally
1446 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1447 parameter[GFX_ARG_OFFSET] : g->width);
1448 anim_frames_per_line = anim_frames_per_row;
1451 // optionally, the x and y offset of frames can be specified directly
1452 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1453 g->offset_x = parameter[GFX_ARG_XOFFSET];
1454 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1455 g->offset_y = parameter[GFX_ARG_YOFFSET];
1457 // optionally, moving animations may have separate start and end graphics
1458 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1460 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1461 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1463 // correct x or y offset2 dependent of vertical or horizontal frame order
1464 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1465 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1466 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1467 else // frames are ordered horizontally
1468 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1469 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1471 // optionally, the x and y offset of 2nd graphic can be specified directly
1472 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1473 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1474 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1475 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1477 // optionally, the second movement tile can be specified as start tile
1478 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1479 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1481 // automatically determine correct number of frames, if not defined
1482 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1483 g->anim_frames = parameter[GFX_ARG_FRAMES];
1484 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1485 g->anim_frames = anim_frames_per_row;
1486 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1487 g->anim_frames = anim_frames_per_col;
1491 if (g->anim_frames < 1) // frames must be at least 1
1494 g->anim_frames_per_line =
1495 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1496 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1498 g->anim_delay = parameter[GFX_ARG_DELAY];
1499 if (g->anim_delay < 1) // delay must be at least 1
1502 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1504 // automatically determine correct start frame, if not defined
1505 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1506 g->anim_start_frame = 0;
1507 else if (g->anim_mode & ANIM_REVERSE)
1508 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1510 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1512 // animation synchronized with global frame counter, not move position
1513 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1515 // optional element for cloning crumble graphics
1516 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1517 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1519 // optional element for cloning digging graphics
1520 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1521 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1523 // optional border size for "crumbling" diggable graphics
1524 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1525 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1527 // used for global animations and player "boring" and "sleeping" actions
1528 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1529 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1530 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1531 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1532 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1533 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1534 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1535 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1536 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1537 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1538 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1539 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1541 // used for global animations
1542 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1543 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1544 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1545 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1546 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1547 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1548 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1549 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1550 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1551 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1552 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1553 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1554 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1555 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1557 // used for toon animations and global animations
1558 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1559 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1560 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1561 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1562 g->direction = parameter[GFX_ARG_DIRECTION];
1563 g->position = parameter[GFX_ARG_POSITION];
1564 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1565 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1567 if (g->step_delay < 1) // delay must be at least 1
1570 // this is only used for drawing font characters
1571 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1572 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1574 // use a different default value for global animations and toons
1575 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1576 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1577 g->draw_masked = TRUE;
1579 // this is used for drawing envelopes, global animations and toons
1580 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1581 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1583 // used for toon animations and global animations
1584 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1585 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1587 // optional graphic for cloning all graphics settings
1588 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1589 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1591 // optional settings for drawing title screens and title messages
1592 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1593 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1594 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1595 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1596 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1597 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1598 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1599 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1600 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1601 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1602 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1603 g->align = parameter[GFX_ARG_ALIGN];
1604 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1605 g->valign = parameter[GFX_ARG_VALIGN];
1606 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1607 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1609 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1610 g->class = parameter[GFX_ARG_CLASS];
1611 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1612 g->style = parameter[GFX_ARG_STYLE];
1614 // this is only used for drawing menu buttons and text
1615 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1616 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1617 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1618 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1621 static void set_graphic_parameters(int graphic)
1623 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1624 char **parameter_raw = image->parameter;
1625 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1626 int parameter[NUM_GFX_ARGS];
1629 // if fallback to default artwork is done, also use the default parameters
1630 if (image->fallback_to_default)
1631 parameter_raw = image->default_parameter;
1633 // get integer values from string parameters
1634 for (i = 0; i < NUM_GFX_ARGS; i++)
1635 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1636 image_config_suffix[i].token,
1637 image_config_suffix[i].type);
1639 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1641 UPDATE_BUSY_STATE();
1644 static void set_cloned_graphic_parameters(int graphic)
1646 int fallback_graphic = IMG_CHAR_EXCLAM;
1647 int max_num_images = getImageListSize();
1648 int clone_graphic = graphic_info[graphic].clone_from;
1649 int num_references_followed = 1;
1651 while (graphic_info[clone_graphic].clone_from != -1 &&
1652 num_references_followed < max_num_images)
1654 clone_graphic = graphic_info[clone_graphic].clone_from;
1656 num_references_followed++;
1659 if (num_references_followed >= max_num_images)
1661 Error(ERR_INFO_LINE, "-");
1662 Error(ERR_INFO, "warning: error found in config file:");
1663 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1664 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1665 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1666 Error(ERR_INFO, "custom graphic rejected for this element/action");
1668 if (graphic == fallback_graphic)
1669 Error(ERR_EXIT, "no fallback graphic available");
1671 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1672 Error(ERR_INFO_LINE, "-");
1674 graphic_info[graphic] = graphic_info[fallback_graphic];
1678 graphic_info[graphic] = graphic_info[clone_graphic];
1679 graphic_info[graphic].clone_from = clone_graphic;
1683 static void InitGraphicInfo(void)
1685 int fallback_graphic = IMG_CHAR_EXCLAM;
1686 int num_images = getImageListSize();
1689 // use image size as default values for width and height for these images
1690 static int full_size_graphics[] =
1693 IMG_GLOBAL_BORDER_MAIN,
1694 IMG_GLOBAL_BORDER_SCORES,
1695 IMG_GLOBAL_BORDER_EDITOR,
1696 IMG_GLOBAL_BORDER_PLAYING,
1699 IMG_BACKGROUND_ENVELOPE_1,
1700 IMG_BACKGROUND_ENVELOPE_2,
1701 IMG_BACKGROUND_ENVELOPE_3,
1702 IMG_BACKGROUND_ENVELOPE_4,
1703 IMG_BACKGROUND_REQUEST,
1706 IMG_BACKGROUND_TITLE_INITIAL,
1707 IMG_BACKGROUND_TITLE,
1708 IMG_BACKGROUND_MAIN,
1709 IMG_BACKGROUND_LEVELS,
1710 IMG_BACKGROUND_LEVELNR,
1711 IMG_BACKGROUND_SCORES,
1712 IMG_BACKGROUND_EDITOR,
1713 IMG_BACKGROUND_INFO,
1714 IMG_BACKGROUND_INFO_ELEMENTS,
1715 IMG_BACKGROUND_INFO_MUSIC,
1716 IMG_BACKGROUND_INFO_CREDITS,
1717 IMG_BACKGROUND_INFO_PROGRAM,
1718 IMG_BACKGROUND_INFO_VERSION,
1719 IMG_BACKGROUND_INFO_LEVELSET,
1720 IMG_BACKGROUND_SETUP,
1721 IMG_BACKGROUND_PLAYING,
1722 IMG_BACKGROUND_DOOR,
1723 IMG_BACKGROUND_TAPE,
1724 IMG_BACKGROUND_PANEL,
1725 IMG_BACKGROUND_PALETTE,
1726 IMG_BACKGROUND_TOOLBOX,
1728 IMG_TITLESCREEN_INITIAL_1,
1729 IMG_TITLESCREEN_INITIAL_2,
1730 IMG_TITLESCREEN_INITIAL_3,
1731 IMG_TITLESCREEN_INITIAL_4,
1732 IMG_TITLESCREEN_INITIAL_5,
1739 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1740 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1741 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1742 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1743 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1744 IMG_BACKGROUND_TITLEMESSAGE_1,
1745 IMG_BACKGROUND_TITLEMESSAGE_2,
1746 IMG_BACKGROUND_TITLEMESSAGE_3,
1747 IMG_BACKGROUND_TITLEMESSAGE_4,
1748 IMG_BACKGROUND_TITLEMESSAGE_5,
1753 FreeGlobalAnimEventInfo();
1755 checked_free(graphic_info);
1757 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1759 // initialize "use_image_size" flag with default value
1760 for (i = 0; i < num_images; i++)
1761 graphic_info[i].use_image_size = FALSE;
1763 // initialize "use_image_size" flag from static configuration above
1764 for (i = 0; full_size_graphics[i] != -1; i++)
1765 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1767 // first set all graphic paramaters ...
1768 for (i = 0; i < num_images; i++)
1769 set_graphic_parameters(i);
1771 // ... then copy these parameters for cloned graphics
1772 for (i = 0; i < num_images; i++)
1773 if (graphic_info[i].clone_from != -1)
1774 set_cloned_graphic_parameters(i);
1776 for (i = 0; i < num_images; i++)
1778 Bitmap *src_bitmap = graphic_info[i].bitmap;
1782 int src_bitmap_width, src_bitmap_height;
1784 // now check if no animation frames are outside of the loaded image
1786 if (graphic_info[i].bitmap == NULL)
1787 continue; // skip check for optional images that are undefined
1789 // get image size (this can differ from the standard element tile size!)
1790 width = graphic_info[i].width;
1791 height = graphic_info[i].height;
1793 // get final bitmap size (with scaling, but without small images)
1794 src_bitmap_width = graphic_info[i].src_image_width;
1795 src_bitmap_height = graphic_info[i].src_image_height;
1797 // check if first animation frame is inside specified bitmap
1799 // do not use getGraphicSourceXY() here to get position of first frame;
1800 // this avoids calculating wrong start position for out-of-bounds frame
1801 src_x = graphic_info[i].src_x;
1802 src_y = graphic_info[i].src_y;
1804 if (program.headless)
1807 if (src_x < 0 || src_y < 0 ||
1808 src_x + width > src_bitmap_width ||
1809 src_y + height > src_bitmap_height)
1811 Error(ERR_INFO_LINE, "-");
1812 Error(ERR_INFO, "warning: error found in config file:");
1813 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1814 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1815 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1816 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1818 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1819 src_x, src_y, src_bitmap_width, src_bitmap_height);
1820 Error(ERR_INFO, "custom graphic rejected for this element/action");
1822 if (i == fallback_graphic)
1823 Error(ERR_EXIT, "no fallback graphic available");
1825 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1826 Error(ERR_INFO_LINE, "-");
1828 graphic_info[i] = graphic_info[fallback_graphic];
1830 // if first frame out of bounds, do not check last frame anymore
1834 // check if last animation frame is inside specified bitmap
1836 last_frame = graphic_info[i].anim_frames - 1;
1837 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1839 if (src_x < 0 || src_y < 0 ||
1840 src_x + width > src_bitmap_width ||
1841 src_y + height > src_bitmap_height)
1843 Error(ERR_INFO_LINE, "-");
1844 Error(ERR_INFO, "warning: error found in config file:");
1845 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1846 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1847 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1848 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1850 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1851 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1852 Error(ERR_INFO, "custom graphic rejected for this element/action");
1854 if (i == fallback_graphic)
1855 Error(ERR_EXIT, "no fallback graphic available");
1857 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1858 Error(ERR_INFO_LINE, "-");
1860 graphic_info[i] = graphic_info[fallback_graphic];
1865 static void InitGraphicCompatibilityInfo(void)
1867 struct FileInfo *fi_global_door =
1868 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1869 int num_images = getImageListSize();
1872 /* the following compatibility handling is needed for the following case:
1873 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1874 graphics mainly used for door and panel graphics, like editor, tape and
1875 in-game buttons with hard-coded bitmap positions and button sizes; as
1876 these graphics now have individual definitions, redefining "global.door"
1877 to change all these graphics at once like before does not work anymore
1878 (because all those individual definitions still have their default values);
1879 to solve this, remap all those individual definitions that are not
1880 redefined to the new bitmap of "global.door" if it was redefined */
1882 // special compatibility handling if image "global.door" was redefined
1883 if (fi_global_door->redefined)
1885 for (i = 0; i < num_images; i++)
1887 struct FileInfo *fi = getImageListEntryFromImageID(i);
1889 // process only those images that still use the default settings
1892 // process all images which default to same image as "global.door"
1893 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1895 // printf("::: special treatment needed for token '%s'\n", fi->token);
1897 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1898 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1904 InitGraphicCompatibilityInfo_Doors();
1907 static void InitElementSoundInfo(void)
1909 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1910 int num_property_mappings = getSoundListPropertyMappingSize();
1913 // set values to -1 to identify later as "uninitialized" values
1914 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1915 for (act = 0; act < NUM_ACTIONS; act++)
1916 element_info[i].sound[act] = -1;
1918 // initialize element/sound mapping from static configuration
1919 for (i = 0; element_to_sound[i].element > -1; i++)
1921 int element = element_to_sound[i].element;
1922 int action = element_to_sound[i].action;
1923 int sound = element_to_sound[i].sound;
1924 boolean is_class = element_to_sound[i].is_class;
1927 action = ACTION_DEFAULT;
1930 element_info[element].sound[action] = sound;
1932 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1933 if (strEqual(element_info[j].class_name,
1934 element_info[element].class_name))
1935 element_info[j].sound[action] = sound;
1938 // initialize element class/sound mapping from dynamic configuration
1939 for (i = 0; i < num_property_mappings; i++)
1941 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1942 int action = property_mapping[i].ext1_index;
1943 int sound = property_mapping[i].artwork_index;
1945 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1949 action = ACTION_DEFAULT;
1951 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1952 if (strEqual(element_info[j].class_name,
1953 element_info[element_class].class_name))
1954 element_info[j].sound[action] = sound;
1957 // initialize element/sound mapping from dynamic configuration
1958 for (i = 0; i < num_property_mappings; i++)
1960 int element = property_mapping[i].base_index;
1961 int action = property_mapping[i].ext1_index;
1962 int sound = property_mapping[i].artwork_index;
1964 if (element >= MAX_NUM_ELEMENTS)
1968 action = ACTION_DEFAULT;
1970 element_info[element].sound[action] = sound;
1973 // now set all '-1' values to element specific default values
1974 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1976 for (act = 0; act < NUM_ACTIONS; act++)
1978 // generic default action sound (defined by "[default]" directive)
1979 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1981 // look for special default action sound (classic game specific)
1982 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1983 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1984 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1985 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1986 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1987 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1988 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1989 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1991 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1992 // !!! make this better !!!
1993 if (i == EL_EMPTY_SPACE)
1994 default_action_sound = element_info[EL_DEFAULT].sound[act];
1996 // no sound for this specific action -- use default action sound
1997 if (element_info[i].sound[act] == -1)
1998 element_info[i].sound[act] = default_action_sound;
2002 // copy sound settings to some elements that are only stored in level file
2003 // in native R'n'D levels, but are used by game engine in native EM levels
2004 for (i = 0; copy_properties[i][0] != -1; i++)
2005 for (j = 1; j <= 4; j++)
2006 for (act = 0; act < NUM_ACTIONS; act++)
2007 element_info[copy_properties[i][j]].sound[act] =
2008 element_info[copy_properties[i][0]].sound[act];
2011 static void InitGameModeSoundInfo(void)
2015 // set values to -1 to identify later as "uninitialized" values
2016 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2019 // initialize gamemode/sound mapping from static configuration
2020 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2022 int gamemode = gamemode_to_sound[i].gamemode;
2023 int sound = gamemode_to_sound[i].sound;
2026 gamemode = GAME_MODE_DEFAULT;
2028 menu.sound[gamemode] = sound;
2031 // now set all '-1' values to levelset specific default values
2032 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2033 if (menu.sound[i] == -1)
2034 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2037 static void set_sound_parameters(int sound, char **parameter_raw)
2039 int parameter[NUM_SND_ARGS];
2042 // get integer values from string parameters
2043 for (i = 0; i < NUM_SND_ARGS; i++)
2045 get_parameter_value(parameter_raw[i],
2046 sound_config_suffix[i].token,
2047 sound_config_suffix[i].type);
2049 // explicit loop mode setting in configuration overrides default value
2050 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2051 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2053 // sound volume to change the original volume when loading the sound file
2054 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2056 // sound priority to give certain sounds a higher or lower priority
2057 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2060 static void InitSoundInfo(void)
2062 int *sound_effect_properties;
2063 int num_sounds = getSoundListSize();
2066 checked_free(sound_info);
2068 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2069 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2071 // initialize sound effect for all elements to "no sound"
2072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2073 for (j = 0; j < NUM_ACTIONS; j++)
2074 element_info[i].sound[j] = SND_UNDEFINED;
2076 for (i = 0; i < num_sounds; i++)
2078 struct FileInfo *sound = getSoundListEntry(i);
2079 int len_effect_text = strlen(sound->token);
2081 sound_effect_properties[i] = ACTION_OTHER;
2082 sound_info[i].loop = FALSE; // default: play sound only once
2084 // determine all loop sounds and identify certain sound classes
2086 for (j = 0; element_action_info[j].suffix; j++)
2088 int len_action_text = strlen(element_action_info[j].suffix);
2090 if (len_action_text < len_effect_text &&
2091 strEqual(&sound->token[len_effect_text - len_action_text],
2092 element_action_info[j].suffix))
2094 sound_effect_properties[i] = element_action_info[j].value;
2095 sound_info[i].loop = element_action_info[j].is_loop_sound;
2101 // associate elements and some selected sound actions
2103 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2105 if (element_info[j].class_name)
2107 int len_class_text = strlen(element_info[j].class_name);
2109 if (len_class_text + 1 < len_effect_text &&
2110 strncmp(sound->token,
2111 element_info[j].class_name, len_class_text) == 0 &&
2112 sound->token[len_class_text] == '.')
2114 int sound_action_value = sound_effect_properties[i];
2116 element_info[j].sound[sound_action_value] = i;
2121 set_sound_parameters(i, sound->parameter);
2124 free(sound_effect_properties);
2127 static void InitGameModeMusicInfo(void)
2129 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2130 int num_property_mappings = getMusicListPropertyMappingSize();
2131 int default_levelset_music = -1;
2134 // set values to -1 to identify later as "uninitialized" values
2135 for (i = 0; i < MAX_LEVELS; i++)
2136 levelset.music[i] = -1;
2137 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2140 // initialize gamemode/music mapping from static configuration
2141 for (i = 0; gamemode_to_music[i].music > -1; i++)
2143 int gamemode = gamemode_to_music[i].gamemode;
2144 int music = gamemode_to_music[i].music;
2147 gamemode = GAME_MODE_DEFAULT;
2149 menu.music[gamemode] = music;
2152 // initialize gamemode/music mapping from dynamic configuration
2153 for (i = 0; i < num_property_mappings; i++)
2155 int prefix = property_mapping[i].base_index;
2156 int gamemode = property_mapping[i].ext2_index;
2157 int level = property_mapping[i].ext3_index;
2158 int music = property_mapping[i].artwork_index;
2160 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2164 gamemode = GAME_MODE_DEFAULT;
2166 // level specific music only allowed for in-game music
2167 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2168 gamemode = GAME_MODE_PLAYING;
2173 default_levelset_music = music;
2176 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2177 levelset.music[level] = music;
2178 if (gamemode != GAME_MODE_PLAYING)
2179 menu.music[gamemode] = music;
2182 // now set all '-1' values to menu specific default values
2183 // (undefined values of "levelset.music[]" might stay at "-1" to
2184 // allow dynamic selection of music files from music directory!)
2185 for (i = 0; i < MAX_LEVELS; i++)
2186 if (levelset.music[i] == -1)
2187 levelset.music[i] = default_levelset_music;
2188 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2189 if (menu.music[i] == -1)
2190 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2193 static void set_music_parameters(int music, char **parameter_raw)
2195 int parameter[NUM_MUS_ARGS];
2198 // get integer values from string parameters
2199 for (i = 0; i < NUM_MUS_ARGS; i++)
2201 get_parameter_value(parameter_raw[i],
2202 music_config_suffix[i].token,
2203 music_config_suffix[i].type);
2205 // explicit loop mode setting in configuration overrides default value
2206 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2207 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2210 static void InitMusicInfo(void)
2212 int num_music = getMusicListSize();
2215 checked_free(music_info);
2217 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2219 for (i = 0; i < num_music; i++)
2221 struct FileInfo *music = getMusicListEntry(i);
2222 int len_music_text = strlen(music->token);
2224 music_info[i].loop = TRUE; // default: play music in loop mode
2226 // determine all loop music
2228 for (j = 0; music_prefix_info[j].prefix; j++)
2230 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2232 if (len_prefix_text < len_music_text &&
2233 strncmp(music->token,
2234 music_prefix_info[j].prefix, len_prefix_text) == 0)
2236 music_info[i].loop = music_prefix_info[j].is_loop_music;
2242 set_music_parameters(i, music->parameter);
2246 static void ReinitializeGraphics(void)
2248 print_timestamp_init("ReinitializeGraphics");
2250 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2252 InitGraphicInfo(); // graphic properties mapping
2253 print_timestamp_time("InitGraphicInfo");
2254 InitElementGraphicInfo(); // element game graphic mapping
2255 print_timestamp_time("InitElementGraphicInfo");
2256 InitElementSpecialGraphicInfo(); // element special graphic mapping
2257 print_timestamp_time("InitElementSpecialGraphicInfo");
2259 InitElementSmallImages(); // scale elements to all needed sizes
2260 print_timestamp_time("InitElementSmallImages");
2261 InitScaledImages(); // scale all other images, if needed
2262 print_timestamp_time("InitScaledImages");
2263 InitBitmapPointers(); // set standard size bitmap pointers
2264 print_timestamp_time("InitBitmapPointers");
2265 InitFontGraphicInfo(); // initialize text drawing functions
2266 print_timestamp_time("InitFontGraphicInfo");
2267 InitGlobalAnimGraphicInfo(); // initialize global animation config
2268 print_timestamp_time("InitGlobalAnimGraphicInfo");
2270 InitImageTextures(); // create textures for certain images
2271 print_timestamp_time("InitImageTextures");
2273 InitGraphicInfo_EM(); // graphic mapping for EM engine
2274 print_timestamp_time("InitGraphicInfo_EM");
2276 InitGraphicCompatibilityInfo();
2277 print_timestamp_time("InitGraphicCompatibilityInfo");
2279 SetMainBackgroundImage(IMG_BACKGROUND);
2280 print_timestamp_time("SetMainBackgroundImage");
2281 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2282 print_timestamp_time("SetDoorBackgroundImage");
2285 print_timestamp_time("InitGadgets");
2287 print_timestamp_time("InitDoors");
2289 print_timestamp_done("ReinitializeGraphics");
2292 static void ReinitializeSounds(void)
2294 InitSoundInfo(); // sound properties mapping
2295 InitElementSoundInfo(); // element game sound mapping
2296 InitGameModeSoundInfo(); // game mode sound mapping
2297 InitGlobalAnimSoundInfo(); // global animation sound settings
2299 InitPlayLevelSound(); // internal game sound settings
2302 static void ReinitializeMusic(void)
2304 InitMusicInfo(); // music properties mapping
2305 InitGameModeMusicInfo(); // game mode music mapping
2306 InitGlobalAnimMusicInfo(); // global animation music settings
2309 static int get_special_property_bit(int element, int property_bit_nr)
2311 struct PropertyBitInfo
2317 static struct PropertyBitInfo pb_can_move_into_acid[] =
2319 // the player may be able fall into acid when gravity is activated
2324 { EL_SP_MURPHY, 0 },
2325 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2327 // all elements that can move may be able to also move into acid
2330 { EL_BUG_RIGHT, 1 },
2333 { EL_SPACESHIP, 2 },
2334 { EL_SPACESHIP_LEFT, 2 },
2335 { EL_SPACESHIP_RIGHT, 2 },
2336 { EL_SPACESHIP_UP, 2 },
2337 { EL_SPACESHIP_DOWN, 2 },
2338 { EL_BD_BUTTERFLY, 3 },
2339 { EL_BD_BUTTERFLY_LEFT, 3 },
2340 { EL_BD_BUTTERFLY_RIGHT, 3 },
2341 { EL_BD_BUTTERFLY_UP, 3 },
2342 { EL_BD_BUTTERFLY_DOWN, 3 },
2343 { EL_BD_FIREFLY, 4 },
2344 { EL_BD_FIREFLY_LEFT, 4 },
2345 { EL_BD_FIREFLY_RIGHT, 4 },
2346 { EL_BD_FIREFLY_UP, 4 },
2347 { EL_BD_FIREFLY_DOWN, 4 },
2349 { EL_YAMYAM_LEFT, 5 },
2350 { EL_YAMYAM_RIGHT, 5 },
2351 { EL_YAMYAM_UP, 5 },
2352 { EL_YAMYAM_DOWN, 5 },
2353 { EL_DARK_YAMYAM, 6 },
2356 { EL_PACMAN_LEFT, 8 },
2357 { EL_PACMAN_RIGHT, 8 },
2358 { EL_PACMAN_UP, 8 },
2359 { EL_PACMAN_DOWN, 8 },
2361 { EL_MOLE_LEFT, 9 },
2362 { EL_MOLE_RIGHT, 9 },
2364 { EL_MOLE_DOWN, 9 },
2368 { EL_SATELLITE, 13 },
2369 { EL_SP_SNIKSNAK, 14 },
2370 { EL_SP_ELECTRON, 15 },
2373 { EL_EMC_ANDROID, 18 },
2378 static struct PropertyBitInfo pb_dont_collide_with[] =
2380 { EL_SP_SNIKSNAK, 0 },
2381 { EL_SP_ELECTRON, 1 },
2389 struct PropertyBitInfo *pb_info;
2392 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2393 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2398 struct PropertyBitInfo *pb_info = NULL;
2401 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2402 if (pb_definition[i].bit_nr == property_bit_nr)
2403 pb_info = pb_definition[i].pb_info;
2405 if (pb_info == NULL)
2408 for (i = 0; pb_info[i].element != -1; i++)
2409 if (pb_info[i].element == element)
2410 return pb_info[i].bit_nr;
2415 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2416 boolean property_value)
2418 int bit_nr = get_special_property_bit(element, property_bit_nr);
2423 *bitfield |= (1 << bit_nr);
2425 *bitfield &= ~(1 << bit_nr);
2429 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2431 int bit_nr = get_special_property_bit(element, property_bit_nr);
2434 return ((*bitfield & (1 << bit_nr)) != 0);
2439 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2441 static int group_nr;
2442 static struct ElementGroupInfo *group;
2443 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2446 if (actual_group == NULL) // not yet initialized
2449 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2451 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2452 group_element - EL_GROUP_START + 1);
2454 // replace element which caused too deep recursion by question mark
2455 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2460 if (recursion_depth == 0) // initialization
2462 group = actual_group;
2463 group_nr = GROUP_NR(group_element);
2465 group->num_elements_resolved = 0;
2466 group->choice_pos = 0;
2468 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2469 element_info[i].in_group[group_nr] = FALSE;
2472 for (i = 0; i < actual_group->num_elements; i++)
2474 int element = actual_group->element[i];
2476 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2479 if (IS_GROUP_ELEMENT(element))
2480 ResolveGroupElementExt(element, recursion_depth + 1);
2483 group->element_resolved[group->num_elements_resolved++] = element;
2484 element_info[element].in_group[group_nr] = TRUE;
2489 void ResolveGroupElement(int group_element)
2491 ResolveGroupElementExt(group_element, 0);
2494 void InitElementPropertiesStatic(void)
2496 static boolean clipboard_elements_initialized = FALSE;
2498 static int ep_diggable[] =
2503 EL_SP_BUGGY_BASE_ACTIVATING,
2506 EL_INVISIBLE_SAND_ACTIVE,
2509 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2510 // (if amoeba can grow into anything diggable, maybe keep these out)
2515 EL_SP_BUGGY_BASE_ACTIVE,
2522 static int ep_collectible_only[] =
2544 EL_DYNABOMB_INCREASE_NUMBER,
2545 EL_DYNABOMB_INCREASE_SIZE,
2546 EL_DYNABOMB_INCREASE_POWER,
2564 // !!! handle separately !!!
2565 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2571 static int ep_dont_run_into[] =
2573 // same elements as in 'ep_dont_touch'
2579 // same elements as in 'ep_dont_collide_with'
2591 // !!! maybe this should better be handled by 'ep_diggable' !!!
2596 EL_SP_BUGGY_BASE_ACTIVE,
2603 static int ep_dont_collide_with[] =
2605 // same elements as in 'ep_dont_touch'
2622 static int ep_dont_touch[] =
2632 static int ep_indestructible[] =
2636 EL_ACID_POOL_TOPLEFT,
2637 EL_ACID_POOL_TOPRIGHT,
2638 EL_ACID_POOL_BOTTOMLEFT,
2639 EL_ACID_POOL_BOTTOM,
2640 EL_ACID_POOL_BOTTOMRIGHT,
2641 EL_SP_HARDWARE_GRAY,
2642 EL_SP_HARDWARE_GREEN,
2643 EL_SP_HARDWARE_BLUE,
2645 EL_SP_HARDWARE_YELLOW,
2646 EL_SP_HARDWARE_BASE_1,
2647 EL_SP_HARDWARE_BASE_2,
2648 EL_SP_HARDWARE_BASE_3,
2649 EL_SP_HARDWARE_BASE_4,
2650 EL_SP_HARDWARE_BASE_5,
2651 EL_SP_HARDWARE_BASE_6,
2652 EL_INVISIBLE_STEELWALL,
2653 EL_INVISIBLE_STEELWALL_ACTIVE,
2654 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2655 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2656 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2657 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2658 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2659 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2660 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2661 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2662 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2663 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2664 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2665 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2667 EL_LIGHT_SWITCH_ACTIVE,
2668 EL_SIGN_EXCLAMATION,
2669 EL_SIGN_RADIOACTIVITY,
2676 EL_SIGN_ENTRY_FORBIDDEN,
2677 EL_SIGN_EMERGENCY_EXIT,
2685 EL_STEEL_EXIT_CLOSED,
2687 EL_STEEL_EXIT_OPENING,
2688 EL_STEEL_EXIT_CLOSING,
2689 EL_EM_STEEL_EXIT_CLOSED,
2690 EL_EM_STEEL_EXIT_OPEN,
2691 EL_EM_STEEL_EXIT_OPENING,
2692 EL_EM_STEEL_EXIT_CLOSING,
2693 EL_DC_STEELWALL_1_LEFT,
2694 EL_DC_STEELWALL_1_RIGHT,
2695 EL_DC_STEELWALL_1_TOP,
2696 EL_DC_STEELWALL_1_BOTTOM,
2697 EL_DC_STEELWALL_1_HORIZONTAL,
2698 EL_DC_STEELWALL_1_VERTICAL,
2699 EL_DC_STEELWALL_1_TOPLEFT,
2700 EL_DC_STEELWALL_1_TOPRIGHT,
2701 EL_DC_STEELWALL_1_BOTTOMLEFT,
2702 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2703 EL_DC_STEELWALL_1_TOPLEFT_2,
2704 EL_DC_STEELWALL_1_TOPRIGHT_2,
2705 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2706 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2707 EL_DC_STEELWALL_2_LEFT,
2708 EL_DC_STEELWALL_2_RIGHT,
2709 EL_DC_STEELWALL_2_TOP,
2710 EL_DC_STEELWALL_2_BOTTOM,
2711 EL_DC_STEELWALL_2_HORIZONTAL,
2712 EL_DC_STEELWALL_2_VERTICAL,
2713 EL_DC_STEELWALL_2_MIDDLE,
2714 EL_DC_STEELWALL_2_SINGLE,
2715 EL_STEELWALL_SLIPPERY,
2729 EL_GATE_1_GRAY_ACTIVE,
2730 EL_GATE_2_GRAY_ACTIVE,
2731 EL_GATE_3_GRAY_ACTIVE,
2732 EL_GATE_4_GRAY_ACTIVE,
2741 EL_EM_GATE_1_GRAY_ACTIVE,
2742 EL_EM_GATE_2_GRAY_ACTIVE,
2743 EL_EM_GATE_3_GRAY_ACTIVE,
2744 EL_EM_GATE_4_GRAY_ACTIVE,
2753 EL_EMC_GATE_5_GRAY_ACTIVE,
2754 EL_EMC_GATE_6_GRAY_ACTIVE,
2755 EL_EMC_GATE_7_GRAY_ACTIVE,
2756 EL_EMC_GATE_8_GRAY_ACTIVE,
2758 EL_DC_GATE_WHITE_GRAY,
2759 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2760 EL_DC_GATE_FAKE_GRAY,
2762 EL_SWITCHGATE_OPENING,
2763 EL_SWITCHGATE_CLOSED,
2764 EL_SWITCHGATE_CLOSING,
2765 EL_DC_SWITCHGATE_SWITCH_UP,
2766 EL_DC_SWITCHGATE_SWITCH_DOWN,
2768 EL_TIMEGATE_OPENING,
2770 EL_TIMEGATE_CLOSING,
2771 EL_DC_TIMEGATE_SWITCH,
2772 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2776 EL_TUBE_VERTICAL_LEFT,
2777 EL_TUBE_VERTICAL_RIGHT,
2778 EL_TUBE_HORIZONTAL_UP,
2779 EL_TUBE_HORIZONTAL_DOWN,
2784 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2785 EL_EXPANDABLE_STEELWALL_VERTICAL,
2786 EL_EXPANDABLE_STEELWALL_ANY,
2791 static int ep_slippery[] =
2805 EL_ROBOT_WHEEL_ACTIVE,
2811 EL_ACID_POOL_TOPLEFT,
2812 EL_ACID_POOL_TOPRIGHT,
2822 EL_STEELWALL_SLIPPERY,
2825 EL_EMC_WALL_SLIPPERY_1,
2826 EL_EMC_WALL_SLIPPERY_2,
2827 EL_EMC_WALL_SLIPPERY_3,
2828 EL_EMC_WALL_SLIPPERY_4,
2830 EL_EMC_MAGIC_BALL_ACTIVE,
2835 static int ep_can_change[] =
2840 static int ep_can_move[] =
2842 // same elements as in 'pb_can_move_into_acid'
2865 static int ep_can_fall[] =
2879 EL_QUICKSAND_FAST_FULL,
2881 EL_BD_MAGIC_WALL_FULL,
2882 EL_DC_MAGIC_WALL_FULL,
2896 static int ep_can_smash_player[] =
2922 static int ep_can_smash_enemies[] =
2931 static int ep_can_smash_everything[] =
2940 static int ep_explodes_by_fire[] =
2942 // same elements as in 'ep_explodes_impact'
2947 // same elements as in 'ep_explodes_smashed'
2957 EL_EM_DYNAMITE_ACTIVE,
2958 EL_DYNABOMB_PLAYER_1_ACTIVE,
2959 EL_DYNABOMB_PLAYER_2_ACTIVE,
2960 EL_DYNABOMB_PLAYER_3_ACTIVE,
2961 EL_DYNABOMB_PLAYER_4_ACTIVE,
2962 EL_DYNABOMB_INCREASE_NUMBER,
2963 EL_DYNABOMB_INCREASE_SIZE,
2964 EL_DYNABOMB_INCREASE_POWER,
2965 EL_SP_DISK_RED_ACTIVE,
2979 static int ep_explodes_smashed[] =
2981 // same elements as in 'ep_explodes_impact'
2995 static int ep_explodes_impact[] =
3004 static int ep_walkable_over[] =
3008 EL_SOKOBAN_FIELD_EMPTY,
3015 EL_EM_STEEL_EXIT_OPEN,
3016 EL_EM_STEEL_EXIT_OPENING,
3025 EL_GATE_1_GRAY_ACTIVE,
3026 EL_GATE_2_GRAY_ACTIVE,
3027 EL_GATE_3_GRAY_ACTIVE,
3028 EL_GATE_4_GRAY_ACTIVE,
3036 static int ep_walkable_inside[] =
3041 EL_TUBE_VERTICAL_LEFT,
3042 EL_TUBE_VERTICAL_RIGHT,
3043 EL_TUBE_HORIZONTAL_UP,
3044 EL_TUBE_HORIZONTAL_DOWN,
3053 static int ep_walkable_under[] =
3058 static int ep_passable_over[] =
3068 EL_EM_GATE_1_GRAY_ACTIVE,
3069 EL_EM_GATE_2_GRAY_ACTIVE,
3070 EL_EM_GATE_3_GRAY_ACTIVE,
3071 EL_EM_GATE_4_GRAY_ACTIVE,
3080 EL_EMC_GATE_5_GRAY_ACTIVE,
3081 EL_EMC_GATE_6_GRAY_ACTIVE,
3082 EL_EMC_GATE_7_GRAY_ACTIVE,
3083 EL_EMC_GATE_8_GRAY_ACTIVE,
3085 EL_DC_GATE_WHITE_GRAY,
3086 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3093 static int ep_passable_inside[] =
3099 EL_SP_PORT_HORIZONTAL,
3100 EL_SP_PORT_VERTICAL,
3102 EL_SP_GRAVITY_PORT_LEFT,
3103 EL_SP_GRAVITY_PORT_RIGHT,
3104 EL_SP_GRAVITY_PORT_UP,
3105 EL_SP_GRAVITY_PORT_DOWN,
3106 EL_SP_GRAVITY_ON_PORT_LEFT,
3107 EL_SP_GRAVITY_ON_PORT_RIGHT,
3108 EL_SP_GRAVITY_ON_PORT_UP,
3109 EL_SP_GRAVITY_ON_PORT_DOWN,
3110 EL_SP_GRAVITY_OFF_PORT_LEFT,
3111 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3112 EL_SP_GRAVITY_OFF_PORT_UP,
3113 EL_SP_GRAVITY_OFF_PORT_DOWN,
3118 static int ep_passable_under[] =
3123 static int ep_droppable[] =
3128 static int ep_explodes_1x1_old[] =
3133 static int ep_pushable[] =
3145 EL_SOKOBAN_FIELD_FULL,
3154 static int ep_explodes_cross_old[] =
3159 static int ep_protected[] =
3161 // same elements as in 'ep_walkable_inside'
3165 EL_TUBE_VERTICAL_LEFT,
3166 EL_TUBE_VERTICAL_RIGHT,
3167 EL_TUBE_HORIZONTAL_UP,
3168 EL_TUBE_HORIZONTAL_DOWN,
3174 // same elements as in 'ep_passable_over'
3183 EL_EM_GATE_1_GRAY_ACTIVE,
3184 EL_EM_GATE_2_GRAY_ACTIVE,
3185 EL_EM_GATE_3_GRAY_ACTIVE,
3186 EL_EM_GATE_4_GRAY_ACTIVE,
3195 EL_EMC_GATE_5_GRAY_ACTIVE,
3196 EL_EMC_GATE_6_GRAY_ACTIVE,
3197 EL_EMC_GATE_7_GRAY_ACTIVE,
3198 EL_EMC_GATE_8_GRAY_ACTIVE,
3200 EL_DC_GATE_WHITE_GRAY,
3201 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3205 // same elements as in 'ep_passable_inside'
3210 EL_SP_PORT_HORIZONTAL,
3211 EL_SP_PORT_VERTICAL,
3213 EL_SP_GRAVITY_PORT_LEFT,
3214 EL_SP_GRAVITY_PORT_RIGHT,
3215 EL_SP_GRAVITY_PORT_UP,
3216 EL_SP_GRAVITY_PORT_DOWN,
3217 EL_SP_GRAVITY_ON_PORT_LEFT,
3218 EL_SP_GRAVITY_ON_PORT_RIGHT,
3219 EL_SP_GRAVITY_ON_PORT_UP,
3220 EL_SP_GRAVITY_ON_PORT_DOWN,
3221 EL_SP_GRAVITY_OFF_PORT_LEFT,
3222 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3223 EL_SP_GRAVITY_OFF_PORT_UP,
3224 EL_SP_GRAVITY_OFF_PORT_DOWN,
3229 static int ep_throwable[] =
3234 static int ep_can_explode[] =
3236 // same elements as in 'ep_explodes_impact'
3241 // same elements as in 'ep_explodes_smashed'
3247 // elements that can explode by explosion or by dragonfire
3251 EL_EM_DYNAMITE_ACTIVE,
3252 EL_DYNABOMB_PLAYER_1_ACTIVE,
3253 EL_DYNABOMB_PLAYER_2_ACTIVE,
3254 EL_DYNABOMB_PLAYER_3_ACTIVE,
3255 EL_DYNABOMB_PLAYER_4_ACTIVE,
3256 EL_DYNABOMB_INCREASE_NUMBER,
3257 EL_DYNABOMB_INCREASE_SIZE,
3258 EL_DYNABOMB_INCREASE_POWER,
3259 EL_SP_DISK_RED_ACTIVE,
3267 // elements that can explode only by explosion
3273 static int ep_gravity_reachable[] =
3279 EL_INVISIBLE_SAND_ACTIVE,
3284 EL_SP_PORT_HORIZONTAL,
3285 EL_SP_PORT_VERTICAL,
3287 EL_SP_GRAVITY_PORT_LEFT,
3288 EL_SP_GRAVITY_PORT_RIGHT,
3289 EL_SP_GRAVITY_PORT_UP,
3290 EL_SP_GRAVITY_PORT_DOWN,
3291 EL_SP_GRAVITY_ON_PORT_LEFT,
3292 EL_SP_GRAVITY_ON_PORT_RIGHT,
3293 EL_SP_GRAVITY_ON_PORT_UP,
3294 EL_SP_GRAVITY_ON_PORT_DOWN,
3295 EL_SP_GRAVITY_OFF_PORT_LEFT,
3296 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3297 EL_SP_GRAVITY_OFF_PORT_UP,
3298 EL_SP_GRAVITY_OFF_PORT_DOWN,
3304 static int ep_player[] =
3311 EL_SOKOBAN_FIELD_PLAYER,
3317 static int ep_can_pass_magic_wall[] =
3331 static int ep_can_pass_dc_magic_wall[] =
3347 static int ep_switchable[] =
3351 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3352 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3353 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3354 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3355 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3356 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3357 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3358 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3359 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3360 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3361 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3362 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3363 EL_SWITCHGATE_SWITCH_UP,
3364 EL_SWITCHGATE_SWITCH_DOWN,
3365 EL_DC_SWITCHGATE_SWITCH_UP,
3366 EL_DC_SWITCHGATE_SWITCH_DOWN,
3368 EL_LIGHT_SWITCH_ACTIVE,
3370 EL_DC_TIMEGATE_SWITCH,
3371 EL_BALLOON_SWITCH_LEFT,
3372 EL_BALLOON_SWITCH_RIGHT,
3373 EL_BALLOON_SWITCH_UP,
3374 EL_BALLOON_SWITCH_DOWN,
3375 EL_BALLOON_SWITCH_ANY,
3376 EL_BALLOON_SWITCH_NONE,
3379 EL_EMC_MAGIC_BALL_SWITCH,
3380 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3385 static int ep_bd_element[] =
3419 static int ep_sp_element[] =
3421 // should always be valid
3424 // standard classic Supaplex elements
3431 EL_SP_HARDWARE_GRAY,
3439 EL_SP_GRAVITY_PORT_RIGHT,
3440 EL_SP_GRAVITY_PORT_DOWN,
3441 EL_SP_GRAVITY_PORT_LEFT,
3442 EL_SP_GRAVITY_PORT_UP,
3447 EL_SP_PORT_VERTICAL,
3448 EL_SP_PORT_HORIZONTAL,
3454 EL_SP_HARDWARE_BASE_1,
3455 EL_SP_HARDWARE_GREEN,
3456 EL_SP_HARDWARE_BLUE,
3458 EL_SP_HARDWARE_YELLOW,
3459 EL_SP_HARDWARE_BASE_2,
3460 EL_SP_HARDWARE_BASE_3,
3461 EL_SP_HARDWARE_BASE_4,
3462 EL_SP_HARDWARE_BASE_5,
3463 EL_SP_HARDWARE_BASE_6,
3467 // additional elements that appeared in newer Supaplex levels
3470 // additional gravity port elements (not switching, but setting gravity)
3471 EL_SP_GRAVITY_ON_PORT_LEFT,
3472 EL_SP_GRAVITY_ON_PORT_RIGHT,
3473 EL_SP_GRAVITY_ON_PORT_UP,
3474 EL_SP_GRAVITY_ON_PORT_DOWN,
3475 EL_SP_GRAVITY_OFF_PORT_LEFT,
3476 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3477 EL_SP_GRAVITY_OFF_PORT_UP,
3478 EL_SP_GRAVITY_OFF_PORT_DOWN,
3480 // more than one Murphy in a level results in an inactive clone
3483 // runtime Supaplex elements
3484 EL_SP_DISK_RED_ACTIVE,
3485 EL_SP_TERMINAL_ACTIVE,
3486 EL_SP_BUGGY_BASE_ACTIVATING,
3487 EL_SP_BUGGY_BASE_ACTIVE,
3494 static int ep_sb_element[] =
3499 EL_SOKOBAN_FIELD_EMPTY,
3500 EL_SOKOBAN_FIELD_FULL,
3501 EL_SOKOBAN_FIELD_PLAYER,
3506 EL_INVISIBLE_STEELWALL,
3511 static int ep_gem[] =
3523 static int ep_food_dark_yamyam[] =
3551 static int ep_food_penguin[] =
3565 static int ep_food_pig[] =
3577 static int ep_historic_wall[] =
3588 EL_GATE_1_GRAY_ACTIVE,
3589 EL_GATE_2_GRAY_ACTIVE,
3590 EL_GATE_3_GRAY_ACTIVE,
3591 EL_GATE_4_GRAY_ACTIVE,
3600 EL_EM_GATE_1_GRAY_ACTIVE,
3601 EL_EM_GATE_2_GRAY_ACTIVE,
3602 EL_EM_GATE_3_GRAY_ACTIVE,
3603 EL_EM_GATE_4_GRAY_ACTIVE,
3610 EL_EXPANDABLE_WALL_HORIZONTAL,
3611 EL_EXPANDABLE_WALL_VERTICAL,
3612 EL_EXPANDABLE_WALL_ANY,
3613 EL_EXPANDABLE_WALL_GROWING,
3614 EL_BD_EXPANDABLE_WALL,
3621 EL_SP_HARDWARE_GRAY,
3622 EL_SP_HARDWARE_GREEN,
3623 EL_SP_HARDWARE_BLUE,
3625 EL_SP_HARDWARE_YELLOW,
3626 EL_SP_HARDWARE_BASE_1,
3627 EL_SP_HARDWARE_BASE_2,
3628 EL_SP_HARDWARE_BASE_3,
3629 EL_SP_HARDWARE_BASE_4,
3630 EL_SP_HARDWARE_BASE_5,
3631 EL_SP_HARDWARE_BASE_6,
3633 EL_SP_TERMINAL_ACTIVE,
3636 EL_INVISIBLE_STEELWALL,
3637 EL_INVISIBLE_STEELWALL_ACTIVE,
3639 EL_INVISIBLE_WALL_ACTIVE,
3640 EL_STEELWALL_SLIPPERY,
3657 static int ep_historic_solid[] =
3661 EL_EXPANDABLE_WALL_HORIZONTAL,
3662 EL_EXPANDABLE_WALL_VERTICAL,
3663 EL_EXPANDABLE_WALL_ANY,
3664 EL_BD_EXPANDABLE_WALL,
3677 EL_QUICKSAND_FILLING,
3678 EL_QUICKSAND_EMPTYING,
3680 EL_MAGIC_WALL_ACTIVE,
3681 EL_MAGIC_WALL_EMPTYING,
3682 EL_MAGIC_WALL_FILLING,
3686 EL_BD_MAGIC_WALL_ACTIVE,
3687 EL_BD_MAGIC_WALL_EMPTYING,
3688 EL_BD_MAGIC_WALL_FULL,
3689 EL_BD_MAGIC_WALL_FILLING,
3690 EL_BD_MAGIC_WALL_DEAD,
3699 EL_SP_TERMINAL_ACTIVE,
3703 EL_INVISIBLE_WALL_ACTIVE,
3704 EL_SWITCHGATE_SWITCH_UP,
3705 EL_SWITCHGATE_SWITCH_DOWN,
3707 EL_TIMEGATE_SWITCH_ACTIVE,
3719 // the following elements are a direct copy of "indestructible" elements,
3720 // except "EL_ACID", which is "indestructible", but not "solid"!
3725 EL_ACID_POOL_TOPLEFT,
3726 EL_ACID_POOL_TOPRIGHT,
3727 EL_ACID_POOL_BOTTOMLEFT,
3728 EL_ACID_POOL_BOTTOM,
3729 EL_ACID_POOL_BOTTOMRIGHT,
3730 EL_SP_HARDWARE_GRAY,
3731 EL_SP_HARDWARE_GREEN,
3732 EL_SP_HARDWARE_BLUE,
3734 EL_SP_HARDWARE_YELLOW,
3735 EL_SP_HARDWARE_BASE_1,
3736 EL_SP_HARDWARE_BASE_2,
3737 EL_SP_HARDWARE_BASE_3,
3738 EL_SP_HARDWARE_BASE_4,
3739 EL_SP_HARDWARE_BASE_5,
3740 EL_SP_HARDWARE_BASE_6,
3741 EL_INVISIBLE_STEELWALL,
3742 EL_INVISIBLE_STEELWALL_ACTIVE,
3743 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3744 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3745 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3746 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3747 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3748 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3749 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3750 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3751 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3752 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3753 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3754 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3756 EL_LIGHT_SWITCH_ACTIVE,
3757 EL_SIGN_EXCLAMATION,
3758 EL_SIGN_RADIOACTIVITY,
3765 EL_SIGN_ENTRY_FORBIDDEN,
3766 EL_SIGN_EMERGENCY_EXIT,
3774 EL_STEEL_EXIT_CLOSED,
3776 EL_STEEL_EXIT_OPENING,
3777 EL_STEEL_EXIT_CLOSING,
3778 EL_EM_STEEL_EXIT_CLOSED,
3779 EL_EM_STEEL_EXIT_OPEN,
3780 EL_EM_STEEL_EXIT_OPENING,
3781 EL_EM_STEEL_EXIT_CLOSING,
3782 EL_DC_STEELWALL_1_LEFT,
3783 EL_DC_STEELWALL_1_RIGHT,
3784 EL_DC_STEELWALL_1_TOP,
3785 EL_DC_STEELWALL_1_BOTTOM,
3786 EL_DC_STEELWALL_1_HORIZONTAL,
3787 EL_DC_STEELWALL_1_VERTICAL,
3788 EL_DC_STEELWALL_1_TOPLEFT,
3789 EL_DC_STEELWALL_1_TOPRIGHT,
3790 EL_DC_STEELWALL_1_BOTTOMLEFT,
3791 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3792 EL_DC_STEELWALL_1_TOPLEFT_2,
3793 EL_DC_STEELWALL_1_TOPRIGHT_2,
3794 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3795 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3796 EL_DC_STEELWALL_2_LEFT,
3797 EL_DC_STEELWALL_2_RIGHT,
3798 EL_DC_STEELWALL_2_TOP,
3799 EL_DC_STEELWALL_2_BOTTOM,
3800 EL_DC_STEELWALL_2_HORIZONTAL,
3801 EL_DC_STEELWALL_2_VERTICAL,
3802 EL_DC_STEELWALL_2_MIDDLE,
3803 EL_DC_STEELWALL_2_SINGLE,
3804 EL_STEELWALL_SLIPPERY,
3818 EL_GATE_1_GRAY_ACTIVE,
3819 EL_GATE_2_GRAY_ACTIVE,
3820 EL_GATE_3_GRAY_ACTIVE,
3821 EL_GATE_4_GRAY_ACTIVE,
3830 EL_EM_GATE_1_GRAY_ACTIVE,
3831 EL_EM_GATE_2_GRAY_ACTIVE,
3832 EL_EM_GATE_3_GRAY_ACTIVE,
3833 EL_EM_GATE_4_GRAY_ACTIVE,
3842 EL_EMC_GATE_5_GRAY_ACTIVE,
3843 EL_EMC_GATE_6_GRAY_ACTIVE,
3844 EL_EMC_GATE_7_GRAY_ACTIVE,
3845 EL_EMC_GATE_8_GRAY_ACTIVE,
3847 EL_DC_GATE_WHITE_GRAY,
3848 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3849 EL_DC_GATE_FAKE_GRAY,
3851 EL_SWITCHGATE_OPENING,
3852 EL_SWITCHGATE_CLOSED,
3853 EL_SWITCHGATE_CLOSING,
3854 EL_DC_SWITCHGATE_SWITCH_UP,
3855 EL_DC_SWITCHGATE_SWITCH_DOWN,
3857 EL_TIMEGATE_OPENING,
3859 EL_TIMEGATE_CLOSING,
3860 EL_DC_TIMEGATE_SWITCH,
3861 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3865 EL_TUBE_VERTICAL_LEFT,
3866 EL_TUBE_VERTICAL_RIGHT,
3867 EL_TUBE_HORIZONTAL_UP,
3868 EL_TUBE_HORIZONTAL_DOWN,
3873 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3874 EL_EXPANDABLE_STEELWALL_VERTICAL,
3875 EL_EXPANDABLE_STEELWALL_ANY,
3880 static int ep_classic_enemy[] =
3897 static int ep_belt[] =
3899 EL_CONVEYOR_BELT_1_LEFT,
3900 EL_CONVEYOR_BELT_1_MIDDLE,
3901 EL_CONVEYOR_BELT_1_RIGHT,
3902 EL_CONVEYOR_BELT_2_LEFT,
3903 EL_CONVEYOR_BELT_2_MIDDLE,
3904 EL_CONVEYOR_BELT_2_RIGHT,
3905 EL_CONVEYOR_BELT_3_LEFT,
3906 EL_CONVEYOR_BELT_3_MIDDLE,
3907 EL_CONVEYOR_BELT_3_RIGHT,
3908 EL_CONVEYOR_BELT_4_LEFT,
3909 EL_CONVEYOR_BELT_4_MIDDLE,
3910 EL_CONVEYOR_BELT_4_RIGHT,
3915 static int ep_belt_active[] =
3917 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3918 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3919 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3920 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3921 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3922 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3923 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3924 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3925 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3926 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3927 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3928 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3933 static int ep_belt_switch[] =
3935 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3936 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3937 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3938 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3939 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3940 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3941 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3942 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3943 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3944 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3945 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3946 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3951 static int ep_tube[] =
3958 EL_TUBE_HORIZONTAL_UP,
3959 EL_TUBE_HORIZONTAL_DOWN,
3961 EL_TUBE_VERTICAL_LEFT,
3962 EL_TUBE_VERTICAL_RIGHT,
3968 static int ep_acid_pool[] =
3970 EL_ACID_POOL_TOPLEFT,
3971 EL_ACID_POOL_TOPRIGHT,
3972 EL_ACID_POOL_BOTTOMLEFT,
3973 EL_ACID_POOL_BOTTOM,
3974 EL_ACID_POOL_BOTTOMRIGHT,
3979 static int ep_keygate[] =
3989 EL_GATE_1_GRAY_ACTIVE,
3990 EL_GATE_2_GRAY_ACTIVE,
3991 EL_GATE_3_GRAY_ACTIVE,
3992 EL_GATE_4_GRAY_ACTIVE,
4001 EL_EM_GATE_1_GRAY_ACTIVE,
4002 EL_EM_GATE_2_GRAY_ACTIVE,
4003 EL_EM_GATE_3_GRAY_ACTIVE,
4004 EL_EM_GATE_4_GRAY_ACTIVE,
4013 EL_EMC_GATE_5_GRAY_ACTIVE,
4014 EL_EMC_GATE_6_GRAY_ACTIVE,
4015 EL_EMC_GATE_7_GRAY_ACTIVE,
4016 EL_EMC_GATE_8_GRAY_ACTIVE,
4018 EL_DC_GATE_WHITE_GRAY,
4019 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4024 static int ep_amoeboid[] =
4036 static int ep_amoebalive[] =
4047 static int ep_has_editor_content[] =
4053 EL_SOKOBAN_FIELD_PLAYER,
4070 static int ep_can_turn_each_move[] =
4072 // !!! do something with this one !!!
4076 static int ep_can_grow[] =
4090 static int ep_active_bomb[] =
4093 EL_EM_DYNAMITE_ACTIVE,
4094 EL_DYNABOMB_PLAYER_1_ACTIVE,
4095 EL_DYNABOMB_PLAYER_2_ACTIVE,
4096 EL_DYNABOMB_PLAYER_3_ACTIVE,
4097 EL_DYNABOMB_PLAYER_4_ACTIVE,
4098 EL_SP_DISK_RED_ACTIVE,
4103 static int ep_inactive[] =
4113 EL_QUICKSAND_FAST_EMPTY,
4136 EL_GATE_1_GRAY_ACTIVE,
4137 EL_GATE_2_GRAY_ACTIVE,
4138 EL_GATE_3_GRAY_ACTIVE,
4139 EL_GATE_4_GRAY_ACTIVE,
4148 EL_EM_GATE_1_GRAY_ACTIVE,
4149 EL_EM_GATE_2_GRAY_ACTIVE,
4150 EL_EM_GATE_3_GRAY_ACTIVE,
4151 EL_EM_GATE_4_GRAY_ACTIVE,
4160 EL_EMC_GATE_5_GRAY_ACTIVE,
4161 EL_EMC_GATE_6_GRAY_ACTIVE,
4162 EL_EMC_GATE_7_GRAY_ACTIVE,
4163 EL_EMC_GATE_8_GRAY_ACTIVE,
4165 EL_DC_GATE_WHITE_GRAY,
4166 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4167 EL_DC_GATE_FAKE_GRAY,
4170 EL_INVISIBLE_STEELWALL,
4178 EL_WALL_EMERALD_YELLOW,
4179 EL_DYNABOMB_INCREASE_NUMBER,
4180 EL_DYNABOMB_INCREASE_SIZE,
4181 EL_DYNABOMB_INCREASE_POWER,
4185 EL_SOKOBAN_FIELD_EMPTY,
4186 EL_SOKOBAN_FIELD_FULL,
4187 EL_WALL_EMERALD_RED,
4188 EL_WALL_EMERALD_PURPLE,
4189 EL_ACID_POOL_TOPLEFT,
4190 EL_ACID_POOL_TOPRIGHT,
4191 EL_ACID_POOL_BOTTOMLEFT,
4192 EL_ACID_POOL_BOTTOM,
4193 EL_ACID_POOL_BOTTOMRIGHT,
4197 EL_BD_MAGIC_WALL_DEAD,
4199 EL_DC_MAGIC_WALL_DEAD,
4200 EL_AMOEBA_TO_DIAMOND,
4208 EL_SP_GRAVITY_PORT_RIGHT,
4209 EL_SP_GRAVITY_PORT_DOWN,
4210 EL_SP_GRAVITY_PORT_LEFT,
4211 EL_SP_GRAVITY_PORT_UP,
4212 EL_SP_PORT_HORIZONTAL,
4213 EL_SP_PORT_VERTICAL,
4224 EL_SP_HARDWARE_GRAY,
4225 EL_SP_HARDWARE_GREEN,
4226 EL_SP_HARDWARE_BLUE,
4228 EL_SP_HARDWARE_YELLOW,
4229 EL_SP_HARDWARE_BASE_1,
4230 EL_SP_HARDWARE_BASE_2,
4231 EL_SP_HARDWARE_BASE_3,
4232 EL_SP_HARDWARE_BASE_4,
4233 EL_SP_HARDWARE_BASE_5,
4234 EL_SP_HARDWARE_BASE_6,
4235 EL_SP_GRAVITY_ON_PORT_LEFT,
4236 EL_SP_GRAVITY_ON_PORT_RIGHT,
4237 EL_SP_GRAVITY_ON_PORT_UP,
4238 EL_SP_GRAVITY_ON_PORT_DOWN,
4239 EL_SP_GRAVITY_OFF_PORT_LEFT,
4240 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4241 EL_SP_GRAVITY_OFF_PORT_UP,
4242 EL_SP_GRAVITY_OFF_PORT_DOWN,
4243 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4244 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4245 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4246 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4247 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4248 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4249 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4250 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4251 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4252 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4253 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4254 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4255 EL_SIGN_EXCLAMATION,
4256 EL_SIGN_RADIOACTIVITY,
4263 EL_SIGN_ENTRY_FORBIDDEN,
4264 EL_SIGN_EMERGENCY_EXIT,
4272 EL_DC_STEELWALL_1_LEFT,
4273 EL_DC_STEELWALL_1_RIGHT,
4274 EL_DC_STEELWALL_1_TOP,
4275 EL_DC_STEELWALL_1_BOTTOM,
4276 EL_DC_STEELWALL_1_HORIZONTAL,
4277 EL_DC_STEELWALL_1_VERTICAL,
4278 EL_DC_STEELWALL_1_TOPLEFT,
4279 EL_DC_STEELWALL_1_TOPRIGHT,
4280 EL_DC_STEELWALL_1_BOTTOMLEFT,
4281 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4282 EL_DC_STEELWALL_1_TOPLEFT_2,
4283 EL_DC_STEELWALL_1_TOPRIGHT_2,
4284 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4285 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4286 EL_DC_STEELWALL_2_LEFT,
4287 EL_DC_STEELWALL_2_RIGHT,
4288 EL_DC_STEELWALL_2_TOP,
4289 EL_DC_STEELWALL_2_BOTTOM,
4290 EL_DC_STEELWALL_2_HORIZONTAL,
4291 EL_DC_STEELWALL_2_VERTICAL,
4292 EL_DC_STEELWALL_2_MIDDLE,
4293 EL_DC_STEELWALL_2_SINGLE,
4294 EL_STEELWALL_SLIPPERY,
4299 EL_EMC_WALL_SLIPPERY_1,
4300 EL_EMC_WALL_SLIPPERY_2,
4301 EL_EMC_WALL_SLIPPERY_3,
4302 EL_EMC_WALL_SLIPPERY_4,
4323 static int ep_em_slippery_wall[] =
4328 static int ep_gfx_crumbled[] =
4339 static int ep_editor_cascade_active[] =
4341 EL_INTERNAL_CASCADE_BD_ACTIVE,
4342 EL_INTERNAL_CASCADE_EM_ACTIVE,
4343 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4344 EL_INTERNAL_CASCADE_RND_ACTIVE,
4345 EL_INTERNAL_CASCADE_SB_ACTIVE,
4346 EL_INTERNAL_CASCADE_SP_ACTIVE,
4347 EL_INTERNAL_CASCADE_DC_ACTIVE,
4348 EL_INTERNAL_CASCADE_DX_ACTIVE,
4349 EL_INTERNAL_CASCADE_MM_ACTIVE,
4350 EL_INTERNAL_CASCADE_DF_ACTIVE,
4351 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4352 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4353 EL_INTERNAL_CASCADE_CE_ACTIVE,
4354 EL_INTERNAL_CASCADE_GE_ACTIVE,
4355 EL_INTERNAL_CASCADE_REF_ACTIVE,
4356 EL_INTERNAL_CASCADE_USER_ACTIVE,
4357 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4362 static int ep_editor_cascade_inactive[] =
4364 EL_INTERNAL_CASCADE_BD,
4365 EL_INTERNAL_CASCADE_EM,
4366 EL_INTERNAL_CASCADE_EMC,
4367 EL_INTERNAL_CASCADE_RND,
4368 EL_INTERNAL_CASCADE_SB,
4369 EL_INTERNAL_CASCADE_SP,
4370 EL_INTERNAL_CASCADE_DC,
4371 EL_INTERNAL_CASCADE_DX,
4372 EL_INTERNAL_CASCADE_MM,
4373 EL_INTERNAL_CASCADE_DF,
4374 EL_INTERNAL_CASCADE_CHARS,
4375 EL_INTERNAL_CASCADE_STEEL_CHARS,
4376 EL_INTERNAL_CASCADE_CE,
4377 EL_INTERNAL_CASCADE_GE,
4378 EL_INTERNAL_CASCADE_REF,
4379 EL_INTERNAL_CASCADE_USER,
4380 EL_INTERNAL_CASCADE_DYNAMIC,
4385 static int ep_obsolete[] =
4389 EL_EM_KEY_1_FILE_OBSOLETE,
4390 EL_EM_KEY_2_FILE_OBSOLETE,
4391 EL_EM_KEY_3_FILE_OBSOLETE,
4392 EL_EM_KEY_4_FILE_OBSOLETE,
4393 EL_ENVELOPE_OBSOLETE,
4402 } element_properties[] =
4404 { ep_diggable, EP_DIGGABLE },
4405 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4406 { ep_dont_run_into, EP_DONT_RUN_INTO },
4407 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4408 { ep_dont_touch, EP_DONT_TOUCH },
4409 { ep_indestructible, EP_INDESTRUCTIBLE },
4410 { ep_slippery, EP_SLIPPERY },
4411 { ep_can_change, EP_CAN_CHANGE },
4412 { ep_can_move, EP_CAN_MOVE },
4413 { ep_can_fall, EP_CAN_FALL },
4414 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4415 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4416 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4417 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4418 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4419 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4420 { ep_walkable_over, EP_WALKABLE_OVER },
4421 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4422 { ep_walkable_under, EP_WALKABLE_UNDER },
4423 { ep_passable_over, EP_PASSABLE_OVER },
4424 { ep_passable_inside, EP_PASSABLE_INSIDE },
4425 { ep_passable_under, EP_PASSABLE_UNDER },
4426 { ep_droppable, EP_DROPPABLE },
4427 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4428 { ep_pushable, EP_PUSHABLE },
4429 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4430 { ep_protected, EP_PROTECTED },
4431 { ep_throwable, EP_THROWABLE },
4432 { ep_can_explode, EP_CAN_EXPLODE },
4433 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4435 { ep_player, EP_PLAYER },
4436 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4437 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4438 { ep_switchable, EP_SWITCHABLE },
4439 { ep_bd_element, EP_BD_ELEMENT },
4440 { ep_sp_element, EP_SP_ELEMENT },
4441 { ep_sb_element, EP_SB_ELEMENT },
4443 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4444 { ep_food_penguin, EP_FOOD_PENGUIN },
4445 { ep_food_pig, EP_FOOD_PIG },
4446 { ep_historic_wall, EP_HISTORIC_WALL },
4447 { ep_historic_solid, EP_HISTORIC_SOLID },
4448 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4449 { ep_belt, EP_BELT },
4450 { ep_belt_active, EP_BELT_ACTIVE },
4451 { ep_belt_switch, EP_BELT_SWITCH },
4452 { ep_tube, EP_TUBE },
4453 { ep_acid_pool, EP_ACID_POOL },
4454 { ep_keygate, EP_KEYGATE },
4455 { ep_amoeboid, EP_AMOEBOID },
4456 { ep_amoebalive, EP_AMOEBALIVE },
4457 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4458 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4459 { ep_can_grow, EP_CAN_GROW },
4460 { ep_active_bomb, EP_ACTIVE_BOMB },
4461 { ep_inactive, EP_INACTIVE },
4463 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4465 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4467 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4468 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4470 { ep_obsolete, EP_OBSOLETE },
4477 // always start with reliable default values (element has no properties)
4478 // (but never initialize clipboard elements after the very first time)
4479 // (to be able to use clipboard elements between several levels)
4480 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4481 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4482 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4483 SET_PROPERTY(i, j, FALSE);
4485 // set all base element properties from above array definitions
4486 for (i = 0; element_properties[i].elements != NULL; i++)
4487 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4488 SET_PROPERTY((element_properties[i].elements)[j],
4489 element_properties[i].property, TRUE);
4491 // copy properties to some elements that are only stored in level file
4492 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4493 for (j = 0; copy_properties[j][0] != -1; j++)
4494 if (HAS_PROPERTY(copy_properties[j][0], i))
4495 for (k = 1; k <= 4; k++)
4496 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4498 // set static element properties that are not listed in array definitions
4499 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4500 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4502 clipboard_elements_initialized = TRUE;
4505 void InitElementPropertiesEngine(int engine_version)
4507 static int no_wall_properties[] =
4510 EP_COLLECTIBLE_ONLY,
4512 EP_DONT_COLLIDE_WITH,
4515 EP_CAN_SMASH_PLAYER,
4516 EP_CAN_SMASH_ENEMIES,
4517 EP_CAN_SMASH_EVERYTHING,
4522 EP_FOOD_DARK_YAMYAM,
4538 /* important: after initialization in InitElementPropertiesStatic(), the
4539 elements are not again initialized to a default value; therefore all
4540 changes have to make sure that they leave the element with a defined
4541 property (which means that conditional property changes must be set to
4542 a reliable default value before) */
4544 // resolve group elements
4545 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4546 ResolveGroupElement(EL_GROUP_START + i);
4548 // set all special, combined or engine dependent element properties
4549 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4551 // do not change (already initialized) clipboard elements here
4552 if (IS_CLIPBOARD_ELEMENT(i))
4555 // ---------- INACTIVE ----------------------------------------------------
4556 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4557 i <= EL_CHAR_END) ||
4558 (i >= EL_STEEL_CHAR_START &&
4559 i <= EL_STEEL_CHAR_END)));
4561 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4562 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4563 IS_WALKABLE_INSIDE(i) ||
4564 IS_WALKABLE_UNDER(i)));
4566 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4567 IS_PASSABLE_INSIDE(i) ||
4568 IS_PASSABLE_UNDER(i)));
4570 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4571 IS_PASSABLE_OVER(i)));
4573 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4574 IS_PASSABLE_INSIDE(i)));
4576 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4577 IS_PASSABLE_UNDER(i)));
4579 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4582 // ---------- COLLECTIBLE -------------------------------------------------
4583 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4587 // ---------- SNAPPABLE ---------------------------------------------------
4588 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4589 IS_COLLECTIBLE(i) ||
4593 // ---------- WALL --------------------------------------------------------
4594 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4596 for (j = 0; no_wall_properties[j] != -1; j++)
4597 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4598 i >= EL_FIRST_RUNTIME_UNREAL)
4599 SET_PROPERTY(i, EP_WALL, FALSE);
4601 if (IS_HISTORIC_WALL(i))
4602 SET_PROPERTY(i, EP_WALL, TRUE);
4604 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4605 if (engine_version < VERSION_IDENT(2,2,0,0))
4606 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4608 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4610 !IS_COLLECTIBLE(i)));
4612 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4613 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4614 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4616 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4619 // ---------- EXPLOSION_PROOF ---------------------------------------------
4621 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4622 else if (engine_version < VERSION_IDENT(2,2,0,0))
4623 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4625 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4629 if (IS_CUSTOM_ELEMENT(i))
4631 // these are additional properties which are initially false when set
4633 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4635 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4636 if (DONT_COLLIDE_WITH(i))
4637 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4639 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4640 if (CAN_SMASH_EVERYTHING(i))
4641 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4642 if (CAN_SMASH_ENEMIES(i))
4643 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4646 // ---------- CAN_SMASH ---------------------------------------------------
4647 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4648 CAN_SMASH_ENEMIES(i) ||
4649 CAN_SMASH_EVERYTHING(i)));
4651 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4652 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4653 EXPLODES_BY_FIRE(i)));
4655 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4656 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4657 EXPLODES_SMASHED(i)));
4659 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4660 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4661 EXPLODES_IMPACT(i)));
4663 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4664 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4666 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4667 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4668 i == EL_BLACK_ORB));
4670 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4671 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4673 IS_CUSTOM_ELEMENT(i)));
4675 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4676 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4677 i == EL_SP_ELECTRON));
4679 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4680 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4681 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4682 getMoveIntoAcidProperty(&level, i));
4684 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4685 if (MAYBE_DONT_COLLIDE_WITH(i))
4686 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4687 getDontCollideWithProperty(&level, i));
4689 // ---------- SP_PORT -----------------------------------------------------
4690 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4691 IS_PASSABLE_INSIDE(i)));
4693 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4694 for (j = 0; j < level.num_android_clone_elements; j++)
4695 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4697 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4699 // ---------- CAN_CHANGE --------------------------------------------------
4700 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4701 for (j = 0; j < element_info[i].num_change_pages; j++)
4702 if (element_info[i].change_page[j].can_change)
4703 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4705 // ---------- HAS_ACTION --------------------------------------------------
4706 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4707 for (j = 0; j < element_info[i].num_change_pages; j++)
4708 if (element_info[i].change_page[j].has_action)
4709 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4711 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4712 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4715 // ---------- GFX_CRUMBLED ------------------------------------------------
4716 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4717 element_info[i].crumbled[ACTION_DEFAULT] !=
4718 element_info[i].graphic[ACTION_DEFAULT]);
4720 // ---------- EDITOR_CASCADE ----------------------------------------------
4721 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4722 IS_EDITOR_CASCADE_INACTIVE(i)));
4725 // dynamically adjust element properties according to game engine version
4727 static int ep_em_slippery_wall[] =
4732 EL_EXPANDABLE_WALL_HORIZONTAL,
4733 EL_EXPANDABLE_WALL_VERTICAL,
4734 EL_EXPANDABLE_WALL_ANY,
4735 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4736 EL_EXPANDABLE_STEELWALL_VERTICAL,
4737 EL_EXPANDABLE_STEELWALL_ANY,
4738 EL_EXPANDABLE_STEELWALL_GROWING,
4742 static int ep_em_explodes_by_fire[] =
4745 EL_EM_DYNAMITE_ACTIVE,
4750 // special EM style gems behaviour
4751 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4752 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4753 level.em_slippery_gems);
4755 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4756 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4757 (level.em_slippery_gems &&
4758 engine_version > VERSION_IDENT(2,0,1,0)));
4760 // special EM style explosion behaviour regarding chain reactions
4761 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4762 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4763 level.em_explodes_by_fire);
4766 // this is needed because some graphics depend on element properties
4767 if (game_status == GAME_MODE_PLAYING)
4768 InitElementGraphicInfo();
4771 void InitElementPropertiesGfxElement(void)
4775 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4777 struct ElementInfo *ei = &element_info[i];
4779 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4783 static void InitGlobal(void)
4788 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4790 // check if element_name_info entry defined for each element in "main.h"
4791 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4792 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4794 element_info[i].token_name = element_name_info[i].token_name;
4795 element_info[i].class_name = element_name_info[i].class_name;
4796 element_info[i].editor_description= element_name_info[i].editor_description;
4799 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4801 // check if global_anim_name_info defined for each entry in "main.h"
4802 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4803 global_anim_name_info[i].token_name == NULL)
4804 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4806 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4809 // create hash from image config list
4810 image_config_hash = newSetupFileHash();
4811 for (i = 0; image_config[i].token != NULL; i++)
4812 setHashEntry(image_config_hash,
4813 image_config[i].token,
4814 image_config[i].value);
4816 // create hash from element token list
4817 element_token_hash = newSetupFileHash();
4818 for (i = 0; element_name_info[i].token_name != NULL; i++)
4819 setHashEntry(element_token_hash,
4820 element_name_info[i].token_name,
4823 // create hash from graphic token list
4824 graphic_token_hash = newSetupFileHash();
4825 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4826 if (strSuffix(image_config[i].value, ".png") ||
4827 strSuffix(image_config[i].value, ".pcx") ||
4828 strSuffix(image_config[i].value, ".wav") ||
4829 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4830 setHashEntry(graphic_token_hash,
4831 image_config[i].token,
4832 int2str(graphic++, 0));
4834 // create hash from font token list
4835 font_token_hash = newSetupFileHash();
4836 for (i = 0; font_info[i].token_name != NULL; i++)
4837 setHashEntry(font_token_hash,
4838 font_info[i].token_name,
4841 // set default filenames for all cloned graphics in static configuration
4842 for (i = 0; image_config[i].token != NULL; i++)
4844 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4846 char *token = image_config[i].token;
4847 char *token_clone_from = getStringCat2(token, ".clone_from");
4848 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4850 if (token_cloned != NULL)
4852 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4854 if (value_cloned != NULL)
4856 // set default filename in static configuration
4857 image_config[i].value = value_cloned;
4859 // set default filename in image config hash
4860 setHashEntry(image_config_hash, token, value_cloned);
4864 free(token_clone_from);
4868 // always start with reliable default values (all elements)
4869 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4870 ActiveElement[i] = i;
4872 // now add all entries that have an active state (active elements)
4873 for (i = 0; element_with_active_state[i].element != -1; i++)
4875 int element = element_with_active_state[i].element;
4876 int element_active = element_with_active_state[i].element_active;
4878 ActiveElement[element] = element_active;
4881 // always start with reliable default values (all buttons)
4882 for (i = 0; i < NUM_IMAGE_FILES; i++)
4883 ActiveButton[i] = i;
4885 // now add all entries that have an active state (active buttons)
4886 for (i = 0; button_with_active_state[i].button != -1; i++)
4888 int button = button_with_active_state[i].button;
4889 int button_active = button_with_active_state[i].button_active;
4891 ActiveButton[button] = button_active;
4894 // always start with reliable default values (all fonts)
4895 for (i = 0; i < NUM_FONTS; i++)
4898 // now add all entries that have an active state (active fonts)
4899 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4901 int font = font_with_active_state[i].font_nr;
4902 int font_active = font_with_active_state[i].font_nr_active;
4904 ActiveFont[font] = font_active;
4907 global.autoplay_leveldir = NULL;
4908 global.convert_leveldir = NULL;
4909 global.create_images_dir = NULL;
4911 global.frames_per_second = 0;
4912 global.show_frames_per_second = FALSE;
4914 global.border_status = GAME_MODE_LOADING;
4915 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4917 global.use_envelope_request = FALSE;
4920 static void Execute_Command(char *command)
4924 if (strEqual(command, "print graphicsinfo.conf"))
4926 Print("# You can configure additional/alternative image files here.\n");
4927 Print("# (The entries below are default and therefore commented out.)\n");
4929 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4931 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4934 for (i = 0; image_config[i].token != NULL; i++)
4935 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4936 image_config[i].value));
4940 else if (strEqual(command, "print soundsinfo.conf"))
4942 Print("# You can configure additional/alternative sound files here.\n");
4943 Print("# (The entries below are default and therefore commented out.)\n");
4945 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4947 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4950 for (i = 0; sound_config[i].token != NULL; i++)
4951 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4952 sound_config[i].value));
4956 else if (strEqual(command, "print musicinfo.conf"))
4958 Print("# You can configure additional/alternative music files here.\n");
4959 Print("# (The entries below are default and therefore commented out.)\n");
4961 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4963 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4966 for (i = 0; music_config[i].token != NULL; i++)
4967 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4968 music_config[i].value));
4972 else if (strEqual(command, "print editorsetup.conf"))
4974 Print("# You can configure your personal editor element list here.\n");
4975 Print("# (The entries below are default and therefore commented out.)\n");
4978 // this is needed to be able to check element list for cascade elements
4979 InitElementPropertiesStatic();
4980 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4982 PrintEditorElementList();
4986 else if (strEqual(command, "print helpanim.conf"))
4988 Print("# You can configure different element help animations here.\n");
4989 Print("# (The entries below are default and therefore commented out.)\n");
4992 for (i = 0; helpanim_config[i].token != NULL; i++)
4994 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4995 helpanim_config[i].value));
4997 if (strEqual(helpanim_config[i].token, "end"))
5003 else if (strEqual(command, "print helptext.conf"))
5005 Print("# You can configure different element help text here.\n");
5006 Print("# (The entries below are default and therefore commented out.)\n");
5009 for (i = 0; helptext_config[i].token != NULL; i++)
5010 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5011 helptext_config[i].value));
5015 else if (strPrefix(command, "dump level "))
5017 char *filename = &command[11];
5019 if (!fileExists(filename))
5020 Error(ERR_EXIT, "cannot open file '%s'", filename);
5022 LoadLevelFromFilename(&level, filename);
5027 else if (strPrefix(command, "dump tape "))
5029 char *filename = &command[10];
5031 if (!fileExists(filename))
5032 Error(ERR_EXIT, "cannot open file '%s'", filename);
5034 LoadTapeFromFilename(filename);
5039 else if (strPrefix(command, "autotest ") ||
5040 strPrefix(command, "autoplay ") ||
5041 strPrefix(command, "autoffwd ") ||
5042 strPrefix(command, "autowarp "))
5044 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5046 global.autoplay_mode =
5047 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5048 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5049 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5050 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5051 AUTOPLAY_MODE_NONE);
5053 while (*str_ptr != '\0') // continue parsing string
5055 // cut leading whitespace from string, replace it by string terminator
5056 while (*str_ptr == ' ' || *str_ptr == '\t')
5059 if (*str_ptr == '\0') // end of string reached
5062 if (global.autoplay_leveldir == NULL) // read level set string
5064 global.autoplay_leveldir = str_ptr;
5065 global.autoplay_all = TRUE; // default: play all tapes
5067 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5068 global.autoplay_level[i] = FALSE;
5070 else // read level number string
5072 int level_nr = atoi(str_ptr); // get level_nr value
5074 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5075 global.autoplay_level[level_nr] = TRUE;
5077 global.autoplay_all = FALSE;
5080 // advance string pointer to the next whitespace (or end of string)
5081 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5085 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5086 program.headless = TRUE;
5088 else if (strPrefix(command, "convert "))
5090 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5091 char *str_ptr = strchr(str_copy, ' ');
5093 global.convert_leveldir = str_copy;
5094 global.convert_level_nr = -1;
5096 if (str_ptr != NULL) // level number follows
5098 *str_ptr++ = '\0'; // terminate leveldir string
5099 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5102 program.headless = TRUE;
5104 else if (strPrefix(command, "create images "))
5106 global.create_images_dir = getStringCopy(&command[14]);
5108 if (access(global.create_images_dir, W_OK) != 0)
5109 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5110 global.create_images_dir);
5112 else if (strPrefix(command, "create CE image "))
5114 CreateCustomElementImages(&command[16]);
5120 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5123 // disable networking if any valid command was recognized
5124 options.network = setup.network_mode = FALSE;
5127 static void InitSetup(void)
5129 LoadSetup(); // global setup info
5130 LoadSetup_AutoSetup(); // global auto setup info
5132 // set some options from setup file
5134 if (setup.options.verbose)
5135 options.verbose = TRUE;
5137 if (setup.debug.show_frames_per_second)
5138 global.show_frames_per_second = TRUE;
5141 static void InitGameInfo(void)
5143 game.restart_level = FALSE;
5144 game.restart_game_message = NULL;
5145 game.request_active = FALSE;
5148 static void InitPlayerInfo(void)
5152 // choose default local player
5153 local_player = &stored_player[0];
5155 for (i = 0; i < MAX_PLAYERS; i++)
5157 stored_player[i].connected_locally = FALSE;
5158 stored_player[i].connected_network = FALSE;
5161 local_player->connected_locally = TRUE;
5164 static void InitArtworkInfo(void)
5169 static char *get_string_in_brackets(char *string)
5171 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5173 sprintf(string_in_brackets, "[%s]", string);
5175 return string_in_brackets;
5178 static char *get_level_id_suffix(int id_nr)
5180 char *id_suffix = checked_malloc(1 + 3 + 1);
5182 if (id_nr < 0 || id_nr > 999)
5185 sprintf(id_suffix, ".%03d", id_nr);
5190 static void InitArtworkConfig(void)
5192 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5194 NUM_GLOBAL_ANIM_TOKENS + 1];
5195 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5196 NUM_GLOBAL_ANIM_TOKENS + 1];
5197 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5198 NUM_GLOBAL_ANIM_TOKENS + 1];
5199 static char *action_id_suffix[NUM_ACTIONS + 1];
5200 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5201 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5202 static char *level_id_suffix[MAX_LEVELS + 1];
5203 static char *dummy[1] = { NULL };
5204 static char *ignore_generic_tokens[] =
5209 "program_copyright",
5214 static char **ignore_image_tokens;
5215 static char **ignore_sound_tokens;
5216 static char **ignore_music_tokens;
5217 int num_ignore_generic_tokens;
5218 int num_ignore_image_tokens;
5219 int num_ignore_sound_tokens;
5220 int num_ignore_music_tokens;
5223 // dynamically determine list of generic tokens to be ignored
5224 num_ignore_generic_tokens = 0;
5225 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5226 num_ignore_generic_tokens++;
5228 // dynamically determine list of image tokens to be ignored
5229 num_ignore_image_tokens = num_ignore_generic_tokens;
5230 for (i = 0; image_config_vars[i].token != NULL; i++)
5231 num_ignore_image_tokens++;
5232 ignore_image_tokens =
5233 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5234 for (i = 0; i < num_ignore_generic_tokens; i++)
5235 ignore_image_tokens[i] = ignore_generic_tokens[i];
5236 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5237 ignore_image_tokens[num_ignore_generic_tokens + i] =
5238 image_config_vars[i].token;
5239 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5241 // dynamically determine list of sound tokens to be ignored
5242 num_ignore_sound_tokens = num_ignore_generic_tokens;
5243 ignore_sound_tokens =
5244 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5245 for (i = 0; i < num_ignore_generic_tokens; i++)
5246 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5247 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5249 // dynamically determine list of music tokens to be ignored
5250 num_ignore_music_tokens = num_ignore_generic_tokens;
5251 ignore_music_tokens =
5252 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5253 for (i = 0; i < num_ignore_generic_tokens; i++)
5254 ignore_music_tokens[i] = ignore_generic_tokens[i];
5255 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5257 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5258 image_id_prefix[i] = element_info[i].token_name;
5259 for (i = 0; i < NUM_FONTS; i++)
5260 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5261 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5262 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5263 global_anim_info[i].token_name;
5264 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5266 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5267 sound_id_prefix[i] = element_info[i].token_name;
5268 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5269 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5270 get_string_in_brackets(element_info[i].class_name);
5271 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5272 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5273 global_anim_info[i].token_name;
5274 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5276 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5277 music_id_prefix[i] = music_prefix_info[i].prefix;
5278 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5279 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5280 global_anim_info[i].token_name;
5281 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5283 for (i = 0; i < NUM_ACTIONS; i++)
5284 action_id_suffix[i] = element_action_info[i].suffix;
5285 action_id_suffix[NUM_ACTIONS] = NULL;
5287 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5288 direction_id_suffix[i] = element_direction_info[i].suffix;
5289 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5291 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5292 special_id_suffix[i] = special_suffix_info[i].suffix;
5293 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5295 for (i = 0; i < MAX_LEVELS; i++)
5296 level_id_suffix[i] = get_level_id_suffix(i);
5297 level_id_suffix[MAX_LEVELS] = NULL;
5299 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5300 image_id_prefix, action_id_suffix, direction_id_suffix,
5301 special_id_suffix, ignore_image_tokens);
5302 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5303 sound_id_prefix, action_id_suffix, dummy,
5304 special_id_suffix, ignore_sound_tokens);
5305 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5306 music_id_prefix, action_id_suffix, special_id_suffix,
5307 level_id_suffix, ignore_music_tokens);
5310 static void InitMixer(void)
5317 static void InitVideoOverlay(void)
5319 // if virtual buttons are not loaded from setup file, repeat initializing
5320 // virtual buttons grid with default values now that video is initialized
5321 if (!setup.touch.grid_initialized)
5324 InitTileCursorInfo();
5328 void InitGfxBuffers(void)
5330 static int win_xsize_last = -1;
5331 static int win_ysize_last = -1;
5333 // create additional image buffers for double-buffering and cross-fading
5335 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5337 // used to temporarily store the backbuffer -- only re-create if changed
5338 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5339 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5341 win_xsize_last = WIN_XSIZE;
5342 win_ysize_last = WIN_YSIZE;
5345 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5346 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5347 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5348 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5350 // initialize screen properties
5351 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5352 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5354 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5355 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5356 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5357 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5358 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5359 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5361 // required if door size definitions have changed
5362 InitGraphicCompatibilityInfo_Doors();
5364 InitGfxBuffers_EM();
5365 InitGfxBuffers_SP();
5368 static void InitGfx(void)
5370 struct GraphicInfo *graphic_info_last = graphic_info;
5371 char *filename_font_initial = NULL;
5372 char *filename_anim_initial = NULL;
5373 Bitmap *bitmap_font_initial = NULL;
5376 // determine settings for initial font (for displaying startup messages)
5377 for (i = 0; image_config[i].token != NULL; i++)
5379 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5381 char font_token[128];
5384 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5385 len_font_token = strlen(font_token);
5387 if (strEqual(image_config[i].token, font_token))
5388 filename_font_initial = image_config[i].value;
5389 else if (strlen(image_config[i].token) > len_font_token &&
5390 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5392 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5393 font_initial[j].src_x = atoi(image_config[i].value);
5394 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5395 font_initial[j].src_y = atoi(image_config[i].value);
5396 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5397 font_initial[j].width = atoi(image_config[i].value);
5398 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5399 font_initial[j].height = atoi(image_config[i].value);
5404 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5406 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5407 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5410 if (filename_font_initial == NULL) // should not happen
5411 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5414 InitGfxCustomArtworkInfo();
5415 InitGfxOtherSettings();
5417 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5419 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5420 font_initial[j].bitmap = bitmap_font_initial;
5422 InitFontGraphicInfo();
5426 DrawInitText("Loading graphics", 120, FC_GREEN);
5428 // initialize settings for busy animation with default values
5429 int parameter[NUM_GFX_ARGS];
5430 for (i = 0; i < NUM_GFX_ARGS; i++)
5431 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5432 image_config_suffix[i].token,
5433 image_config_suffix[i].type);
5435 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5436 int len_anim_token = strlen(anim_token);
5438 // read settings for busy animation from default custom artwork config
5439 char *gfx_config_filename = getPath3(options.graphics_directory,
5441 GRAPHICSINFO_FILENAME);
5443 if (fileExists(gfx_config_filename))
5445 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5447 if (setup_file_hash)
5449 char *filename = getHashEntry(setup_file_hash, anim_token);
5453 filename_anim_initial = getStringCopy(filename);
5455 for (j = 0; image_config_suffix[j].token != NULL; j++)
5457 int type = image_config_suffix[j].type;
5458 char *suffix = image_config_suffix[j].token;
5459 char *token = getStringCat2(anim_token, suffix);
5460 char *value = getHashEntry(setup_file_hash, token);
5462 checked_free(token);
5465 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5469 freeSetupFileHash(setup_file_hash);
5473 if (filename_anim_initial == NULL)
5475 // read settings for busy animation from static default artwork config
5476 for (i = 0; image_config[i].token != NULL; i++)
5478 if (strEqual(image_config[i].token, anim_token))
5479 filename_anim_initial = getStringCopy(image_config[i].value);
5480 else if (strlen(image_config[i].token) > len_anim_token &&
5481 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5483 for (j = 0; image_config_suffix[j].token != NULL; j++)
5485 if (strEqual(&image_config[i].token[len_anim_token],
5486 image_config_suffix[j].token))
5488 get_graphic_parameter_value(image_config[i].value,
5489 image_config_suffix[j].token,
5490 image_config_suffix[j].type);
5496 if (filename_anim_initial == NULL) // should not happen
5497 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5499 anim_initial.bitmaps =
5500 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5502 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5503 LoadCustomImage(filename_anim_initial);
5505 checked_free(filename_anim_initial);
5507 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5509 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5511 graphic_info = graphic_info_last;
5513 init.busy.width = anim_initial.width;
5514 init.busy.height = anim_initial.height;
5516 InitMenuDesignSettings_Static();
5518 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5519 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5520 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5521 InitGfxDrawTileCursorFunction(DrawTileCursor);
5523 gfx.fade_border_source_status = global.border_status;
5524 gfx.fade_border_target_status = global.border_status;
5525 gfx.masked_border_bitmap_ptr = backbuffer;
5527 // use copy of busy animation to prevent change while reloading artwork
5531 static void InitGfxBackground(void)
5533 fieldbuffer = bitmap_db_field;
5534 SetDrawtoField(DRAW_TO_BACKBUFFER);
5536 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5538 redraw_mask = REDRAW_ALL;
5541 static void InitLevelInfo(void)
5543 LoadLevelInfo(); // global level info
5544 LoadLevelSetup_LastSeries(); // last played series info
5545 LoadLevelSetup_SeriesInfo(); // last played level info
5547 if (global.autoplay_leveldir &&
5548 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5550 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5551 global.autoplay_leveldir);
5552 if (leveldir_current == NULL)
5553 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5556 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5559 static void InitLevelArtworkInfo(void)
5561 LoadLevelArtworkInfo();
5564 static void InitImages(void)
5566 print_timestamp_init("InitImages");
5569 printf("::: leveldir_current->identifier == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5571 printf("::: leveldir_current->graphics_path == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5573 printf("::: leveldir_current->graphics_set == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5575 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5576 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5579 setLevelArtworkDir(artwork.gfx_first);
5582 printf("::: leveldir_current->identifier == '%s'\n",
5583 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5584 printf("::: leveldir_current->graphics_path == '%s'\n",
5585 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5586 printf("::: leveldir_current->graphics_set == '%s'\n",
5587 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5588 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5589 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5593 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5594 leveldir_current->identifier,
5595 artwork.gfx_current_identifier,
5596 artwork.gfx_current->identifier,
5597 leveldir_current->graphics_set,
5598 leveldir_current->graphics_path);
5601 UPDATE_BUSY_STATE();
5603 ReloadCustomImages();
5604 print_timestamp_time("ReloadCustomImages");
5606 UPDATE_BUSY_STATE();
5608 LoadCustomElementDescriptions();
5609 print_timestamp_time("LoadCustomElementDescriptions");
5611 UPDATE_BUSY_STATE();
5613 LoadMenuDesignSettings();
5614 print_timestamp_time("LoadMenuDesignSettings");
5616 UPDATE_BUSY_STATE();
5618 ReinitializeGraphics();
5619 print_timestamp_time("ReinitializeGraphics");
5621 LoadMenuDesignSettings_AfterGraphics();
5622 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5624 UPDATE_BUSY_STATE();
5626 print_timestamp_done("InitImages");
5629 static void InitSound(char *identifier)
5631 print_timestamp_init("InitSound");
5633 if (identifier == NULL)
5634 identifier = artwork.snd_current->identifier;
5636 // set artwork path to send it to the sound server process
5637 setLevelArtworkDir(artwork.snd_first);
5639 InitReloadCustomSounds(identifier);
5640 print_timestamp_time("InitReloadCustomSounds");
5642 ReinitializeSounds();
5643 print_timestamp_time("ReinitializeSounds");
5645 print_timestamp_done("InitSound");
5648 static void InitMusic(char *identifier)
5650 print_timestamp_init("InitMusic");
5652 if (identifier == NULL)
5653 identifier = artwork.mus_current->identifier;
5655 // set artwork path to send it to the sound server process
5656 setLevelArtworkDir(artwork.mus_first);
5658 InitReloadCustomMusic(identifier);
5659 print_timestamp_time("InitReloadCustomMusic");
5661 ReinitializeMusic();
5662 print_timestamp_time("ReinitializeMusic");
5664 print_timestamp_done("InitMusic");
5667 static void InitArtworkDone(void)
5669 if (program.headless)
5672 InitGlobalAnimations();
5675 static void InitNetworkSettings(void)
5677 boolean network_enabled = (options.network || setup.network_mode);
5678 char *network_server = (options.server_host != NULL ? options.server_host :
5679 setup.network_server_hostname);
5681 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5682 network_server = NULL;
5684 InitNetworkInfo(network_enabled,
5688 options.server_port);
5691 void InitNetworkServer(void)
5693 if (!network.enabled || network.connected)
5696 LimitScreenUpdates(FALSE);
5698 if (game_status == GAME_MODE_LOADING)
5701 if (!ConnectToServer(network.server_host, network.server_port))
5703 network.enabled = FALSE;
5705 setup.network_mode = FALSE;
5709 SendToServer_ProtocolVersion();
5710 SendToServer_PlayerName(setup.player_name);
5711 SendToServer_NrWanted(setup.network_player_nr + 1);
5713 network.connected = TRUE;
5716 // short time to recognize result of network initialization
5717 if (game_status == GAME_MODE_LOADING)
5718 Delay_WithScreenUpdates(1000);
5721 static boolean CheckArtworkConfigForCustomElements(char *filename)
5723 SetupFileHash *setup_file_hash;
5724 boolean redefined_ce_found = FALSE;
5726 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5728 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5730 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5732 char *token = HASH_ITERATION_TOKEN(itr);
5734 if (strPrefix(token, "custom_"))
5736 redefined_ce_found = TRUE;
5741 END_HASH_ITERATION(setup_file_hash, itr)
5743 freeSetupFileHash(setup_file_hash);
5746 return redefined_ce_found;
5749 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5751 char *filename_base, *filename_local;
5752 boolean redefined_ce_found = FALSE;
5754 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5757 printf("::: leveldir_current->identifier == '%s'\n",
5758 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5759 printf("::: leveldir_current->graphics_path == '%s'\n",
5760 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5761 printf("::: leveldir_current->graphics_set == '%s'\n",
5762 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5763 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5764 leveldir_current == NULL ? "[NULL]" :
5765 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5768 // first look for special artwork configured in level series config
5769 filename_base = getCustomArtworkLevelConfigFilename(type);
5772 printf("::: filename_base == '%s'\n", filename_base);
5775 if (fileExists(filename_base))
5776 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5778 filename_local = getCustomArtworkConfigFilename(type);
5781 printf("::: filename_local == '%s'\n", filename_local);
5784 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5785 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5788 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5791 return redefined_ce_found;
5794 static void InitOverrideArtwork(void)
5796 boolean redefined_ce_found = FALSE;
5798 // to check if this level set redefines any CEs, do not use overriding
5799 gfx.override_level_graphics = FALSE;
5800 gfx.override_level_sounds = FALSE;
5801 gfx.override_level_music = FALSE;
5803 // now check if this level set has definitions for custom elements
5804 if (setup.override_level_graphics == AUTO ||
5805 setup.override_level_sounds == AUTO ||
5806 setup.override_level_music == AUTO)
5807 redefined_ce_found =
5808 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5809 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5810 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5813 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5816 if (redefined_ce_found)
5818 // this level set has CE definitions: change "AUTO" to "FALSE"
5819 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5820 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5821 gfx.override_level_music = (setup.override_level_music == TRUE);
5825 // this level set has no CE definitions: change "AUTO" to "TRUE"
5826 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5827 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5828 gfx.override_level_music = (setup.override_level_music != FALSE);
5832 printf("::: => %d, %d, %d\n",
5833 gfx.override_level_graphics,
5834 gfx.override_level_sounds,
5835 gfx.override_level_music);
5839 static char *getNewArtworkIdentifier(int type)
5841 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5842 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5843 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5844 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5845 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5846 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5847 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5848 char *leveldir_identifier = leveldir_current->identifier;
5849 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5850 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5851 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5852 char *artwork_current_identifier;
5853 char *artwork_new_identifier = NULL; // default: nothing has changed
5855 // leveldir_current may be invalid (level group, parent link)
5856 if (!validLevelSeries(leveldir_current))
5859 /* 1st step: determine artwork set to be activated in descending order:
5860 --------------------------------------------------------------------
5861 1. setup artwork (when configured to override everything else)
5862 2. artwork set configured in "levelinfo.conf" of current level set
5863 (artwork in level directory will have priority when loading later)
5864 3. artwork in level directory (stored in artwork sub-directory)
5865 4. setup artwork (currently configured in setup menu) */
5867 if (setup_override_artwork)
5868 artwork_current_identifier = setup_artwork_set;
5869 else if (leveldir_artwork_set != NULL)
5870 artwork_current_identifier = leveldir_artwork_set;
5871 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5872 artwork_current_identifier = leveldir_identifier;
5874 artwork_current_identifier = setup_artwork_set;
5877 /* 2nd step: check if it is really needed to reload artwork set
5878 ------------------------------------------------------------ */
5880 // ---------- reload if level set and also artwork set has changed ----------
5881 if (leveldir_current_identifier[type] != leveldir_identifier &&
5882 (last_has_level_artwork_set[type] || has_level_artwork_set))
5883 artwork_new_identifier = artwork_current_identifier;
5885 leveldir_current_identifier[type] = leveldir_identifier;
5886 last_has_level_artwork_set[type] = has_level_artwork_set;
5888 // ---------- reload if "override artwork" setting has changed --------------
5889 if (last_override_level_artwork[type] != setup_override_artwork)
5890 artwork_new_identifier = artwork_current_identifier;
5892 last_override_level_artwork[type] = setup_override_artwork;
5894 // ---------- reload if current artwork identifier has changed --------------
5895 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5896 artwork_current_identifier))
5897 artwork_new_identifier = artwork_current_identifier;
5899 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5901 // ---------- do not reload directly after starting -------------------------
5902 if (!initialized[type])
5903 artwork_new_identifier = NULL;
5905 initialized[type] = TRUE;
5907 return artwork_new_identifier;
5910 void ReloadCustomArtwork(int force_reload)
5912 int last_game_status = game_status; // save current game status
5913 char *gfx_new_identifier;
5914 char *snd_new_identifier;
5915 char *mus_new_identifier;
5916 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5917 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5918 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5919 boolean reload_needed;
5921 InitOverrideArtwork();
5923 force_reload_gfx |= AdjustGraphicsForEMC();
5925 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5926 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5927 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5929 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5930 snd_new_identifier != NULL || force_reload_snd ||
5931 mus_new_identifier != NULL || force_reload_mus);
5936 print_timestamp_init("ReloadCustomArtwork");
5938 SetGameStatus(GAME_MODE_LOADING);
5940 FadeOut(REDRAW_ALL);
5942 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5943 print_timestamp_time("ClearRectangle");
5947 if (gfx_new_identifier != NULL || force_reload_gfx)
5950 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5951 artwork.gfx_current_identifier,
5953 artwork.gfx_current->identifier,
5954 leveldir_current->graphics_set);
5958 print_timestamp_time("InitImages");
5961 if (snd_new_identifier != NULL || force_reload_snd)
5963 InitSound(snd_new_identifier);
5964 print_timestamp_time("InitSound");
5967 if (mus_new_identifier != NULL || force_reload_mus)
5969 InitMusic(mus_new_identifier);
5970 print_timestamp_time("InitMusic");
5975 SetGameStatus(last_game_status); // restore current game status
5977 init_last = init; // switch to new busy animation
5979 FadeOut(REDRAW_ALL);
5981 RedrawGlobalBorder();
5983 // force redraw of (open or closed) door graphics
5984 SetDoorState(DOOR_OPEN_ALL);
5985 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5987 FadeSetEnterScreen();
5988 FadeSkipNextFadeOut();
5990 print_timestamp_done("ReloadCustomArtwork");
5992 LimitScreenUpdates(FALSE);
5995 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5997 if (global.autoplay_leveldir == NULL)
5998 KeyboardAutoRepeatOff();
6001 void DisplayExitMessage(char *format, va_list ap)
6003 // also check for initialized video (headless flag may be temporarily unset)
6004 if (program.headless || !video.initialized)
6007 // check if draw buffer and fonts for exit message are already available
6008 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6011 int font_1 = FC_RED;
6012 int font_2 = FC_YELLOW;
6013 int font_3 = FC_BLUE;
6014 int font_width = getFontWidth(font_2);
6015 int font_height = getFontHeight(font_2);
6018 int sxsize = WIN_XSIZE - 2 * sx;
6019 int sysize = WIN_YSIZE - 2 * sy;
6020 int line_length = sxsize / font_width;
6021 int max_lines = sysize / font_height;
6022 int num_lines_printed;
6026 gfx.sxsize = sxsize;
6027 gfx.sysize = sysize;
6031 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6033 DrawTextSCentered(sy, font_1, "Fatal error:");
6034 sy += 3 * font_height;;
6037 DrawTextBufferVA(sx, sy, format, ap, font_2,
6038 line_length, line_length, max_lines,
6039 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6040 sy += (num_lines_printed + 3) * font_height;
6042 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6043 sy += 3 * font_height;
6046 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6047 line_length, line_length, max_lines,
6048 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6050 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6052 redraw_mask = REDRAW_ALL;
6054 // force drawing exit message even if screen updates are currently limited
6055 LimitScreenUpdates(FALSE);
6059 // deactivate toons on error message screen
6060 setup.toons = FALSE;
6062 WaitForEventToContinue();
6066 // ============================================================================
6068 // ============================================================================
6072 print_timestamp_init("OpenAll");
6074 SetGameStatus(GAME_MODE_LOADING);
6078 InitGlobal(); // initialize some global variables
6080 print_timestamp_time("[init global stuff]");
6084 print_timestamp_time("[init setup/config stuff (1)]");
6088 if (options.execute_command)
6089 Execute_Command(options.execute_command);
6091 InitNetworkSettings();
6095 if (network.serveronly)
6097 #if defined(PLATFORM_UNIX)
6098 NetworkServer(network.server_port, TRUE);
6100 Error(ERR_WARN, "networking only supported in Unix version");
6103 exit(0); // never reached, server loops forever
6107 print_timestamp_time("[init setup/config stuff (2)]");
6109 print_timestamp_time("[init setup/config stuff (3)]");
6110 InitArtworkInfo(); // needed before loading gfx, sound & music
6111 print_timestamp_time("[init setup/config stuff (4)]");
6112 InitArtworkConfig(); // needed before forking sound child process
6113 print_timestamp_time("[init setup/config stuff (5)]");
6115 print_timestamp_time("[init setup/config stuff (6)]");
6117 InitRND(NEW_RANDOMIZE);
6118 InitSimpleRandom(NEW_RANDOMIZE);
6122 print_timestamp_time("[init setup/config stuff]");
6124 InitVideoDefaults();
6126 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6129 InitEventFilter(FilterMouseMotionEvents);
6131 print_timestamp_time("[init video stuff]");
6133 InitElementPropertiesStatic();
6134 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6135 InitElementPropertiesGfxElement();
6137 print_timestamp_time("[init element properties stuff]");
6141 print_timestamp_time("InitGfx");
6144 print_timestamp_time("InitLevelInfo");
6146 InitLevelArtworkInfo();
6147 print_timestamp_time("InitLevelArtworkInfo");
6149 InitOverrideArtwork(); // needs to know current level directory
6150 print_timestamp_time("InitOverrideArtwork");
6152 InitImages(); // needs to know current level directory
6153 print_timestamp_time("InitImages");
6155 InitSound(NULL); // needs to know current level directory
6156 print_timestamp_time("InitSound");
6158 InitMusic(NULL); // needs to know current level directory
6159 print_timestamp_time("InitMusic");
6163 InitGfxBackground();
6169 if (global.autoplay_leveldir)
6174 else if (global.convert_leveldir)
6179 else if (global.create_images_dir)
6181 CreateLevelSketchImages();
6185 InitNetworkServer();
6187 SetGameStatus(GAME_MODE_MAIN);
6189 FadeSetEnterScreen();
6190 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6191 FadeSkipNextFadeOut();
6193 print_timestamp_time("[post-artwork]");
6195 print_timestamp_done("OpenAll");
6200 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6202 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6203 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6204 #if defined(PLATFORM_ANDROID)
6205 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6206 SDL_AndroidGetInternalStoragePath());
6207 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6208 SDL_AndroidGetExternalStoragePath());
6209 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6210 (SDL_AndroidGetExternalStorageState() &
6211 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6212 SDL_AndroidGetExternalStorageState() &
6213 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6218 void CloseAllAndExit(int exit_value)
6223 CloseAudio(); // called after freeing sounds (needed for SDL)
6231 // set a flag to tell the network server thread to quit and wait for it
6232 // using SDL_WaitThread()
6234 // Code used with SDL 1.2:
6235 // if (network_server) // terminate network server
6236 // SDL_KillThread(server_thread);
6238 CloseVideoDisplay();
6239 ClosePlatformDependentStuff();
6241 if (exit_value != 0 && !options.execute_command)
6243 // fall back to default level set (current set may have caused an error)
6244 SaveLevelSetup_LastSeries_Deactivate();
6246 // tell user where to find error log file which may contain more details
6247 // (error notification now directly displayed on screen inside R'n'D
6248 // NotifyUserAboutErrorFile(); // currently only works for Windows