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,
287 FreeAllImageTextures();
289 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
290 CreateImageTextures(i);
292 for (i = 0; i < MAX_NUM_TOONS; i++)
293 CreateImageTextures(IMG_TOON_1 + i);
295 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
297 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
299 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
301 int graphic = global_anim_info[i].graphic[j][k];
303 if (graphic == IMG_UNDEFINED)
306 CreateImageTextures(graphic);
311 for (i = 0; texture_graphics[i] > -1; i++)
312 CreateImageTextures(texture_graphics[i]);
316 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
317 void SetBitmaps_EM(Bitmap **em_bitmap)
319 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
320 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
325 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
326 void SetBitmaps_SP(Bitmap **sp_bitmap)
328 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
332 static int getFontBitmapID(int font_nr)
336 // (special case: do not use special font for GAME_MODE_LOADING)
337 if (game_status >= GAME_MODE_TITLE_INITIAL &&
338 game_status <= GAME_MODE_PSEUDO_PREVIEW)
339 special = game_status;
340 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
341 special = GFX_SPECIAL_ARG_MAIN;
344 return font_info[font_nr].special_bitmap_id[special];
349 static int getFontFromToken(char *token)
351 char *value = getHashEntry(font_token_hash, token);
356 // if font not found, use reliable default value
357 return FONT_INITIAL_1;
360 static void InitFontGraphicInfo(void)
362 static struct FontBitmapInfo *font_bitmap_info = NULL;
363 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
364 int num_property_mappings = getImageListPropertyMappingSize();
365 int num_font_bitmaps = NUM_FONTS;
368 if (graphic_info == NULL) // still at startup phase
370 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
371 getFontBitmapID, getFontFromToken);
376 // ---------- initialize font graphic definitions ----------
378 // always start with reliable default values (normal font graphics)
379 for (i = 0; i < NUM_FONTS; i++)
380 font_info[i].graphic = IMG_FONT_INITIAL_1;
382 // initialize normal font/graphic mapping from static configuration
383 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
385 int font_nr = font_to_graphic[i].font_nr;
386 int special = font_to_graphic[i].special;
387 int graphic = font_to_graphic[i].graphic;
392 font_info[font_nr].graphic = graphic;
395 // always start with reliable default values (special font graphics)
396 for (i = 0; i < NUM_FONTS; i++)
398 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
400 font_info[i].special_graphic[j] = font_info[i].graphic;
401 font_info[i].special_bitmap_id[j] = i;
405 // initialize special font/graphic mapping from static configuration
406 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
408 int font_nr = font_to_graphic[i].font_nr;
409 int special = font_to_graphic[i].special;
410 int graphic = font_to_graphic[i].graphic;
411 int base_graphic = font2baseimg(font_nr);
413 if (IS_SPECIAL_GFX_ARG(special))
415 boolean base_redefined =
416 getImageListEntryFromImageID(base_graphic)->redefined;
417 boolean special_redefined =
418 getImageListEntryFromImageID(graphic)->redefined;
419 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
421 /* if the base font ("font.title_1", for example) has been redefined,
422 but not the special font ("font.title_1.LEVELS", for example), do not
423 use an existing (in this case considered obsolete) special font
424 anymore, but use the automatically determined default font */
425 /* special case: cloned special fonts must be explicitly redefined,
426 but are not automatically redefined by redefining base font */
427 if (base_redefined && !special_redefined && !special_cloned)
430 font_info[font_nr].special_graphic[special] = graphic;
431 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
436 // initialize special font/graphic mapping from dynamic configuration
437 for (i = 0; i < num_property_mappings; i++)
439 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
440 int special = property_mapping[i].ext3_index;
441 int graphic = property_mapping[i].artwork_index;
443 if (font_nr < 0 || font_nr >= NUM_FONTS)
446 if (IS_SPECIAL_GFX_ARG(special))
448 font_info[font_nr].special_graphic[special] = graphic;
449 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
454 /* correct special font/graphic mapping for cloned fonts for downwards
455 compatibility of PREVIEW fonts -- this is only needed for implicit
456 redefinition of special font by redefined base font, and only if other
457 fonts are cloned from this special font (like in the "Zelda" level set) */
458 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
460 int font_nr = font_to_graphic[i].font_nr;
461 int special = font_to_graphic[i].special;
462 int graphic = font_to_graphic[i].graphic;
464 if (IS_SPECIAL_GFX_ARG(special))
466 boolean special_redefined =
467 getImageListEntryFromImageID(graphic)->redefined;
468 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
470 if (special_cloned && !special_redefined)
474 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
476 int font_nr2 = font_to_graphic[j].font_nr;
477 int special2 = font_to_graphic[j].special;
478 int graphic2 = font_to_graphic[j].graphic;
480 if (IS_SPECIAL_GFX_ARG(special2) &&
481 graphic2 == graphic_info[graphic].clone_from)
483 font_info[font_nr].special_graphic[special] =
484 font_info[font_nr2].special_graphic[special2];
485 font_info[font_nr].special_bitmap_id[special] =
486 font_info[font_nr2].special_bitmap_id[special2];
493 // reset non-redefined ".active" font graphics if normal font is redefined
494 // (this different treatment is needed because normal and active fonts are
495 // independently defined ("active" is not a property of font definitions!)
496 for (i = 0; i < NUM_FONTS; i++)
498 int font_nr_base = i;
499 int font_nr_active = FONT_ACTIVE(font_nr_base);
501 // check only those fonts with exist as normal and ".active" variant
502 if (font_nr_base != font_nr_active)
504 int base_graphic = font_info[font_nr_base].graphic;
505 int active_graphic = font_info[font_nr_active].graphic;
506 boolean base_redefined =
507 getImageListEntryFromImageID(base_graphic)->redefined;
508 boolean active_redefined =
509 getImageListEntryFromImageID(active_graphic)->redefined;
511 /* if the base font ("font.menu_1", for example) has been redefined,
512 but not the active font ("font.menu_1.active", for example), do not
513 use an existing (in this case considered obsolete) active font
514 anymore, but use the automatically determined default font */
515 if (base_redefined && !active_redefined)
516 font_info[font_nr_active].graphic = base_graphic;
518 // now also check each "special" font (which may be the same as above)
519 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
521 int base_graphic = font_info[font_nr_base].special_graphic[j];
522 int active_graphic = font_info[font_nr_active].special_graphic[j];
523 boolean base_redefined =
524 getImageListEntryFromImageID(base_graphic)->redefined;
525 boolean active_redefined =
526 getImageListEntryFromImageID(active_graphic)->redefined;
528 // same as above, but check special graphic definitions, for example:
529 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
530 if (base_redefined && !active_redefined)
532 font_info[font_nr_active].special_graphic[j] =
533 font_info[font_nr_base].special_graphic[j];
534 font_info[font_nr_active].special_bitmap_id[j] =
535 font_info[font_nr_base].special_bitmap_id[j];
541 // ---------- initialize font bitmap array ----------
543 if (font_bitmap_info != NULL)
544 FreeFontInfo(font_bitmap_info);
547 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
549 // ---------- initialize font bitmap definitions ----------
551 for (i = 0; i < NUM_FONTS; i++)
553 if (i < NUM_INITIAL_FONTS)
555 font_bitmap_info[i] = font_initial[i];
559 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
561 int font_bitmap_id = font_info[i].special_bitmap_id[j];
562 int graphic = font_info[i].special_graphic[j];
564 // set 'graphic_info' for font entries, if uninitialized (guessed)
565 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
567 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
568 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
571 // copy font relevant information from graphics information
572 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
573 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
574 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
575 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
576 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
578 font_bitmap_info[font_bitmap_id].offset_x =
579 graphic_info[graphic].offset_x;
580 font_bitmap_info[font_bitmap_id].offset_y =
581 graphic_info[graphic].offset_y;
583 font_bitmap_info[font_bitmap_id].draw_xoffset =
584 graphic_info[graphic].draw_xoffset;
585 font_bitmap_info[font_bitmap_id].draw_yoffset =
586 graphic_info[graphic].draw_yoffset;
588 font_bitmap_info[font_bitmap_id].num_chars =
589 graphic_info[graphic].anim_frames;
590 font_bitmap_info[font_bitmap_id].num_chars_per_line =
591 graphic_info[graphic].anim_frames_per_line;
595 InitFontInfo(font_bitmap_info, num_font_bitmaps,
596 getFontBitmapID, getFontFromToken);
599 static void InitGlobalAnimGraphicInfo(void)
601 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
602 int num_property_mappings = getImageListPropertyMappingSize();
605 if (graphic_info == NULL) // still at startup phase
608 // always start with reliable default values (no global animations)
609 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
610 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
611 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
612 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
614 // initialize global animation definitions from static configuration
615 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
617 int j = GLOBAL_ANIM_ID_PART_BASE;
618 int k = GFX_SPECIAL_ARG_DEFAULT;
620 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
623 // initialize global animation definitions from dynamic configuration
624 for (i = 0; i < num_property_mappings; i++)
626 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
627 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
628 int special = property_mapping[i].ext3_index;
629 int graphic = property_mapping[i].artwork_index;
631 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
634 // set animation part to base part, if not specified
635 if (!IS_GLOBAL_ANIM_PART(part_nr))
636 part_nr = GLOBAL_ANIM_ID_PART_BASE;
638 // set animation screen to default, if not specified
639 if (!IS_SPECIAL_GFX_ARG(special))
640 special = GFX_SPECIAL_ARG_DEFAULT;
642 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
644 // fix default value for ".draw_masked" (for backward compatibility)
645 struct GraphicInfo *g = &graphic_info[graphic];
646 struct FileInfo *image = getImageListEntryFromImageID(graphic);
647 char **parameter_raw = image->parameter;
648 int p = GFX_ARG_DRAW_MASKED;
649 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
650 image_config_suffix[p].token,
651 image_config_suffix[p].type);
653 // if ".draw_masked" parameter is undefined, use default value "TRUE"
654 if (draw_masked == ARG_UNDEFINED_VALUE)
655 g->draw_masked = TRUE;
659 printf("::: InitGlobalAnimGraphicInfo\n");
661 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
662 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
663 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
664 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
665 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
666 printf("::: - anim %d, part %d, mode %d => %d\n",
667 i, j, k, global_anim_info[i].graphic[j][k]);
671 static void InitGlobalAnimSoundInfo(void)
673 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
674 int num_property_mappings = getSoundListPropertyMappingSize();
677 // always start with reliable default values (no global animation sounds)
678 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
679 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
680 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
681 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
683 // initialize global animation sound definitions from dynamic configuration
684 for (i = 0; i < num_property_mappings; i++)
686 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
687 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
688 int special = property_mapping[i].ext3_index;
689 int sound = property_mapping[i].artwork_index;
691 // sound uses control definition; map it to position of graphic (artwork)
692 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
694 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
697 // set animation part to base part, if not specified
698 if (!IS_GLOBAL_ANIM_PART(part_nr))
699 part_nr = GLOBAL_ANIM_ID_PART_BASE;
701 // set animation screen to default, if not specified
702 if (!IS_SPECIAL_GFX_ARG(special))
703 special = GFX_SPECIAL_ARG_DEFAULT;
705 global_anim_info[anim_nr].sound[part_nr][special] = sound;
709 printf("::: InitGlobalAnimSoundInfo\n");
711 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
712 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
713 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
714 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
715 printf("::: - anim %d, part %d, mode %d => %d\n",
716 i, j, k, global_anim_info[i].sound[j][k]);
720 static void InitGlobalAnimMusicInfo(void)
722 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
723 int num_property_mappings = getMusicListPropertyMappingSize();
726 // always start with reliable default values (no global animation music)
727 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
728 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
729 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
730 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
732 // initialize global animation music definitions from dynamic configuration
733 for (i = 0; i < num_property_mappings; i++)
735 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
736 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
737 int special = property_mapping[i].ext2_index;
738 int music = property_mapping[i].artwork_index;
740 // music uses control definition; map it to position of graphic (artwork)
741 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
743 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
746 // set animation part to base part, if not specified
747 if (!IS_GLOBAL_ANIM_PART(part_nr))
748 part_nr = GLOBAL_ANIM_ID_PART_BASE;
750 // set animation screen to default, if not specified
751 if (!IS_SPECIAL_GFX_ARG(special))
752 special = GFX_SPECIAL_ARG_DEFAULT;
754 global_anim_info[anim_nr].music[part_nr][special] = music;
758 printf("::: InitGlobalAnimMusicInfo\n");
760 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
761 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
762 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
763 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
764 printf("::: - anim %d, part %d, mode %d => %d\n",
765 i, j, k, global_anim_info[i].music[j][k]);
769 static void InitElementGraphicInfo(void)
771 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
772 int num_property_mappings = getImageListPropertyMappingSize();
775 if (graphic_info == NULL) // still at startup phase
778 // set values to -1 to identify later as "uninitialized" values
779 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
781 for (act = 0; act < NUM_ACTIONS; act++)
783 element_info[i].graphic[act] = -1;
784 element_info[i].crumbled[act] = -1;
786 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
788 element_info[i].direction_graphic[act][dir] = -1;
789 element_info[i].direction_crumbled[act][dir] = -1;
796 // initialize normal element/graphic mapping from static configuration
797 for (i = 0; element_to_graphic[i].element > -1; i++)
799 int element = element_to_graphic[i].element;
800 int action = element_to_graphic[i].action;
801 int direction = element_to_graphic[i].direction;
802 boolean crumbled = element_to_graphic[i].crumbled;
803 int graphic = element_to_graphic[i].graphic;
804 int base_graphic = el2baseimg(element);
806 if (graphic_info[graphic].bitmap == NULL)
809 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
812 boolean base_redefined =
813 getImageListEntryFromImageID(base_graphic)->redefined;
814 boolean act_dir_redefined =
815 getImageListEntryFromImageID(graphic)->redefined;
817 /* if the base graphic ("emerald", for example) has been redefined,
818 but not the action graphic ("emerald.falling", for example), do not
819 use an existing (in this case considered obsolete) action graphic
820 anymore, but use the automatically determined default graphic */
821 if (base_redefined && !act_dir_redefined)
826 action = ACTION_DEFAULT;
831 element_info[element].direction_crumbled[action][direction] = graphic;
833 element_info[element].crumbled[action] = graphic;
838 element_info[element].direction_graphic[action][direction] = graphic;
840 element_info[element].graphic[action] = graphic;
844 // initialize normal element/graphic mapping from dynamic configuration
845 for (i = 0; i < num_property_mappings; i++)
847 int element = property_mapping[i].base_index;
848 int action = property_mapping[i].ext1_index;
849 int direction = property_mapping[i].ext2_index;
850 int special = property_mapping[i].ext3_index;
851 int graphic = property_mapping[i].artwork_index;
852 boolean crumbled = FALSE;
854 if (special == GFX_SPECIAL_ARG_CRUMBLED)
860 if (graphic_info[graphic].bitmap == NULL)
863 if (element >= MAX_NUM_ELEMENTS || special != -1)
867 action = ACTION_DEFAULT;
872 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
873 element_info[element].direction_crumbled[action][dir] = -1;
876 element_info[element].direction_crumbled[action][direction] = graphic;
878 element_info[element].crumbled[action] = graphic;
883 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
884 element_info[element].direction_graphic[action][dir] = -1;
887 element_info[element].direction_graphic[action][direction] = graphic;
889 element_info[element].graphic[action] = graphic;
893 // now copy all graphics that are defined to be cloned from other graphics
894 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
896 int graphic = element_info[i].graphic[ACTION_DEFAULT];
897 int crumbled_like, diggable_like;
902 crumbled_like = graphic_info[graphic].crumbled_like;
903 diggable_like = graphic_info[graphic].diggable_like;
905 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
907 for (act = 0; act < NUM_ACTIONS; act++)
908 element_info[i].crumbled[act] =
909 element_info[crumbled_like].crumbled[act];
910 for (act = 0; act < NUM_ACTIONS; act++)
911 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
912 element_info[i].direction_crumbled[act][dir] =
913 element_info[crumbled_like].direction_crumbled[act][dir];
916 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
918 element_info[i].graphic[ACTION_DIGGING] =
919 element_info[diggable_like].graphic[ACTION_DIGGING];
920 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
921 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
922 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
926 // set hardcoded definitions for some runtime elements without graphic
927 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
929 // set hardcoded definitions for some internal elements without graphic
930 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
932 if (IS_EDITOR_CASCADE_INACTIVE(i))
933 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
934 else if (IS_EDITOR_CASCADE_ACTIVE(i))
935 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
938 // now set all undefined/invalid graphics to -1 to set to default after it
939 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
941 for (act = 0; act < NUM_ACTIONS; act++)
945 graphic = element_info[i].graphic[act];
946 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
947 element_info[i].graphic[act] = -1;
949 graphic = element_info[i].crumbled[act];
950 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
951 element_info[i].crumbled[act] = -1;
953 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
955 graphic = element_info[i].direction_graphic[act][dir];
956 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
957 element_info[i].direction_graphic[act][dir] = -1;
959 graphic = element_info[i].direction_crumbled[act][dir];
960 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
961 element_info[i].direction_crumbled[act][dir] = -1;
968 // adjust graphics with 2nd tile for movement according to direction
969 // (do this before correcting '-1' values to minimize calculations)
970 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
972 for (act = 0; act < NUM_ACTIONS; act++)
974 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
976 int graphic = element_info[i].direction_graphic[act][dir];
977 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
979 if (act == ACTION_FALLING) // special case
980 graphic = element_info[i].graphic[act];
983 graphic_info[graphic].double_movement &&
984 graphic_info[graphic].swap_double_tiles != 0)
986 struct GraphicInfo *g = &graphic_info[graphic];
987 int src_x_front = g->src_x;
988 int src_y_front = g->src_y;
989 int src_x_back = g->src_x + g->offset2_x;
990 int src_y_back = g->src_y + g->offset2_y;
991 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
993 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
994 src_y_front < src_y_back);
995 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
996 boolean swap_movement_tiles_autodetected =
997 (!frames_are_ordered_diagonally &&
998 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
999 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1000 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1001 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1003 // swap frontside and backside graphic tile coordinates, if needed
1004 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1006 // get current (wrong) backside tile coordinates
1007 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1009 // set frontside tile coordinates to backside tile coordinates
1010 g->src_x = src_x_back;
1011 g->src_y = src_y_back;
1013 // invert tile offset to point to new backside tile coordinates
1017 // do not swap front and backside tiles again after correction
1018 g->swap_double_tiles = 0;
1025 UPDATE_BUSY_STATE();
1027 // now set all '-1' values to element specific default values
1028 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1030 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1031 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1032 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1033 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1035 if (default_graphic == -1)
1036 default_graphic = IMG_UNKNOWN;
1038 if (default_crumbled == -1)
1039 default_crumbled = default_graphic;
1041 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1043 default_direction_graphic[dir] =
1044 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1045 default_direction_crumbled[dir] =
1046 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1048 if (default_direction_graphic[dir] == -1)
1049 default_direction_graphic[dir] = default_graphic;
1051 if (default_direction_crumbled[dir] == -1)
1052 default_direction_crumbled[dir] = default_direction_graphic[dir];
1055 for (act = 0; act < NUM_ACTIONS; act++)
1057 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1058 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1059 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1060 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1061 act == ACTION_TURNING_FROM_RIGHT ||
1062 act == ACTION_TURNING_FROM_UP ||
1063 act == ACTION_TURNING_FROM_DOWN);
1065 // generic default action graphic (defined by "[default]" directive)
1066 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1067 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1068 int default_remove_graphic = IMG_EMPTY;
1070 if (act_remove && default_action_graphic != -1)
1071 default_remove_graphic = default_action_graphic;
1073 // look for special default action graphic (classic game specific)
1074 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1075 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1076 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1077 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1078 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1079 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1080 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1081 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1083 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1084 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1085 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1086 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1087 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1088 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1089 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1090 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1092 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1093 // !!! make this better !!!
1094 if (i == EL_EMPTY_SPACE)
1096 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1097 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1100 if (default_action_graphic == -1)
1101 default_action_graphic = default_graphic;
1103 if (default_action_crumbled == -1)
1104 default_action_crumbled = default_action_graphic;
1106 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1108 // use action graphic as the default direction graphic, if undefined
1109 int default_action_direction_graphic = element_info[i].graphic[act];
1110 int default_action_direction_crumbled = element_info[i].crumbled[act];
1112 // no graphic for current action -- use default direction graphic
1113 if (default_action_direction_graphic == -1)
1114 default_action_direction_graphic =
1115 (act_remove ? default_remove_graphic :
1117 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1118 default_action_graphic != default_graphic ?
1119 default_action_graphic :
1120 default_direction_graphic[dir]);
1122 if (element_info[i].direction_graphic[act][dir] == -1)
1123 element_info[i].direction_graphic[act][dir] =
1124 default_action_direction_graphic;
1126 if (default_action_direction_crumbled == -1)
1127 default_action_direction_crumbled =
1128 element_info[i].direction_graphic[act][dir];
1130 if (element_info[i].direction_crumbled[act][dir] == -1)
1131 element_info[i].direction_crumbled[act][dir] =
1132 default_action_direction_crumbled;
1135 // no graphic for this specific action -- use default action graphic
1136 if (element_info[i].graphic[act] == -1)
1137 element_info[i].graphic[act] =
1138 (act_remove ? default_remove_graphic :
1139 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1140 default_action_graphic);
1142 if (element_info[i].crumbled[act] == -1)
1143 element_info[i].crumbled[act] = element_info[i].graphic[act];
1147 UPDATE_BUSY_STATE();
1150 static void InitElementSpecialGraphicInfo(void)
1152 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1153 int num_property_mappings = getImageListPropertyMappingSize();
1156 // always start with reliable default values
1157 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1158 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1159 element_info[i].special_graphic[j] =
1160 element_info[i].graphic[ACTION_DEFAULT];
1162 // initialize special element/graphic mapping from static configuration
1163 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1165 int element = element_to_special_graphic[i].element;
1166 int special = element_to_special_graphic[i].special;
1167 int graphic = element_to_special_graphic[i].graphic;
1168 int base_graphic = el2baseimg(element);
1169 boolean base_redefined =
1170 getImageListEntryFromImageID(base_graphic)->redefined;
1171 boolean special_redefined =
1172 getImageListEntryFromImageID(graphic)->redefined;
1174 /* if the base graphic ("emerald", for example) has been redefined,
1175 but not the special graphic ("emerald.EDITOR", for example), do not
1176 use an existing (in this case considered obsolete) special graphic
1177 anymore, but use the automatically created (down-scaled) graphic */
1178 if (base_redefined && !special_redefined)
1181 element_info[element].special_graphic[special] = graphic;
1184 // initialize special element/graphic mapping from dynamic configuration
1185 for (i = 0; i < num_property_mappings; i++)
1187 int element = property_mapping[i].base_index;
1188 int action = property_mapping[i].ext1_index;
1189 int direction = property_mapping[i].ext2_index;
1190 int special = property_mapping[i].ext3_index;
1191 int graphic = property_mapping[i].artwork_index;
1193 // for action ".active", replace element with active element, if exists
1194 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1196 element = ELEMENT_ACTIVE(element);
1200 if (element >= MAX_NUM_ELEMENTS)
1203 // do not change special graphic if action or direction was specified
1204 if (action != -1 || direction != -1)
1207 if (IS_SPECIAL_GFX_ARG(special))
1208 element_info[element].special_graphic[special] = graphic;
1211 // now set all undefined/invalid graphics to default
1212 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1213 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1214 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1215 element_info[i].special_graphic[j] =
1216 element_info[i].graphic[ACTION_DEFAULT];
1219 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1221 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1222 return get_parameter_value(value_raw, suffix, type);
1224 if (strEqual(value_raw, ARG_UNDEFINED))
1225 return ARG_UNDEFINED_VALUE;
1227 if (type == TYPE_ELEMENT)
1229 char *value = getHashEntry(element_token_hash, value_raw);
1233 Error(ERR_INFO_LINE, "-");
1234 Error(ERR_INFO, "warning: error found in config file:");
1235 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1236 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1237 Error(ERR_INFO, "custom graphic rejected for this element/action");
1238 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1239 Error(ERR_INFO_LINE, "-");
1242 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1244 else if (type == TYPE_GRAPHIC)
1246 char *value = getHashEntry(graphic_token_hash, value_raw);
1247 int fallback_graphic = IMG_CHAR_EXCLAM;
1251 Error(ERR_INFO_LINE, "-");
1252 Error(ERR_INFO, "warning: error found in config file:");
1253 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1254 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1255 Error(ERR_INFO, "custom graphic rejected for this element/action");
1256 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1257 Error(ERR_INFO_LINE, "-");
1260 return (value != NULL ? atoi(value) : fallback_graphic);
1266 static int get_scaled_graphic_width(int graphic)
1268 int original_width = getOriginalImageWidthFromImageID(graphic);
1269 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1271 return original_width * scale_up_factor;
1274 static int get_scaled_graphic_height(int graphic)
1276 int original_height = getOriginalImageHeightFromImageID(graphic);
1277 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1279 return original_height * scale_up_factor;
1282 static void set_graphic_parameters_ext(int graphic, int *parameter,
1283 Bitmap **src_bitmaps)
1285 struct GraphicInfo *g = &graphic_info[graphic];
1286 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1287 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1288 int anim_frames_per_line = 1;
1290 // always start with reliable default values
1291 g->src_image_width = 0;
1292 g->src_image_height = 0;
1295 g->width = TILEX; // default for element graphics
1296 g->height = TILEY; // default for element graphics
1297 g->offset_x = 0; // one or both of these values ...
1298 g->offset_y = 0; // ... will be corrected later
1299 g->offset2_x = 0; // one or both of these values ...
1300 g->offset2_y = 0; // ... will be corrected later
1301 g->swap_double_tiles = -1; // auto-detect tile swapping
1302 g->crumbled_like = -1; // do not use clone element
1303 g->diggable_like = -1; // do not use clone element
1304 g->border_size = TILEX / 8; // "CRUMBLED" border size
1305 g->scale_up_factor = 1; // default: no scaling up
1306 g->tile_size = TILESIZE; // default: standard tile size
1307 g->clone_from = -1; // do not use clone graphic
1308 g->init_delay_fixed = 0;
1309 g->init_delay_random = 0;
1310 g->init_delay_action = -1;
1311 g->anim_delay_fixed = 0;
1312 g->anim_delay_random = 0;
1313 g->anim_delay_action = -1;
1314 g->post_delay_fixed = 0;
1315 g->post_delay_random = 0;
1316 g->post_delay_action = -1;
1317 g->init_event = ANIM_EVENT_UNDEFINED;
1318 g->anim_event = ANIM_EVENT_UNDEFINED;
1319 g->init_event_action = -1;
1320 g->anim_event_action = -1;
1321 g->draw_masked = FALSE;
1323 g->fade_mode = FADE_MODE_DEFAULT;
1327 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1328 g->align = ALIGN_CENTER; // default for title screens
1329 g->valign = VALIGN_MIDDLE; // default for title screens
1330 g->sort_priority = 0; // default for title screens
1332 g->style = STYLE_DEFAULT;
1334 g->bitmaps = src_bitmaps;
1335 g->bitmap = src_bitmap;
1337 // optional zoom factor for scaling up the image to a larger size
1338 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1339 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1340 if (g->scale_up_factor < 1)
1341 g->scale_up_factor = 1; // no scaling
1343 // optional tile size for using non-standard image size
1344 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1346 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1349 // CHECK: should tile sizes less than standard tile size be allowed?
1350 if (g->tile_size < TILESIZE)
1351 g->tile_size = TILESIZE; // standard tile size
1354 // when setting tile size, also set width and height accordingly
1355 g->width = g->tile_size;
1356 g->height = g->tile_size;
1359 if (g->use_image_size)
1361 // set new default bitmap size (with scaling, but without small images)
1362 g->width = get_scaled_graphic_width(graphic);
1363 g->height = get_scaled_graphic_height(graphic);
1366 // optional width and height of each animation frame
1367 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1368 g->width = parameter[GFX_ARG_WIDTH];
1369 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1370 g->height = parameter[GFX_ARG_HEIGHT];
1372 // optional x and y tile position of animation frame sequence
1373 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1374 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1375 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1376 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1378 // optional x and y pixel position of animation frame sequence
1379 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1380 g->src_x = parameter[GFX_ARG_X];
1381 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1382 g->src_y = parameter[GFX_ARG_Y];
1388 Error(ERR_INFO_LINE, "-");
1389 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1390 g->width, getTokenFromImageID(graphic), TILEX);
1391 Error(ERR_INFO_LINE, "-");
1393 g->width = TILEX; // will be checked to be inside bitmap later
1398 Error(ERR_INFO_LINE, "-");
1399 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1400 g->height, getTokenFromImageID(graphic), TILEY);
1401 Error(ERR_INFO_LINE, "-");
1403 g->height = TILEY; // will be checked to be inside bitmap later
1409 // get final bitmap size (with scaling, but without small images)
1410 int src_image_width = get_scaled_graphic_width(graphic);
1411 int src_image_height = get_scaled_graphic_height(graphic);
1413 if (src_image_width == 0 || src_image_height == 0)
1415 // only happens when loaded outside artwork system (like "global.busy")
1416 src_image_width = src_bitmap->width;
1417 src_image_height = src_bitmap->height;
1420 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1422 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1423 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1427 anim_frames_per_row = MAX(1, src_image_width / g->width);
1428 anim_frames_per_col = MAX(1, src_image_height / g->height);
1431 g->src_image_width = src_image_width;
1432 g->src_image_height = src_image_height;
1435 // correct x or y offset dependent of vertical or horizontal frame order
1436 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1438 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1439 parameter[GFX_ARG_OFFSET] : g->height);
1440 anim_frames_per_line = anim_frames_per_col;
1442 else // frames are ordered horizontally
1444 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1445 parameter[GFX_ARG_OFFSET] : g->width);
1446 anim_frames_per_line = anim_frames_per_row;
1449 // optionally, the x and y offset of frames can be specified directly
1450 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1451 g->offset_x = parameter[GFX_ARG_XOFFSET];
1452 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1453 g->offset_y = parameter[GFX_ARG_YOFFSET];
1455 // optionally, moving animations may have separate start and end graphics
1456 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1458 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1459 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1461 // correct x or y offset2 dependent of vertical or horizontal frame order
1462 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1463 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1464 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1465 else // frames are ordered horizontally
1466 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1467 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1469 // optionally, the x and y offset of 2nd graphic can be specified directly
1470 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1471 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1472 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1473 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1475 // optionally, the second movement tile can be specified as start tile
1476 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1477 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1479 // automatically determine correct number of frames, if not defined
1480 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1481 g->anim_frames = parameter[GFX_ARG_FRAMES];
1482 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1483 g->anim_frames = anim_frames_per_row;
1484 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1485 g->anim_frames = anim_frames_per_col;
1489 if (g->anim_frames < 1) // frames must be at least 1
1492 g->anim_frames_per_line =
1493 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1494 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1496 g->anim_delay = parameter[GFX_ARG_DELAY];
1497 if (g->anim_delay < 1) // delay must be at least 1
1500 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1502 // automatically determine correct start frame, if not defined
1503 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1504 g->anim_start_frame = 0;
1505 else if (g->anim_mode & ANIM_REVERSE)
1506 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1508 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1510 // animation synchronized with global frame counter, not move position
1511 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1513 // optional element for cloning crumble graphics
1514 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1515 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1517 // optional element for cloning digging graphics
1518 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1519 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1521 // optional border size for "crumbling" diggable graphics
1522 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1523 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1525 // used for global animations and player "boring" and "sleeping" actions
1526 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1527 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1528 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1529 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1530 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1531 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1532 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1533 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1534 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1535 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1536 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1537 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1539 // used for global animations
1540 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1541 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1542 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1543 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1544 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1545 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1546 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1547 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1548 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1549 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1550 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1551 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1552 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1553 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1555 // used for toon animations and global animations
1556 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1557 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1558 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1559 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1560 g->direction = parameter[GFX_ARG_DIRECTION];
1561 g->position = parameter[GFX_ARG_POSITION];
1562 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1563 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1565 if (g->step_delay < 1) // delay must be at least 1
1568 // this is only used for drawing font characters
1569 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1570 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1572 // use a different default value for global animations and toons
1573 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1574 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1575 g->draw_masked = TRUE;
1577 // this is used for drawing envelopes, global animations and toons
1578 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1579 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1581 // used for toon animations and global animations
1582 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1583 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1585 // optional graphic for cloning all graphics settings
1586 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1587 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1589 // optional settings for drawing title screens and title messages
1590 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1591 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1592 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1593 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1594 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1595 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1596 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1597 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1598 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1599 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1600 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1601 g->align = parameter[GFX_ARG_ALIGN];
1602 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1603 g->valign = parameter[GFX_ARG_VALIGN];
1604 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1605 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1607 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1608 g->class = parameter[GFX_ARG_CLASS];
1609 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1610 g->style = parameter[GFX_ARG_STYLE];
1612 // this is only used for drawing menu buttons and text
1613 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1614 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1615 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1616 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1619 static void set_graphic_parameters(int graphic)
1621 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1622 char **parameter_raw = image->parameter;
1623 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1624 int parameter[NUM_GFX_ARGS];
1627 // if fallback to default artwork is done, also use the default parameters
1628 if (image->fallback_to_default)
1629 parameter_raw = image->default_parameter;
1631 // get integer values from string parameters
1632 for (i = 0; i < NUM_GFX_ARGS; i++)
1633 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1634 image_config_suffix[i].token,
1635 image_config_suffix[i].type);
1637 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1639 UPDATE_BUSY_STATE();
1642 static void set_cloned_graphic_parameters(int graphic)
1644 int fallback_graphic = IMG_CHAR_EXCLAM;
1645 int max_num_images = getImageListSize();
1646 int clone_graphic = graphic_info[graphic].clone_from;
1647 int num_references_followed = 1;
1649 while (graphic_info[clone_graphic].clone_from != -1 &&
1650 num_references_followed < max_num_images)
1652 clone_graphic = graphic_info[clone_graphic].clone_from;
1654 num_references_followed++;
1657 if (num_references_followed >= max_num_images)
1659 Error(ERR_INFO_LINE, "-");
1660 Error(ERR_INFO, "warning: error found in config file:");
1661 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1662 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1663 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1664 Error(ERR_INFO, "custom graphic rejected for this element/action");
1666 if (graphic == fallback_graphic)
1667 Error(ERR_EXIT, "no fallback graphic available");
1669 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1670 Error(ERR_INFO_LINE, "-");
1672 graphic_info[graphic] = graphic_info[fallback_graphic];
1676 graphic_info[graphic] = graphic_info[clone_graphic];
1677 graphic_info[graphic].clone_from = clone_graphic;
1681 static void InitGraphicInfo(void)
1683 int fallback_graphic = IMG_CHAR_EXCLAM;
1684 int num_images = getImageListSize();
1687 // use image size as default values for width and height for these images
1688 static int full_size_graphics[] =
1691 IMG_GLOBAL_BORDER_MAIN,
1692 IMG_GLOBAL_BORDER_SCORES,
1693 IMG_GLOBAL_BORDER_EDITOR,
1694 IMG_GLOBAL_BORDER_PLAYING,
1697 IMG_BACKGROUND_ENVELOPE_1,
1698 IMG_BACKGROUND_ENVELOPE_2,
1699 IMG_BACKGROUND_ENVELOPE_3,
1700 IMG_BACKGROUND_ENVELOPE_4,
1701 IMG_BACKGROUND_REQUEST,
1704 IMG_BACKGROUND_TITLE_INITIAL,
1705 IMG_BACKGROUND_TITLE,
1706 IMG_BACKGROUND_MAIN,
1707 IMG_BACKGROUND_LEVELS,
1708 IMG_BACKGROUND_LEVELNR,
1709 IMG_BACKGROUND_SCORES,
1710 IMG_BACKGROUND_EDITOR,
1711 IMG_BACKGROUND_INFO,
1712 IMG_BACKGROUND_INFO_ELEMENTS,
1713 IMG_BACKGROUND_INFO_MUSIC,
1714 IMG_BACKGROUND_INFO_CREDITS,
1715 IMG_BACKGROUND_INFO_PROGRAM,
1716 IMG_BACKGROUND_INFO_VERSION,
1717 IMG_BACKGROUND_INFO_LEVELSET,
1718 IMG_BACKGROUND_SETUP,
1719 IMG_BACKGROUND_PLAYING,
1720 IMG_BACKGROUND_DOOR,
1721 IMG_BACKGROUND_TAPE,
1722 IMG_BACKGROUND_PANEL,
1723 IMG_BACKGROUND_PALETTE,
1724 IMG_BACKGROUND_TOOLBOX,
1726 IMG_TITLESCREEN_INITIAL_1,
1727 IMG_TITLESCREEN_INITIAL_2,
1728 IMG_TITLESCREEN_INITIAL_3,
1729 IMG_TITLESCREEN_INITIAL_4,
1730 IMG_TITLESCREEN_INITIAL_5,
1737 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1738 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1739 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1740 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1741 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1742 IMG_BACKGROUND_TITLEMESSAGE_1,
1743 IMG_BACKGROUND_TITLEMESSAGE_2,
1744 IMG_BACKGROUND_TITLEMESSAGE_3,
1745 IMG_BACKGROUND_TITLEMESSAGE_4,
1746 IMG_BACKGROUND_TITLEMESSAGE_5,
1751 FreeGlobalAnimEventInfo();
1753 checked_free(graphic_info);
1755 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1757 // initialize "use_image_size" flag with default value
1758 for (i = 0; i < num_images; i++)
1759 graphic_info[i].use_image_size = FALSE;
1761 // initialize "use_image_size" flag from static configuration above
1762 for (i = 0; full_size_graphics[i] != -1; i++)
1763 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1765 // first set all graphic paramaters ...
1766 for (i = 0; i < num_images; i++)
1767 set_graphic_parameters(i);
1769 // ... then copy these parameters for cloned graphics
1770 for (i = 0; i < num_images; i++)
1771 if (graphic_info[i].clone_from != -1)
1772 set_cloned_graphic_parameters(i);
1774 for (i = 0; i < num_images; i++)
1776 Bitmap *src_bitmap = graphic_info[i].bitmap;
1780 int src_bitmap_width, src_bitmap_height;
1782 // now check if no animation frames are outside of the loaded image
1784 if (graphic_info[i].bitmap == NULL)
1785 continue; // skip check for optional images that are undefined
1787 // get image size (this can differ from the standard element tile size!)
1788 width = graphic_info[i].width;
1789 height = graphic_info[i].height;
1791 // get final bitmap size (with scaling, but without small images)
1792 src_bitmap_width = graphic_info[i].src_image_width;
1793 src_bitmap_height = graphic_info[i].src_image_height;
1795 // check if first animation frame is inside specified bitmap
1797 // do not use getGraphicSourceXY() here to get position of first frame;
1798 // this avoids calculating wrong start position for out-of-bounds frame
1799 src_x = graphic_info[i].src_x;
1800 src_y = graphic_info[i].src_y;
1802 if (program.headless)
1805 if (src_x < 0 || src_y < 0 ||
1806 src_x + width > src_bitmap_width ||
1807 src_y + height > src_bitmap_height)
1809 Error(ERR_INFO_LINE, "-");
1810 Error(ERR_INFO, "warning: error found in config file:");
1811 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1812 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1813 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1814 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1816 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1817 src_x, src_y, src_bitmap_width, src_bitmap_height);
1818 Error(ERR_INFO, "custom graphic rejected for this element/action");
1820 if (i == fallback_graphic)
1821 Error(ERR_EXIT, "no fallback graphic available");
1823 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1824 Error(ERR_INFO_LINE, "-");
1826 graphic_info[i] = graphic_info[fallback_graphic];
1828 // if first frame out of bounds, do not check last frame anymore
1832 // check if last animation frame is inside specified bitmap
1834 last_frame = graphic_info[i].anim_frames - 1;
1835 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1837 if (src_x < 0 || src_y < 0 ||
1838 src_x + width > src_bitmap_width ||
1839 src_y + height > src_bitmap_height)
1841 Error(ERR_INFO_LINE, "-");
1842 Error(ERR_INFO, "warning: error found in config file:");
1843 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1844 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1845 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1846 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1848 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1849 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1850 Error(ERR_INFO, "custom graphic rejected for this element/action");
1852 if (i == fallback_graphic)
1853 Error(ERR_EXIT, "no fallback graphic available");
1855 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1856 Error(ERR_INFO_LINE, "-");
1858 graphic_info[i] = graphic_info[fallback_graphic];
1863 static void InitGraphicCompatibilityInfo(void)
1865 struct FileInfo *fi_global_door =
1866 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1867 int num_images = getImageListSize();
1870 /* the following compatibility handling is needed for the following case:
1871 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1872 graphics mainly used for door and panel graphics, like editor, tape and
1873 in-game buttons with hard-coded bitmap positions and button sizes; as
1874 these graphics now have individual definitions, redefining "global.door"
1875 to change all these graphics at once like before does not work anymore
1876 (because all those individual definitions still have their default values);
1877 to solve this, remap all those individual definitions that are not
1878 redefined to the new bitmap of "global.door" if it was redefined */
1880 // special compatibility handling if image "global.door" was redefined
1881 if (fi_global_door->redefined)
1883 for (i = 0; i < num_images; i++)
1885 struct FileInfo *fi = getImageListEntryFromImageID(i);
1887 // process only those images that still use the default settings
1890 // process all images which default to same image as "global.door"
1891 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1893 // printf("::: special treatment needed for token '%s'\n", fi->token);
1895 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1896 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1902 InitGraphicCompatibilityInfo_Doors();
1905 static void InitElementSoundInfo(void)
1907 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1908 int num_property_mappings = getSoundListPropertyMappingSize();
1911 // set values to -1 to identify later as "uninitialized" values
1912 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1913 for (act = 0; act < NUM_ACTIONS; act++)
1914 element_info[i].sound[act] = -1;
1916 // initialize element/sound mapping from static configuration
1917 for (i = 0; element_to_sound[i].element > -1; i++)
1919 int element = element_to_sound[i].element;
1920 int action = element_to_sound[i].action;
1921 int sound = element_to_sound[i].sound;
1922 boolean is_class = element_to_sound[i].is_class;
1925 action = ACTION_DEFAULT;
1928 element_info[element].sound[action] = sound;
1930 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1931 if (strEqual(element_info[j].class_name,
1932 element_info[element].class_name))
1933 element_info[j].sound[action] = sound;
1936 // initialize element class/sound mapping from dynamic configuration
1937 for (i = 0; i < num_property_mappings; i++)
1939 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1940 int action = property_mapping[i].ext1_index;
1941 int sound = property_mapping[i].artwork_index;
1943 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1947 action = ACTION_DEFAULT;
1949 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1950 if (strEqual(element_info[j].class_name,
1951 element_info[element_class].class_name))
1952 element_info[j].sound[action] = sound;
1955 // initialize element/sound mapping from dynamic configuration
1956 for (i = 0; i < num_property_mappings; i++)
1958 int element = property_mapping[i].base_index;
1959 int action = property_mapping[i].ext1_index;
1960 int sound = property_mapping[i].artwork_index;
1962 if (element >= MAX_NUM_ELEMENTS)
1966 action = ACTION_DEFAULT;
1968 element_info[element].sound[action] = sound;
1971 // now set all '-1' values to element specific default values
1972 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1974 for (act = 0; act < NUM_ACTIONS; act++)
1976 // generic default action sound (defined by "[default]" directive)
1977 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1979 // look for special default action sound (classic game specific)
1980 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1981 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1982 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1983 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1984 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1985 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1986 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1987 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1989 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1990 // !!! make this better !!!
1991 if (i == EL_EMPTY_SPACE)
1992 default_action_sound = element_info[EL_DEFAULT].sound[act];
1994 // no sound for this specific action -- use default action sound
1995 if (element_info[i].sound[act] == -1)
1996 element_info[i].sound[act] = default_action_sound;
2000 // copy sound settings to some elements that are only stored in level file
2001 // in native R'n'D levels, but are used by game engine in native EM levels
2002 for (i = 0; copy_properties[i][0] != -1; i++)
2003 for (j = 1; j <= 4; j++)
2004 for (act = 0; act < NUM_ACTIONS; act++)
2005 element_info[copy_properties[i][j]].sound[act] =
2006 element_info[copy_properties[i][0]].sound[act];
2009 static void InitGameModeSoundInfo(void)
2013 // set values to -1 to identify later as "uninitialized" values
2014 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2017 // initialize gamemode/sound mapping from static configuration
2018 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2020 int gamemode = gamemode_to_sound[i].gamemode;
2021 int sound = gamemode_to_sound[i].sound;
2024 gamemode = GAME_MODE_DEFAULT;
2026 menu.sound[gamemode] = sound;
2029 // now set all '-1' values to levelset specific default values
2030 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2031 if (menu.sound[i] == -1)
2032 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2035 static void set_sound_parameters(int sound, char **parameter_raw)
2037 int parameter[NUM_SND_ARGS];
2040 // get integer values from string parameters
2041 for (i = 0; i < NUM_SND_ARGS; i++)
2043 get_parameter_value(parameter_raw[i],
2044 sound_config_suffix[i].token,
2045 sound_config_suffix[i].type);
2047 // explicit loop mode setting in configuration overrides default value
2048 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2049 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2051 // sound volume to change the original volume when loading the sound file
2052 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2054 // sound priority to give certain sounds a higher or lower priority
2055 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2058 static void InitSoundInfo(void)
2060 int *sound_effect_properties;
2061 int num_sounds = getSoundListSize();
2064 checked_free(sound_info);
2066 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2067 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2069 // initialize sound effect for all elements to "no sound"
2070 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2071 for (j = 0; j < NUM_ACTIONS; j++)
2072 element_info[i].sound[j] = SND_UNDEFINED;
2074 for (i = 0; i < num_sounds; i++)
2076 struct FileInfo *sound = getSoundListEntry(i);
2077 int len_effect_text = strlen(sound->token);
2079 sound_effect_properties[i] = ACTION_OTHER;
2080 sound_info[i].loop = FALSE; // default: play sound only once
2082 // determine all loop sounds and identify certain sound classes
2084 for (j = 0; element_action_info[j].suffix; j++)
2086 int len_action_text = strlen(element_action_info[j].suffix);
2088 if (len_action_text < len_effect_text &&
2089 strEqual(&sound->token[len_effect_text - len_action_text],
2090 element_action_info[j].suffix))
2092 sound_effect_properties[i] = element_action_info[j].value;
2093 sound_info[i].loop = element_action_info[j].is_loop_sound;
2099 // associate elements and some selected sound actions
2101 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2103 if (element_info[j].class_name)
2105 int len_class_text = strlen(element_info[j].class_name);
2107 if (len_class_text + 1 < len_effect_text &&
2108 strncmp(sound->token,
2109 element_info[j].class_name, len_class_text) == 0 &&
2110 sound->token[len_class_text] == '.')
2112 int sound_action_value = sound_effect_properties[i];
2114 element_info[j].sound[sound_action_value] = i;
2119 set_sound_parameters(i, sound->parameter);
2122 free(sound_effect_properties);
2125 static void InitGameModeMusicInfo(void)
2127 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2128 int num_property_mappings = getMusicListPropertyMappingSize();
2129 int default_levelset_music = -1;
2132 // set values to -1 to identify later as "uninitialized" values
2133 for (i = 0; i < MAX_LEVELS; i++)
2134 levelset.music[i] = -1;
2135 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2138 // initialize gamemode/music mapping from static configuration
2139 for (i = 0; gamemode_to_music[i].music > -1; i++)
2141 int gamemode = gamemode_to_music[i].gamemode;
2142 int music = gamemode_to_music[i].music;
2145 gamemode = GAME_MODE_DEFAULT;
2147 menu.music[gamemode] = music;
2150 // initialize gamemode/music mapping from dynamic configuration
2151 for (i = 0; i < num_property_mappings; i++)
2153 int prefix = property_mapping[i].base_index;
2154 int gamemode = property_mapping[i].ext2_index;
2155 int level = property_mapping[i].ext3_index;
2156 int music = property_mapping[i].artwork_index;
2158 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2162 gamemode = GAME_MODE_DEFAULT;
2164 // level specific music only allowed for in-game music
2165 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2166 gamemode = GAME_MODE_PLAYING;
2171 default_levelset_music = music;
2174 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2175 levelset.music[level] = music;
2176 if (gamemode != GAME_MODE_PLAYING)
2177 menu.music[gamemode] = music;
2180 // now set all '-1' values to menu specific default values
2181 // (undefined values of "levelset.music[]" might stay at "-1" to
2182 // allow dynamic selection of music files from music directory!)
2183 for (i = 0; i < MAX_LEVELS; i++)
2184 if (levelset.music[i] == -1)
2185 levelset.music[i] = default_levelset_music;
2186 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2187 if (menu.music[i] == -1)
2188 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2191 static void set_music_parameters(int music, char **parameter_raw)
2193 int parameter[NUM_MUS_ARGS];
2196 // get integer values from string parameters
2197 for (i = 0; i < NUM_MUS_ARGS; i++)
2199 get_parameter_value(parameter_raw[i],
2200 music_config_suffix[i].token,
2201 music_config_suffix[i].type);
2203 // explicit loop mode setting in configuration overrides default value
2204 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2205 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2208 static void InitMusicInfo(void)
2210 int num_music = getMusicListSize();
2213 checked_free(music_info);
2215 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2217 for (i = 0; i < num_music; i++)
2219 struct FileInfo *music = getMusicListEntry(i);
2220 int len_music_text = strlen(music->token);
2222 music_info[i].loop = TRUE; // default: play music in loop mode
2224 // determine all loop music
2226 for (j = 0; music_prefix_info[j].prefix; j++)
2228 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2230 if (len_prefix_text < len_music_text &&
2231 strncmp(music->token,
2232 music_prefix_info[j].prefix, len_prefix_text) == 0)
2234 music_info[i].loop = music_prefix_info[j].is_loop_music;
2240 set_music_parameters(i, music->parameter);
2244 static void ReinitializeGraphics(void)
2246 print_timestamp_init("ReinitializeGraphics");
2248 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2250 InitGraphicInfo(); // graphic properties mapping
2251 print_timestamp_time("InitGraphicInfo");
2252 InitElementGraphicInfo(); // element game graphic mapping
2253 print_timestamp_time("InitElementGraphicInfo");
2254 InitElementSpecialGraphicInfo(); // element special graphic mapping
2255 print_timestamp_time("InitElementSpecialGraphicInfo");
2257 InitElementSmallImages(); // scale elements to all needed sizes
2258 print_timestamp_time("InitElementSmallImages");
2259 InitScaledImages(); // scale all other images, if needed
2260 print_timestamp_time("InitScaledImages");
2261 InitBitmapPointers(); // set standard size bitmap pointers
2262 print_timestamp_time("InitBitmapPointers");
2263 InitFontGraphicInfo(); // initialize text drawing functions
2264 print_timestamp_time("InitFontGraphicInfo");
2265 InitGlobalAnimGraphicInfo(); // initialize global animation config
2266 print_timestamp_time("InitGlobalAnimGraphicInfo");
2268 InitImageTextures(); // create textures for certain images
2269 print_timestamp_time("InitImageTextures");
2271 InitGraphicInfo_EM(); // graphic mapping for EM engine
2272 print_timestamp_time("InitGraphicInfo_EM");
2274 InitGraphicCompatibilityInfo();
2275 print_timestamp_time("InitGraphicCompatibilityInfo");
2277 SetMainBackgroundImage(IMG_BACKGROUND);
2278 print_timestamp_time("SetMainBackgroundImage");
2279 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2280 print_timestamp_time("SetDoorBackgroundImage");
2283 print_timestamp_time("InitGadgets");
2285 print_timestamp_time("InitDoors");
2287 print_timestamp_done("ReinitializeGraphics");
2290 static void ReinitializeSounds(void)
2292 InitSoundInfo(); // sound properties mapping
2293 InitElementSoundInfo(); // element game sound mapping
2294 InitGameModeSoundInfo(); // game mode sound mapping
2295 InitGlobalAnimSoundInfo(); // global animation sound settings
2297 InitPlayLevelSound(); // internal game sound settings
2300 static void ReinitializeMusic(void)
2302 InitMusicInfo(); // music properties mapping
2303 InitGameModeMusicInfo(); // game mode music mapping
2304 InitGlobalAnimMusicInfo(); // global animation music settings
2307 static int get_special_property_bit(int element, int property_bit_nr)
2309 struct PropertyBitInfo
2315 static struct PropertyBitInfo pb_can_move_into_acid[] =
2317 // the player may be able fall into acid when gravity is activated
2322 { EL_SP_MURPHY, 0 },
2323 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2325 // all elements that can move may be able to also move into acid
2328 { EL_BUG_RIGHT, 1 },
2331 { EL_SPACESHIP, 2 },
2332 { EL_SPACESHIP_LEFT, 2 },
2333 { EL_SPACESHIP_RIGHT, 2 },
2334 { EL_SPACESHIP_UP, 2 },
2335 { EL_SPACESHIP_DOWN, 2 },
2336 { EL_BD_BUTTERFLY, 3 },
2337 { EL_BD_BUTTERFLY_LEFT, 3 },
2338 { EL_BD_BUTTERFLY_RIGHT, 3 },
2339 { EL_BD_BUTTERFLY_UP, 3 },
2340 { EL_BD_BUTTERFLY_DOWN, 3 },
2341 { EL_BD_FIREFLY, 4 },
2342 { EL_BD_FIREFLY_LEFT, 4 },
2343 { EL_BD_FIREFLY_RIGHT, 4 },
2344 { EL_BD_FIREFLY_UP, 4 },
2345 { EL_BD_FIREFLY_DOWN, 4 },
2347 { EL_YAMYAM_LEFT, 5 },
2348 { EL_YAMYAM_RIGHT, 5 },
2349 { EL_YAMYAM_UP, 5 },
2350 { EL_YAMYAM_DOWN, 5 },
2351 { EL_DARK_YAMYAM, 6 },
2354 { EL_PACMAN_LEFT, 8 },
2355 { EL_PACMAN_RIGHT, 8 },
2356 { EL_PACMAN_UP, 8 },
2357 { EL_PACMAN_DOWN, 8 },
2359 { EL_MOLE_LEFT, 9 },
2360 { EL_MOLE_RIGHT, 9 },
2362 { EL_MOLE_DOWN, 9 },
2366 { EL_SATELLITE, 13 },
2367 { EL_SP_SNIKSNAK, 14 },
2368 { EL_SP_ELECTRON, 15 },
2371 { EL_EMC_ANDROID, 18 },
2376 static struct PropertyBitInfo pb_dont_collide_with[] =
2378 { EL_SP_SNIKSNAK, 0 },
2379 { EL_SP_ELECTRON, 1 },
2387 struct PropertyBitInfo *pb_info;
2390 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2391 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2396 struct PropertyBitInfo *pb_info = NULL;
2399 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2400 if (pb_definition[i].bit_nr == property_bit_nr)
2401 pb_info = pb_definition[i].pb_info;
2403 if (pb_info == NULL)
2406 for (i = 0; pb_info[i].element != -1; i++)
2407 if (pb_info[i].element == element)
2408 return pb_info[i].bit_nr;
2413 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2414 boolean property_value)
2416 int bit_nr = get_special_property_bit(element, property_bit_nr);
2421 *bitfield |= (1 << bit_nr);
2423 *bitfield &= ~(1 << bit_nr);
2427 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2429 int bit_nr = get_special_property_bit(element, property_bit_nr);
2432 return ((*bitfield & (1 << bit_nr)) != 0);
2437 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2439 static int group_nr;
2440 static struct ElementGroupInfo *group;
2441 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2444 if (actual_group == NULL) // not yet initialized
2447 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2449 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2450 group_element - EL_GROUP_START + 1);
2452 // replace element which caused too deep recursion by question mark
2453 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2458 if (recursion_depth == 0) // initialization
2460 group = actual_group;
2461 group_nr = GROUP_NR(group_element);
2463 group->num_elements_resolved = 0;
2464 group->choice_pos = 0;
2466 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2467 element_info[i].in_group[group_nr] = FALSE;
2470 for (i = 0; i < actual_group->num_elements; i++)
2472 int element = actual_group->element[i];
2474 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2477 if (IS_GROUP_ELEMENT(element))
2478 ResolveGroupElementExt(element, recursion_depth + 1);
2481 group->element_resolved[group->num_elements_resolved++] = element;
2482 element_info[element].in_group[group_nr] = TRUE;
2487 void ResolveGroupElement(int group_element)
2489 ResolveGroupElementExt(group_element, 0);
2492 void InitElementPropertiesStatic(void)
2494 static boolean clipboard_elements_initialized = FALSE;
2496 static int ep_diggable[] =
2501 EL_SP_BUGGY_BASE_ACTIVATING,
2504 EL_INVISIBLE_SAND_ACTIVE,
2507 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2508 // (if amoeba can grow into anything diggable, maybe keep these out)
2513 EL_SP_BUGGY_BASE_ACTIVE,
2520 static int ep_collectible_only[] =
2542 EL_DYNABOMB_INCREASE_NUMBER,
2543 EL_DYNABOMB_INCREASE_SIZE,
2544 EL_DYNABOMB_INCREASE_POWER,
2562 // !!! handle separately !!!
2563 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2569 static int ep_dont_run_into[] =
2571 // same elements as in 'ep_dont_touch'
2577 // same elements as in 'ep_dont_collide_with'
2589 // !!! maybe this should better be handled by 'ep_diggable' !!!
2594 EL_SP_BUGGY_BASE_ACTIVE,
2601 static int ep_dont_collide_with[] =
2603 // same elements as in 'ep_dont_touch'
2620 static int ep_dont_touch[] =
2630 static int ep_indestructible[] =
2634 EL_ACID_POOL_TOPLEFT,
2635 EL_ACID_POOL_TOPRIGHT,
2636 EL_ACID_POOL_BOTTOMLEFT,
2637 EL_ACID_POOL_BOTTOM,
2638 EL_ACID_POOL_BOTTOMRIGHT,
2639 EL_SP_HARDWARE_GRAY,
2640 EL_SP_HARDWARE_GREEN,
2641 EL_SP_HARDWARE_BLUE,
2643 EL_SP_HARDWARE_YELLOW,
2644 EL_SP_HARDWARE_BASE_1,
2645 EL_SP_HARDWARE_BASE_2,
2646 EL_SP_HARDWARE_BASE_3,
2647 EL_SP_HARDWARE_BASE_4,
2648 EL_SP_HARDWARE_BASE_5,
2649 EL_SP_HARDWARE_BASE_6,
2650 EL_INVISIBLE_STEELWALL,
2651 EL_INVISIBLE_STEELWALL_ACTIVE,
2652 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2653 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2654 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2655 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2656 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2657 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2658 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2659 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2660 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2661 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2662 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2663 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2665 EL_LIGHT_SWITCH_ACTIVE,
2666 EL_SIGN_EXCLAMATION,
2667 EL_SIGN_RADIOACTIVITY,
2674 EL_SIGN_ENTRY_FORBIDDEN,
2675 EL_SIGN_EMERGENCY_EXIT,
2683 EL_STEEL_EXIT_CLOSED,
2685 EL_STEEL_EXIT_OPENING,
2686 EL_STEEL_EXIT_CLOSING,
2687 EL_EM_STEEL_EXIT_CLOSED,
2688 EL_EM_STEEL_EXIT_OPEN,
2689 EL_EM_STEEL_EXIT_OPENING,
2690 EL_EM_STEEL_EXIT_CLOSING,
2691 EL_DC_STEELWALL_1_LEFT,
2692 EL_DC_STEELWALL_1_RIGHT,
2693 EL_DC_STEELWALL_1_TOP,
2694 EL_DC_STEELWALL_1_BOTTOM,
2695 EL_DC_STEELWALL_1_HORIZONTAL,
2696 EL_DC_STEELWALL_1_VERTICAL,
2697 EL_DC_STEELWALL_1_TOPLEFT,
2698 EL_DC_STEELWALL_1_TOPRIGHT,
2699 EL_DC_STEELWALL_1_BOTTOMLEFT,
2700 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2701 EL_DC_STEELWALL_1_TOPLEFT_2,
2702 EL_DC_STEELWALL_1_TOPRIGHT_2,
2703 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2704 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2705 EL_DC_STEELWALL_2_LEFT,
2706 EL_DC_STEELWALL_2_RIGHT,
2707 EL_DC_STEELWALL_2_TOP,
2708 EL_DC_STEELWALL_2_BOTTOM,
2709 EL_DC_STEELWALL_2_HORIZONTAL,
2710 EL_DC_STEELWALL_2_VERTICAL,
2711 EL_DC_STEELWALL_2_MIDDLE,
2712 EL_DC_STEELWALL_2_SINGLE,
2713 EL_STEELWALL_SLIPPERY,
2727 EL_GATE_1_GRAY_ACTIVE,
2728 EL_GATE_2_GRAY_ACTIVE,
2729 EL_GATE_3_GRAY_ACTIVE,
2730 EL_GATE_4_GRAY_ACTIVE,
2739 EL_EM_GATE_1_GRAY_ACTIVE,
2740 EL_EM_GATE_2_GRAY_ACTIVE,
2741 EL_EM_GATE_3_GRAY_ACTIVE,
2742 EL_EM_GATE_4_GRAY_ACTIVE,
2751 EL_EMC_GATE_5_GRAY_ACTIVE,
2752 EL_EMC_GATE_6_GRAY_ACTIVE,
2753 EL_EMC_GATE_7_GRAY_ACTIVE,
2754 EL_EMC_GATE_8_GRAY_ACTIVE,
2756 EL_DC_GATE_WHITE_GRAY,
2757 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2758 EL_DC_GATE_FAKE_GRAY,
2760 EL_SWITCHGATE_OPENING,
2761 EL_SWITCHGATE_CLOSED,
2762 EL_SWITCHGATE_CLOSING,
2763 EL_DC_SWITCHGATE_SWITCH_UP,
2764 EL_DC_SWITCHGATE_SWITCH_DOWN,
2766 EL_TIMEGATE_OPENING,
2768 EL_TIMEGATE_CLOSING,
2769 EL_DC_TIMEGATE_SWITCH,
2770 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2774 EL_TUBE_VERTICAL_LEFT,
2775 EL_TUBE_VERTICAL_RIGHT,
2776 EL_TUBE_HORIZONTAL_UP,
2777 EL_TUBE_HORIZONTAL_DOWN,
2782 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2783 EL_EXPANDABLE_STEELWALL_VERTICAL,
2784 EL_EXPANDABLE_STEELWALL_ANY,
2789 static int ep_slippery[] =
2803 EL_ROBOT_WHEEL_ACTIVE,
2809 EL_ACID_POOL_TOPLEFT,
2810 EL_ACID_POOL_TOPRIGHT,
2820 EL_STEELWALL_SLIPPERY,
2823 EL_EMC_WALL_SLIPPERY_1,
2824 EL_EMC_WALL_SLIPPERY_2,
2825 EL_EMC_WALL_SLIPPERY_3,
2826 EL_EMC_WALL_SLIPPERY_4,
2828 EL_EMC_MAGIC_BALL_ACTIVE,
2833 static int ep_can_change[] =
2838 static int ep_can_move[] =
2840 // same elements as in 'pb_can_move_into_acid'
2863 static int ep_can_fall[] =
2877 EL_QUICKSAND_FAST_FULL,
2879 EL_BD_MAGIC_WALL_FULL,
2880 EL_DC_MAGIC_WALL_FULL,
2894 static int ep_can_smash_player[] =
2920 static int ep_can_smash_enemies[] =
2929 static int ep_can_smash_everything[] =
2938 static int ep_explodes_by_fire[] =
2940 // same elements as in 'ep_explodes_impact'
2945 // same elements as in 'ep_explodes_smashed'
2955 EL_EM_DYNAMITE_ACTIVE,
2956 EL_DYNABOMB_PLAYER_1_ACTIVE,
2957 EL_DYNABOMB_PLAYER_2_ACTIVE,
2958 EL_DYNABOMB_PLAYER_3_ACTIVE,
2959 EL_DYNABOMB_PLAYER_4_ACTIVE,
2960 EL_DYNABOMB_INCREASE_NUMBER,
2961 EL_DYNABOMB_INCREASE_SIZE,
2962 EL_DYNABOMB_INCREASE_POWER,
2963 EL_SP_DISK_RED_ACTIVE,
2977 static int ep_explodes_smashed[] =
2979 // same elements as in 'ep_explodes_impact'
2993 static int ep_explodes_impact[] =
3002 static int ep_walkable_over[] =
3006 EL_SOKOBAN_FIELD_EMPTY,
3013 EL_EM_STEEL_EXIT_OPEN,
3014 EL_EM_STEEL_EXIT_OPENING,
3023 EL_GATE_1_GRAY_ACTIVE,
3024 EL_GATE_2_GRAY_ACTIVE,
3025 EL_GATE_3_GRAY_ACTIVE,
3026 EL_GATE_4_GRAY_ACTIVE,
3034 static int ep_walkable_inside[] =
3039 EL_TUBE_VERTICAL_LEFT,
3040 EL_TUBE_VERTICAL_RIGHT,
3041 EL_TUBE_HORIZONTAL_UP,
3042 EL_TUBE_HORIZONTAL_DOWN,
3051 static int ep_walkable_under[] =
3056 static int ep_passable_over[] =
3066 EL_EM_GATE_1_GRAY_ACTIVE,
3067 EL_EM_GATE_2_GRAY_ACTIVE,
3068 EL_EM_GATE_3_GRAY_ACTIVE,
3069 EL_EM_GATE_4_GRAY_ACTIVE,
3078 EL_EMC_GATE_5_GRAY_ACTIVE,
3079 EL_EMC_GATE_6_GRAY_ACTIVE,
3080 EL_EMC_GATE_7_GRAY_ACTIVE,
3081 EL_EMC_GATE_8_GRAY_ACTIVE,
3083 EL_DC_GATE_WHITE_GRAY,
3084 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3091 static int ep_passable_inside[] =
3097 EL_SP_PORT_HORIZONTAL,
3098 EL_SP_PORT_VERTICAL,
3100 EL_SP_GRAVITY_PORT_LEFT,
3101 EL_SP_GRAVITY_PORT_RIGHT,
3102 EL_SP_GRAVITY_PORT_UP,
3103 EL_SP_GRAVITY_PORT_DOWN,
3104 EL_SP_GRAVITY_ON_PORT_LEFT,
3105 EL_SP_GRAVITY_ON_PORT_RIGHT,
3106 EL_SP_GRAVITY_ON_PORT_UP,
3107 EL_SP_GRAVITY_ON_PORT_DOWN,
3108 EL_SP_GRAVITY_OFF_PORT_LEFT,
3109 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3110 EL_SP_GRAVITY_OFF_PORT_UP,
3111 EL_SP_GRAVITY_OFF_PORT_DOWN,
3116 static int ep_passable_under[] =
3121 static int ep_droppable[] =
3126 static int ep_explodes_1x1_old[] =
3131 static int ep_pushable[] =
3143 EL_SOKOBAN_FIELD_FULL,
3152 static int ep_explodes_cross_old[] =
3157 static int ep_protected[] =
3159 // same elements as in 'ep_walkable_inside'
3163 EL_TUBE_VERTICAL_LEFT,
3164 EL_TUBE_VERTICAL_RIGHT,
3165 EL_TUBE_HORIZONTAL_UP,
3166 EL_TUBE_HORIZONTAL_DOWN,
3172 // same elements as in 'ep_passable_over'
3181 EL_EM_GATE_1_GRAY_ACTIVE,
3182 EL_EM_GATE_2_GRAY_ACTIVE,
3183 EL_EM_GATE_3_GRAY_ACTIVE,
3184 EL_EM_GATE_4_GRAY_ACTIVE,
3193 EL_EMC_GATE_5_GRAY_ACTIVE,
3194 EL_EMC_GATE_6_GRAY_ACTIVE,
3195 EL_EMC_GATE_7_GRAY_ACTIVE,
3196 EL_EMC_GATE_8_GRAY_ACTIVE,
3198 EL_DC_GATE_WHITE_GRAY,
3199 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3203 // same elements as in 'ep_passable_inside'
3208 EL_SP_PORT_HORIZONTAL,
3209 EL_SP_PORT_VERTICAL,
3211 EL_SP_GRAVITY_PORT_LEFT,
3212 EL_SP_GRAVITY_PORT_RIGHT,
3213 EL_SP_GRAVITY_PORT_UP,
3214 EL_SP_GRAVITY_PORT_DOWN,
3215 EL_SP_GRAVITY_ON_PORT_LEFT,
3216 EL_SP_GRAVITY_ON_PORT_RIGHT,
3217 EL_SP_GRAVITY_ON_PORT_UP,
3218 EL_SP_GRAVITY_ON_PORT_DOWN,
3219 EL_SP_GRAVITY_OFF_PORT_LEFT,
3220 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3221 EL_SP_GRAVITY_OFF_PORT_UP,
3222 EL_SP_GRAVITY_OFF_PORT_DOWN,
3227 static int ep_throwable[] =
3232 static int ep_can_explode[] =
3234 // same elements as in 'ep_explodes_impact'
3239 // same elements as in 'ep_explodes_smashed'
3245 // elements that can explode by explosion or by dragonfire
3249 EL_EM_DYNAMITE_ACTIVE,
3250 EL_DYNABOMB_PLAYER_1_ACTIVE,
3251 EL_DYNABOMB_PLAYER_2_ACTIVE,
3252 EL_DYNABOMB_PLAYER_3_ACTIVE,
3253 EL_DYNABOMB_PLAYER_4_ACTIVE,
3254 EL_DYNABOMB_INCREASE_NUMBER,
3255 EL_DYNABOMB_INCREASE_SIZE,
3256 EL_DYNABOMB_INCREASE_POWER,
3257 EL_SP_DISK_RED_ACTIVE,
3265 // elements that can explode only by explosion
3271 static int ep_gravity_reachable[] =
3277 EL_INVISIBLE_SAND_ACTIVE,
3282 EL_SP_PORT_HORIZONTAL,
3283 EL_SP_PORT_VERTICAL,
3285 EL_SP_GRAVITY_PORT_LEFT,
3286 EL_SP_GRAVITY_PORT_RIGHT,
3287 EL_SP_GRAVITY_PORT_UP,
3288 EL_SP_GRAVITY_PORT_DOWN,
3289 EL_SP_GRAVITY_ON_PORT_LEFT,
3290 EL_SP_GRAVITY_ON_PORT_RIGHT,
3291 EL_SP_GRAVITY_ON_PORT_UP,
3292 EL_SP_GRAVITY_ON_PORT_DOWN,
3293 EL_SP_GRAVITY_OFF_PORT_LEFT,
3294 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3295 EL_SP_GRAVITY_OFF_PORT_UP,
3296 EL_SP_GRAVITY_OFF_PORT_DOWN,
3302 static int ep_player[] =
3309 EL_SOKOBAN_FIELD_PLAYER,
3315 static int ep_can_pass_magic_wall[] =
3329 static int ep_can_pass_dc_magic_wall[] =
3345 static int ep_switchable[] =
3349 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3350 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3351 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3352 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3353 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3354 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3355 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3356 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3357 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3358 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3359 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3360 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3361 EL_SWITCHGATE_SWITCH_UP,
3362 EL_SWITCHGATE_SWITCH_DOWN,
3363 EL_DC_SWITCHGATE_SWITCH_UP,
3364 EL_DC_SWITCHGATE_SWITCH_DOWN,
3366 EL_LIGHT_SWITCH_ACTIVE,
3368 EL_DC_TIMEGATE_SWITCH,
3369 EL_BALLOON_SWITCH_LEFT,
3370 EL_BALLOON_SWITCH_RIGHT,
3371 EL_BALLOON_SWITCH_UP,
3372 EL_BALLOON_SWITCH_DOWN,
3373 EL_BALLOON_SWITCH_ANY,
3374 EL_BALLOON_SWITCH_NONE,
3377 EL_EMC_MAGIC_BALL_SWITCH,
3378 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3383 static int ep_bd_element[] =
3417 static int ep_sp_element[] =
3419 // should always be valid
3422 // standard classic Supaplex elements
3429 EL_SP_HARDWARE_GRAY,
3437 EL_SP_GRAVITY_PORT_RIGHT,
3438 EL_SP_GRAVITY_PORT_DOWN,
3439 EL_SP_GRAVITY_PORT_LEFT,
3440 EL_SP_GRAVITY_PORT_UP,
3445 EL_SP_PORT_VERTICAL,
3446 EL_SP_PORT_HORIZONTAL,
3452 EL_SP_HARDWARE_BASE_1,
3453 EL_SP_HARDWARE_GREEN,
3454 EL_SP_HARDWARE_BLUE,
3456 EL_SP_HARDWARE_YELLOW,
3457 EL_SP_HARDWARE_BASE_2,
3458 EL_SP_HARDWARE_BASE_3,
3459 EL_SP_HARDWARE_BASE_4,
3460 EL_SP_HARDWARE_BASE_5,
3461 EL_SP_HARDWARE_BASE_6,
3465 // additional elements that appeared in newer Supaplex levels
3468 // additional gravity port elements (not switching, but setting gravity)
3469 EL_SP_GRAVITY_ON_PORT_LEFT,
3470 EL_SP_GRAVITY_ON_PORT_RIGHT,
3471 EL_SP_GRAVITY_ON_PORT_UP,
3472 EL_SP_GRAVITY_ON_PORT_DOWN,
3473 EL_SP_GRAVITY_OFF_PORT_LEFT,
3474 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3475 EL_SP_GRAVITY_OFF_PORT_UP,
3476 EL_SP_GRAVITY_OFF_PORT_DOWN,
3478 // more than one Murphy in a level results in an inactive clone
3481 // runtime Supaplex elements
3482 EL_SP_DISK_RED_ACTIVE,
3483 EL_SP_TERMINAL_ACTIVE,
3484 EL_SP_BUGGY_BASE_ACTIVATING,
3485 EL_SP_BUGGY_BASE_ACTIVE,
3492 static int ep_sb_element[] =
3497 EL_SOKOBAN_FIELD_EMPTY,
3498 EL_SOKOBAN_FIELD_FULL,
3499 EL_SOKOBAN_FIELD_PLAYER,
3504 EL_INVISIBLE_STEELWALL,
3509 static int ep_gem[] =
3521 static int ep_food_dark_yamyam[] =
3549 static int ep_food_penguin[] =
3563 static int ep_food_pig[] =
3575 static int ep_historic_wall[] =
3586 EL_GATE_1_GRAY_ACTIVE,
3587 EL_GATE_2_GRAY_ACTIVE,
3588 EL_GATE_3_GRAY_ACTIVE,
3589 EL_GATE_4_GRAY_ACTIVE,
3598 EL_EM_GATE_1_GRAY_ACTIVE,
3599 EL_EM_GATE_2_GRAY_ACTIVE,
3600 EL_EM_GATE_3_GRAY_ACTIVE,
3601 EL_EM_GATE_4_GRAY_ACTIVE,
3608 EL_EXPANDABLE_WALL_HORIZONTAL,
3609 EL_EXPANDABLE_WALL_VERTICAL,
3610 EL_EXPANDABLE_WALL_ANY,
3611 EL_EXPANDABLE_WALL_GROWING,
3612 EL_BD_EXPANDABLE_WALL,
3619 EL_SP_HARDWARE_GRAY,
3620 EL_SP_HARDWARE_GREEN,
3621 EL_SP_HARDWARE_BLUE,
3623 EL_SP_HARDWARE_YELLOW,
3624 EL_SP_HARDWARE_BASE_1,
3625 EL_SP_HARDWARE_BASE_2,
3626 EL_SP_HARDWARE_BASE_3,
3627 EL_SP_HARDWARE_BASE_4,
3628 EL_SP_HARDWARE_BASE_5,
3629 EL_SP_HARDWARE_BASE_6,
3631 EL_SP_TERMINAL_ACTIVE,
3634 EL_INVISIBLE_STEELWALL,
3635 EL_INVISIBLE_STEELWALL_ACTIVE,
3637 EL_INVISIBLE_WALL_ACTIVE,
3638 EL_STEELWALL_SLIPPERY,
3655 static int ep_historic_solid[] =
3659 EL_EXPANDABLE_WALL_HORIZONTAL,
3660 EL_EXPANDABLE_WALL_VERTICAL,
3661 EL_EXPANDABLE_WALL_ANY,
3662 EL_BD_EXPANDABLE_WALL,
3675 EL_QUICKSAND_FILLING,
3676 EL_QUICKSAND_EMPTYING,
3678 EL_MAGIC_WALL_ACTIVE,
3679 EL_MAGIC_WALL_EMPTYING,
3680 EL_MAGIC_WALL_FILLING,
3684 EL_BD_MAGIC_WALL_ACTIVE,
3685 EL_BD_MAGIC_WALL_EMPTYING,
3686 EL_BD_MAGIC_WALL_FULL,
3687 EL_BD_MAGIC_WALL_FILLING,
3688 EL_BD_MAGIC_WALL_DEAD,
3697 EL_SP_TERMINAL_ACTIVE,
3701 EL_INVISIBLE_WALL_ACTIVE,
3702 EL_SWITCHGATE_SWITCH_UP,
3703 EL_SWITCHGATE_SWITCH_DOWN,
3705 EL_TIMEGATE_SWITCH_ACTIVE,
3717 // the following elements are a direct copy of "indestructible" elements,
3718 // except "EL_ACID", which is "indestructible", but not "solid"!
3723 EL_ACID_POOL_TOPLEFT,
3724 EL_ACID_POOL_TOPRIGHT,
3725 EL_ACID_POOL_BOTTOMLEFT,
3726 EL_ACID_POOL_BOTTOM,
3727 EL_ACID_POOL_BOTTOMRIGHT,
3728 EL_SP_HARDWARE_GRAY,
3729 EL_SP_HARDWARE_GREEN,
3730 EL_SP_HARDWARE_BLUE,
3732 EL_SP_HARDWARE_YELLOW,
3733 EL_SP_HARDWARE_BASE_1,
3734 EL_SP_HARDWARE_BASE_2,
3735 EL_SP_HARDWARE_BASE_3,
3736 EL_SP_HARDWARE_BASE_4,
3737 EL_SP_HARDWARE_BASE_5,
3738 EL_SP_HARDWARE_BASE_6,
3739 EL_INVISIBLE_STEELWALL,
3740 EL_INVISIBLE_STEELWALL_ACTIVE,
3741 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3742 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3743 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3744 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3745 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3746 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3747 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3748 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3749 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3750 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3751 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3752 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3754 EL_LIGHT_SWITCH_ACTIVE,
3755 EL_SIGN_EXCLAMATION,
3756 EL_SIGN_RADIOACTIVITY,
3763 EL_SIGN_ENTRY_FORBIDDEN,
3764 EL_SIGN_EMERGENCY_EXIT,
3772 EL_STEEL_EXIT_CLOSED,
3774 EL_STEEL_EXIT_OPENING,
3775 EL_STEEL_EXIT_CLOSING,
3776 EL_EM_STEEL_EXIT_CLOSED,
3777 EL_EM_STEEL_EXIT_OPEN,
3778 EL_EM_STEEL_EXIT_OPENING,
3779 EL_EM_STEEL_EXIT_CLOSING,
3780 EL_DC_STEELWALL_1_LEFT,
3781 EL_DC_STEELWALL_1_RIGHT,
3782 EL_DC_STEELWALL_1_TOP,
3783 EL_DC_STEELWALL_1_BOTTOM,
3784 EL_DC_STEELWALL_1_HORIZONTAL,
3785 EL_DC_STEELWALL_1_VERTICAL,
3786 EL_DC_STEELWALL_1_TOPLEFT,
3787 EL_DC_STEELWALL_1_TOPRIGHT,
3788 EL_DC_STEELWALL_1_BOTTOMLEFT,
3789 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3790 EL_DC_STEELWALL_1_TOPLEFT_2,
3791 EL_DC_STEELWALL_1_TOPRIGHT_2,
3792 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3793 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3794 EL_DC_STEELWALL_2_LEFT,
3795 EL_DC_STEELWALL_2_RIGHT,
3796 EL_DC_STEELWALL_2_TOP,
3797 EL_DC_STEELWALL_2_BOTTOM,
3798 EL_DC_STEELWALL_2_HORIZONTAL,
3799 EL_DC_STEELWALL_2_VERTICAL,
3800 EL_DC_STEELWALL_2_MIDDLE,
3801 EL_DC_STEELWALL_2_SINGLE,
3802 EL_STEELWALL_SLIPPERY,
3816 EL_GATE_1_GRAY_ACTIVE,
3817 EL_GATE_2_GRAY_ACTIVE,
3818 EL_GATE_3_GRAY_ACTIVE,
3819 EL_GATE_4_GRAY_ACTIVE,
3828 EL_EM_GATE_1_GRAY_ACTIVE,
3829 EL_EM_GATE_2_GRAY_ACTIVE,
3830 EL_EM_GATE_3_GRAY_ACTIVE,
3831 EL_EM_GATE_4_GRAY_ACTIVE,
3840 EL_EMC_GATE_5_GRAY_ACTIVE,
3841 EL_EMC_GATE_6_GRAY_ACTIVE,
3842 EL_EMC_GATE_7_GRAY_ACTIVE,
3843 EL_EMC_GATE_8_GRAY_ACTIVE,
3845 EL_DC_GATE_WHITE_GRAY,
3846 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3847 EL_DC_GATE_FAKE_GRAY,
3849 EL_SWITCHGATE_OPENING,
3850 EL_SWITCHGATE_CLOSED,
3851 EL_SWITCHGATE_CLOSING,
3852 EL_DC_SWITCHGATE_SWITCH_UP,
3853 EL_DC_SWITCHGATE_SWITCH_DOWN,
3855 EL_TIMEGATE_OPENING,
3857 EL_TIMEGATE_CLOSING,
3858 EL_DC_TIMEGATE_SWITCH,
3859 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3863 EL_TUBE_VERTICAL_LEFT,
3864 EL_TUBE_VERTICAL_RIGHT,
3865 EL_TUBE_HORIZONTAL_UP,
3866 EL_TUBE_HORIZONTAL_DOWN,
3871 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3872 EL_EXPANDABLE_STEELWALL_VERTICAL,
3873 EL_EXPANDABLE_STEELWALL_ANY,
3878 static int ep_classic_enemy[] =
3895 static int ep_belt[] =
3897 EL_CONVEYOR_BELT_1_LEFT,
3898 EL_CONVEYOR_BELT_1_MIDDLE,
3899 EL_CONVEYOR_BELT_1_RIGHT,
3900 EL_CONVEYOR_BELT_2_LEFT,
3901 EL_CONVEYOR_BELT_2_MIDDLE,
3902 EL_CONVEYOR_BELT_2_RIGHT,
3903 EL_CONVEYOR_BELT_3_LEFT,
3904 EL_CONVEYOR_BELT_3_MIDDLE,
3905 EL_CONVEYOR_BELT_3_RIGHT,
3906 EL_CONVEYOR_BELT_4_LEFT,
3907 EL_CONVEYOR_BELT_4_MIDDLE,
3908 EL_CONVEYOR_BELT_4_RIGHT,
3913 static int ep_belt_active[] =
3915 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3916 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3917 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3918 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3919 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3920 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3921 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3922 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3923 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3924 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3925 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3926 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3931 static int ep_belt_switch[] =
3933 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3934 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3935 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3936 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3937 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3938 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3939 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3940 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3941 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3942 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3943 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3944 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3949 static int ep_tube[] =
3956 EL_TUBE_HORIZONTAL_UP,
3957 EL_TUBE_HORIZONTAL_DOWN,
3959 EL_TUBE_VERTICAL_LEFT,
3960 EL_TUBE_VERTICAL_RIGHT,
3966 static int ep_acid_pool[] =
3968 EL_ACID_POOL_TOPLEFT,
3969 EL_ACID_POOL_TOPRIGHT,
3970 EL_ACID_POOL_BOTTOMLEFT,
3971 EL_ACID_POOL_BOTTOM,
3972 EL_ACID_POOL_BOTTOMRIGHT,
3977 static int ep_keygate[] =
3987 EL_GATE_1_GRAY_ACTIVE,
3988 EL_GATE_2_GRAY_ACTIVE,
3989 EL_GATE_3_GRAY_ACTIVE,
3990 EL_GATE_4_GRAY_ACTIVE,
3999 EL_EM_GATE_1_GRAY_ACTIVE,
4000 EL_EM_GATE_2_GRAY_ACTIVE,
4001 EL_EM_GATE_3_GRAY_ACTIVE,
4002 EL_EM_GATE_4_GRAY_ACTIVE,
4011 EL_EMC_GATE_5_GRAY_ACTIVE,
4012 EL_EMC_GATE_6_GRAY_ACTIVE,
4013 EL_EMC_GATE_7_GRAY_ACTIVE,
4014 EL_EMC_GATE_8_GRAY_ACTIVE,
4016 EL_DC_GATE_WHITE_GRAY,
4017 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4022 static int ep_amoeboid[] =
4034 static int ep_amoebalive[] =
4045 static int ep_has_editor_content[] =
4051 EL_SOKOBAN_FIELD_PLAYER,
4068 static int ep_can_turn_each_move[] =
4070 // !!! do something with this one !!!
4074 static int ep_can_grow[] =
4088 static int ep_active_bomb[] =
4091 EL_EM_DYNAMITE_ACTIVE,
4092 EL_DYNABOMB_PLAYER_1_ACTIVE,
4093 EL_DYNABOMB_PLAYER_2_ACTIVE,
4094 EL_DYNABOMB_PLAYER_3_ACTIVE,
4095 EL_DYNABOMB_PLAYER_4_ACTIVE,
4096 EL_SP_DISK_RED_ACTIVE,
4101 static int ep_inactive[] =
4111 EL_QUICKSAND_FAST_EMPTY,
4134 EL_GATE_1_GRAY_ACTIVE,
4135 EL_GATE_2_GRAY_ACTIVE,
4136 EL_GATE_3_GRAY_ACTIVE,
4137 EL_GATE_4_GRAY_ACTIVE,
4146 EL_EM_GATE_1_GRAY_ACTIVE,
4147 EL_EM_GATE_2_GRAY_ACTIVE,
4148 EL_EM_GATE_3_GRAY_ACTIVE,
4149 EL_EM_GATE_4_GRAY_ACTIVE,
4158 EL_EMC_GATE_5_GRAY_ACTIVE,
4159 EL_EMC_GATE_6_GRAY_ACTIVE,
4160 EL_EMC_GATE_7_GRAY_ACTIVE,
4161 EL_EMC_GATE_8_GRAY_ACTIVE,
4163 EL_DC_GATE_WHITE_GRAY,
4164 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4165 EL_DC_GATE_FAKE_GRAY,
4168 EL_INVISIBLE_STEELWALL,
4176 EL_WALL_EMERALD_YELLOW,
4177 EL_DYNABOMB_INCREASE_NUMBER,
4178 EL_DYNABOMB_INCREASE_SIZE,
4179 EL_DYNABOMB_INCREASE_POWER,
4183 EL_SOKOBAN_FIELD_EMPTY,
4184 EL_SOKOBAN_FIELD_FULL,
4185 EL_WALL_EMERALD_RED,
4186 EL_WALL_EMERALD_PURPLE,
4187 EL_ACID_POOL_TOPLEFT,
4188 EL_ACID_POOL_TOPRIGHT,
4189 EL_ACID_POOL_BOTTOMLEFT,
4190 EL_ACID_POOL_BOTTOM,
4191 EL_ACID_POOL_BOTTOMRIGHT,
4195 EL_BD_MAGIC_WALL_DEAD,
4197 EL_DC_MAGIC_WALL_DEAD,
4198 EL_AMOEBA_TO_DIAMOND,
4206 EL_SP_GRAVITY_PORT_RIGHT,
4207 EL_SP_GRAVITY_PORT_DOWN,
4208 EL_SP_GRAVITY_PORT_LEFT,
4209 EL_SP_GRAVITY_PORT_UP,
4210 EL_SP_PORT_HORIZONTAL,
4211 EL_SP_PORT_VERTICAL,
4222 EL_SP_HARDWARE_GRAY,
4223 EL_SP_HARDWARE_GREEN,
4224 EL_SP_HARDWARE_BLUE,
4226 EL_SP_HARDWARE_YELLOW,
4227 EL_SP_HARDWARE_BASE_1,
4228 EL_SP_HARDWARE_BASE_2,
4229 EL_SP_HARDWARE_BASE_3,
4230 EL_SP_HARDWARE_BASE_4,
4231 EL_SP_HARDWARE_BASE_5,
4232 EL_SP_HARDWARE_BASE_6,
4233 EL_SP_GRAVITY_ON_PORT_LEFT,
4234 EL_SP_GRAVITY_ON_PORT_RIGHT,
4235 EL_SP_GRAVITY_ON_PORT_UP,
4236 EL_SP_GRAVITY_ON_PORT_DOWN,
4237 EL_SP_GRAVITY_OFF_PORT_LEFT,
4238 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4239 EL_SP_GRAVITY_OFF_PORT_UP,
4240 EL_SP_GRAVITY_OFF_PORT_DOWN,
4241 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4242 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4243 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4244 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4245 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4246 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4247 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4248 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4249 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4250 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4251 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4252 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4253 EL_SIGN_EXCLAMATION,
4254 EL_SIGN_RADIOACTIVITY,
4261 EL_SIGN_ENTRY_FORBIDDEN,
4262 EL_SIGN_EMERGENCY_EXIT,
4270 EL_DC_STEELWALL_1_LEFT,
4271 EL_DC_STEELWALL_1_RIGHT,
4272 EL_DC_STEELWALL_1_TOP,
4273 EL_DC_STEELWALL_1_BOTTOM,
4274 EL_DC_STEELWALL_1_HORIZONTAL,
4275 EL_DC_STEELWALL_1_VERTICAL,
4276 EL_DC_STEELWALL_1_TOPLEFT,
4277 EL_DC_STEELWALL_1_TOPRIGHT,
4278 EL_DC_STEELWALL_1_BOTTOMLEFT,
4279 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4280 EL_DC_STEELWALL_1_TOPLEFT_2,
4281 EL_DC_STEELWALL_1_TOPRIGHT_2,
4282 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4283 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4284 EL_DC_STEELWALL_2_LEFT,
4285 EL_DC_STEELWALL_2_RIGHT,
4286 EL_DC_STEELWALL_2_TOP,
4287 EL_DC_STEELWALL_2_BOTTOM,
4288 EL_DC_STEELWALL_2_HORIZONTAL,
4289 EL_DC_STEELWALL_2_VERTICAL,
4290 EL_DC_STEELWALL_2_MIDDLE,
4291 EL_DC_STEELWALL_2_SINGLE,
4292 EL_STEELWALL_SLIPPERY,
4297 EL_EMC_WALL_SLIPPERY_1,
4298 EL_EMC_WALL_SLIPPERY_2,
4299 EL_EMC_WALL_SLIPPERY_3,
4300 EL_EMC_WALL_SLIPPERY_4,
4321 static int ep_em_slippery_wall[] =
4326 static int ep_gfx_crumbled[] =
4337 static int ep_editor_cascade_active[] =
4339 EL_INTERNAL_CASCADE_BD_ACTIVE,
4340 EL_INTERNAL_CASCADE_EM_ACTIVE,
4341 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4342 EL_INTERNAL_CASCADE_RND_ACTIVE,
4343 EL_INTERNAL_CASCADE_SB_ACTIVE,
4344 EL_INTERNAL_CASCADE_SP_ACTIVE,
4345 EL_INTERNAL_CASCADE_DC_ACTIVE,
4346 EL_INTERNAL_CASCADE_DX_ACTIVE,
4347 EL_INTERNAL_CASCADE_MM_ACTIVE,
4348 EL_INTERNAL_CASCADE_DF_ACTIVE,
4349 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4350 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4351 EL_INTERNAL_CASCADE_CE_ACTIVE,
4352 EL_INTERNAL_CASCADE_GE_ACTIVE,
4353 EL_INTERNAL_CASCADE_REF_ACTIVE,
4354 EL_INTERNAL_CASCADE_USER_ACTIVE,
4355 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4360 static int ep_editor_cascade_inactive[] =
4362 EL_INTERNAL_CASCADE_BD,
4363 EL_INTERNAL_CASCADE_EM,
4364 EL_INTERNAL_CASCADE_EMC,
4365 EL_INTERNAL_CASCADE_RND,
4366 EL_INTERNAL_CASCADE_SB,
4367 EL_INTERNAL_CASCADE_SP,
4368 EL_INTERNAL_CASCADE_DC,
4369 EL_INTERNAL_CASCADE_DX,
4370 EL_INTERNAL_CASCADE_MM,
4371 EL_INTERNAL_CASCADE_DF,
4372 EL_INTERNAL_CASCADE_CHARS,
4373 EL_INTERNAL_CASCADE_STEEL_CHARS,
4374 EL_INTERNAL_CASCADE_CE,
4375 EL_INTERNAL_CASCADE_GE,
4376 EL_INTERNAL_CASCADE_REF,
4377 EL_INTERNAL_CASCADE_USER,
4378 EL_INTERNAL_CASCADE_DYNAMIC,
4383 static int ep_obsolete[] =
4387 EL_EM_KEY_1_FILE_OBSOLETE,
4388 EL_EM_KEY_2_FILE_OBSOLETE,
4389 EL_EM_KEY_3_FILE_OBSOLETE,
4390 EL_EM_KEY_4_FILE_OBSOLETE,
4391 EL_ENVELOPE_OBSOLETE,
4400 } element_properties[] =
4402 { ep_diggable, EP_DIGGABLE },
4403 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4404 { ep_dont_run_into, EP_DONT_RUN_INTO },
4405 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4406 { ep_dont_touch, EP_DONT_TOUCH },
4407 { ep_indestructible, EP_INDESTRUCTIBLE },
4408 { ep_slippery, EP_SLIPPERY },
4409 { ep_can_change, EP_CAN_CHANGE },
4410 { ep_can_move, EP_CAN_MOVE },
4411 { ep_can_fall, EP_CAN_FALL },
4412 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4413 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4414 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4415 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4416 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4417 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4418 { ep_walkable_over, EP_WALKABLE_OVER },
4419 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4420 { ep_walkable_under, EP_WALKABLE_UNDER },
4421 { ep_passable_over, EP_PASSABLE_OVER },
4422 { ep_passable_inside, EP_PASSABLE_INSIDE },
4423 { ep_passable_under, EP_PASSABLE_UNDER },
4424 { ep_droppable, EP_DROPPABLE },
4425 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4426 { ep_pushable, EP_PUSHABLE },
4427 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4428 { ep_protected, EP_PROTECTED },
4429 { ep_throwable, EP_THROWABLE },
4430 { ep_can_explode, EP_CAN_EXPLODE },
4431 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4433 { ep_player, EP_PLAYER },
4434 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4435 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4436 { ep_switchable, EP_SWITCHABLE },
4437 { ep_bd_element, EP_BD_ELEMENT },
4438 { ep_sp_element, EP_SP_ELEMENT },
4439 { ep_sb_element, EP_SB_ELEMENT },
4441 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4442 { ep_food_penguin, EP_FOOD_PENGUIN },
4443 { ep_food_pig, EP_FOOD_PIG },
4444 { ep_historic_wall, EP_HISTORIC_WALL },
4445 { ep_historic_solid, EP_HISTORIC_SOLID },
4446 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4447 { ep_belt, EP_BELT },
4448 { ep_belt_active, EP_BELT_ACTIVE },
4449 { ep_belt_switch, EP_BELT_SWITCH },
4450 { ep_tube, EP_TUBE },
4451 { ep_acid_pool, EP_ACID_POOL },
4452 { ep_keygate, EP_KEYGATE },
4453 { ep_amoeboid, EP_AMOEBOID },
4454 { ep_amoebalive, EP_AMOEBALIVE },
4455 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4456 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4457 { ep_can_grow, EP_CAN_GROW },
4458 { ep_active_bomb, EP_ACTIVE_BOMB },
4459 { ep_inactive, EP_INACTIVE },
4461 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4463 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4465 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4466 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4468 { ep_obsolete, EP_OBSOLETE },
4475 // always start with reliable default values (element has no properties)
4476 // (but never initialize clipboard elements after the very first time)
4477 // (to be able to use clipboard elements between several levels)
4478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4479 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4480 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4481 SET_PROPERTY(i, j, FALSE);
4483 // set all base element properties from above array definitions
4484 for (i = 0; element_properties[i].elements != NULL; i++)
4485 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4486 SET_PROPERTY((element_properties[i].elements)[j],
4487 element_properties[i].property, TRUE);
4489 // copy properties to some elements that are only stored in level file
4490 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4491 for (j = 0; copy_properties[j][0] != -1; j++)
4492 if (HAS_PROPERTY(copy_properties[j][0], i))
4493 for (k = 1; k <= 4; k++)
4494 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4496 // set static element properties that are not listed in array definitions
4497 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4498 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4500 clipboard_elements_initialized = TRUE;
4503 void InitElementPropertiesEngine(int engine_version)
4505 static int no_wall_properties[] =
4508 EP_COLLECTIBLE_ONLY,
4510 EP_DONT_COLLIDE_WITH,
4513 EP_CAN_SMASH_PLAYER,
4514 EP_CAN_SMASH_ENEMIES,
4515 EP_CAN_SMASH_EVERYTHING,
4520 EP_FOOD_DARK_YAMYAM,
4536 /* important: after initialization in InitElementPropertiesStatic(), the
4537 elements are not again initialized to a default value; therefore all
4538 changes have to make sure that they leave the element with a defined
4539 property (which means that conditional property changes must be set to
4540 a reliable default value before) */
4542 // resolve group elements
4543 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4544 ResolveGroupElement(EL_GROUP_START + i);
4546 // set all special, combined or engine dependent element properties
4547 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4549 // do not change (already initialized) clipboard elements here
4550 if (IS_CLIPBOARD_ELEMENT(i))
4553 // ---------- INACTIVE ----------------------------------------------------
4554 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4555 i <= EL_CHAR_END) ||
4556 (i >= EL_STEEL_CHAR_START &&
4557 i <= EL_STEEL_CHAR_END)));
4559 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4560 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4561 IS_WALKABLE_INSIDE(i) ||
4562 IS_WALKABLE_UNDER(i)));
4564 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4565 IS_PASSABLE_INSIDE(i) ||
4566 IS_PASSABLE_UNDER(i)));
4568 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4569 IS_PASSABLE_OVER(i)));
4571 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4572 IS_PASSABLE_INSIDE(i)));
4574 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4575 IS_PASSABLE_UNDER(i)));
4577 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4580 // ---------- COLLECTIBLE -------------------------------------------------
4581 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4585 // ---------- SNAPPABLE ---------------------------------------------------
4586 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4587 IS_COLLECTIBLE(i) ||
4591 // ---------- WALL --------------------------------------------------------
4592 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4594 for (j = 0; no_wall_properties[j] != -1; j++)
4595 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4596 i >= EL_FIRST_RUNTIME_UNREAL)
4597 SET_PROPERTY(i, EP_WALL, FALSE);
4599 if (IS_HISTORIC_WALL(i))
4600 SET_PROPERTY(i, EP_WALL, TRUE);
4602 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4603 if (engine_version < VERSION_IDENT(2,2,0,0))
4604 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4606 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4608 !IS_COLLECTIBLE(i)));
4610 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4611 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4612 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4614 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4617 // ---------- EXPLOSION_PROOF ---------------------------------------------
4619 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4620 else if (engine_version < VERSION_IDENT(2,2,0,0))
4621 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4623 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4627 if (IS_CUSTOM_ELEMENT(i))
4629 // these are additional properties which are initially false when set
4631 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4633 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4634 if (DONT_COLLIDE_WITH(i))
4635 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4637 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4638 if (CAN_SMASH_EVERYTHING(i))
4639 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4640 if (CAN_SMASH_ENEMIES(i))
4641 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4644 // ---------- CAN_SMASH ---------------------------------------------------
4645 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4646 CAN_SMASH_ENEMIES(i) ||
4647 CAN_SMASH_EVERYTHING(i)));
4649 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4650 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4651 EXPLODES_BY_FIRE(i)));
4653 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4654 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4655 EXPLODES_SMASHED(i)));
4657 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4658 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4659 EXPLODES_IMPACT(i)));
4661 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4662 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4664 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4665 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4666 i == EL_BLACK_ORB));
4668 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4669 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4671 IS_CUSTOM_ELEMENT(i)));
4673 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4674 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4675 i == EL_SP_ELECTRON));
4677 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4678 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4679 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4680 getMoveIntoAcidProperty(&level, i));
4682 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4683 if (MAYBE_DONT_COLLIDE_WITH(i))
4684 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4685 getDontCollideWithProperty(&level, i));
4687 // ---------- SP_PORT -----------------------------------------------------
4688 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4689 IS_PASSABLE_INSIDE(i)));
4691 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4692 for (j = 0; j < level.num_android_clone_elements; j++)
4693 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4695 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4697 // ---------- CAN_CHANGE --------------------------------------------------
4698 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4699 for (j = 0; j < element_info[i].num_change_pages; j++)
4700 if (element_info[i].change_page[j].can_change)
4701 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4703 // ---------- HAS_ACTION --------------------------------------------------
4704 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4705 for (j = 0; j < element_info[i].num_change_pages; j++)
4706 if (element_info[i].change_page[j].has_action)
4707 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4709 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4710 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4713 // ---------- GFX_CRUMBLED ------------------------------------------------
4714 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4715 element_info[i].crumbled[ACTION_DEFAULT] !=
4716 element_info[i].graphic[ACTION_DEFAULT]);
4718 // ---------- EDITOR_CASCADE ----------------------------------------------
4719 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4720 IS_EDITOR_CASCADE_INACTIVE(i)));
4723 // dynamically adjust element properties according to game engine version
4725 static int ep_em_slippery_wall[] =
4730 EL_EXPANDABLE_WALL_HORIZONTAL,
4731 EL_EXPANDABLE_WALL_VERTICAL,
4732 EL_EXPANDABLE_WALL_ANY,
4733 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4734 EL_EXPANDABLE_STEELWALL_VERTICAL,
4735 EL_EXPANDABLE_STEELWALL_ANY,
4736 EL_EXPANDABLE_STEELWALL_GROWING,
4740 static int ep_em_explodes_by_fire[] =
4743 EL_EM_DYNAMITE_ACTIVE,
4748 // special EM style gems behaviour
4749 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4750 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4751 level.em_slippery_gems);
4753 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4754 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4755 (level.em_slippery_gems &&
4756 engine_version > VERSION_IDENT(2,0,1,0)));
4758 // special EM style explosion behaviour regarding chain reactions
4759 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4760 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4761 level.em_explodes_by_fire);
4764 // this is needed because some graphics depend on element properties
4765 if (game_status == GAME_MODE_PLAYING)
4766 InitElementGraphicInfo();
4769 void InitElementPropertiesGfxElement(void)
4773 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4775 struct ElementInfo *ei = &element_info[i];
4777 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4781 static void InitGlobal(void)
4786 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4788 // check if element_name_info entry defined for each element in "main.h"
4789 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4790 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4792 element_info[i].token_name = element_name_info[i].token_name;
4793 element_info[i].class_name = element_name_info[i].class_name;
4794 element_info[i].editor_description= element_name_info[i].editor_description;
4797 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4799 // check if global_anim_name_info defined for each entry in "main.h"
4800 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4801 global_anim_name_info[i].token_name == NULL)
4802 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4804 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4807 // create hash from image config list
4808 image_config_hash = newSetupFileHash();
4809 for (i = 0; image_config[i].token != NULL; i++)
4810 setHashEntry(image_config_hash,
4811 image_config[i].token,
4812 image_config[i].value);
4814 // create hash from element token list
4815 element_token_hash = newSetupFileHash();
4816 for (i = 0; element_name_info[i].token_name != NULL; i++)
4817 setHashEntry(element_token_hash,
4818 element_name_info[i].token_name,
4821 // create hash from graphic token list
4822 graphic_token_hash = newSetupFileHash();
4823 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4824 if (strSuffix(image_config[i].value, ".png") ||
4825 strSuffix(image_config[i].value, ".pcx") ||
4826 strSuffix(image_config[i].value, ".wav") ||
4827 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4828 setHashEntry(graphic_token_hash,
4829 image_config[i].token,
4830 int2str(graphic++, 0));
4832 // create hash from font token list
4833 font_token_hash = newSetupFileHash();
4834 for (i = 0; font_info[i].token_name != NULL; i++)
4835 setHashEntry(font_token_hash,
4836 font_info[i].token_name,
4839 // set default filenames for all cloned graphics in static configuration
4840 for (i = 0; image_config[i].token != NULL; i++)
4842 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4844 char *token = image_config[i].token;
4845 char *token_clone_from = getStringCat2(token, ".clone_from");
4846 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4848 if (token_cloned != NULL)
4850 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4852 if (value_cloned != NULL)
4854 // set default filename in static configuration
4855 image_config[i].value = value_cloned;
4857 // set default filename in image config hash
4858 setHashEntry(image_config_hash, token, value_cloned);
4862 free(token_clone_from);
4866 // always start with reliable default values (all elements)
4867 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4868 ActiveElement[i] = i;
4870 // now add all entries that have an active state (active elements)
4871 for (i = 0; element_with_active_state[i].element != -1; i++)
4873 int element = element_with_active_state[i].element;
4874 int element_active = element_with_active_state[i].element_active;
4876 ActiveElement[element] = element_active;
4879 // always start with reliable default values (all buttons)
4880 for (i = 0; i < NUM_IMAGE_FILES; i++)
4881 ActiveButton[i] = i;
4883 // now add all entries that have an active state (active buttons)
4884 for (i = 0; button_with_active_state[i].button != -1; i++)
4886 int button = button_with_active_state[i].button;
4887 int button_active = button_with_active_state[i].button_active;
4889 ActiveButton[button] = button_active;
4892 // always start with reliable default values (all fonts)
4893 for (i = 0; i < NUM_FONTS; i++)
4896 // now add all entries that have an active state (active fonts)
4897 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4899 int font = font_with_active_state[i].font_nr;
4900 int font_active = font_with_active_state[i].font_nr_active;
4902 ActiveFont[font] = font_active;
4905 global.autoplay_leveldir = NULL;
4906 global.convert_leveldir = NULL;
4907 global.create_images_dir = NULL;
4909 global.frames_per_second = 0;
4910 global.show_frames_per_second = FALSE;
4912 global.border_status = GAME_MODE_LOADING;
4913 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4915 global.use_envelope_request = FALSE;
4918 static void Execute_Command(char *command)
4922 if (strEqual(command, "print graphicsinfo.conf"))
4924 Print("# You can configure additional/alternative image files here.\n");
4925 Print("# (The entries below are default and therefore commented out.)\n");
4927 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4929 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4932 for (i = 0; image_config[i].token != NULL; i++)
4933 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4934 image_config[i].value));
4938 else if (strEqual(command, "print soundsinfo.conf"))
4940 Print("# You can configure additional/alternative sound files here.\n");
4941 Print("# (The entries below are default and therefore commented out.)\n");
4943 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4945 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4948 for (i = 0; sound_config[i].token != NULL; i++)
4949 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4950 sound_config[i].value));
4954 else if (strEqual(command, "print musicinfo.conf"))
4956 Print("# You can configure additional/alternative music files here.\n");
4957 Print("# (The entries below are default and therefore commented out.)\n");
4959 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4961 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4964 for (i = 0; music_config[i].token != NULL; i++)
4965 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4966 music_config[i].value));
4970 else if (strEqual(command, "print editorsetup.conf"))
4972 Print("# You can configure your personal editor element list here.\n");
4973 Print("# (The entries below are default and therefore commented out.)\n");
4976 // this is needed to be able to check element list for cascade elements
4977 InitElementPropertiesStatic();
4978 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4980 PrintEditorElementList();
4984 else if (strEqual(command, "print helpanim.conf"))
4986 Print("# You can configure different element help animations here.\n");
4987 Print("# (The entries below are default and therefore commented out.)\n");
4990 for (i = 0; helpanim_config[i].token != NULL; i++)
4992 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4993 helpanim_config[i].value));
4995 if (strEqual(helpanim_config[i].token, "end"))
5001 else if (strEqual(command, "print helptext.conf"))
5003 Print("# You can configure different element help text here.\n");
5004 Print("# (The entries below are default and therefore commented out.)\n");
5007 for (i = 0; helptext_config[i].token != NULL; i++)
5008 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5009 helptext_config[i].value));
5013 else if (strPrefix(command, "dump level "))
5015 char *filename = &command[11];
5017 if (!fileExists(filename))
5018 Error(ERR_EXIT, "cannot open file '%s'", filename);
5020 LoadLevelFromFilename(&level, filename);
5025 else if (strPrefix(command, "dump tape "))
5027 char *filename = &command[10];
5029 if (!fileExists(filename))
5030 Error(ERR_EXIT, "cannot open file '%s'", filename);
5032 LoadTapeFromFilename(filename);
5037 else if (strPrefix(command, "autotest ") ||
5038 strPrefix(command, "autoplay ") ||
5039 strPrefix(command, "autoffwd ") ||
5040 strPrefix(command, "autowarp "))
5042 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5044 global.autoplay_mode =
5045 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5046 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5047 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5048 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5049 AUTOPLAY_MODE_NONE);
5051 while (*str_ptr != '\0') // continue parsing string
5053 // cut leading whitespace from string, replace it by string terminator
5054 while (*str_ptr == ' ' || *str_ptr == '\t')
5057 if (*str_ptr == '\0') // end of string reached
5060 if (global.autoplay_leveldir == NULL) // read level set string
5062 global.autoplay_leveldir = str_ptr;
5063 global.autoplay_all = TRUE; // default: play all tapes
5065 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5066 global.autoplay_level[i] = FALSE;
5068 else // read level number string
5070 int level_nr = atoi(str_ptr); // get level_nr value
5072 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5073 global.autoplay_level[level_nr] = TRUE;
5075 global.autoplay_all = FALSE;
5078 // advance string pointer to the next whitespace (or end of string)
5079 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5083 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5084 program.headless = TRUE;
5086 else if (strPrefix(command, "convert "))
5088 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5089 char *str_ptr = strchr(str_copy, ' ');
5091 global.convert_leveldir = str_copy;
5092 global.convert_level_nr = -1;
5094 if (str_ptr != NULL) // level number follows
5096 *str_ptr++ = '\0'; // terminate leveldir string
5097 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5100 program.headless = TRUE;
5102 else if (strPrefix(command, "create images "))
5104 global.create_images_dir = getStringCopy(&command[14]);
5106 if (access(global.create_images_dir, W_OK) != 0)
5107 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5108 global.create_images_dir);
5110 else if (strPrefix(command, "create CE image "))
5112 CreateCustomElementImages(&command[16]);
5118 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5121 // disable networking if any valid command was recognized
5122 options.network = setup.network_mode = FALSE;
5125 static void InitSetup(void)
5127 LoadSetup(); // global setup info
5128 LoadSetup_AutoSetup(); // global auto setup info
5130 // set some options from setup file
5132 if (setup.options.verbose)
5133 options.verbose = TRUE;
5135 if (setup.debug.show_frames_per_second)
5136 global.show_frames_per_second = TRUE;
5139 static void InitGameInfo(void)
5141 game.restart_level = FALSE;
5142 game.restart_game_message = NULL;
5143 game.request_active = FALSE;
5146 static void InitPlayerInfo(void)
5150 // choose default local player
5151 local_player = &stored_player[0];
5153 for (i = 0; i < MAX_PLAYERS; i++)
5155 stored_player[i].connected_locally = FALSE;
5156 stored_player[i].connected_network = FALSE;
5159 local_player->connected_locally = TRUE;
5162 static void InitArtworkInfo(void)
5167 static char *get_string_in_brackets(char *string)
5169 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5171 sprintf(string_in_brackets, "[%s]", string);
5173 return string_in_brackets;
5176 static char *get_level_id_suffix(int id_nr)
5178 char *id_suffix = checked_malloc(1 + 3 + 1);
5180 if (id_nr < 0 || id_nr > 999)
5183 sprintf(id_suffix, ".%03d", id_nr);
5188 static void InitArtworkConfig(void)
5190 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5192 NUM_GLOBAL_ANIM_TOKENS + 1];
5193 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5194 NUM_GLOBAL_ANIM_TOKENS + 1];
5195 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5196 NUM_GLOBAL_ANIM_TOKENS + 1];
5197 static char *action_id_suffix[NUM_ACTIONS + 1];
5198 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5199 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5200 static char *level_id_suffix[MAX_LEVELS + 1];
5201 static char *dummy[1] = { NULL };
5202 static char *ignore_generic_tokens[] =
5207 "program_copyright",
5212 static char **ignore_image_tokens;
5213 static char **ignore_sound_tokens;
5214 static char **ignore_music_tokens;
5215 int num_ignore_generic_tokens;
5216 int num_ignore_image_tokens;
5217 int num_ignore_sound_tokens;
5218 int num_ignore_music_tokens;
5221 // dynamically determine list of generic tokens to be ignored
5222 num_ignore_generic_tokens = 0;
5223 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5224 num_ignore_generic_tokens++;
5226 // dynamically determine list of image tokens to be ignored
5227 num_ignore_image_tokens = num_ignore_generic_tokens;
5228 for (i = 0; image_config_vars[i].token != NULL; i++)
5229 num_ignore_image_tokens++;
5230 ignore_image_tokens =
5231 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5232 for (i = 0; i < num_ignore_generic_tokens; i++)
5233 ignore_image_tokens[i] = ignore_generic_tokens[i];
5234 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5235 ignore_image_tokens[num_ignore_generic_tokens + i] =
5236 image_config_vars[i].token;
5237 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5239 // dynamically determine list of sound tokens to be ignored
5240 num_ignore_sound_tokens = num_ignore_generic_tokens;
5241 ignore_sound_tokens =
5242 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5243 for (i = 0; i < num_ignore_generic_tokens; i++)
5244 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5245 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5247 // dynamically determine list of music tokens to be ignored
5248 num_ignore_music_tokens = num_ignore_generic_tokens;
5249 ignore_music_tokens =
5250 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5251 for (i = 0; i < num_ignore_generic_tokens; i++)
5252 ignore_music_tokens[i] = ignore_generic_tokens[i];
5253 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5255 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5256 image_id_prefix[i] = element_info[i].token_name;
5257 for (i = 0; i < NUM_FONTS; i++)
5258 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5259 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5260 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5261 global_anim_info[i].token_name;
5262 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5264 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5265 sound_id_prefix[i] = element_info[i].token_name;
5266 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5267 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5268 get_string_in_brackets(element_info[i].class_name);
5269 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5270 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5271 global_anim_info[i].token_name;
5272 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5274 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5275 music_id_prefix[i] = music_prefix_info[i].prefix;
5276 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5277 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5278 global_anim_info[i].token_name;
5279 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5281 for (i = 0; i < NUM_ACTIONS; i++)
5282 action_id_suffix[i] = element_action_info[i].suffix;
5283 action_id_suffix[NUM_ACTIONS] = NULL;
5285 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5286 direction_id_suffix[i] = element_direction_info[i].suffix;
5287 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5289 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5290 special_id_suffix[i] = special_suffix_info[i].suffix;
5291 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5293 for (i = 0; i < MAX_LEVELS; i++)
5294 level_id_suffix[i] = get_level_id_suffix(i);
5295 level_id_suffix[MAX_LEVELS] = NULL;
5297 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5298 image_id_prefix, action_id_suffix, direction_id_suffix,
5299 special_id_suffix, ignore_image_tokens);
5300 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5301 sound_id_prefix, action_id_suffix, dummy,
5302 special_id_suffix, ignore_sound_tokens);
5303 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5304 music_id_prefix, action_id_suffix, special_id_suffix,
5305 level_id_suffix, ignore_music_tokens);
5308 static void InitMixer(void)
5315 static void InitVideoOverlay(void)
5317 // if virtual buttons are not loaded from setup file, repeat initializing
5318 // virtual buttons grid with default values now that video is initialized
5319 if (!setup.touch.grid_initialized)
5322 InitTileCursorInfo();
5326 void InitGfxBuffers(void)
5328 static int win_xsize_last = -1;
5329 static int win_ysize_last = -1;
5331 // create additional image buffers for double-buffering and cross-fading
5333 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5335 // used to temporarily store the backbuffer -- only re-create if changed
5336 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5337 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5339 win_xsize_last = WIN_XSIZE;
5340 win_ysize_last = WIN_YSIZE;
5343 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5344 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5345 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5346 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5348 // initialize screen properties
5349 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5350 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5352 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5353 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5354 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5355 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5356 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5357 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5359 // required if door size definitions have changed
5360 InitGraphicCompatibilityInfo_Doors();
5362 InitGfxBuffers_EM();
5363 InitGfxBuffers_SP();
5366 static void InitGfx(void)
5368 struct GraphicInfo *graphic_info_last = graphic_info;
5369 char *filename_font_initial = NULL;
5370 char *filename_anim_initial = NULL;
5371 Bitmap *bitmap_font_initial = NULL;
5374 // determine settings for initial font (for displaying startup messages)
5375 for (i = 0; image_config[i].token != NULL; i++)
5377 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5379 char font_token[128];
5382 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5383 len_font_token = strlen(font_token);
5385 if (strEqual(image_config[i].token, font_token))
5386 filename_font_initial = image_config[i].value;
5387 else if (strlen(image_config[i].token) > len_font_token &&
5388 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5390 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5391 font_initial[j].src_x = atoi(image_config[i].value);
5392 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5393 font_initial[j].src_y = atoi(image_config[i].value);
5394 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5395 font_initial[j].width = atoi(image_config[i].value);
5396 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5397 font_initial[j].height = atoi(image_config[i].value);
5402 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5404 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5405 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5408 if (filename_font_initial == NULL) // should not happen
5409 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5412 InitGfxCustomArtworkInfo();
5413 InitGfxOtherSettings();
5415 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5417 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5418 font_initial[j].bitmap = bitmap_font_initial;
5420 InitFontGraphicInfo();
5424 DrawInitText("Loading graphics", 120, FC_GREEN);
5426 // initialize settings for busy animation with default values
5427 int parameter[NUM_GFX_ARGS];
5428 for (i = 0; i < NUM_GFX_ARGS; i++)
5429 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5430 image_config_suffix[i].token,
5431 image_config_suffix[i].type);
5433 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5434 int len_anim_token = strlen(anim_token);
5436 // read settings for busy animation from default custom artwork config
5437 char *gfx_config_filename = getPath3(options.graphics_directory,
5439 GRAPHICSINFO_FILENAME);
5441 if (fileExists(gfx_config_filename))
5443 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5445 if (setup_file_hash)
5447 char *filename = getHashEntry(setup_file_hash, anim_token);
5451 filename_anim_initial = getStringCopy(filename);
5453 for (j = 0; image_config_suffix[j].token != NULL; j++)
5455 int type = image_config_suffix[j].type;
5456 char *suffix = image_config_suffix[j].token;
5457 char *token = getStringCat2(anim_token, suffix);
5458 char *value = getHashEntry(setup_file_hash, token);
5460 checked_free(token);
5463 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5467 freeSetupFileHash(setup_file_hash);
5471 if (filename_anim_initial == NULL)
5473 // read settings for busy animation from static default artwork config
5474 for (i = 0; image_config[i].token != NULL; i++)
5476 if (strEqual(image_config[i].token, anim_token))
5477 filename_anim_initial = getStringCopy(image_config[i].value);
5478 else if (strlen(image_config[i].token) > len_anim_token &&
5479 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5481 for (j = 0; image_config_suffix[j].token != NULL; j++)
5483 if (strEqual(&image_config[i].token[len_anim_token],
5484 image_config_suffix[j].token))
5486 get_graphic_parameter_value(image_config[i].value,
5487 image_config_suffix[j].token,
5488 image_config_suffix[j].type);
5494 if (filename_anim_initial == NULL) // should not happen
5495 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5497 anim_initial.bitmaps =
5498 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5500 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5501 LoadCustomImage(filename_anim_initial);
5503 checked_free(filename_anim_initial);
5505 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5507 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5509 graphic_info = graphic_info_last;
5511 init.busy.width = anim_initial.width;
5512 init.busy.height = anim_initial.height;
5514 InitMenuDesignSettings_Static();
5516 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5517 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5518 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5519 InitGfxDrawTileCursorFunction(DrawTileCursor);
5521 gfx.fade_border_source_status = global.border_status;
5522 gfx.fade_border_target_status = global.border_status;
5523 gfx.masked_border_bitmap_ptr = backbuffer;
5525 // use copy of busy animation to prevent change while reloading artwork
5529 static void InitGfxBackground(void)
5531 fieldbuffer = bitmap_db_field;
5532 SetDrawtoField(DRAW_TO_BACKBUFFER);
5534 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5536 redraw_mask = REDRAW_ALL;
5539 static void InitLevelInfo(void)
5541 LoadLevelInfo(); // global level info
5542 LoadLevelSetup_LastSeries(); // last played series info
5543 LoadLevelSetup_SeriesInfo(); // last played level info
5545 if (global.autoplay_leveldir &&
5546 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5548 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5549 global.autoplay_leveldir);
5550 if (leveldir_current == NULL)
5551 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5554 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5557 static void InitLevelArtworkInfo(void)
5559 LoadLevelArtworkInfo();
5562 static void InitImages(void)
5564 print_timestamp_init("InitImages");
5567 printf("::: leveldir_current->identifier == '%s'\n",
5568 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5569 printf("::: leveldir_current->graphics_path == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5571 printf("::: leveldir_current->graphics_set == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5573 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5577 setLevelArtworkDir(artwork.gfx_first);
5580 printf("::: leveldir_current->identifier == '%s'\n",
5581 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5582 printf("::: leveldir_current->graphics_path == '%s'\n",
5583 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5584 printf("::: leveldir_current->graphics_set == '%s'\n",
5585 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5586 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5587 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5591 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5592 leveldir_current->identifier,
5593 artwork.gfx_current_identifier,
5594 artwork.gfx_current->identifier,
5595 leveldir_current->graphics_set,
5596 leveldir_current->graphics_path);
5599 UPDATE_BUSY_STATE();
5601 ReloadCustomImages();
5602 print_timestamp_time("ReloadCustomImages");
5604 UPDATE_BUSY_STATE();
5606 LoadCustomElementDescriptions();
5607 print_timestamp_time("LoadCustomElementDescriptions");
5609 UPDATE_BUSY_STATE();
5611 LoadMenuDesignSettings();
5612 print_timestamp_time("LoadMenuDesignSettings");
5614 UPDATE_BUSY_STATE();
5616 ReinitializeGraphics();
5617 print_timestamp_time("ReinitializeGraphics");
5619 LoadMenuDesignSettings_AfterGraphics();
5620 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5622 UPDATE_BUSY_STATE();
5624 print_timestamp_done("InitImages");
5627 static void InitSound(char *identifier)
5629 print_timestamp_init("InitSound");
5631 if (identifier == NULL)
5632 identifier = artwork.snd_current->identifier;
5634 // set artwork path to send it to the sound server process
5635 setLevelArtworkDir(artwork.snd_first);
5637 InitReloadCustomSounds(identifier);
5638 print_timestamp_time("InitReloadCustomSounds");
5640 ReinitializeSounds();
5641 print_timestamp_time("ReinitializeSounds");
5643 print_timestamp_done("InitSound");
5646 static void InitMusic(char *identifier)
5648 print_timestamp_init("InitMusic");
5650 if (identifier == NULL)
5651 identifier = artwork.mus_current->identifier;
5653 // set artwork path to send it to the sound server process
5654 setLevelArtworkDir(artwork.mus_first);
5656 InitReloadCustomMusic(identifier);
5657 print_timestamp_time("InitReloadCustomMusic");
5659 ReinitializeMusic();
5660 print_timestamp_time("ReinitializeMusic");
5662 print_timestamp_done("InitMusic");
5665 static void InitArtworkDone(void)
5667 if (program.headless)
5670 InitGlobalAnimations();
5673 static void InitNetworkSettings(void)
5675 boolean network_enabled = (options.network || setup.network_mode);
5676 char *network_server = (options.server_host != NULL ? options.server_host :
5677 setup.network_server_hostname);
5679 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5680 network_server = NULL;
5682 InitNetworkInfo(network_enabled,
5686 options.server_port);
5689 void InitNetworkServer(void)
5691 if (!network.enabled || network.connected)
5694 LimitScreenUpdates(FALSE);
5696 if (game_status == GAME_MODE_LOADING)
5699 if (!ConnectToServer(network.server_host, network.server_port))
5701 network.enabled = FALSE;
5703 setup.network_mode = FALSE;
5707 SendToServer_ProtocolVersion();
5708 SendToServer_PlayerName(setup.player_name);
5709 SendToServer_NrWanted(setup.network_player_nr + 1);
5711 network.connected = TRUE;
5714 // short time to recognize result of network initialization
5715 if (game_status == GAME_MODE_LOADING)
5716 Delay_WithScreenUpdates(1000);
5719 static boolean CheckArtworkConfigForCustomElements(char *filename)
5721 SetupFileHash *setup_file_hash;
5722 boolean redefined_ce_found = FALSE;
5724 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5726 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5728 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5730 char *token = HASH_ITERATION_TOKEN(itr);
5732 if (strPrefix(token, "custom_"))
5734 redefined_ce_found = TRUE;
5739 END_HASH_ITERATION(setup_file_hash, itr)
5741 freeSetupFileHash(setup_file_hash);
5744 return redefined_ce_found;
5747 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5749 char *filename_base, *filename_local;
5750 boolean redefined_ce_found = FALSE;
5752 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5755 printf("::: leveldir_current->identifier == '%s'\n",
5756 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5757 printf("::: leveldir_current->graphics_path == '%s'\n",
5758 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5759 printf("::: leveldir_current->graphics_set == '%s'\n",
5760 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5761 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5762 leveldir_current == NULL ? "[NULL]" :
5763 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5766 // first look for special artwork configured in level series config
5767 filename_base = getCustomArtworkLevelConfigFilename(type);
5770 printf("::: filename_base == '%s'\n", filename_base);
5773 if (fileExists(filename_base))
5774 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5776 filename_local = getCustomArtworkConfigFilename(type);
5779 printf("::: filename_local == '%s'\n", filename_local);
5782 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5783 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5786 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5789 return redefined_ce_found;
5792 static void InitOverrideArtwork(void)
5794 boolean redefined_ce_found = FALSE;
5796 // to check if this level set redefines any CEs, do not use overriding
5797 gfx.override_level_graphics = FALSE;
5798 gfx.override_level_sounds = FALSE;
5799 gfx.override_level_music = FALSE;
5801 // now check if this level set has definitions for custom elements
5802 if (setup.override_level_graphics == AUTO ||
5803 setup.override_level_sounds == AUTO ||
5804 setup.override_level_music == AUTO)
5805 redefined_ce_found =
5806 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5807 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5808 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5811 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5814 if (redefined_ce_found)
5816 // this level set has CE definitions: change "AUTO" to "FALSE"
5817 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5818 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5819 gfx.override_level_music = (setup.override_level_music == TRUE);
5823 // this level set has no CE definitions: change "AUTO" to "TRUE"
5824 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5825 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5826 gfx.override_level_music = (setup.override_level_music != FALSE);
5830 printf("::: => %d, %d, %d\n",
5831 gfx.override_level_graphics,
5832 gfx.override_level_sounds,
5833 gfx.override_level_music);
5837 static char *getNewArtworkIdentifier(int type)
5839 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5840 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5841 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5842 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5843 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5844 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5845 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5846 char *leveldir_identifier = leveldir_current->identifier;
5847 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5848 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5849 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5850 char *artwork_current_identifier;
5851 char *artwork_new_identifier = NULL; // default: nothing has changed
5853 // leveldir_current may be invalid (level group, parent link)
5854 if (!validLevelSeries(leveldir_current))
5857 /* 1st step: determine artwork set to be activated in descending order:
5858 --------------------------------------------------------------------
5859 1. setup artwork (when configured to override everything else)
5860 2. artwork set configured in "levelinfo.conf" of current level set
5861 (artwork in level directory will have priority when loading later)
5862 3. artwork in level directory (stored in artwork sub-directory)
5863 4. setup artwork (currently configured in setup menu) */
5865 if (setup_override_artwork)
5866 artwork_current_identifier = setup_artwork_set;
5867 else if (leveldir_artwork_set != NULL)
5868 artwork_current_identifier = leveldir_artwork_set;
5869 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5870 artwork_current_identifier = leveldir_identifier;
5872 artwork_current_identifier = setup_artwork_set;
5875 /* 2nd step: check if it is really needed to reload artwork set
5876 ------------------------------------------------------------ */
5878 // ---------- reload if level set and also artwork set has changed ----------
5879 if (leveldir_current_identifier[type] != leveldir_identifier &&
5880 (last_has_level_artwork_set[type] || has_level_artwork_set))
5881 artwork_new_identifier = artwork_current_identifier;
5883 leveldir_current_identifier[type] = leveldir_identifier;
5884 last_has_level_artwork_set[type] = has_level_artwork_set;
5886 // ---------- reload if "override artwork" setting has changed --------------
5887 if (last_override_level_artwork[type] != setup_override_artwork)
5888 artwork_new_identifier = artwork_current_identifier;
5890 last_override_level_artwork[type] = setup_override_artwork;
5892 // ---------- reload if current artwork identifier has changed --------------
5893 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5894 artwork_current_identifier))
5895 artwork_new_identifier = artwork_current_identifier;
5897 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5899 // ---------- do not reload directly after starting -------------------------
5900 if (!initialized[type])
5901 artwork_new_identifier = NULL;
5903 initialized[type] = TRUE;
5905 return artwork_new_identifier;
5908 void ReloadCustomArtwork(int force_reload)
5910 int last_game_status = game_status; // save current game status
5911 char *gfx_new_identifier;
5912 char *snd_new_identifier;
5913 char *mus_new_identifier;
5914 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5915 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5916 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5917 boolean reload_needed;
5919 InitOverrideArtwork();
5921 force_reload_gfx |= AdjustGraphicsForEMC();
5923 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5924 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5925 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5927 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5928 snd_new_identifier != NULL || force_reload_snd ||
5929 mus_new_identifier != NULL || force_reload_mus);
5934 print_timestamp_init("ReloadCustomArtwork");
5936 SetGameStatus(GAME_MODE_LOADING);
5938 FadeOut(REDRAW_ALL);
5940 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5941 print_timestamp_time("ClearRectangle");
5945 if (gfx_new_identifier != NULL || force_reload_gfx)
5948 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5949 artwork.gfx_current_identifier,
5951 artwork.gfx_current->identifier,
5952 leveldir_current->graphics_set);
5956 print_timestamp_time("InitImages");
5959 if (snd_new_identifier != NULL || force_reload_snd)
5961 InitSound(snd_new_identifier);
5962 print_timestamp_time("InitSound");
5965 if (mus_new_identifier != NULL || force_reload_mus)
5967 InitMusic(mus_new_identifier);
5968 print_timestamp_time("InitMusic");
5973 SetGameStatus(last_game_status); // restore current game status
5975 init_last = init; // switch to new busy animation
5977 FadeOut(REDRAW_ALL);
5979 RedrawGlobalBorder();
5981 // force redraw of (open or closed) door graphics
5982 SetDoorState(DOOR_OPEN_ALL);
5983 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5985 FadeSetEnterScreen();
5986 FadeSkipNextFadeOut();
5988 print_timestamp_done("ReloadCustomArtwork");
5990 LimitScreenUpdates(FALSE);
5993 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5995 if (global.autoplay_leveldir == NULL)
5996 KeyboardAutoRepeatOff();
5999 void DisplayExitMessage(char *format, va_list ap)
6001 // also check for initialized video (headless flag may be temporarily unset)
6002 if (program.headless || !video.initialized)
6005 // check if draw buffer and fonts for exit message are already available
6006 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6009 int font_1 = FC_RED;
6010 int font_2 = FC_YELLOW;
6011 int font_3 = FC_BLUE;
6012 int font_width = getFontWidth(font_2);
6013 int font_height = getFontHeight(font_2);
6016 int sxsize = WIN_XSIZE - 2 * sx;
6017 int sysize = WIN_YSIZE - 2 * sy;
6018 int line_length = sxsize / font_width;
6019 int max_lines = sysize / font_height;
6020 int num_lines_printed;
6024 gfx.sxsize = sxsize;
6025 gfx.sysize = sysize;
6029 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6031 DrawTextSCentered(sy, font_1, "Fatal error:");
6032 sy += 3 * font_height;;
6035 DrawTextBufferVA(sx, sy, format, ap, font_2,
6036 line_length, line_length, max_lines,
6037 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6038 sy += (num_lines_printed + 3) * font_height;
6040 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6041 sy += 3 * font_height;
6044 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6045 line_length, line_length, max_lines,
6046 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6048 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6050 redraw_mask = REDRAW_ALL;
6052 // force drawing exit message even if screen updates are currently limited
6053 LimitScreenUpdates(FALSE);
6057 // deactivate toons on error message screen
6058 setup.toons = FALSE;
6060 WaitForEventToContinue();
6064 // ============================================================================
6066 // ============================================================================
6070 print_timestamp_init("OpenAll");
6072 SetGameStatus(GAME_MODE_LOADING);
6076 InitGlobal(); // initialize some global variables
6078 print_timestamp_time("[init global stuff]");
6082 print_timestamp_time("[init setup/config stuff (1)]");
6086 if (options.execute_command)
6087 Execute_Command(options.execute_command);
6089 InitNetworkSettings();
6093 if (network.serveronly)
6095 #if defined(PLATFORM_UNIX)
6096 NetworkServer(network.server_port, TRUE);
6098 Error(ERR_WARN, "networking only supported in Unix version");
6101 exit(0); // never reached, server loops forever
6105 print_timestamp_time("[init setup/config stuff (2)]");
6107 print_timestamp_time("[init setup/config stuff (3)]");
6108 InitArtworkInfo(); // needed before loading gfx, sound & music
6109 print_timestamp_time("[init setup/config stuff (4)]");
6110 InitArtworkConfig(); // needed before forking sound child process
6111 print_timestamp_time("[init setup/config stuff (5)]");
6113 print_timestamp_time("[init setup/config stuff (6)]");
6115 InitRND(NEW_RANDOMIZE);
6116 InitSimpleRandom(NEW_RANDOMIZE);
6120 print_timestamp_time("[init setup/config stuff]");
6122 InitVideoDefaults();
6124 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6127 InitEventFilter(FilterMouseMotionEvents);
6129 print_timestamp_time("[init video stuff]");
6131 InitElementPropertiesStatic();
6132 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6133 InitElementPropertiesGfxElement();
6135 print_timestamp_time("[init element properties stuff]");
6139 print_timestamp_time("InitGfx");
6142 print_timestamp_time("InitLevelInfo");
6144 InitLevelArtworkInfo();
6145 print_timestamp_time("InitLevelArtworkInfo");
6147 InitOverrideArtwork(); // needs to know current level directory
6148 print_timestamp_time("InitOverrideArtwork");
6150 InitImages(); // needs to know current level directory
6151 print_timestamp_time("InitImages");
6153 InitSound(NULL); // needs to know current level directory
6154 print_timestamp_time("InitSound");
6156 InitMusic(NULL); // needs to know current level directory
6157 print_timestamp_time("InitMusic");
6161 InitGfxBackground();
6167 if (global.autoplay_leveldir)
6172 else if (global.convert_leveldir)
6177 else if (global.create_images_dir)
6179 CreateLevelSketchImages();
6183 InitNetworkServer();
6185 SetGameStatus(GAME_MODE_MAIN);
6187 FadeSetEnterScreen();
6188 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6189 FadeSkipNextFadeOut();
6191 print_timestamp_time("[post-artwork]");
6193 print_timestamp_done("OpenAll");
6198 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6200 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6201 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6202 #if defined(PLATFORM_ANDROID)
6203 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6204 SDL_AndroidGetInternalStoragePath());
6205 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6206 SDL_AndroidGetExternalStoragePath());
6207 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6208 (SDL_AndroidGetExternalStorageState() &
6209 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6210 SDL_AndroidGetExternalStorageState() &
6211 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6216 void CloseAllAndExit(int exit_value)
6221 CloseAudio(); // called after freeing sounds (needed for SDL)
6229 // set a flag to tell the network server thread to quit and wait for it
6230 // using SDL_WaitThread()
6232 // Code used with SDL 1.2:
6233 // if (network_server) // terminate network server
6234 // SDL_KillThread(server_thread);
6236 CloseVideoDisplay();
6237 ClosePlatformDependentStuff();
6239 if (exit_value != 0 && !options.execute_command)
6241 // fall back to default level set (current set may have caused an error)
6242 SaveLevelSetup_LastSeries_Deactivate();
6244 // tell user where to find error log file which may contain more details
6245 // (error notification now directly displayed on screen inside R'n'D
6246 // NotifyUserAboutErrorFile(); // currently only works for Windows