1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
38 #define CONFIG_TOKEN_BACKGROUND_LOADING "background.LOADING"
40 #define INITIAL_IMG_GLOBAL_BUSY 0
41 #define INITIAL_IMG_BACKGROUND_LOADING 1
43 #define NUM_INITIAL_IMAGES 2
46 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
47 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
49 static int copy_properties[][5] =
53 EL_BUG_LEFT, EL_BUG_RIGHT,
54 EL_BUG_UP, EL_BUG_DOWN
58 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
59 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
63 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
64 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
68 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
69 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
73 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
74 EL_PACMAN_UP, EL_PACMAN_DOWN
78 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
79 EL_YAMYAM_UP, EL_YAMYAM_DOWN
83 EL_MOLE_LEFT, EL_MOLE_RIGHT,
84 EL_MOLE_UP, EL_MOLE_DOWN
88 EL_SPRING_LEFT, EL_SPRING_RIGHT,
89 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
98 // forward declaration for internal use
99 static int get_graphic_parameter_value(char *, char *, int);
102 static void SetLoadingBackgroundImage(void)
104 struct GraphicInfo *graphic_info_last = graphic_info;
106 graphic_info = image_initial;
108 SetDrawDeactivationMask(REDRAW_NONE);
109 SetDrawBackgroundMask(REDRAW_ALL);
111 SetWindowBackgroundImage(INITIAL_IMG_BACKGROUND_LOADING);
113 graphic_info = graphic_info_last;
116 static void DrawInitAnim(void)
118 struct GraphicInfo *graphic_info_last = graphic_info;
120 static unsigned int action_delay = 0;
121 unsigned int action_delay_value = GameFrameDelay;
122 int sync_frame = FrameCounter;
125 // prevent OS (Windows) from complaining about program not responding
128 if (game_status != GAME_MODE_LOADING)
131 if (image_initial[INITIAL_IMG_GLOBAL_BUSY].bitmap == NULL || window == NULL)
134 if (!DelayReached(&action_delay, action_delay_value))
137 if (init_last.busy.x == -1)
138 init_last.busy.x = WIN_XSIZE / 2;
139 if (init_last.busy.y == -1)
140 init_last.busy.y = WIN_YSIZE / 2;
142 x = ALIGNED_TEXT_XPOS(&init_last.busy);
143 y = ALIGNED_TEXT_YPOS(&init_last.busy);
145 graphic_info = image_initial; // graphic == 0 => image_initial
147 if (sync_frame % image_initial[INITIAL_IMG_GLOBAL_BUSY].anim_delay == 0)
151 int width = graphic_info[graphic].width;
152 int height = graphic_info[graphic].height;
153 int frame = getGraphicAnimationFrame(graphic, sync_frame);
155 ClearRectangleOnBackground(drawto, x, y, width, height);
157 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
158 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
160 BlitBitmap(drawto, window, x, y, width, height, x, y);
163 graphic_info = graphic_info_last;
168 static void DrawProgramInfo(void)
170 int font1_nr = FC_YELLOW;
171 int font2_nr = FC_RED;
172 int font2_height = getFontHeight(font2_nr);
175 int ypos3 = WIN_YSIZE - 20 - font2_height;
177 DrawInitText(getProgramInitString(), ypos1, font1_nr);
178 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
179 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
182 static void FreeGadgets(void)
184 FreeLevelEditorGadgets();
191 void InitGadgets(void)
193 static boolean gadgets_initialized = FALSE;
195 if (gadgets_initialized)
198 CreateLevelEditorGadgets();
202 CreateScreenGadgets();
204 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
206 gadgets_initialized = TRUE;
209 static void InitElementSmallImagesScaledUp(int graphic)
211 struct GraphicInfo *g = &graphic_info[graphic];
213 // create small and game tile sized bitmaps (and scale up, if needed)
214 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
217 static void InitElementSmallImages(void)
219 print_timestamp_init("InitElementSmallImages");
221 static int special_graphics[] =
235 IMG_EDITOR_ELEMENT_BORDER,
236 IMG_EDITOR_ELEMENT_BORDER_INPUT,
237 IMG_EDITOR_CASCADE_LIST,
238 IMG_EDITOR_CASCADE_LIST_ACTIVE,
241 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
242 int num_property_mappings = getImageListPropertyMappingSize();
245 print_timestamp_time("getImageListPropertyMapping/Size");
247 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
248 // initialize normal element images from static configuration
249 for (i = 0; element_to_graphic[i].element > -1; i++)
250 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
251 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
253 // initialize special element images from static configuration
254 for (i = 0; element_to_special_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
256 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
258 // initialize element images from dynamic configuration
259 for (i = 0; i < num_property_mappings; i++)
260 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
261 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
262 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
264 // initialize special non-element images from above list
265 for (i = 0; special_graphics[i] > -1; i++)
266 InitElementSmallImagesScaledUp(special_graphics[i]);
267 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
269 print_timestamp_done("InitElementSmallImages");
272 static void InitScaledImagesScaledUp(int graphic)
274 struct GraphicInfo *g = &graphic_info[graphic];
276 ScaleImage(graphic, g->scale_up_factor);
279 static void InitScaledImages(void)
281 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
282 int num_property_mappings = getImageListPropertyMappingSize();
285 // scale normal images from static configuration, if not already scaled
286 for (i = 0; i < NUM_IMAGE_FILES; i++)
287 InitScaledImagesScaledUp(i);
289 // scale images from dynamic configuration, if not already scaled
290 for (i = 0; i < num_property_mappings; i++)
291 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
294 static void InitBitmapPointers(void)
296 int num_images = getImageListSize();
299 // standard size bitmap may have changed -- update default bitmap pointer
300 for (i = 0; i < num_images; i++)
301 if (graphic_info[i].bitmaps)
302 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
305 void InitImageTextures(void)
307 static int texture_graphics[] =
309 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
310 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
311 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
312 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
313 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
314 IMG_MENU_BUTTON_TOUCH_BACK,
315 IMG_MENU_BUTTON_TOUCH_NEXT,
316 IMG_MENU_BUTTON_TOUCH_BACK2,
317 IMG_MENU_BUTTON_TOUCH_NEXT2,
322 FreeAllImageTextures();
324 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
325 CreateImageTextures(i);
327 for (i = 0; i < MAX_NUM_TOONS; i++)
328 CreateImageTextures(IMG_TOON_1 + i);
330 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
332 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
334 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
336 int graphic = global_anim_info[i].graphic[j][k];
338 if (graphic == IMG_UNDEFINED)
341 CreateImageTextures(graphic);
346 for (i = 0; texture_graphics[i] > -1; i++)
347 CreateImageTextures(texture_graphics[i]);
350 static int getFontBitmapID(int font_nr)
354 // (special case: do not use special font for GAME_MODE_LOADING)
355 if (game_status >= GAME_MODE_TITLE_INITIAL &&
356 game_status <= GAME_MODE_PSEUDO_PREVIEW)
357 special = game_status;
358 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
359 special = GFX_SPECIAL_ARG_MAIN;
360 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
361 special = GFX_SPECIAL_ARG_NAMES;
364 return font_info[font_nr].special_bitmap_id[special];
369 static int getFontFromToken(char *token)
371 char *value = getHashEntry(font_token_hash, token);
376 // if font not found, use reliable default value
377 return FONT_INITIAL_1;
380 static void InitFontGraphicInfo(void)
382 static struct FontBitmapInfo *font_bitmap_info = NULL;
383 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
384 int num_property_mappings = getImageListPropertyMappingSize();
385 int num_font_bitmaps = NUM_FONTS;
388 if (graphic_info == NULL) // still at startup phase
390 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
391 getFontBitmapID, getFontFromToken);
396 // ---------- initialize font graphic definitions ----------
398 // always start with reliable default values (normal font graphics)
399 for (i = 0; i < NUM_FONTS; i++)
400 font_info[i].graphic = IMG_FONT_INITIAL_1;
402 // initialize normal font/graphic mapping from static configuration
403 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
405 int font_nr = font_to_graphic[i].font_nr;
406 int special = font_to_graphic[i].special;
407 int graphic = font_to_graphic[i].graphic;
412 font_info[font_nr].graphic = graphic;
415 // always start with reliable default values (special font graphics)
416 for (i = 0; i < NUM_FONTS; i++)
418 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
420 font_info[i].special_graphic[j] = font_info[i].graphic;
421 font_info[i].special_bitmap_id[j] = i;
425 // initialize special font/graphic mapping from static configuration
426 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
428 int font_nr = font_to_graphic[i].font_nr;
429 int special = font_to_graphic[i].special;
430 int graphic = font_to_graphic[i].graphic;
431 int base_graphic = font2baseimg(font_nr);
433 if (IS_SPECIAL_GFX_ARG(special))
435 boolean base_redefined =
436 getImageListEntryFromImageID(base_graphic)->redefined;
437 boolean special_redefined =
438 getImageListEntryFromImageID(graphic)->redefined;
439 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
441 /* if the base font ("font.title_1", for example) has been redefined,
442 but not the special font ("font.title_1.LEVELS", for example), do not
443 use an existing (in this case considered obsolete) special font
444 anymore, but use the automatically determined default font */
445 /* special case: cloned special fonts must be explicitly redefined,
446 but are not automatically redefined by redefining base font */
447 if (base_redefined && !special_redefined && !special_cloned)
450 font_info[font_nr].special_graphic[special] = graphic;
451 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
456 // initialize special font/graphic mapping from dynamic configuration
457 for (i = 0; i < num_property_mappings; i++)
459 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
460 int special = property_mapping[i].ext3_index;
461 int graphic = property_mapping[i].artwork_index;
463 if (font_nr < 0 || font_nr >= NUM_FONTS)
466 if (IS_SPECIAL_GFX_ARG(special))
468 font_info[font_nr].special_graphic[special] = graphic;
469 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
474 /* correct special font/graphic mapping for cloned fonts for downwards
475 compatibility of PREVIEW fonts -- this is only needed for implicit
476 redefinition of special font by redefined base font, and only if other
477 fonts are cloned from this special font (like in the "Zelda" level set) */
478 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
480 int font_nr = font_to_graphic[i].font_nr;
481 int special = font_to_graphic[i].special;
482 int graphic = font_to_graphic[i].graphic;
484 if (IS_SPECIAL_GFX_ARG(special))
486 boolean special_redefined =
487 getImageListEntryFromImageID(graphic)->redefined;
488 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
490 if (special_cloned && !special_redefined)
494 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
496 int font_nr2 = font_to_graphic[j].font_nr;
497 int special2 = font_to_graphic[j].special;
498 int graphic2 = font_to_graphic[j].graphic;
500 if (IS_SPECIAL_GFX_ARG(special2) &&
501 graphic2 == graphic_info[graphic].clone_from)
503 font_info[font_nr].special_graphic[special] =
504 font_info[font_nr2].special_graphic[special2];
505 font_info[font_nr].special_bitmap_id[special] =
506 font_info[font_nr2].special_bitmap_id[special2];
513 // reset non-redefined ".active" font graphics if normal font is redefined
514 // (this different treatment is needed because normal and active fonts are
515 // independently defined ("active" is not a property of font definitions!)
516 for (i = 0; i < NUM_FONTS; i++)
518 int font_nr_base = i;
519 int font_nr_active = FONT_ACTIVE(font_nr_base);
521 // check only those fonts with exist as normal and ".active" variant
522 if (font_nr_base != font_nr_active)
524 int base_graphic = font_info[font_nr_base].graphic;
525 int active_graphic = font_info[font_nr_active].graphic;
526 boolean base_redefined =
527 getImageListEntryFromImageID(base_graphic)->redefined;
528 boolean active_redefined =
529 getImageListEntryFromImageID(active_graphic)->redefined;
531 /* if the base font ("font.menu_1", for example) has been redefined,
532 but not the active font ("font.menu_1.active", for example), do not
533 use an existing (in this case considered obsolete) active font
534 anymore, but use the automatically determined default font */
535 if (base_redefined && !active_redefined)
536 font_info[font_nr_active].graphic = base_graphic;
538 // now also check each "special" font (which may be the same as above)
539 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
541 int base_graphic = font_info[font_nr_base].special_graphic[j];
542 int active_graphic = font_info[font_nr_active].special_graphic[j];
543 boolean base_redefined =
544 getImageListEntryFromImageID(base_graphic)->redefined;
545 boolean active_redefined =
546 getImageListEntryFromImageID(active_graphic)->redefined;
548 // same as above, but check special graphic definitions, for example:
549 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
550 if (base_redefined && !active_redefined)
552 font_info[font_nr_active].special_graphic[j] =
553 font_info[font_nr_base].special_graphic[j];
554 font_info[font_nr_active].special_bitmap_id[j] =
555 font_info[font_nr_base].special_bitmap_id[j];
561 // ---------- initialize font bitmap array ----------
563 if (font_bitmap_info != NULL)
564 FreeFontInfo(font_bitmap_info);
567 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
569 // ---------- initialize font bitmap definitions ----------
571 for (i = 0; i < NUM_FONTS; i++)
573 if (i < NUM_INITIAL_FONTS)
575 font_bitmap_info[i] = font_initial[i];
579 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
581 int font_bitmap_id = font_info[i].special_bitmap_id[j];
582 int graphic = font_info[i].special_graphic[j];
584 // set 'graphic_info' for font entries, if uninitialized (guessed)
585 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
587 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
588 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
591 // copy font relevant information from graphics information
592 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
593 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
594 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
595 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
596 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
598 font_bitmap_info[font_bitmap_id].offset_x =
599 graphic_info[graphic].offset_x;
600 font_bitmap_info[font_bitmap_id].offset_y =
601 graphic_info[graphic].offset_y;
603 font_bitmap_info[font_bitmap_id].draw_xoffset =
604 graphic_info[graphic].draw_xoffset;
605 font_bitmap_info[font_bitmap_id].draw_yoffset =
606 graphic_info[graphic].draw_yoffset;
608 font_bitmap_info[font_bitmap_id].num_chars =
609 graphic_info[graphic].anim_frames;
610 font_bitmap_info[font_bitmap_id].num_chars_per_line =
611 graphic_info[graphic].anim_frames_per_line;
615 InitFontInfo(font_bitmap_info, num_font_bitmaps,
616 getFontBitmapID, getFontFromToken);
619 static void InitGlobalAnimGraphicInfo(void)
621 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
622 int num_property_mappings = getImageListPropertyMappingSize();
625 if (graphic_info == NULL) // still at startup phase
628 // always start with reliable default values (no global animations)
629 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
630 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
631 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
632 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
634 // initialize global animation definitions from static configuration
635 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
637 int j = GLOBAL_ANIM_ID_PART_BASE;
638 int k = GFX_SPECIAL_ARG_DEFAULT;
640 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
643 // initialize global animation definitions from dynamic configuration
644 for (i = 0; i < num_property_mappings; i++)
646 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
647 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
648 int special = property_mapping[i].ext3_index;
649 int graphic = property_mapping[i].artwork_index;
651 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
654 // set animation part to base part, if not specified
655 if (!IS_GLOBAL_ANIM_PART(part_nr))
656 part_nr = GLOBAL_ANIM_ID_PART_BASE;
658 // set animation screen to default, if not specified
659 if (!IS_SPECIAL_GFX_ARG(special))
660 special = GFX_SPECIAL_ARG_DEFAULT;
662 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
664 // fix default value for ".draw_masked" (for backward compatibility)
665 struct GraphicInfo *g = &graphic_info[graphic];
666 struct FileInfo *image = getImageListEntryFromImageID(graphic);
667 char **parameter_raw = image->parameter;
668 int p = GFX_ARG_DRAW_MASKED;
669 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
670 image_config_suffix[p].token,
671 image_config_suffix[p].type);
673 // if ".draw_masked" parameter is undefined, use default value "TRUE"
674 if (draw_masked == ARG_UNDEFINED_VALUE)
675 g->draw_masked = TRUE;
679 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
680 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
681 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
682 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
683 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
684 Debug("init:InitGlobalAnimGraphicInfo",
685 "anim %d, part %d, mode %d => %d",
686 i, j, k, global_anim_info[i].graphic[j][k]);
690 static void InitGlobalAnimSoundInfo(void)
692 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
693 int num_property_mappings = getSoundListPropertyMappingSize();
696 // always start with reliable default values (no global animation sounds)
697 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
698 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
699 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
700 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
702 // initialize global animation sound definitions from dynamic configuration
703 for (i = 0; i < num_property_mappings; i++)
705 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
706 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
707 int special = property_mapping[i].ext3_index;
708 int sound = property_mapping[i].artwork_index;
710 // sound uses control definition; map it to position of graphic (artwork)
711 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
713 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
716 // set animation part to base part, if not specified
717 if (!IS_GLOBAL_ANIM_PART(part_nr))
718 part_nr = GLOBAL_ANIM_ID_PART_BASE;
720 // set animation screen to default, if not specified
721 if (!IS_SPECIAL_GFX_ARG(special))
722 special = GFX_SPECIAL_ARG_DEFAULT;
724 global_anim_info[anim_nr].sound[part_nr][special] = sound;
728 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
729 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
730 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
731 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
732 Debug("init:InitGlobalAnimSoundInfo",
733 "anim %d, part %d, mode %d => %d",
734 i, j, k, global_anim_info[i].sound[j][k]);
738 static void InitGlobalAnimMusicInfo(void)
740 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
741 int num_property_mappings = getMusicListPropertyMappingSize();
744 // always start with reliable default values (no global animation music)
745 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
746 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
747 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
748 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
750 // initialize global animation music definitions from dynamic configuration
751 for (i = 0; i < num_property_mappings; i++)
753 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
754 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
755 int special = property_mapping[i].ext2_index;
756 int music = property_mapping[i].artwork_index;
758 // music uses control definition; map it to position of graphic (artwork)
759 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
761 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
764 // set animation part to base part, if not specified
765 if (!IS_GLOBAL_ANIM_PART(part_nr))
766 part_nr = GLOBAL_ANIM_ID_PART_BASE;
768 // set animation screen to default, if not specified
769 if (!IS_SPECIAL_GFX_ARG(special))
770 special = GFX_SPECIAL_ARG_DEFAULT;
772 global_anim_info[anim_nr].music[part_nr][special] = music;
776 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
777 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
778 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
779 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
780 Debug("init:InitGlobalAnimMusicInfo",
781 "anim %d, part %d, mode %d => %d",
782 i, j, k, global_anim_info[i].music[j][k]);
786 static void InitElementGraphicInfo(void)
788 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
789 int num_property_mappings = getImageListPropertyMappingSize();
792 if (graphic_info == NULL) // still at startup phase
795 // set values to -1 to identify later as "uninitialized" values
796 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
798 for (act = 0; act < NUM_ACTIONS; act++)
800 element_info[i].graphic[act] = -1;
801 element_info[i].crumbled[act] = -1;
803 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
805 element_info[i].direction_graphic[act][dir] = -1;
806 element_info[i].direction_crumbled[act][dir] = -1;
813 // initialize normal element/graphic mapping from static configuration
814 for (i = 0; element_to_graphic[i].element > -1; i++)
816 int element = element_to_graphic[i].element;
817 int action = element_to_graphic[i].action;
818 int direction = element_to_graphic[i].direction;
819 boolean crumbled = element_to_graphic[i].crumbled;
820 int graphic = element_to_graphic[i].graphic;
821 int base_graphic = el2baseimg(element);
823 if (graphic_info[graphic].bitmap == NULL)
826 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
829 boolean base_redefined =
830 getImageListEntryFromImageID(base_graphic)->redefined;
831 boolean act_dir_redefined =
832 getImageListEntryFromImageID(graphic)->redefined;
834 /* if the base graphic ("emerald", for example) has been redefined,
835 but not the action graphic ("emerald.falling", for example), do not
836 use an existing (in this case considered obsolete) action graphic
837 anymore, but use the automatically determined default graphic */
838 if (base_redefined && !act_dir_redefined)
843 action = ACTION_DEFAULT;
848 element_info[element].direction_crumbled[action][direction] = graphic;
850 element_info[element].crumbled[action] = graphic;
855 element_info[element].direction_graphic[action][direction] = graphic;
857 element_info[element].graphic[action] = graphic;
861 // initialize normal element/graphic mapping from dynamic configuration
862 for (i = 0; i < num_property_mappings; i++)
864 int element = property_mapping[i].base_index;
865 int action = property_mapping[i].ext1_index;
866 int direction = property_mapping[i].ext2_index;
867 int special = property_mapping[i].ext3_index;
868 int graphic = property_mapping[i].artwork_index;
869 boolean crumbled = FALSE;
871 if (special == GFX_SPECIAL_ARG_CRUMBLED)
877 if (graphic_info[graphic].bitmap == NULL)
880 if (element >= MAX_NUM_ELEMENTS || special != -1)
884 action = ACTION_DEFAULT;
889 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
890 element_info[element].direction_crumbled[action][dir] = -1;
893 element_info[element].direction_crumbled[action][direction] = graphic;
895 element_info[element].crumbled[action] = graphic;
900 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
901 element_info[element].direction_graphic[action][dir] = -1;
904 element_info[element].direction_graphic[action][direction] = graphic;
906 element_info[element].graphic[action] = graphic;
910 // now copy all graphics that are defined to be cloned from other graphics
911 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
913 int graphic = element_info[i].graphic[ACTION_DEFAULT];
914 int crumbled_like, diggable_like;
919 crumbled_like = graphic_info[graphic].crumbled_like;
920 diggable_like = graphic_info[graphic].diggable_like;
922 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
924 for (act = 0; act < NUM_ACTIONS; act++)
925 element_info[i].crumbled[act] =
926 element_info[crumbled_like].crumbled[act];
927 for (act = 0; act < NUM_ACTIONS; act++)
928 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
929 element_info[i].direction_crumbled[act][dir] =
930 element_info[crumbled_like].direction_crumbled[act][dir];
933 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
935 element_info[i].graphic[ACTION_DIGGING] =
936 element_info[diggable_like].graphic[ACTION_DIGGING];
937 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
938 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
939 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
943 // set hardcoded definitions for some runtime elements without graphic
944 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
946 // set hardcoded definitions for some internal elements without graphic
947 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
949 if (IS_EDITOR_CASCADE_INACTIVE(i))
950 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
951 else if (IS_EDITOR_CASCADE_ACTIVE(i))
952 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
955 // now set all undefined/invalid graphics to -1 to set to default after it
956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
958 for (act = 0; act < NUM_ACTIONS; act++)
962 graphic = element_info[i].graphic[act];
963 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
964 element_info[i].graphic[act] = -1;
966 graphic = element_info[i].crumbled[act];
967 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
968 element_info[i].crumbled[act] = -1;
970 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
972 graphic = element_info[i].direction_graphic[act][dir];
973 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
974 element_info[i].direction_graphic[act][dir] = -1;
976 graphic = element_info[i].direction_crumbled[act][dir];
977 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
978 element_info[i].direction_crumbled[act][dir] = -1;
985 // adjust graphics with 2nd tile for movement according to direction
986 // (do this before correcting '-1' values to minimize calculations)
987 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
989 for (act = 0; act < NUM_ACTIONS; act++)
991 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
993 int graphic = element_info[i].direction_graphic[act][dir];
994 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
996 if (act == ACTION_FALLING) // special case
997 graphic = element_info[i].graphic[act];
1000 graphic_info[graphic].double_movement &&
1001 graphic_info[graphic].swap_double_tiles != 0)
1003 struct GraphicInfo *g = &graphic_info[graphic];
1004 int src_x_front = g->src_x;
1005 int src_y_front = g->src_y;
1006 int src_x_back = g->src_x + g->offset2_x;
1007 int src_y_back = g->src_y + g->offset2_y;
1008 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1010 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1011 src_y_front < src_y_back);
1012 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1013 boolean swap_movement_tiles_autodetected =
1014 (!frames_are_ordered_diagonally &&
1015 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
1016 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
1017 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
1018 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1020 // swap frontside and backside graphic tile coordinates, if needed
1021 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1023 // get current (wrong) backside tile coordinates
1024 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1026 // set frontside tile coordinates to backside tile coordinates
1027 g->src_x = src_x_back;
1028 g->src_y = src_y_back;
1030 // invert tile offset to point to new backside tile coordinates
1034 // do not swap front and backside tiles again after correction
1035 g->swap_double_tiles = 0;
1042 UPDATE_BUSY_STATE();
1044 // now set all '-1' values to element specific default values
1045 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1047 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1048 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1049 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1050 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1052 if (default_graphic == -1)
1053 default_graphic = IMG_UNKNOWN;
1055 if (default_crumbled == -1)
1056 default_crumbled = default_graphic;
1058 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1060 default_direction_graphic[dir] =
1061 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1062 default_direction_crumbled[dir] =
1063 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1065 if (default_direction_graphic[dir] == -1)
1066 default_direction_graphic[dir] = default_graphic;
1068 if (default_direction_crumbled[dir] == -1)
1069 default_direction_crumbled[dir] = default_direction_graphic[dir];
1072 for (act = 0; act < NUM_ACTIONS; act++)
1074 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1075 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1076 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1077 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1078 act == ACTION_TURNING_FROM_RIGHT ||
1079 act == ACTION_TURNING_FROM_UP ||
1080 act == ACTION_TURNING_FROM_DOWN);
1082 // generic default action graphic (defined by "[default]" directive)
1083 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1084 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1085 int default_remove_graphic = IMG_EMPTY;
1087 if (act_remove && default_action_graphic != -1)
1088 default_remove_graphic = default_action_graphic;
1090 // look for special default action graphic (classic game specific)
1091 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1092 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1093 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1094 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1095 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1096 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1097 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1098 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1100 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1101 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1102 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1103 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1104 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1105 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1106 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1107 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1109 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1110 // !!! make this better !!!
1111 if (i == EL_EMPTY_SPACE)
1113 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1114 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1117 if (default_action_graphic == -1)
1118 default_action_graphic = default_graphic;
1120 if (default_action_crumbled == -1)
1121 default_action_crumbled = default_action_graphic;
1123 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1125 // use action graphic as the default direction graphic, if undefined
1126 int default_action_direction_graphic = element_info[i].graphic[act];
1127 int default_action_direction_crumbled = element_info[i].crumbled[act];
1129 // no graphic for current action -- use default direction graphic
1130 if (default_action_direction_graphic == -1)
1131 default_action_direction_graphic =
1132 (act_remove ? default_remove_graphic :
1134 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1135 default_action_graphic != default_graphic ?
1136 default_action_graphic :
1137 default_direction_graphic[dir]);
1139 if (element_info[i].direction_graphic[act][dir] == -1)
1140 element_info[i].direction_graphic[act][dir] =
1141 default_action_direction_graphic;
1143 if (default_action_direction_crumbled == -1)
1144 default_action_direction_crumbled =
1145 element_info[i].direction_graphic[act][dir];
1147 if (element_info[i].direction_crumbled[act][dir] == -1)
1148 element_info[i].direction_crumbled[act][dir] =
1149 default_action_direction_crumbled;
1152 // no graphic for this specific action -- use default action graphic
1153 if (element_info[i].graphic[act] == -1)
1154 element_info[i].graphic[act] =
1155 (act_remove ? default_remove_graphic :
1156 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1157 default_action_graphic);
1159 if (element_info[i].crumbled[act] == -1)
1160 element_info[i].crumbled[act] = element_info[i].graphic[act];
1164 UPDATE_BUSY_STATE();
1167 static void InitElementSpecialGraphicInfo(void)
1169 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1170 int num_property_mappings = getImageListPropertyMappingSize();
1173 // always start with reliable default values
1174 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1175 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1176 element_info[i].special_graphic[j] =
1177 element_info[i].graphic[ACTION_DEFAULT];
1179 // initialize special element/graphic mapping from static configuration
1180 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1182 int element = element_to_special_graphic[i].element;
1183 int special = element_to_special_graphic[i].special;
1184 int graphic = element_to_special_graphic[i].graphic;
1185 int base_graphic = el2baseimg(element);
1186 boolean base_redefined =
1187 getImageListEntryFromImageID(base_graphic)->redefined;
1188 boolean special_redefined =
1189 getImageListEntryFromImageID(graphic)->redefined;
1191 /* if the base graphic ("emerald", for example) has been redefined,
1192 but not the special graphic ("emerald.EDITOR", for example), do not
1193 use an existing (in this case considered obsolete) special graphic
1194 anymore, but use the automatically created (down-scaled) graphic */
1195 if (base_redefined && !special_redefined)
1198 element_info[element].special_graphic[special] = graphic;
1201 // initialize special element/graphic mapping from dynamic configuration
1202 for (i = 0; i < num_property_mappings; i++)
1204 int element = property_mapping[i].base_index;
1205 int action = property_mapping[i].ext1_index;
1206 int direction = property_mapping[i].ext2_index;
1207 int special = property_mapping[i].ext3_index;
1208 int graphic = property_mapping[i].artwork_index;
1210 // for action ".active", replace element with active element, if exists
1211 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1213 element = ELEMENT_ACTIVE(element);
1217 if (element >= MAX_NUM_ELEMENTS)
1220 // do not change special graphic if action or direction was specified
1221 if (action != -1 || direction != -1)
1224 if (IS_SPECIAL_GFX_ARG(special))
1225 element_info[element].special_graphic[special] = graphic;
1228 // now set all undefined/invalid graphics to default
1229 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1230 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1231 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1232 element_info[i].special_graphic[j] =
1233 element_info[i].graphic[ACTION_DEFAULT];
1236 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1238 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1239 return get_parameter_value(value_raw, suffix, type);
1241 if (strEqual(value_raw, ARG_UNDEFINED))
1242 return ARG_UNDEFINED_VALUE;
1244 if (type == TYPE_ELEMENT)
1246 char *value = getHashEntry(element_token_hash, value_raw);
1251 Warn("error found in config file:");
1252 Warn("- config file: '%s'", getImageConfigFilename());
1253 Warn("error: invalid element token '%s'", value_raw);
1254 Warn("custom graphic rejected for this element/action");
1255 Warn("fallback done to undefined element for this graphic");
1259 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1261 else if (type == TYPE_GRAPHIC)
1263 char *value = getHashEntry(graphic_token_hash, value_raw);
1264 int fallback_graphic = IMG_CHAR_EXCLAM;
1269 Warn("error found in config file:");
1270 Warn("- config file: '%s'", getImageConfigFilename());
1271 Warn("error: invalid graphic token '%s'", value_raw);
1272 Warn("custom graphic rejected for this element/action");
1273 Warn("fallback done to 'char_exclam' for this graphic");
1277 return (value != NULL ? atoi(value) : fallback_graphic);
1283 static int get_scaled_graphic_width(int graphic)
1285 int original_width = getOriginalImageWidthFromImageID(graphic);
1286 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1288 return original_width * scale_up_factor;
1291 static int get_scaled_graphic_height(int graphic)
1293 int original_height = getOriginalImageHeightFromImageID(graphic);
1294 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1296 return original_height * scale_up_factor;
1299 static void set_graphic_parameters_ext(int graphic, int *parameter,
1300 Bitmap **src_bitmaps)
1302 struct GraphicInfo *g = &graphic_info[graphic];
1303 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1304 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1305 int anim_frames_per_line = 1;
1307 // always start with reliable default values
1308 g->src_image_width = 0;
1309 g->src_image_height = 0;
1312 g->width = TILEX; // default for element graphics
1313 g->height = TILEY; // default for element graphics
1314 g->offset_x = 0; // one or both of these values ...
1315 g->offset_y = 0; // ... will be corrected later
1316 g->offset2_x = 0; // one or both of these values ...
1317 g->offset2_y = 0; // ... will be corrected later
1318 g->swap_double_tiles = -1; // auto-detect tile swapping
1319 g->crumbled_like = -1; // do not use clone element
1320 g->diggable_like = -1; // do not use clone element
1321 g->border_size = TILEX / 8; // "CRUMBLED" border size
1322 g->scale_up_factor = 1; // default: no scaling up
1323 g->tile_size = TILESIZE; // default: standard tile size
1324 g->clone_from = -1; // do not use clone graphic
1325 g->init_delay_fixed = 0;
1326 g->init_delay_random = 0;
1327 g->init_delay_action = -1;
1328 g->anim_delay_fixed = 0;
1329 g->anim_delay_random = 0;
1330 g->anim_delay_action = -1;
1331 g->post_delay_fixed = 0;
1332 g->post_delay_random = 0;
1333 g->post_delay_action = -1;
1334 g->init_event = ANIM_EVENT_UNDEFINED;
1335 g->anim_event = ANIM_EVENT_UNDEFINED;
1336 g->init_event_action = -1;
1337 g->anim_event_action = -1;
1338 g->draw_masked = FALSE;
1340 g->fade_mode = FADE_MODE_DEFAULT;
1344 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1345 g->align = ALIGN_CENTER; // default for title screens
1346 g->valign = VALIGN_MIDDLE; // default for title screens
1347 g->sort_priority = 0; // default for title screens
1349 g->style = STYLE_DEFAULT;
1351 g->bitmaps = src_bitmaps;
1352 g->bitmap = src_bitmap;
1354 // optional zoom factor for scaling up the image to a larger size
1355 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1356 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1357 if (g->scale_up_factor < 1)
1358 g->scale_up_factor = 1; // no scaling
1360 // optional tile size for using non-standard image size
1361 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1363 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1366 // CHECK: should tile sizes less than standard tile size be allowed?
1367 if (g->tile_size < TILESIZE)
1368 g->tile_size = TILESIZE; // standard tile size
1371 // when setting tile size, also set width and height accordingly
1372 g->width = g->tile_size;
1373 g->height = g->tile_size;
1376 if (g->use_image_size)
1378 // set new default bitmap size (with scaling, but without small images)
1379 g->width = get_scaled_graphic_width(graphic);
1380 g->height = get_scaled_graphic_height(graphic);
1383 // optional width and height of each animation frame
1384 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1385 g->width = parameter[GFX_ARG_WIDTH];
1386 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1387 g->height = parameter[GFX_ARG_HEIGHT];
1389 // optional x and y tile position of animation frame sequence
1390 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1391 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1392 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1393 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1395 // optional x and y pixel position of animation frame sequence
1396 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1397 g->src_x = parameter[GFX_ARG_X];
1398 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1399 g->src_y = parameter[GFX_ARG_Y];
1406 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1407 g->width, getTokenFromImageID(graphic), TILEX);
1410 g->width = TILEX; // will be checked to be inside bitmap later
1416 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1417 g->height, getTokenFromImageID(graphic), TILEY);
1420 g->height = TILEY; // will be checked to be inside bitmap later
1426 // get final bitmap size (with scaling, but without small images)
1427 int src_image_width = get_scaled_graphic_width(graphic);
1428 int src_image_height = get_scaled_graphic_height(graphic);
1430 if (src_image_width == 0 || src_image_height == 0)
1432 // only happens when loaded outside artwork system (like "global.busy")
1433 src_image_width = src_bitmap->width;
1434 src_image_height = src_bitmap->height;
1437 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1439 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1440 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1444 anim_frames_per_row = MAX(1, src_image_width / g->width);
1445 anim_frames_per_col = MAX(1, src_image_height / g->height);
1448 g->src_image_width = src_image_width;
1449 g->src_image_height = src_image_height;
1452 // correct x or y offset dependent of vertical or horizontal frame order
1453 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1455 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1456 parameter[GFX_ARG_OFFSET] : g->height);
1457 anim_frames_per_line = anim_frames_per_col;
1459 else // frames are ordered horizontally
1461 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1462 parameter[GFX_ARG_OFFSET] : g->width);
1463 anim_frames_per_line = anim_frames_per_row;
1466 // optionally, the x and y offset of frames can be specified directly
1467 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1468 g->offset_x = parameter[GFX_ARG_XOFFSET];
1469 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1470 g->offset_y = parameter[GFX_ARG_YOFFSET];
1472 // optionally, moving animations may have separate start and end graphics
1473 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1475 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1476 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1478 // correct x or y offset2 dependent of vertical or horizontal frame order
1479 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1480 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1481 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1482 else // frames are ordered horizontally
1483 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1484 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1486 // optionally, the x and y offset of 2nd graphic can be specified directly
1487 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1488 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1489 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1490 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1492 // optionally, the second movement tile can be specified as start tile
1493 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1494 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1496 // automatically determine correct number of frames, if not defined
1497 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1498 g->anim_frames = parameter[GFX_ARG_FRAMES];
1499 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1500 g->anim_frames = anim_frames_per_row;
1501 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1502 g->anim_frames = anim_frames_per_col;
1506 if (g->anim_frames < 1) // frames must be at least 1
1509 g->anim_frames_per_line =
1510 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1511 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1513 g->anim_delay = parameter[GFX_ARG_DELAY];
1514 if (g->anim_delay < 1) // delay must be at least 1
1517 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1519 // automatically determine correct start frame, if not defined
1520 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1521 g->anim_start_frame = 0;
1522 else if (g->anim_mode & ANIM_REVERSE)
1523 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1525 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1527 // animation synchronized with global frame counter, not move position
1528 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1530 // optional element for cloning crumble graphics
1531 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1532 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1534 // optional element for cloning digging graphics
1535 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1536 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1538 // optional border size for "crumbling" diggable graphics
1539 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1540 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1542 // used for global animations and player "boring" and "sleeping" actions
1543 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1544 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1545 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1546 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1547 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1548 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1549 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1550 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1551 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1552 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1553 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1554 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1556 // used for global animations
1557 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1558 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1559 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1560 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1561 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1562 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1563 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1564 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1565 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1566 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1567 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1568 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1569 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1570 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1572 // used for toon animations and global animations
1573 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1574 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1575 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1576 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1577 g->direction = parameter[GFX_ARG_DIRECTION];
1578 g->position = parameter[GFX_ARG_POSITION];
1579 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1580 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1582 if (g->step_delay < 1) // delay must be at least 1
1585 // this is only used for drawing font characters
1586 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1587 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1589 // use a different default value for global animations and toons
1590 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1591 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1592 g->draw_masked = TRUE;
1594 // this is used for drawing envelopes, global animations and toons
1595 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1596 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1598 // used for toon animations and global animations
1599 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1600 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1602 // optional graphic for cloning all graphics settings
1603 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1604 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1606 // optional settings for drawing title screens and title messages
1607 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1608 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1609 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1610 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1611 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1612 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1613 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1614 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1615 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1616 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1617 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1618 g->align = parameter[GFX_ARG_ALIGN];
1619 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1620 g->valign = parameter[GFX_ARG_VALIGN];
1621 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1622 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1624 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1625 g->class = parameter[GFX_ARG_CLASS];
1626 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1627 g->style = parameter[GFX_ARG_STYLE];
1629 // this is only used for drawing menu buttons and text
1630 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1631 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1632 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1633 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1636 static void set_graphic_parameters(int graphic)
1638 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1639 char **parameter_raw = image->parameter;
1640 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1641 int parameter[NUM_GFX_ARGS];
1644 // if fallback to default artwork is done, also use the default parameters
1645 if (image->fallback_to_default)
1646 parameter_raw = image->default_parameter;
1648 // get integer values from string parameters
1649 for (i = 0; i < NUM_GFX_ARGS; i++)
1650 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1651 image_config_suffix[i].token,
1652 image_config_suffix[i].type);
1654 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1656 UPDATE_BUSY_STATE();
1659 static void set_cloned_graphic_parameters(int graphic)
1661 int fallback_graphic = IMG_CHAR_EXCLAM;
1662 int max_num_images = getImageListSize();
1663 int clone_graphic = graphic_info[graphic].clone_from;
1664 int num_references_followed = 1;
1666 while (graphic_info[clone_graphic].clone_from != -1 &&
1667 num_references_followed < max_num_images)
1669 clone_graphic = graphic_info[clone_graphic].clone_from;
1671 num_references_followed++;
1674 if (num_references_followed >= max_num_images)
1677 Warn("error found in config file:");
1678 Warn("- config file: '%s'", getImageConfigFilename());
1679 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1680 Warn("error: loop discovered when resolving cloned graphics");
1681 Warn("custom graphic rejected for this element/action");
1683 if (graphic == fallback_graphic)
1684 Fail("no fallback graphic available");
1686 Warn("fallback done to 'char_exclam' for this graphic");
1689 graphic_info[graphic] = graphic_info[fallback_graphic];
1693 graphic_info[graphic] = graphic_info[clone_graphic];
1694 graphic_info[graphic].clone_from = clone_graphic;
1698 static void InitGraphicInfo(void)
1700 int fallback_graphic = IMG_CHAR_EXCLAM;
1701 int num_images = getImageListSize();
1704 // use image size as default values for width and height for these images
1705 static int full_size_graphics[] =
1708 IMG_GLOBAL_BORDER_MAIN,
1709 IMG_GLOBAL_BORDER_SCORES,
1710 IMG_GLOBAL_BORDER_EDITOR,
1711 IMG_GLOBAL_BORDER_PLAYING,
1714 IMG_BACKGROUND_ENVELOPE_1,
1715 IMG_BACKGROUND_ENVELOPE_2,
1716 IMG_BACKGROUND_ENVELOPE_3,
1717 IMG_BACKGROUND_ENVELOPE_4,
1718 IMG_BACKGROUND_REQUEST,
1721 IMG_BACKGROUND_TITLE_INITIAL,
1722 IMG_BACKGROUND_TITLE,
1723 IMG_BACKGROUND_MAIN,
1724 IMG_BACKGROUND_NAMES,
1725 IMG_BACKGROUND_LEVELS,
1726 IMG_BACKGROUND_LEVELNR,
1727 IMG_BACKGROUND_SCORES,
1728 IMG_BACKGROUND_EDITOR,
1729 IMG_BACKGROUND_INFO,
1730 IMG_BACKGROUND_INFO_ELEMENTS,
1731 IMG_BACKGROUND_INFO_MUSIC,
1732 IMG_BACKGROUND_INFO_CREDITS,
1733 IMG_BACKGROUND_INFO_PROGRAM,
1734 IMG_BACKGROUND_INFO_VERSION,
1735 IMG_BACKGROUND_INFO_LEVELSET,
1736 IMG_BACKGROUND_SETUP,
1737 IMG_BACKGROUND_PLAYING,
1738 IMG_BACKGROUND_DOOR,
1739 IMG_BACKGROUND_TAPE,
1740 IMG_BACKGROUND_PANEL,
1741 IMG_BACKGROUND_PALETTE,
1742 IMG_BACKGROUND_TOOLBOX,
1744 IMG_TITLESCREEN_INITIAL_1,
1745 IMG_TITLESCREEN_INITIAL_2,
1746 IMG_TITLESCREEN_INITIAL_3,
1747 IMG_TITLESCREEN_INITIAL_4,
1748 IMG_TITLESCREEN_INITIAL_5,
1755 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1756 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1757 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1758 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1759 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1760 IMG_BACKGROUND_TITLEMESSAGE_1,
1761 IMG_BACKGROUND_TITLEMESSAGE_2,
1762 IMG_BACKGROUND_TITLEMESSAGE_3,
1763 IMG_BACKGROUND_TITLEMESSAGE_4,
1764 IMG_BACKGROUND_TITLEMESSAGE_5,
1769 FreeGlobalAnimEventInfo();
1771 checked_free(graphic_info);
1773 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1775 // initialize "use_image_size" flag with default value
1776 for (i = 0; i < num_images; i++)
1777 graphic_info[i].use_image_size = FALSE;
1779 // initialize "use_image_size" flag from static configuration above
1780 for (i = 0; full_size_graphics[i] != -1; i++)
1781 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1783 // first set all graphic paramaters ...
1784 for (i = 0; i < num_images; i++)
1785 set_graphic_parameters(i);
1787 // ... then copy these parameters for cloned graphics
1788 for (i = 0; i < num_images; i++)
1789 if (graphic_info[i].clone_from != -1)
1790 set_cloned_graphic_parameters(i);
1792 for (i = 0; i < num_images; i++)
1794 Bitmap *src_bitmap = graphic_info[i].bitmap;
1798 int src_bitmap_width, src_bitmap_height;
1800 // now check if no animation frames are outside of the loaded image
1802 if (graphic_info[i].bitmap == NULL)
1803 continue; // skip check for optional images that are undefined
1805 // get image size (this can differ from the standard element tile size!)
1806 width = graphic_info[i].width;
1807 height = graphic_info[i].height;
1809 // get final bitmap size (with scaling, but without small images)
1810 src_bitmap_width = graphic_info[i].src_image_width;
1811 src_bitmap_height = graphic_info[i].src_image_height;
1813 // check if first animation frame is inside specified bitmap
1815 // do not use getGraphicSourceXY() here to get position of first frame;
1816 // this avoids calculating wrong start position for out-of-bounds frame
1817 src_x = graphic_info[i].src_x;
1818 src_y = graphic_info[i].src_y;
1820 if (program.headless)
1823 if (src_x < 0 || src_y < 0 ||
1824 src_x + width > src_bitmap_width ||
1825 src_y + height > src_bitmap_height)
1828 Warn("error found in config file:");
1829 Warn("- config file: '%s'", getImageConfigFilename());
1830 Warn("- config token: '%s'", getTokenFromImageID(i));
1831 Warn("- image file: '%s'", src_bitmap->source_filename);
1832 Warn("- frame size: %d, %d", width, height);
1833 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1834 src_x, src_y, src_bitmap_width, src_bitmap_height);
1835 Warn("custom graphic rejected for this element/action");
1837 if (i == fallback_graphic)
1838 Fail("no fallback graphic available");
1840 Warn("fallback done to 'char_exclam' for this graphic");
1843 graphic_info[i] = graphic_info[fallback_graphic];
1845 // if first frame out of bounds, do not check last frame anymore
1849 // check if last animation frame is inside specified bitmap
1851 last_frame = graphic_info[i].anim_frames - 1;
1852 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1854 if (src_x < 0 || src_y < 0 ||
1855 src_x + width > src_bitmap_width ||
1856 src_y + height > src_bitmap_height)
1859 Warn("error found in config file:");
1860 Warn("- config file: '%s'", getImageConfigFilename());
1861 Warn("- config token: '%s'", getTokenFromImageID(i));
1862 Warn("- image file: '%s'", src_bitmap->source_filename);
1863 Warn("- frame size: %d, %d", width, height);
1864 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1865 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1866 Warn("custom graphic rejected for this element/action");
1868 if (i == fallback_graphic)
1869 Fail("no fallback graphic available");
1871 Warn("fallback done to 'char_exclam' for this graphic");
1874 graphic_info[i] = graphic_info[fallback_graphic];
1879 static void InitGraphicCompatibilityInfo(void)
1881 struct FileInfo *fi_global_door =
1882 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1883 int num_images = getImageListSize();
1886 /* the following compatibility handling is needed for the following case:
1887 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1888 graphics mainly used for door and panel graphics, like editor, tape and
1889 in-game buttons with hard-coded bitmap positions and button sizes; as
1890 these graphics now have individual definitions, redefining "global.door"
1891 to change all these graphics at once like before does not work anymore
1892 (because all those individual definitions still have their default values);
1893 to solve this, remap all those individual definitions that are not
1894 redefined to the new bitmap of "global.door" if it was redefined */
1896 // special compatibility handling if image "global.door" was redefined
1897 if (fi_global_door->redefined)
1899 for (i = 0; i < num_images; i++)
1901 struct FileInfo *fi = getImageListEntryFromImageID(i);
1903 // process only those images that still use the default settings
1906 // process all images which default to same image as "global.door"
1907 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1910 Debug("init:InitGraphicCompatibilityInfo",
1911 "special treatment needed for token '%s'", fi->token);
1914 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1915 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1921 InitGraphicCompatibilityInfo_Doors();
1924 static void InitElementSoundInfo(void)
1926 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1927 int num_property_mappings = getSoundListPropertyMappingSize();
1930 // set values to -1 to identify later as "uninitialized" values
1931 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1932 for (act = 0; act < NUM_ACTIONS; act++)
1933 element_info[i].sound[act] = -1;
1935 // initialize element/sound mapping from static configuration
1936 for (i = 0; element_to_sound[i].element > -1; i++)
1938 int element = element_to_sound[i].element;
1939 int action = element_to_sound[i].action;
1940 int sound = element_to_sound[i].sound;
1941 boolean is_class = element_to_sound[i].is_class;
1944 action = ACTION_DEFAULT;
1947 element_info[element].sound[action] = sound;
1949 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1950 if (strEqual(element_info[j].class_name,
1951 element_info[element].class_name))
1952 element_info[j].sound[action] = sound;
1955 // initialize element class/sound mapping from dynamic configuration
1956 for (i = 0; i < num_property_mappings; i++)
1958 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1959 int action = property_mapping[i].ext1_index;
1960 int sound = property_mapping[i].artwork_index;
1962 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1966 action = ACTION_DEFAULT;
1968 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1969 if (strEqual(element_info[j].class_name,
1970 element_info[element_class].class_name))
1971 element_info[j].sound[action] = sound;
1974 // initialize element/sound mapping from dynamic configuration
1975 for (i = 0; i < num_property_mappings; i++)
1977 int element = property_mapping[i].base_index;
1978 int action = property_mapping[i].ext1_index;
1979 int sound = property_mapping[i].artwork_index;
1981 if (element >= MAX_NUM_ELEMENTS)
1985 action = ACTION_DEFAULT;
1987 element_info[element].sound[action] = sound;
1990 // now set all '-1' values to element specific default values
1991 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1993 for (act = 0; act < NUM_ACTIONS; act++)
1995 // generic default action sound (defined by "[default]" directive)
1996 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1998 // look for special default action sound (classic game specific)
1999 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2000 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2001 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2002 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2003 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2004 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2005 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2006 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2008 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2009 // !!! make this better !!!
2010 if (i == EL_EMPTY_SPACE)
2011 default_action_sound = element_info[EL_DEFAULT].sound[act];
2013 // no sound for this specific action -- use default action sound
2014 if (element_info[i].sound[act] == -1)
2015 element_info[i].sound[act] = default_action_sound;
2019 // copy sound settings to some elements that are only stored in level file
2020 // in native R'n'D levels, but are used by game engine in native EM levels
2021 for (i = 0; copy_properties[i][0] != -1; i++)
2022 for (j = 1; j <= 4; j++)
2023 for (act = 0; act < NUM_ACTIONS; act++)
2024 element_info[copy_properties[i][j]].sound[act] =
2025 element_info[copy_properties[i][0]].sound[act];
2028 static void InitGameModeSoundInfo(void)
2032 // set values to -1 to identify later as "uninitialized" values
2033 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2036 // initialize gamemode/sound mapping from static configuration
2037 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2039 int gamemode = gamemode_to_sound[i].gamemode;
2040 int sound = gamemode_to_sound[i].sound;
2043 gamemode = GAME_MODE_DEFAULT;
2045 menu.sound[gamemode] = sound;
2048 // now set all '-1' values to levelset specific default values
2049 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2050 if (menu.sound[i] == -1)
2051 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2054 static void set_sound_parameters(int sound, char **parameter_raw)
2056 int parameter[NUM_SND_ARGS];
2059 // get integer values from string parameters
2060 for (i = 0; i < NUM_SND_ARGS; i++)
2062 get_parameter_value(parameter_raw[i],
2063 sound_config_suffix[i].token,
2064 sound_config_suffix[i].type);
2066 // explicit loop mode setting in configuration overrides default value
2067 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2068 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2070 // sound volume to change the original volume when loading the sound file
2071 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2073 // sound priority to give certain sounds a higher or lower priority
2074 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2077 static void InitSoundInfo(void)
2079 int *sound_effect_properties;
2080 int num_sounds = getSoundListSize();
2083 checked_free(sound_info);
2085 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2086 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2088 // initialize sound effect for all elements to "no sound"
2089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2090 for (j = 0; j < NUM_ACTIONS; j++)
2091 element_info[i].sound[j] = SND_UNDEFINED;
2093 for (i = 0; i < num_sounds; i++)
2095 struct FileInfo *sound = getSoundListEntry(i);
2096 int len_effect_text = strlen(sound->token);
2098 sound_effect_properties[i] = ACTION_OTHER;
2099 sound_info[i].loop = FALSE; // default: play sound only once
2101 // determine all loop sounds and identify certain sound classes
2103 for (j = 0; element_action_info[j].suffix; j++)
2105 int len_action_text = strlen(element_action_info[j].suffix);
2107 if (len_action_text < len_effect_text &&
2108 strEqual(&sound->token[len_effect_text - len_action_text],
2109 element_action_info[j].suffix))
2111 sound_effect_properties[i] = element_action_info[j].value;
2112 sound_info[i].loop = element_action_info[j].is_loop_sound;
2118 // associate elements and some selected sound actions
2120 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2122 if (element_info[j].class_name)
2124 int len_class_text = strlen(element_info[j].class_name);
2126 if (len_class_text + 1 < len_effect_text &&
2127 strncmp(sound->token,
2128 element_info[j].class_name, len_class_text) == 0 &&
2129 sound->token[len_class_text] == '.')
2131 int sound_action_value = sound_effect_properties[i];
2133 element_info[j].sound[sound_action_value] = i;
2138 set_sound_parameters(i, sound->parameter);
2141 free(sound_effect_properties);
2144 static void InitGameModeMusicInfo(void)
2146 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2147 int num_property_mappings = getMusicListPropertyMappingSize();
2148 int default_levelset_music = -1;
2151 // set values to -1 to identify later as "uninitialized" values
2152 for (i = 0; i < MAX_LEVELS; i++)
2153 levelset.music[i] = -1;
2154 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2157 // initialize gamemode/music mapping from static configuration
2158 for (i = 0; gamemode_to_music[i].music > -1; i++)
2160 int gamemode = gamemode_to_music[i].gamemode;
2161 int music = gamemode_to_music[i].music;
2164 gamemode = GAME_MODE_DEFAULT;
2166 menu.music[gamemode] = music;
2169 // initialize gamemode/music mapping from dynamic configuration
2170 for (i = 0; i < num_property_mappings; i++)
2172 int prefix = property_mapping[i].base_index;
2173 int gamemode = property_mapping[i].ext2_index;
2174 int level = property_mapping[i].ext3_index;
2175 int music = property_mapping[i].artwork_index;
2177 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2181 gamemode = GAME_MODE_DEFAULT;
2183 // level specific music only allowed for in-game music
2184 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2185 gamemode = GAME_MODE_PLAYING;
2190 default_levelset_music = music;
2193 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2194 levelset.music[level] = music;
2195 if (gamemode != GAME_MODE_PLAYING)
2196 menu.music[gamemode] = music;
2199 // now set all '-1' values to menu specific default values
2200 // (undefined values of "levelset.music[]" might stay at "-1" to
2201 // allow dynamic selection of music files from music directory!)
2202 for (i = 0; i < MAX_LEVELS; i++)
2203 if (levelset.music[i] == -1)
2204 levelset.music[i] = default_levelset_music;
2205 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2206 if (menu.music[i] == -1)
2207 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2210 static void set_music_parameters(int music, char **parameter_raw)
2212 int parameter[NUM_MUS_ARGS];
2215 // get integer values from string parameters
2216 for (i = 0; i < NUM_MUS_ARGS; i++)
2218 get_parameter_value(parameter_raw[i],
2219 music_config_suffix[i].token,
2220 music_config_suffix[i].type);
2222 // explicit loop mode setting in configuration overrides default value
2223 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2224 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2227 static void InitMusicInfo(void)
2229 int num_music = getMusicListSize();
2232 checked_free(music_info);
2234 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2236 for (i = 0; i < num_music; i++)
2238 struct FileInfo *music = getMusicListEntry(i);
2239 int len_music_text = strlen(music->token);
2241 music_info[i].loop = TRUE; // default: play music in loop mode
2243 // determine all loop music
2245 for (j = 0; music_prefix_info[j].prefix; j++)
2247 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2249 if (len_prefix_text < len_music_text &&
2250 strncmp(music->token,
2251 music_prefix_info[j].prefix, len_prefix_text) == 0)
2253 music_info[i].loop = music_prefix_info[j].is_loop_music;
2259 set_music_parameters(i, music->parameter);
2264 static void InitGameInfoFromArtworkInfo(void)
2266 // special case: store initial value of custom artwork setting
2267 game.use_masked_elements_initial = game.use_masked_elements;
2270 static void ReinitializeGraphics(void)
2272 print_timestamp_init("ReinitializeGraphics");
2274 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2276 InitGraphicInfo(); // graphic properties mapping
2277 print_timestamp_time("InitGraphicInfo");
2278 InitElementGraphicInfo(); // element game graphic mapping
2279 print_timestamp_time("InitElementGraphicInfo");
2280 InitElementSpecialGraphicInfo(); // element special graphic mapping
2281 print_timestamp_time("InitElementSpecialGraphicInfo");
2283 InitElementSmallImages(); // scale elements to all needed sizes
2284 print_timestamp_time("InitElementSmallImages");
2285 InitScaledImages(); // scale all other images, if needed
2286 print_timestamp_time("InitScaledImages");
2287 InitBitmapPointers(); // set standard size bitmap pointers
2288 print_timestamp_time("InitBitmapPointers");
2289 InitFontGraphicInfo(); // initialize text drawing functions
2290 print_timestamp_time("InitFontGraphicInfo");
2291 InitGlobalAnimGraphicInfo(); // initialize global animation config
2292 print_timestamp_time("InitGlobalAnimGraphicInfo");
2294 InitImageTextures(); // create textures for certain images
2295 print_timestamp_time("InitImageTextures");
2297 InitGraphicInfo_EM(); // graphic mapping for EM engine
2298 print_timestamp_time("InitGraphicInfo_EM");
2300 InitGraphicCompatibilityInfo();
2301 print_timestamp_time("InitGraphicCompatibilityInfo");
2304 print_timestamp_time("InitGadgets");
2306 print_timestamp_time("InitDoors");
2308 InitGameInfoFromArtworkInfo();
2310 print_timestamp_done("ReinitializeGraphics");
2313 static void ReinitializeSounds(void)
2315 InitSoundInfo(); // sound properties mapping
2316 InitElementSoundInfo(); // element game sound mapping
2317 InitGameModeSoundInfo(); // game mode sound mapping
2318 InitGlobalAnimSoundInfo(); // global animation sound settings
2320 InitPlayLevelSound(); // internal game sound settings
2323 static void ReinitializeMusic(void)
2325 InitMusicInfo(); // music properties mapping
2326 InitGameModeMusicInfo(); // game mode music mapping
2327 InitGlobalAnimMusicInfo(); // global animation music settings
2330 static int get_special_property_bit(int element, int property_bit_nr)
2332 struct PropertyBitInfo
2338 static struct PropertyBitInfo pb_can_move_into_acid[] =
2340 // the player may be able fall into acid when gravity is activated
2345 { EL_SP_MURPHY, 0 },
2346 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2348 // all elements that can move may be able to also move into acid
2351 { EL_BUG_RIGHT, 1 },
2354 { EL_SPACESHIP, 2 },
2355 { EL_SPACESHIP_LEFT, 2 },
2356 { EL_SPACESHIP_RIGHT, 2 },
2357 { EL_SPACESHIP_UP, 2 },
2358 { EL_SPACESHIP_DOWN, 2 },
2359 { EL_BD_BUTTERFLY, 3 },
2360 { EL_BD_BUTTERFLY_LEFT, 3 },
2361 { EL_BD_BUTTERFLY_RIGHT, 3 },
2362 { EL_BD_BUTTERFLY_UP, 3 },
2363 { EL_BD_BUTTERFLY_DOWN, 3 },
2364 { EL_BD_FIREFLY, 4 },
2365 { EL_BD_FIREFLY_LEFT, 4 },
2366 { EL_BD_FIREFLY_RIGHT, 4 },
2367 { EL_BD_FIREFLY_UP, 4 },
2368 { EL_BD_FIREFLY_DOWN, 4 },
2370 { EL_YAMYAM_LEFT, 5 },
2371 { EL_YAMYAM_RIGHT, 5 },
2372 { EL_YAMYAM_UP, 5 },
2373 { EL_YAMYAM_DOWN, 5 },
2374 { EL_DARK_YAMYAM, 6 },
2377 { EL_PACMAN_LEFT, 8 },
2378 { EL_PACMAN_RIGHT, 8 },
2379 { EL_PACMAN_UP, 8 },
2380 { EL_PACMAN_DOWN, 8 },
2382 { EL_MOLE_LEFT, 9 },
2383 { EL_MOLE_RIGHT, 9 },
2385 { EL_MOLE_DOWN, 9 },
2389 { EL_SATELLITE, 13 },
2390 { EL_SP_SNIKSNAK, 14 },
2391 { EL_SP_ELECTRON, 15 },
2394 { EL_SPRING_LEFT, 17 },
2395 { EL_SPRING_RIGHT, 17 },
2396 { EL_EMC_ANDROID, 18 },
2401 static struct PropertyBitInfo pb_dont_collide_with[] =
2403 { EL_SP_SNIKSNAK, 0 },
2404 { EL_SP_ELECTRON, 1 },
2412 struct PropertyBitInfo *pb_info;
2415 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2416 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2421 struct PropertyBitInfo *pb_info = NULL;
2424 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2425 if (pb_definition[i].bit_nr == property_bit_nr)
2426 pb_info = pb_definition[i].pb_info;
2428 if (pb_info == NULL)
2431 for (i = 0; pb_info[i].element != -1; i++)
2432 if (pb_info[i].element == element)
2433 return pb_info[i].bit_nr;
2438 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2439 boolean property_value)
2441 int bit_nr = get_special_property_bit(element, property_bit_nr);
2446 *bitfield |= (1 << bit_nr);
2448 *bitfield &= ~(1 << bit_nr);
2452 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2454 int bit_nr = get_special_property_bit(element, property_bit_nr);
2457 return ((*bitfield & (1 << bit_nr)) != 0);
2462 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2464 static int group_nr;
2465 static struct ElementGroupInfo *group;
2466 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2469 if (actual_group == NULL) // not yet initialized
2472 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2474 Warn("recursion too deep when resolving group element %d",
2475 group_element - EL_GROUP_START + 1);
2477 // replace element which caused too deep recursion by question mark
2478 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2483 if (recursion_depth == 0) // initialization
2485 group = actual_group;
2486 group_nr = GROUP_NR(group_element);
2488 group->num_elements_resolved = 0;
2489 group->choice_pos = 0;
2491 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2492 element_info[i].in_group[group_nr] = FALSE;
2495 for (i = 0; i < actual_group->num_elements; i++)
2497 int element = actual_group->element[i];
2499 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2502 if (IS_GROUP_ELEMENT(element))
2503 ResolveGroupElementExt(element, recursion_depth + 1);
2506 group->element_resolved[group->num_elements_resolved++] = element;
2507 element_info[element].in_group[group_nr] = TRUE;
2512 void ResolveGroupElement(int group_element)
2514 ResolveGroupElementExt(group_element, 0);
2517 void InitElementPropertiesStatic(void)
2519 static boolean clipboard_elements_initialized = FALSE;
2521 static int ep_diggable[] =
2526 EL_SP_BUGGY_BASE_ACTIVATING,
2529 EL_INVISIBLE_SAND_ACTIVE,
2532 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2533 // (if amoeba can grow into anything diggable, maybe keep these out)
2538 EL_SP_BUGGY_BASE_ACTIVE,
2545 static int ep_collectible_only[] =
2567 EL_DYNABOMB_INCREASE_NUMBER,
2568 EL_DYNABOMB_INCREASE_SIZE,
2569 EL_DYNABOMB_INCREASE_POWER,
2587 // !!! handle separately !!!
2588 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2594 static int ep_dont_run_into[] =
2596 // same elements as in 'ep_dont_touch'
2602 // same elements as in 'ep_dont_collide_with'
2614 // !!! maybe this should better be handled by 'ep_diggable' !!!
2619 EL_SP_BUGGY_BASE_ACTIVE,
2626 static int ep_dont_collide_with[] =
2628 // same elements as in 'ep_dont_touch'
2645 static int ep_dont_touch[] =
2655 static int ep_indestructible[] =
2659 EL_ACID_POOL_TOPLEFT,
2660 EL_ACID_POOL_TOPRIGHT,
2661 EL_ACID_POOL_BOTTOMLEFT,
2662 EL_ACID_POOL_BOTTOM,
2663 EL_ACID_POOL_BOTTOMRIGHT,
2664 EL_SP_HARDWARE_GRAY,
2665 EL_SP_HARDWARE_GREEN,
2666 EL_SP_HARDWARE_BLUE,
2668 EL_SP_HARDWARE_YELLOW,
2669 EL_SP_HARDWARE_BASE_1,
2670 EL_SP_HARDWARE_BASE_2,
2671 EL_SP_HARDWARE_BASE_3,
2672 EL_SP_HARDWARE_BASE_4,
2673 EL_SP_HARDWARE_BASE_5,
2674 EL_SP_HARDWARE_BASE_6,
2675 EL_INVISIBLE_STEELWALL,
2676 EL_INVISIBLE_STEELWALL_ACTIVE,
2677 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2678 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2679 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2680 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2681 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2682 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2683 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2684 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2685 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2686 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2687 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2688 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2690 EL_LIGHT_SWITCH_ACTIVE,
2691 EL_SIGN_EXCLAMATION,
2692 EL_SIGN_RADIOACTIVITY,
2699 EL_SIGN_ENTRY_FORBIDDEN,
2700 EL_SIGN_EMERGENCY_EXIT,
2708 EL_STEEL_EXIT_CLOSED,
2710 EL_STEEL_EXIT_OPENING,
2711 EL_STEEL_EXIT_CLOSING,
2712 EL_EM_STEEL_EXIT_CLOSED,
2713 EL_EM_STEEL_EXIT_OPEN,
2714 EL_EM_STEEL_EXIT_OPENING,
2715 EL_EM_STEEL_EXIT_CLOSING,
2716 EL_DC_STEELWALL_1_LEFT,
2717 EL_DC_STEELWALL_1_RIGHT,
2718 EL_DC_STEELWALL_1_TOP,
2719 EL_DC_STEELWALL_1_BOTTOM,
2720 EL_DC_STEELWALL_1_HORIZONTAL,
2721 EL_DC_STEELWALL_1_VERTICAL,
2722 EL_DC_STEELWALL_1_TOPLEFT,
2723 EL_DC_STEELWALL_1_TOPRIGHT,
2724 EL_DC_STEELWALL_1_BOTTOMLEFT,
2725 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2726 EL_DC_STEELWALL_1_TOPLEFT_2,
2727 EL_DC_STEELWALL_1_TOPRIGHT_2,
2728 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2729 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2730 EL_DC_STEELWALL_2_LEFT,
2731 EL_DC_STEELWALL_2_RIGHT,
2732 EL_DC_STEELWALL_2_TOP,
2733 EL_DC_STEELWALL_2_BOTTOM,
2734 EL_DC_STEELWALL_2_HORIZONTAL,
2735 EL_DC_STEELWALL_2_VERTICAL,
2736 EL_DC_STEELWALL_2_MIDDLE,
2737 EL_DC_STEELWALL_2_SINGLE,
2738 EL_STEELWALL_SLIPPERY,
2752 EL_GATE_1_GRAY_ACTIVE,
2753 EL_GATE_2_GRAY_ACTIVE,
2754 EL_GATE_3_GRAY_ACTIVE,
2755 EL_GATE_4_GRAY_ACTIVE,
2764 EL_EM_GATE_1_GRAY_ACTIVE,
2765 EL_EM_GATE_2_GRAY_ACTIVE,
2766 EL_EM_GATE_3_GRAY_ACTIVE,
2767 EL_EM_GATE_4_GRAY_ACTIVE,
2776 EL_EMC_GATE_5_GRAY_ACTIVE,
2777 EL_EMC_GATE_6_GRAY_ACTIVE,
2778 EL_EMC_GATE_7_GRAY_ACTIVE,
2779 EL_EMC_GATE_8_GRAY_ACTIVE,
2781 EL_DC_GATE_WHITE_GRAY,
2782 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2783 EL_DC_GATE_FAKE_GRAY,
2785 EL_SWITCHGATE_OPENING,
2786 EL_SWITCHGATE_CLOSED,
2787 EL_SWITCHGATE_CLOSING,
2788 EL_DC_SWITCHGATE_SWITCH_UP,
2789 EL_DC_SWITCHGATE_SWITCH_DOWN,
2791 EL_TIMEGATE_OPENING,
2793 EL_TIMEGATE_CLOSING,
2794 EL_DC_TIMEGATE_SWITCH,
2795 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2799 EL_TUBE_VERTICAL_LEFT,
2800 EL_TUBE_VERTICAL_RIGHT,
2801 EL_TUBE_HORIZONTAL_UP,
2802 EL_TUBE_HORIZONTAL_DOWN,
2807 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2808 EL_EXPANDABLE_STEELWALL_VERTICAL,
2809 EL_EXPANDABLE_STEELWALL_ANY,
2814 static int ep_slippery[] =
2828 EL_ROBOT_WHEEL_ACTIVE,
2834 EL_ACID_POOL_TOPLEFT,
2835 EL_ACID_POOL_TOPRIGHT,
2845 EL_STEELWALL_SLIPPERY,
2848 EL_EMC_WALL_SLIPPERY_1,
2849 EL_EMC_WALL_SLIPPERY_2,
2850 EL_EMC_WALL_SLIPPERY_3,
2851 EL_EMC_WALL_SLIPPERY_4,
2853 EL_EMC_MAGIC_BALL_ACTIVE,
2858 static int ep_can_change[] =
2863 static int ep_can_move[] =
2865 // same elements as in 'pb_can_move_into_acid'
2888 static int ep_can_fall[] =
2903 EL_QUICKSAND_FAST_FULL,
2905 EL_BD_MAGIC_WALL_FULL,
2906 EL_DC_MAGIC_WALL_FULL,
2920 static int ep_can_smash_player[] =
2946 static int ep_can_smash_enemies[] =
2955 static int ep_can_smash_everything[] =
2964 static int ep_explodes_by_fire[] =
2966 // same elements as in 'ep_explodes_impact'
2971 // same elements as in 'ep_explodes_smashed'
2981 EL_EM_DYNAMITE_ACTIVE,
2982 EL_DYNABOMB_PLAYER_1_ACTIVE,
2983 EL_DYNABOMB_PLAYER_2_ACTIVE,
2984 EL_DYNABOMB_PLAYER_3_ACTIVE,
2985 EL_DYNABOMB_PLAYER_4_ACTIVE,
2986 EL_DYNABOMB_INCREASE_NUMBER,
2987 EL_DYNABOMB_INCREASE_SIZE,
2988 EL_DYNABOMB_INCREASE_POWER,
2989 EL_SP_DISK_RED_ACTIVE,
3003 static int ep_explodes_smashed[] =
3005 // same elements as in 'ep_explodes_impact'
3019 static int ep_explodes_impact[] =
3028 static int ep_walkable_over[] =
3048 EL_SOKOBAN_FIELD_EMPTY,
3055 EL_EM_STEEL_EXIT_OPEN,
3056 EL_EM_STEEL_EXIT_OPENING,
3065 EL_GATE_1_GRAY_ACTIVE,
3066 EL_GATE_2_GRAY_ACTIVE,
3067 EL_GATE_3_GRAY_ACTIVE,
3068 EL_GATE_4_GRAY_ACTIVE,
3076 static int ep_walkable_inside[] =
3081 EL_TUBE_VERTICAL_LEFT,
3082 EL_TUBE_VERTICAL_RIGHT,
3083 EL_TUBE_HORIZONTAL_UP,
3084 EL_TUBE_HORIZONTAL_DOWN,
3093 static int ep_walkable_under[] =
3098 static int ep_passable_over[] =
3108 EL_EM_GATE_1_GRAY_ACTIVE,
3109 EL_EM_GATE_2_GRAY_ACTIVE,
3110 EL_EM_GATE_3_GRAY_ACTIVE,
3111 EL_EM_GATE_4_GRAY_ACTIVE,
3120 EL_EMC_GATE_5_GRAY_ACTIVE,
3121 EL_EMC_GATE_6_GRAY_ACTIVE,
3122 EL_EMC_GATE_7_GRAY_ACTIVE,
3123 EL_EMC_GATE_8_GRAY_ACTIVE,
3125 EL_DC_GATE_WHITE_GRAY,
3126 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3133 static int ep_passable_inside[] =
3139 EL_SP_PORT_HORIZONTAL,
3140 EL_SP_PORT_VERTICAL,
3142 EL_SP_GRAVITY_PORT_LEFT,
3143 EL_SP_GRAVITY_PORT_RIGHT,
3144 EL_SP_GRAVITY_PORT_UP,
3145 EL_SP_GRAVITY_PORT_DOWN,
3146 EL_SP_GRAVITY_ON_PORT_LEFT,
3147 EL_SP_GRAVITY_ON_PORT_RIGHT,
3148 EL_SP_GRAVITY_ON_PORT_UP,
3149 EL_SP_GRAVITY_ON_PORT_DOWN,
3150 EL_SP_GRAVITY_OFF_PORT_LEFT,
3151 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3152 EL_SP_GRAVITY_OFF_PORT_UP,
3153 EL_SP_GRAVITY_OFF_PORT_DOWN,
3158 static int ep_passable_under[] =
3163 static int ep_droppable[] =
3168 static int ep_explodes_1x1_old[] =
3173 static int ep_pushable[] =
3185 EL_SOKOBAN_FIELD_FULL,
3194 static int ep_explodes_cross_old[] =
3199 static int ep_protected[] =
3201 // same elements as in 'ep_walkable_inside'
3205 EL_TUBE_VERTICAL_LEFT,
3206 EL_TUBE_VERTICAL_RIGHT,
3207 EL_TUBE_HORIZONTAL_UP,
3208 EL_TUBE_HORIZONTAL_DOWN,
3214 // same elements as in 'ep_passable_over'
3223 EL_EM_GATE_1_GRAY_ACTIVE,
3224 EL_EM_GATE_2_GRAY_ACTIVE,
3225 EL_EM_GATE_3_GRAY_ACTIVE,
3226 EL_EM_GATE_4_GRAY_ACTIVE,
3235 EL_EMC_GATE_5_GRAY_ACTIVE,
3236 EL_EMC_GATE_6_GRAY_ACTIVE,
3237 EL_EMC_GATE_7_GRAY_ACTIVE,
3238 EL_EMC_GATE_8_GRAY_ACTIVE,
3240 EL_DC_GATE_WHITE_GRAY,
3241 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3245 // same elements as in 'ep_passable_inside'
3250 EL_SP_PORT_HORIZONTAL,
3251 EL_SP_PORT_VERTICAL,
3253 EL_SP_GRAVITY_PORT_LEFT,
3254 EL_SP_GRAVITY_PORT_RIGHT,
3255 EL_SP_GRAVITY_PORT_UP,
3256 EL_SP_GRAVITY_PORT_DOWN,
3257 EL_SP_GRAVITY_ON_PORT_LEFT,
3258 EL_SP_GRAVITY_ON_PORT_RIGHT,
3259 EL_SP_GRAVITY_ON_PORT_UP,
3260 EL_SP_GRAVITY_ON_PORT_DOWN,
3261 EL_SP_GRAVITY_OFF_PORT_LEFT,
3262 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3263 EL_SP_GRAVITY_OFF_PORT_UP,
3264 EL_SP_GRAVITY_OFF_PORT_DOWN,
3269 static int ep_throwable[] =
3274 static int ep_can_explode[] =
3276 // same elements as in 'ep_explodes_impact'
3281 // same elements as in 'ep_explodes_smashed'
3287 // elements that can explode by explosion or by dragonfire
3291 EL_EM_DYNAMITE_ACTIVE,
3292 EL_DYNABOMB_PLAYER_1_ACTIVE,
3293 EL_DYNABOMB_PLAYER_2_ACTIVE,
3294 EL_DYNABOMB_PLAYER_3_ACTIVE,
3295 EL_DYNABOMB_PLAYER_4_ACTIVE,
3296 EL_DYNABOMB_INCREASE_NUMBER,
3297 EL_DYNABOMB_INCREASE_SIZE,
3298 EL_DYNABOMB_INCREASE_POWER,
3299 EL_SP_DISK_RED_ACTIVE,
3307 // elements that can explode only by explosion
3313 static int ep_gravity_reachable[] =
3319 EL_INVISIBLE_SAND_ACTIVE,
3324 EL_SP_PORT_HORIZONTAL,
3325 EL_SP_PORT_VERTICAL,
3327 EL_SP_GRAVITY_PORT_LEFT,
3328 EL_SP_GRAVITY_PORT_RIGHT,
3329 EL_SP_GRAVITY_PORT_UP,
3330 EL_SP_GRAVITY_PORT_DOWN,
3331 EL_SP_GRAVITY_ON_PORT_LEFT,
3332 EL_SP_GRAVITY_ON_PORT_RIGHT,
3333 EL_SP_GRAVITY_ON_PORT_UP,
3334 EL_SP_GRAVITY_ON_PORT_DOWN,
3335 EL_SP_GRAVITY_OFF_PORT_LEFT,
3336 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3337 EL_SP_GRAVITY_OFF_PORT_UP,
3338 EL_SP_GRAVITY_OFF_PORT_DOWN,
3344 static int ep_empty_space[] =
3367 static int ep_player[] =
3374 EL_SOKOBAN_FIELD_PLAYER,
3380 static int ep_can_pass_magic_wall[] =
3394 static int ep_can_pass_dc_magic_wall[] =
3410 static int ep_switchable[] =
3414 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3415 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3416 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3417 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3418 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3419 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3420 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3421 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3422 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3423 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3424 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3425 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3426 EL_SWITCHGATE_SWITCH_UP,
3427 EL_SWITCHGATE_SWITCH_DOWN,
3428 EL_DC_SWITCHGATE_SWITCH_UP,
3429 EL_DC_SWITCHGATE_SWITCH_DOWN,
3431 EL_LIGHT_SWITCH_ACTIVE,
3433 EL_DC_TIMEGATE_SWITCH,
3434 EL_BALLOON_SWITCH_LEFT,
3435 EL_BALLOON_SWITCH_RIGHT,
3436 EL_BALLOON_SWITCH_UP,
3437 EL_BALLOON_SWITCH_DOWN,
3438 EL_BALLOON_SWITCH_ANY,
3439 EL_BALLOON_SWITCH_NONE,
3442 EL_EMC_MAGIC_BALL_SWITCH,
3443 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3448 static int ep_bd_element[] =
3482 static int ep_sp_element[] =
3484 // should always be valid
3487 // standard classic Supaplex elements
3494 EL_SP_HARDWARE_GRAY,
3502 EL_SP_GRAVITY_PORT_RIGHT,
3503 EL_SP_GRAVITY_PORT_DOWN,
3504 EL_SP_GRAVITY_PORT_LEFT,
3505 EL_SP_GRAVITY_PORT_UP,
3510 EL_SP_PORT_VERTICAL,
3511 EL_SP_PORT_HORIZONTAL,
3517 EL_SP_HARDWARE_BASE_1,
3518 EL_SP_HARDWARE_GREEN,
3519 EL_SP_HARDWARE_BLUE,
3521 EL_SP_HARDWARE_YELLOW,
3522 EL_SP_HARDWARE_BASE_2,
3523 EL_SP_HARDWARE_BASE_3,
3524 EL_SP_HARDWARE_BASE_4,
3525 EL_SP_HARDWARE_BASE_5,
3526 EL_SP_HARDWARE_BASE_6,
3530 // additional elements that appeared in newer Supaplex levels
3533 // additional gravity port elements (not switching, but setting gravity)
3534 EL_SP_GRAVITY_ON_PORT_LEFT,
3535 EL_SP_GRAVITY_ON_PORT_RIGHT,
3536 EL_SP_GRAVITY_ON_PORT_UP,
3537 EL_SP_GRAVITY_ON_PORT_DOWN,
3538 EL_SP_GRAVITY_OFF_PORT_LEFT,
3539 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3540 EL_SP_GRAVITY_OFF_PORT_UP,
3541 EL_SP_GRAVITY_OFF_PORT_DOWN,
3543 // more than one Murphy in a level results in an inactive clone
3546 // runtime Supaplex elements
3547 EL_SP_DISK_RED_ACTIVE,
3548 EL_SP_TERMINAL_ACTIVE,
3549 EL_SP_BUGGY_BASE_ACTIVATING,
3550 EL_SP_BUGGY_BASE_ACTIVE,
3557 static int ep_sb_element[] =
3562 EL_SOKOBAN_FIELD_EMPTY,
3563 EL_SOKOBAN_FIELD_FULL,
3564 EL_SOKOBAN_FIELD_PLAYER,
3569 EL_INVISIBLE_STEELWALL,
3574 static int ep_gem[] =
3586 static int ep_food_dark_yamyam[] =
3614 static int ep_food_penguin[] =
3628 static int ep_food_pig[] =
3640 static int ep_historic_wall[] =
3651 EL_GATE_1_GRAY_ACTIVE,
3652 EL_GATE_2_GRAY_ACTIVE,
3653 EL_GATE_3_GRAY_ACTIVE,
3654 EL_GATE_4_GRAY_ACTIVE,
3663 EL_EM_GATE_1_GRAY_ACTIVE,
3664 EL_EM_GATE_2_GRAY_ACTIVE,
3665 EL_EM_GATE_3_GRAY_ACTIVE,
3666 EL_EM_GATE_4_GRAY_ACTIVE,
3673 EL_EXPANDABLE_WALL_HORIZONTAL,
3674 EL_EXPANDABLE_WALL_VERTICAL,
3675 EL_EXPANDABLE_WALL_ANY,
3676 EL_EXPANDABLE_WALL_GROWING,
3677 EL_BD_EXPANDABLE_WALL,
3684 EL_SP_HARDWARE_GRAY,
3685 EL_SP_HARDWARE_GREEN,
3686 EL_SP_HARDWARE_BLUE,
3688 EL_SP_HARDWARE_YELLOW,
3689 EL_SP_HARDWARE_BASE_1,
3690 EL_SP_HARDWARE_BASE_2,
3691 EL_SP_HARDWARE_BASE_3,
3692 EL_SP_HARDWARE_BASE_4,
3693 EL_SP_HARDWARE_BASE_5,
3694 EL_SP_HARDWARE_BASE_6,
3696 EL_SP_TERMINAL_ACTIVE,
3699 EL_INVISIBLE_STEELWALL,
3700 EL_INVISIBLE_STEELWALL_ACTIVE,
3702 EL_INVISIBLE_WALL_ACTIVE,
3703 EL_STEELWALL_SLIPPERY,
3720 static int ep_historic_solid[] =
3724 EL_EXPANDABLE_WALL_HORIZONTAL,
3725 EL_EXPANDABLE_WALL_VERTICAL,
3726 EL_EXPANDABLE_WALL_ANY,
3727 EL_BD_EXPANDABLE_WALL,
3740 EL_QUICKSAND_FILLING,
3741 EL_QUICKSAND_EMPTYING,
3743 EL_MAGIC_WALL_ACTIVE,
3744 EL_MAGIC_WALL_EMPTYING,
3745 EL_MAGIC_WALL_FILLING,
3749 EL_BD_MAGIC_WALL_ACTIVE,
3750 EL_BD_MAGIC_WALL_EMPTYING,
3751 EL_BD_MAGIC_WALL_FULL,
3752 EL_BD_MAGIC_WALL_FILLING,
3753 EL_BD_MAGIC_WALL_DEAD,
3762 EL_SP_TERMINAL_ACTIVE,
3766 EL_INVISIBLE_WALL_ACTIVE,
3767 EL_SWITCHGATE_SWITCH_UP,
3768 EL_SWITCHGATE_SWITCH_DOWN,
3770 EL_TIMEGATE_SWITCH_ACTIVE,
3782 // the following elements are a direct copy of "indestructible" elements,
3783 // except "EL_ACID", which is "indestructible", but not "solid"!
3788 EL_ACID_POOL_TOPLEFT,
3789 EL_ACID_POOL_TOPRIGHT,
3790 EL_ACID_POOL_BOTTOMLEFT,
3791 EL_ACID_POOL_BOTTOM,
3792 EL_ACID_POOL_BOTTOMRIGHT,
3793 EL_SP_HARDWARE_GRAY,
3794 EL_SP_HARDWARE_GREEN,
3795 EL_SP_HARDWARE_BLUE,
3797 EL_SP_HARDWARE_YELLOW,
3798 EL_SP_HARDWARE_BASE_1,
3799 EL_SP_HARDWARE_BASE_2,
3800 EL_SP_HARDWARE_BASE_3,
3801 EL_SP_HARDWARE_BASE_4,
3802 EL_SP_HARDWARE_BASE_5,
3803 EL_SP_HARDWARE_BASE_6,
3804 EL_INVISIBLE_STEELWALL,
3805 EL_INVISIBLE_STEELWALL_ACTIVE,
3806 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3807 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3808 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3809 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3810 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3811 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3812 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3813 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3814 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3815 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3816 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3817 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3819 EL_LIGHT_SWITCH_ACTIVE,
3820 EL_SIGN_EXCLAMATION,
3821 EL_SIGN_RADIOACTIVITY,
3828 EL_SIGN_ENTRY_FORBIDDEN,
3829 EL_SIGN_EMERGENCY_EXIT,
3837 EL_STEEL_EXIT_CLOSED,
3839 EL_STEEL_EXIT_OPENING,
3840 EL_STEEL_EXIT_CLOSING,
3841 EL_EM_STEEL_EXIT_CLOSED,
3842 EL_EM_STEEL_EXIT_OPEN,
3843 EL_EM_STEEL_EXIT_OPENING,
3844 EL_EM_STEEL_EXIT_CLOSING,
3845 EL_DC_STEELWALL_1_LEFT,
3846 EL_DC_STEELWALL_1_RIGHT,
3847 EL_DC_STEELWALL_1_TOP,
3848 EL_DC_STEELWALL_1_BOTTOM,
3849 EL_DC_STEELWALL_1_HORIZONTAL,
3850 EL_DC_STEELWALL_1_VERTICAL,
3851 EL_DC_STEELWALL_1_TOPLEFT,
3852 EL_DC_STEELWALL_1_TOPRIGHT,
3853 EL_DC_STEELWALL_1_BOTTOMLEFT,
3854 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3855 EL_DC_STEELWALL_1_TOPLEFT_2,
3856 EL_DC_STEELWALL_1_TOPRIGHT_2,
3857 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3858 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3859 EL_DC_STEELWALL_2_LEFT,
3860 EL_DC_STEELWALL_2_RIGHT,
3861 EL_DC_STEELWALL_2_TOP,
3862 EL_DC_STEELWALL_2_BOTTOM,
3863 EL_DC_STEELWALL_2_HORIZONTAL,
3864 EL_DC_STEELWALL_2_VERTICAL,
3865 EL_DC_STEELWALL_2_MIDDLE,
3866 EL_DC_STEELWALL_2_SINGLE,
3867 EL_STEELWALL_SLIPPERY,
3881 EL_GATE_1_GRAY_ACTIVE,
3882 EL_GATE_2_GRAY_ACTIVE,
3883 EL_GATE_3_GRAY_ACTIVE,
3884 EL_GATE_4_GRAY_ACTIVE,
3893 EL_EM_GATE_1_GRAY_ACTIVE,
3894 EL_EM_GATE_2_GRAY_ACTIVE,
3895 EL_EM_GATE_3_GRAY_ACTIVE,
3896 EL_EM_GATE_4_GRAY_ACTIVE,
3905 EL_EMC_GATE_5_GRAY_ACTIVE,
3906 EL_EMC_GATE_6_GRAY_ACTIVE,
3907 EL_EMC_GATE_7_GRAY_ACTIVE,
3908 EL_EMC_GATE_8_GRAY_ACTIVE,
3910 EL_DC_GATE_WHITE_GRAY,
3911 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3912 EL_DC_GATE_FAKE_GRAY,
3914 EL_SWITCHGATE_OPENING,
3915 EL_SWITCHGATE_CLOSED,
3916 EL_SWITCHGATE_CLOSING,
3917 EL_DC_SWITCHGATE_SWITCH_UP,
3918 EL_DC_SWITCHGATE_SWITCH_DOWN,
3920 EL_TIMEGATE_OPENING,
3922 EL_TIMEGATE_CLOSING,
3923 EL_DC_TIMEGATE_SWITCH,
3924 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3928 EL_TUBE_VERTICAL_LEFT,
3929 EL_TUBE_VERTICAL_RIGHT,
3930 EL_TUBE_HORIZONTAL_UP,
3931 EL_TUBE_HORIZONTAL_DOWN,
3936 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3937 EL_EXPANDABLE_STEELWALL_VERTICAL,
3938 EL_EXPANDABLE_STEELWALL_ANY,
3943 static int ep_classic_enemy[] =
3960 static int ep_belt[] =
3962 EL_CONVEYOR_BELT_1_LEFT,
3963 EL_CONVEYOR_BELT_1_MIDDLE,
3964 EL_CONVEYOR_BELT_1_RIGHT,
3965 EL_CONVEYOR_BELT_2_LEFT,
3966 EL_CONVEYOR_BELT_2_MIDDLE,
3967 EL_CONVEYOR_BELT_2_RIGHT,
3968 EL_CONVEYOR_BELT_3_LEFT,
3969 EL_CONVEYOR_BELT_3_MIDDLE,
3970 EL_CONVEYOR_BELT_3_RIGHT,
3971 EL_CONVEYOR_BELT_4_LEFT,
3972 EL_CONVEYOR_BELT_4_MIDDLE,
3973 EL_CONVEYOR_BELT_4_RIGHT,
3978 static int ep_belt_active[] =
3980 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3981 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3982 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3983 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3984 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3985 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3986 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3987 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3988 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3989 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3990 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3991 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3996 static int ep_belt_switch[] =
3998 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3999 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4000 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4001 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4002 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4003 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4004 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4005 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4006 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4007 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4008 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4009 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4014 static int ep_tube[] =
4021 EL_TUBE_HORIZONTAL_UP,
4022 EL_TUBE_HORIZONTAL_DOWN,
4024 EL_TUBE_VERTICAL_LEFT,
4025 EL_TUBE_VERTICAL_RIGHT,
4031 static int ep_acid_pool[] =
4033 EL_ACID_POOL_TOPLEFT,
4034 EL_ACID_POOL_TOPRIGHT,
4035 EL_ACID_POOL_BOTTOMLEFT,
4036 EL_ACID_POOL_BOTTOM,
4037 EL_ACID_POOL_BOTTOMRIGHT,
4042 static int ep_keygate[] =
4052 EL_GATE_1_GRAY_ACTIVE,
4053 EL_GATE_2_GRAY_ACTIVE,
4054 EL_GATE_3_GRAY_ACTIVE,
4055 EL_GATE_4_GRAY_ACTIVE,
4064 EL_EM_GATE_1_GRAY_ACTIVE,
4065 EL_EM_GATE_2_GRAY_ACTIVE,
4066 EL_EM_GATE_3_GRAY_ACTIVE,
4067 EL_EM_GATE_4_GRAY_ACTIVE,
4076 EL_EMC_GATE_5_GRAY_ACTIVE,
4077 EL_EMC_GATE_6_GRAY_ACTIVE,
4078 EL_EMC_GATE_7_GRAY_ACTIVE,
4079 EL_EMC_GATE_8_GRAY_ACTIVE,
4081 EL_DC_GATE_WHITE_GRAY,
4082 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4087 static int ep_amoeboid[] =
4099 static int ep_amoebalive[] =
4110 static int ep_has_editor_content[] =
4116 EL_SOKOBAN_FIELD_PLAYER,
4133 static int ep_can_turn_each_move[] =
4135 // !!! do something with this one !!!
4139 static int ep_can_grow[] =
4153 static int ep_active_bomb[] =
4156 EL_EM_DYNAMITE_ACTIVE,
4157 EL_DYNABOMB_PLAYER_1_ACTIVE,
4158 EL_DYNABOMB_PLAYER_2_ACTIVE,
4159 EL_DYNABOMB_PLAYER_3_ACTIVE,
4160 EL_DYNABOMB_PLAYER_4_ACTIVE,
4161 EL_SP_DISK_RED_ACTIVE,
4166 static int ep_inactive[] =
4192 EL_QUICKSAND_FAST_EMPTY,
4215 EL_GATE_1_GRAY_ACTIVE,
4216 EL_GATE_2_GRAY_ACTIVE,
4217 EL_GATE_3_GRAY_ACTIVE,
4218 EL_GATE_4_GRAY_ACTIVE,
4227 EL_EM_GATE_1_GRAY_ACTIVE,
4228 EL_EM_GATE_2_GRAY_ACTIVE,
4229 EL_EM_GATE_3_GRAY_ACTIVE,
4230 EL_EM_GATE_4_GRAY_ACTIVE,
4239 EL_EMC_GATE_5_GRAY_ACTIVE,
4240 EL_EMC_GATE_6_GRAY_ACTIVE,
4241 EL_EMC_GATE_7_GRAY_ACTIVE,
4242 EL_EMC_GATE_8_GRAY_ACTIVE,
4244 EL_DC_GATE_WHITE_GRAY,
4245 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4246 EL_DC_GATE_FAKE_GRAY,
4249 EL_INVISIBLE_STEELWALL,
4257 EL_WALL_EMERALD_YELLOW,
4258 EL_DYNABOMB_INCREASE_NUMBER,
4259 EL_DYNABOMB_INCREASE_SIZE,
4260 EL_DYNABOMB_INCREASE_POWER,
4264 EL_SOKOBAN_FIELD_EMPTY,
4265 EL_SOKOBAN_FIELD_FULL,
4266 EL_WALL_EMERALD_RED,
4267 EL_WALL_EMERALD_PURPLE,
4268 EL_ACID_POOL_TOPLEFT,
4269 EL_ACID_POOL_TOPRIGHT,
4270 EL_ACID_POOL_BOTTOMLEFT,
4271 EL_ACID_POOL_BOTTOM,
4272 EL_ACID_POOL_BOTTOMRIGHT,
4276 EL_BD_MAGIC_WALL_DEAD,
4278 EL_DC_MAGIC_WALL_DEAD,
4279 EL_AMOEBA_TO_DIAMOND,
4287 EL_SP_GRAVITY_PORT_RIGHT,
4288 EL_SP_GRAVITY_PORT_DOWN,
4289 EL_SP_GRAVITY_PORT_LEFT,
4290 EL_SP_GRAVITY_PORT_UP,
4291 EL_SP_PORT_HORIZONTAL,
4292 EL_SP_PORT_VERTICAL,
4303 EL_SP_HARDWARE_GRAY,
4304 EL_SP_HARDWARE_GREEN,
4305 EL_SP_HARDWARE_BLUE,
4307 EL_SP_HARDWARE_YELLOW,
4308 EL_SP_HARDWARE_BASE_1,
4309 EL_SP_HARDWARE_BASE_2,
4310 EL_SP_HARDWARE_BASE_3,
4311 EL_SP_HARDWARE_BASE_4,
4312 EL_SP_HARDWARE_BASE_5,
4313 EL_SP_HARDWARE_BASE_6,
4314 EL_SP_GRAVITY_ON_PORT_LEFT,
4315 EL_SP_GRAVITY_ON_PORT_RIGHT,
4316 EL_SP_GRAVITY_ON_PORT_UP,
4317 EL_SP_GRAVITY_ON_PORT_DOWN,
4318 EL_SP_GRAVITY_OFF_PORT_LEFT,
4319 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4320 EL_SP_GRAVITY_OFF_PORT_UP,
4321 EL_SP_GRAVITY_OFF_PORT_DOWN,
4322 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4323 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4324 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4325 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4326 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4327 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4328 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4329 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4330 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4331 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4332 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4333 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4334 EL_SIGN_EXCLAMATION,
4335 EL_SIGN_RADIOACTIVITY,
4342 EL_SIGN_ENTRY_FORBIDDEN,
4343 EL_SIGN_EMERGENCY_EXIT,
4351 EL_DC_STEELWALL_1_LEFT,
4352 EL_DC_STEELWALL_1_RIGHT,
4353 EL_DC_STEELWALL_1_TOP,
4354 EL_DC_STEELWALL_1_BOTTOM,
4355 EL_DC_STEELWALL_1_HORIZONTAL,
4356 EL_DC_STEELWALL_1_VERTICAL,
4357 EL_DC_STEELWALL_1_TOPLEFT,
4358 EL_DC_STEELWALL_1_TOPRIGHT,
4359 EL_DC_STEELWALL_1_BOTTOMLEFT,
4360 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4361 EL_DC_STEELWALL_1_TOPLEFT_2,
4362 EL_DC_STEELWALL_1_TOPRIGHT_2,
4363 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4364 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4365 EL_DC_STEELWALL_2_LEFT,
4366 EL_DC_STEELWALL_2_RIGHT,
4367 EL_DC_STEELWALL_2_TOP,
4368 EL_DC_STEELWALL_2_BOTTOM,
4369 EL_DC_STEELWALL_2_HORIZONTAL,
4370 EL_DC_STEELWALL_2_VERTICAL,
4371 EL_DC_STEELWALL_2_MIDDLE,
4372 EL_DC_STEELWALL_2_SINGLE,
4373 EL_STEELWALL_SLIPPERY,
4378 EL_EMC_WALL_SLIPPERY_1,
4379 EL_EMC_WALL_SLIPPERY_2,
4380 EL_EMC_WALL_SLIPPERY_3,
4381 EL_EMC_WALL_SLIPPERY_4,
4402 static int ep_em_slippery_wall[] =
4407 static int ep_gfx_crumbled[] =
4418 static int ep_editor_cascade_active[] =
4420 EL_INTERNAL_CASCADE_BD_ACTIVE,
4421 EL_INTERNAL_CASCADE_EM_ACTIVE,
4422 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4423 EL_INTERNAL_CASCADE_RND_ACTIVE,
4424 EL_INTERNAL_CASCADE_SB_ACTIVE,
4425 EL_INTERNAL_CASCADE_SP_ACTIVE,
4426 EL_INTERNAL_CASCADE_DC_ACTIVE,
4427 EL_INTERNAL_CASCADE_DX_ACTIVE,
4428 EL_INTERNAL_CASCADE_MM_ACTIVE,
4429 EL_INTERNAL_CASCADE_DF_ACTIVE,
4430 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4431 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4432 EL_INTERNAL_CASCADE_CE_ACTIVE,
4433 EL_INTERNAL_CASCADE_GE_ACTIVE,
4434 EL_INTERNAL_CASCADE_ES_ACTIVE,
4435 EL_INTERNAL_CASCADE_REF_ACTIVE,
4436 EL_INTERNAL_CASCADE_USER_ACTIVE,
4437 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4442 static int ep_editor_cascade_inactive[] =
4444 EL_INTERNAL_CASCADE_BD,
4445 EL_INTERNAL_CASCADE_EM,
4446 EL_INTERNAL_CASCADE_EMC,
4447 EL_INTERNAL_CASCADE_RND,
4448 EL_INTERNAL_CASCADE_SB,
4449 EL_INTERNAL_CASCADE_SP,
4450 EL_INTERNAL_CASCADE_DC,
4451 EL_INTERNAL_CASCADE_DX,
4452 EL_INTERNAL_CASCADE_MM,
4453 EL_INTERNAL_CASCADE_DF,
4454 EL_INTERNAL_CASCADE_CHARS,
4455 EL_INTERNAL_CASCADE_STEEL_CHARS,
4456 EL_INTERNAL_CASCADE_CE,
4457 EL_INTERNAL_CASCADE_GE,
4458 EL_INTERNAL_CASCADE_ES,
4459 EL_INTERNAL_CASCADE_REF,
4460 EL_INTERNAL_CASCADE_USER,
4461 EL_INTERNAL_CASCADE_DYNAMIC,
4466 static int ep_obsolete[] =
4470 EL_EM_KEY_1_FILE_OBSOLETE,
4471 EL_EM_KEY_2_FILE_OBSOLETE,
4472 EL_EM_KEY_3_FILE_OBSOLETE,
4473 EL_EM_KEY_4_FILE_OBSOLETE,
4474 EL_ENVELOPE_OBSOLETE,
4483 } element_properties[] =
4485 { ep_diggable, EP_DIGGABLE },
4486 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4487 { ep_dont_run_into, EP_DONT_RUN_INTO },
4488 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4489 { ep_dont_touch, EP_DONT_TOUCH },
4490 { ep_indestructible, EP_INDESTRUCTIBLE },
4491 { ep_slippery, EP_SLIPPERY },
4492 { ep_can_change, EP_CAN_CHANGE },
4493 { ep_can_move, EP_CAN_MOVE },
4494 { ep_can_fall, EP_CAN_FALL },
4495 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4496 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4497 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4498 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4499 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4500 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4501 { ep_walkable_over, EP_WALKABLE_OVER },
4502 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4503 { ep_walkable_under, EP_WALKABLE_UNDER },
4504 { ep_passable_over, EP_PASSABLE_OVER },
4505 { ep_passable_inside, EP_PASSABLE_INSIDE },
4506 { ep_passable_under, EP_PASSABLE_UNDER },
4507 { ep_droppable, EP_DROPPABLE },
4508 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4509 { ep_pushable, EP_PUSHABLE },
4510 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4511 { ep_protected, EP_PROTECTED },
4512 { ep_throwable, EP_THROWABLE },
4513 { ep_can_explode, EP_CAN_EXPLODE },
4514 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4516 { ep_empty_space, EP_EMPTY_SPACE },
4517 { ep_player, EP_PLAYER },
4518 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4519 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4520 { ep_switchable, EP_SWITCHABLE },
4521 { ep_bd_element, EP_BD_ELEMENT },
4522 { ep_sp_element, EP_SP_ELEMENT },
4523 { ep_sb_element, EP_SB_ELEMENT },
4525 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4526 { ep_food_penguin, EP_FOOD_PENGUIN },
4527 { ep_food_pig, EP_FOOD_PIG },
4528 { ep_historic_wall, EP_HISTORIC_WALL },
4529 { ep_historic_solid, EP_HISTORIC_SOLID },
4530 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4531 { ep_belt, EP_BELT },
4532 { ep_belt_active, EP_BELT_ACTIVE },
4533 { ep_belt_switch, EP_BELT_SWITCH },
4534 { ep_tube, EP_TUBE },
4535 { ep_acid_pool, EP_ACID_POOL },
4536 { ep_keygate, EP_KEYGATE },
4537 { ep_amoeboid, EP_AMOEBOID },
4538 { ep_amoebalive, EP_AMOEBALIVE },
4539 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4540 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4541 { ep_can_grow, EP_CAN_GROW },
4542 { ep_active_bomb, EP_ACTIVE_BOMB },
4543 { ep_inactive, EP_INACTIVE },
4545 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4547 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4549 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4550 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4552 { ep_obsolete, EP_OBSOLETE },
4559 // always start with reliable default values (element has no properties)
4560 // (but never initialize clipboard elements after the very first time)
4561 // (to be able to use clipboard elements between several levels)
4562 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4563 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4564 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4565 SET_PROPERTY(i, j, FALSE);
4567 // set all base element properties from above array definitions
4568 for (i = 0; element_properties[i].elements != NULL; i++)
4569 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4570 SET_PROPERTY((element_properties[i].elements)[j],
4571 element_properties[i].property, TRUE);
4573 // copy properties to some elements that are only stored in level file
4574 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4575 for (j = 0; copy_properties[j][0] != -1; j++)
4576 if (HAS_PROPERTY(copy_properties[j][0], i))
4577 for (k = 1; k <= 4; k++)
4578 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4580 // set static element properties that are not listed in array definitions
4581 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4582 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4584 clipboard_elements_initialized = TRUE;
4587 void InitElementPropertiesEngine(int engine_version)
4589 static int no_wall_properties[] =
4592 EP_COLLECTIBLE_ONLY,
4594 EP_DONT_COLLIDE_WITH,
4597 EP_CAN_SMASH_PLAYER,
4598 EP_CAN_SMASH_ENEMIES,
4599 EP_CAN_SMASH_EVERYTHING,
4604 EP_FOOD_DARK_YAMYAM,
4620 /* important: after initialization in InitElementPropertiesStatic(), the
4621 elements are not again initialized to a default value; therefore all
4622 changes have to make sure that they leave the element with a defined
4623 property (which means that conditional property changes must be set to
4624 a reliable default value before) */
4626 // resolve group elements
4627 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4628 ResolveGroupElement(EL_GROUP_START + i);
4630 // set all special, combined or engine dependent element properties
4631 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4633 // do not change (already initialized) clipboard elements here
4634 if (IS_CLIPBOARD_ELEMENT(i))
4637 // ---------- INACTIVE ----------------------------------------------------
4638 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4639 i <= EL_CHAR_END) ||
4640 (i >= EL_STEEL_CHAR_START &&
4641 i <= EL_STEEL_CHAR_END)));
4643 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4644 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4645 IS_WALKABLE_INSIDE(i) ||
4646 IS_WALKABLE_UNDER(i)));
4648 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4649 IS_PASSABLE_INSIDE(i) ||
4650 IS_PASSABLE_UNDER(i)));
4652 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4653 IS_PASSABLE_OVER(i)));
4655 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4656 IS_PASSABLE_INSIDE(i)));
4658 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4659 IS_PASSABLE_UNDER(i)));
4661 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4664 // ---------- COLLECTIBLE -------------------------------------------------
4665 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4669 // ---------- SNAPPABLE ---------------------------------------------------
4670 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4671 IS_COLLECTIBLE(i) ||
4675 // ---------- WALL --------------------------------------------------------
4676 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4678 for (j = 0; no_wall_properties[j] != -1; j++)
4679 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4680 i >= EL_FIRST_RUNTIME_UNREAL)
4681 SET_PROPERTY(i, EP_WALL, FALSE);
4683 if (IS_HISTORIC_WALL(i))
4684 SET_PROPERTY(i, EP_WALL, TRUE);
4686 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4687 if (engine_version < VERSION_IDENT(2,2,0,0))
4688 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4690 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4692 !IS_COLLECTIBLE(i)));
4694 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4695 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4696 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4698 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4701 // ---------- EXPLOSION_PROOF ---------------------------------------------
4703 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4704 else if (engine_version < VERSION_IDENT(2,2,0,0))
4705 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4707 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4711 if (IS_CUSTOM_ELEMENT(i))
4713 // these are additional properties which are initially false when set
4715 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4717 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4718 if (DONT_COLLIDE_WITH(i))
4719 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4721 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4722 if (CAN_SMASH_EVERYTHING(i))
4723 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4724 if (CAN_SMASH_ENEMIES(i))
4725 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4728 // ---------- CAN_SMASH ---------------------------------------------------
4729 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4730 CAN_SMASH_ENEMIES(i) ||
4731 CAN_SMASH_EVERYTHING(i)));
4733 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4734 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4735 EXPLODES_BY_FIRE(i)));
4737 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4738 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4739 EXPLODES_SMASHED(i)));
4741 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4742 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4743 EXPLODES_IMPACT(i)));
4745 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4746 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4748 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4749 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4750 i == EL_BLACK_ORB));
4752 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4753 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4755 IS_CUSTOM_ELEMENT(i)));
4757 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4758 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4759 i == EL_SP_ELECTRON));
4761 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4762 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4763 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4764 getMoveIntoAcidProperty(&level, i));
4766 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4767 if (MAYBE_DONT_COLLIDE_WITH(i))
4768 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4769 getDontCollideWithProperty(&level, i));
4771 // ---------- SP_PORT -----------------------------------------------------
4772 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4773 IS_PASSABLE_INSIDE(i)));
4775 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4776 for (j = 0; j < level.num_android_clone_elements; j++)
4777 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4779 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4781 // ---------- CAN_CHANGE --------------------------------------------------
4782 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4783 for (j = 0; j < element_info[i].num_change_pages; j++)
4784 if (element_info[i].change_page[j].can_change)
4785 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4787 // ---------- HAS_ACTION --------------------------------------------------
4788 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4789 for (j = 0; j < element_info[i].num_change_pages; j++)
4790 if (element_info[i].change_page[j].has_action)
4791 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4793 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4794 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4797 // ---------- GFX_CRUMBLED ------------------------------------------------
4798 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4799 element_info[i].crumbled[ACTION_DEFAULT] !=
4800 element_info[i].graphic[ACTION_DEFAULT]);
4802 // ---------- EDITOR_CASCADE ----------------------------------------------
4803 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4804 IS_EDITOR_CASCADE_INACTIVE(i)));
4807 // dynamically adjust element properties according to game engine version
4809 static int ep_em_slippery_wall[] =
4814 EL_EXPANDABLE_WALL_HORIZONTAL,
4815 EL_EXPANDABLE_WALL_VERTICAL,
4816 EL_EXPANDABLE_WALL_ANY,
4817 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4818 EL_EXPANDABLE_STEELWALL_VERTICAL,
4819 EL_EXPANDABLE_STEELWALL_ANY,
4820 EL_EXPANDABLE_STEELWALL_GROWING,
4824 static int ep_em_explodes_by_fire[] =
4827 EL_EM_DYNAMITE_ACTIVE,
4832 // special EM style gems behaviour
4833 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4834 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4835 level.em_slippery_gems);
4837 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4838 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4839 (level.em_slippery_gems &&
4840 engine_version > VERSION_IDENT(2,0,1,0)));
4842 // special EM style explosion behaviour regarding chain reactions
4843 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4844 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4845 level.em_explodes_by_fire);
4848 // this is needed because some graphics depend on element properties
4849 if (game_status == GAME_MODE_PLAYING)
4850 InitElementGraphicInfo();
4853 void InitElementPropertiesGfxElement(void)
4857 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4859 struct ElementInfo *ei = &element_info[i];
4861 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4865 static void InitGlobal(void)
4870 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4872 // check if element_name_info entry defined for each element in "main.h"
4873 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4874 Fail("undefined 'element_name_info' entry for element %d", i);
4876 element_info[i].token_name = element_name_info[i].token_name;
4877 element_info[i].class_name = element_name_info[i].class_name;
4878 element_info[i].editor_description= element_name_info[i].editor_description;
4881 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4883 // check if global_anim_name_info defined for each entry in "main.h"
4884 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4885 global_anim_name_info[i].token_name == NULL)
4886 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4888 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4891 // create hash from image config list
4892 image_config_hash = newSetupFileHash();
4893 for (i = 0; image_config[i].token != NULL; i++)
4894 setHashEntry(image_config_hash,
4895 image_config[i].token,
4896 image_config[i].value);
4898 // create hash from element token list
4899 element_token_hash = newSetupFileHash();
4900 for (i = 0; element_name_info[i].token_name != NULL; i++)
4901 setHashEntry(element_token_hash,
4902 element_name_info[i].token_name,
4905 // create hash from graphic token list
4906 graphic_token_hash = newSetupFileHash();
4907 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4908 if (strSuffix(image_config[i].value, ".png") ||
4909 strSuffix(image_config[i].value, ".pcx") ||
4910 strSuffix(image_config[i].value, ".wav") ||
4911 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4912 setHashEntry(graphic_token_hash,
4913 image_config[i].token,
4914 int2str(graphic++, 0));
4916 // create hash from font token list
4917 font_token_hash = newSetupFileHash();
4918 for (i = 0; font_info[i].token_name != NULL; i++)
4919 setHashEntry(font_token_hash,
4920 font_info[i].token_name,
4923 // set default filenames for all cloned graphics in static configuration
4924 for (i = 0; image_config[i].token != NULL; i++)
4926 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4928 char *token = image_config[i].token;
4929 char *token_clone_from = getStringCat2(token, ".clone_from");
4930 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4932 if (token_cloned != NULL)
4934 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4936 if (value_cloned != NULL)
4938 // set default filename in static configuration
4939 image_config[i].value = value_cloned;
4941 // set default filename in image config hash
4942 setHashEntry(image_config_hash, token, value_cloned);
4946 free(token_clone_from);
4950 // always start with reliable default values (all elements)
4951 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4952 ActiveElement[i] = i;
4954 // now add all entries that have an active state (active elements)
4955 for (i = 0; element_with_active_state[i].element != -1; i++)
4957 int element = element_with_active_state[i].element;
4958 int element_active = element_with_active_state[i].element_active;
4960 ActiveElement[element] = element_active;
4963 // always start with reliable default values (all buttons)
4964 for (i = 0; i < NUM_IMAGE_FILES; i++)
4965 ActiveButton[i] = i;
4967 // now add all entries that have an active state (active buttons)
4968 for (i = 0; button_with_active_state[i].button != -1; i++)
4970 int button = button_with_active_state[i].button;
4971 int button_active = button_with_active_state[i].button_active;
4973 ActiveButton[button] = button_active;
4976 // always start with reliable default values (all fonts)
4977 for (i = 0; i < NUM_FONTS; i++)
4980 // now add all entries that have an active state (active fonts)
4981 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4983 int font = font_with_active_state[i].font_nr;
4984 int font_active = font_with_active_state[i].font_nr_active;
4986 ActiveFont[font] = font_active;
4989 global.autoplay_leveldir = NULL;
4990 global.patchtapes_leveldir = NULL;
4991 global.convert_leveldir = NULL;
4992 global.dumplevel_leveldir = NULL;
4993 global.dumptape_leveldir = NULL;
4994 global.create_sketch_images_dir = NULL;
4995 global.create_collect_images_dir = NULL;
4997 global.frames_per_second = 0;
4998 global.show_frames_per_second = FALSE;
5000 global.border_status = GAME_MODE_LOADING;
5001 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5003 global.use_envelope_request = FALSE;
5005 global.user_names = NULL;
5008 static void Execute_Command(char *command)
5012 if (strEqual(command, "print graphicsinfo.conf"))
5014 Print("# You can configure additional/alternative image files here.\n");
5015 Print("# (The entries below are default and therefore commented out.)\n");
5017 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5019 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5022 for (i = 0; image_config[i].token != NULL; i++)
5023 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5024 image_config[i].value));
5028 else if (strEqual(command, "print soundsinfo.conf"))
5030 Print("# You can configure additional/alternative sound files here.\n");
5031 Print("# (The entries below are default and therefore commented out.)\n");
5033 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5035 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5038 for (i = 0; sound_config[i].token != NULL; i++)
5039 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5040 sound_config[i].value));
5044 else if (strEqual(command, "print musicinfo.conf"))
5046 Print("# You can configure additional/alternative music files here.\n");
5047 Print("# (The entries below are default and therefore commented out.)\n");
5049 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5051 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5054 for (i = 0; music_config[i].token != NULL; i++)
5055 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5056 music_config[i].value));
5060 else if (strEqual(command, "print editorsetup.conf"))
5062 Print("# You can configure your personal editor element list here.\n");
5063 Print("# (The entries below are default and therefore commented out.)\n");
5066 // this is needed to be able to check element list for cascade elements
5067 InitElementPropertiesStatic();
5068 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5070 PrintEditorElementList();
5074 else if (strEqual(command, "print helpanim.conf"))
5076 Print("# You can configure different element help animations here.\n");
5077 Print("# (The entries below are default and therefore commented out.)\n");
5080 for (i = 0; helpanim_config[i].token != NULL; i++)
5082 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5083 helpanim_config[i].value));
5085 if (strEqual(helpanim_config[i].token, "end"))
5091 else if (strEqual(command, "print helptext.conf"))
5093 Print("# You can configure different element help text here.\n");
5094 Print("# (The entries below are default and therefore commented out.)\n");
5097 for (i = 0; helptext_config[i].token != NULL; i++)
5098 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5099 helptext_config[i].value));
5103 else if (strPrefix(command, "dump level "))
5105 char *filename = &command[11];
5107 if (fileExists(filename))
5109 LoadLevelFromFilename(&level, filename);
5115 char *leveldir = getStringCopy(filename); // read command parameters
5116 char *level_nr = strchr(leveldir, ' ');
5118 if (level_nr == NULL)
5119 Fail("cannot open file '%s'", filename);
5123 global.dumplevel_leveldir = leveldir;
5124 global.dumplevel_level_nr = atoi(level_nr);
5126 program.headless = TRUE;
5128 else if (strPrefix(command, "dump tape "))
5130 char *filename = &command[10];
5132 if (fileExists(filename))
5134 LoadTapeFromFilename(filename);
5140 char *leveldir = getStringCopy(filename); // read command parameters
5141 char *level_nr = strchr(leveldir, ' ');
5143 if (level_nr == NULL)
5144 Fail("cannot open file '%s'", filename);
5148 global.dumptape_leveldir = leveldir;
5149 global.dumptape_level_nr = atoi(level_nr);
5151 program.headless = TRUE;
5153 else if (strPrefix(command, "autoplay ") ||
5154 strPrefix(command, "autoffwd ") ||
5155 strPrefix(command, "autowarp ") ||
5156 strPrefix(command, "autotest ") ||
5157 strPrefix(command, "autosave ") ||
5158 strPrefix(command, "autoupload ") ||
5159 strPrefix(command, "autofix "))
5161 char *arg_ptr = strchr(command, ' ');
5162 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5164 global.autoplay_mode =
5165 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5166 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5167 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5168 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5169 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5170 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5171 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5172 AUTOPLAY_MODE_NONE);
5174 while (*str_ptr != '\0') // continue parsing string
5176 // cut leading whitespace from string, replace it by string terminator
5177 while (*str_ptr == ' ' || *str_ptr == '\t')
5180 if (*str_ptr == '\0') // end of string reached
5183 if (global.autoplay_leveldir == NULL) // read level set string
5185 global.autoplay_leveldir = str_ptr;
5186 global.autoplay_all = TRUE; // default: play all tapes
5188 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5189 global.autoplay_level[i] = FALSE;
5191 else // read level number string
5193 int level_nr = atoi(str_ptr); // get level_nr value
5195 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5196 global.autoplay_level[level_nr] = TRUE;
5198 global.autoplay_all = FALSE;
5201 // advance string pointer to the next whitespace (or end of string)
5202 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5206 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5207 program.headless = TRUE;
5209 else if (strPrefix(command, "patch tapes "))
5211 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5213 // skip leading whitespace
5214 while (*str_ptr == ' ' || *str_ptr == '\t')
5217 if (*str_ptr == '\0')
5218 Fail("cannot find MODE in command '%s'", command);
5220 global.patchtapes_mode = str_ptr; // store patch mode
5222 // advance to next whitespace (or end of string)
5223 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5226 while (*str_ptr != '\0') // continue parsing string
5228 // cut leading whitespace from string, replace it by string terminator
5229 while (*str_ptr == ' ' || *str_ptr == '\t')
5232 if (*str_ptr == '\0') // end of string reached
5235 if (global.patchtapes_leveldir == NULL) // read level set string
5237 global.patchtapes_leveldir = str_ptr;
5238 global.patchtapes_all = TRUE; // default: patch all tapes
5240 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5241 global.patchtapes_level[i] = FALSE;
5243 else // read level number string
5245 int level_nr = atoi(str_ptr); // get level_nr value
5247 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5248 global.patchtapes_level[level_nr] = TRUE;
5250 global.patchtapes_all = FALSE;
5253 // advance string pointer to the next whitespace (or end of string)
5254 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5258 if (global.patchtapes_leveldir == NULL)
5260 if (strEqual(global.patchtapes_mode, "help"))
5261 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5263 Fail("cannot find LEVELDIR in command '%s'", command);
5266 program.headless = TRUE;
5268 else if (strPrefix(command, "convert "))
5270 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5271 char *str_ptr = strchr(str_copy, ' ');
5273 global.convert_leveldir = str_copy;
5274 global.convert_level_nr = -1;
5276 if (str_ptr != NULL) // level number follows
5278 *str_ptr++ = '\0'; // terminate leveldir string
5279 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5282 program.headless = TRUE;
5284 else if (strPrefix(command, "create sketch images "))
5286 global.create_sketch_images_dir = getStringCopy(&command[21]);
5288 if (access(global.create_sketch_images_dir, W_OK) != 0)
5289 Fail("image target directory '%s' not found or not writable",
5290 global.create_sketch_images_dir);
5292 else if (strPrefix(command, "create collect image "))
5294 global.create_collect_images_dir = getStringCopy(&command[21]);
5296 if (access(global.create_collect_images_dir, W_OK) != 0)
5297 Fail("image target directory '%s' not found or not writable",
5298 global.create_collect_images_dir);
5300 else if (strPrefix(command, "create CE image "))
5302 CreateCustomElementImages(&command[16]);
5308 FailWithHelp("unrecognized command '%s'", command);
5311 // disable networking if any valid command was recognized
5312 options.network = setup.network_mode = FALSE;
5315 static void InitSetup(void)
5317 LoadUserNames(); // global user names
5318 LoadUserSetup(); // global user number
5320 LoadSetup(); // global setup info
5322 // set some options from setup file
5324 if (setup.options.verbose)
5325 options.verbose = TRUE;
5327 if (setup.debug.show_frames_per_second)
5328 global.show_frames_per_second = TRUE;
5331 static void InitGameInfo(void)
5333 game.restart_level = FALSE;
5334 game.restart_game_message = NULL;
5336 game.request_active = FALSE;
5337 game.request_active_or_moving = FALSE;
5339 game.use_masked_elements_initial = FALSE;
5342 static void InitPlayerInfo(void)
5346 // choose default local player
5347 local_player = &stored_player[0];
5349 for (i = 0; i < MAX_PLAYERS; i++)
5351 stored_player[i].connected_locally = FALSE;
5352 stored_player[i].connected_network = FALSE;
5355 local_player->connected_locally = TRUE;
5358 static void InitArtworkInfo(void)
5363 static char *get_string_in_brackets(char *string)
5365 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5367 sprintf(string_in_brackets, "[%s]", string);
5369 return string_in_brackets;
5372 static char *get_level_id_suffix(int id_nr)
5374 char *id_suffix = checked_malloc(1 + 3 + 1);
5376 if (id_nr < 0 || id_nr > 999)
5379 sprintf(id_suffix, ".%03d", id_nr);
5384 static void InitArtworkConfig(void)
5386 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5388 NUM_GLOBAL_ANIM_TOKENS + 1];
5389 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5390 NUM_GLOBAL_ANIM_TOKENS + 1];
5391 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5392 NUM_GLOBAL_ANIM_TOKENS + 1];
5393 static char *action_id_suffix[NUM_ACTIONS + 1];
5394 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5395 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5396 static char *level_id_suffix[MAX_LEVELS + 1];
5397 static char *dummy[1] = { NULL };
5398 static char *ignore_generic_tokens[] =
5403 "program_copyright",
5408 static char **ignore_image_tokens;
5409 static char **ignore_sound_tokens;
5410 static char **ignore_music_tokens;
5411 int num_ignore_generic_tokens;
5412 int num_ignore_image_tokens;
5413 int num_ignore_sound_tokens;
5414 int num_ignore_music_tokens;
5417 // dynamically determine list of generic tokens to be ignored
5418 num_ignore_generic_tokens = 0;
5419 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5420 num_ignore_generic_tokens++;
5422 // dynamically determine list of image tokens to be ignored
5423 num_ignore_image_tokens = num_ignore_generic_tokens;
5424 for (i = 0; image_config_vars[i].token != NULL; i++)
5425 num_ignore_image_tokens++;
5426 ignore_image_tokens =
5427 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5428 for (i = 0; i < num_ignore_generic_tokens; i++)
5429 ignore_image_tokens[i] = ignore_generic_tokens[i];
5430 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5431 ignore_image_tokens[num_ignore_generic_tokens + i] =
5432 image_config_vars[i].token;
5433 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5435 // dynamically determine list of sound tokens to be ignored
5436 num_ignore_sound_tokens = num_ignore_generic_tokens;
5437 ignore_sound_tokens =
5438 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5439 for (i = 0; i < num_ignore_generic_tokens; i++)
5440 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5441 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5443 // dynamically determine list of music tokens to be ignored
5444 num_ignore_music_tokens = num_ignore_generic_tokens;
5445 ignore_music_tokens =
5446 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5447 for (i = 0; i < num_ignore_generic_tokens; i++)
5448 ignore_music_tokens[i] = ignore_generic_tokens[i];
5449 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5451 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5452 image_id_prefix[i] = element_info[i].token_name;
5453 for (i = 0; i < NUM_FONTS; i++)
5454 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5455 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5456 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5457 global_anim_info[i].token_name;
5458 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5461 sound_id_prefix[i] = element_info[i].token_name;
5462 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5463 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5464 get_string_in_brackets(element_info[i].class_name);
5465 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5466 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5467 global_anim_info[i].token_name;
5468 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5470 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5471 music_id_prefix[i] = music_prefix_info[i].prefix;
5472 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5473 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5474 global_anim_info[i].token_name;
5475 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5477 for (i = 0; i < NUM_ACTIONS; i++)
5478 action_id_suffix[i] = element_action_info[i].suffix;
5479 action_id_suffix[NUM_ACTIONS] = NULL;
5481 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5482 direction_id_suffix[i] = element_direction_info[i].suffix;
5483 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5485 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5486 special_id_suffix[i] = special_suffix_info[i].suffix;
5487 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5489 for (i = 0; i < MAX_LEVELS; i++)
5490 level_id_suffix[i] = get_level_id_suffix(i);
5491 level_id_suffix[MAX_LEVELS] = NULL;
5493 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5494 image_id_prefix, action_id_suffix, direction_id_suffix,
5495 special_id_suffix, ignore_image_tokens);
5496 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5497 sound_id_prefix, action_id_suffix, dummy,
5498 special_id_suffix, ignore_sound_tokens);
5499 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5500 music_id_prefix, action_id_suffix, special_id_suffix,
5501 level_id_suffix, ignore_music_tokens);
5504 static void InitMixer(void)
5511 static void InitVideoOverlay(void)
5513 // if virtual buttons are not loaded from setup file, repeat initializing
5514 // virtual buttons grid with default values now that video is initialized
5515 if (!setup.touch.grid_initialized)
5518 InitTileCursorInfo();
5522 void InitGfxBuffers(void)
5524 static int win_xsize_last = -1;
5525 static int win_ysize_last = -1;
5527 // create additional image buffers for double-buffering and cross-fading
5529 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5531 // used to temporarily store the backbuffer -- only re-create if changed
5532 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5533 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5535 win_xsize_last = WIN_XSIZE;
5536 win_ysize_last = WIN_YSIZE;
5539 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5540 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5541 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5542 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5544 // initialize screen properties
5545 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5546 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5548 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5549 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5550 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5551 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5552 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5553 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5555 // required if door size definitions have changed
5556 InitGraphicCompatibilityInfo_Doors();
5558 InitGfxBuffers_EM();
5559 InitGfxBuffers_SP();
5562 static void InitGfx(void)
5564 struct GraphicInfo *graphic_info_last = graphic_info;
5565 char *filename_font_initial = NULL;
5566 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5567 char *image_token[NUM_INITIAL_IMAGES] =
5569 CONFIG_TOKEN_GLOBAL_BUSY,
5570 CONFIG_TOKEN_BACKGROUND_LOADING
5572 Bitmap *bitmap_font_initial = NULL;
5573 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5576 // determine settings for initial font (for displaying startup messages)
5577 for (i = 0; image_config[i].token != NULL; i++)
5579 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5581 char font_token[128];
5584 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5585 len_font_token = strlen(font_token);
5587 if (strEqual(image_config[i].token, font_token))
5589 filename_font_initial = image_config[i].value;
5591 else if (strlen(image_config[i].token) > len_font_token &&
5592 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5594 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5595 font_initial[j].src_x = atoi(image_config[i].value);
5596 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5597 font_initial[j].src_y = atoi(image_config[i].value);
5598 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5599 font_initial[j].width = atoi(image_config[i].value);
5600 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5601 font_initial[j].height = atoi(image_config[i].value);
5606 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5608 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5609 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5612 if (filename_font_initial == NULL) // should not happen
5613 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5616 InitGfxCustomArtworkInfo();
5617 InitGfxOtherSettings();
5619 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5621 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5623 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5624 font_initial[j].bitmap = bitmap_font_initial;
5626 InitFontGraphicInfo();
5630 DrawInitTextHead("Loading graphics");
5632 InitMenuDesignSettings_Static();
5634 // initialize settings for initial images with default values
5635 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5636 for (j = 0; j < NUM_GFX_ARGS; j++)
5638 get_graphic_parameter_value(image_config_suffix[j].value,
5639 image_config_suffix[j].token,
5640 image_config_suffix[j].type);
5642 // read settings for initial images from default custom artwork config
5643 char *gfx_config_filename = getPath3(options.graphics_directory,
5645 GRAPHICSINFO_FILENAME);
5647 if (fileExists(gfx_config_filename))
5649 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5651 if (setup_file_hash)
5653 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5655 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5659 filename_image_initial[i] = getStringCopy(filename);
5661 for (j = 0; image_config_suffix[j].token != NULL; j++)
5663 int type = image_config_suffix[j].type;
5664 char *suffix = image_config_suffix[j].token;
5665 char *token = getStringCat2(image_token[i], suffix);
5666 char *value = getHashEntry(setup_file_hash, token);
5668 checked_free(token);
5672 get_graphic_parameter_value(value, suffix, type);
5677 // read values from custom graphics config file
5678 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5680 freeSetupFileHash(setup_file_hash);
5684 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5686 if (filename_image_initial[i] == NULL)
5688 int len_token = strlen(image_token[i]);
5690 // read settings for initial images from static default artwork config
5691 for (j = 0; image_config[j].token != NULL; j++)
5693 if (strEqual(image_config[j].token, image_token[i]))
5695 filename_image_initial[i] = getStringCopy(image_config[j].value);
5697 else if (strlen(image_config[j].token) > len_token &&
5698 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5700 for (k = 0; image_config_suffix[k].token != NULL; k++)
5702 if (strEqual(&image_config[j].token[len_token],
5703 image_config_suffix[k].token))
5705 get_graphic_parameter_value(image_config[j].value,
5706 image_config_suffix[k].token,
5707 image_config_suffix[k].type);
5714 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5716 if (filename_image_initial[i] == NULL) // should not happen
5717 Fail("cannot get filename for '%s'", image_token[i]);
5719 image_initial[i].bitmaps =
5720 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5722 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5723 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5724 LoadCustomImage(filename_image_initial[i]);
5726 checked_free(filename_image_initial[i]);
5729 graphic_info = image_initial; // graphic == 0 => image_initial
5731 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5732 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5734 graphic_info = graphic_info_last;
5736 SetLoadingBackgroundImage();
5738 ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5740 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5741 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5742 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5743 InitGfxDrawTileCursorFunction(DrawTileCursor);
5745 gfx.fade_border_source_status = global.border_status;
5746 gfx.fade_border_target_status = global.border_status;
5747 gfx.masked_border_bitmap_ptr = backbuffer;
5749 // use copy of busy animation to prevent change while reloading artwork
5753 static void InitGfxBackground(void)
5755 fieldbuffer = bitmap_db_field;
5756 SetDrawtoField(DRAW_TO_BACKBUFFER);
5758 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5760 redraw_mask = REDRAW_ALL;
5763 static void InitLevelInfo(void)
5765 LoadLevelInfo(); // global level info
5766 LoadLevelSetup_LastSeries(); // last played series info
5767 LoadLevelSetup_SeriesInfo(); // last played level info
5769 if (global.autoplay_leveldir &&
5770 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5772 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5773 global.autoplay_leveldir);
5774 if (leveldir_current == NULL)
5775 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5778 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5781 static void InitLevelArtworkInfo(void)
5783 LoadLevelArtworkInfo();
5786 static void InitImages(void)
5788 print_timestamp_init("InitImages");
5791 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5792 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5793 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5794 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5795 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5796 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5797 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5798 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5801 setLevelArtworkDir(artwork.gfx_first);
5804 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5805 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5806 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5807 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5808 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5809 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5810 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5811 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5815 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5816 leveldir_current->identifier,
5817 artwork.gfx_current_identifier,
5818 artwork.gfx_current->identifier,
5819 leveldir_current->graphics_set,
5820 leveldir_current->graphics_path);
5823 UPDATE_BUSY_STATE();
5825 ReloadCustomImages();
5826 print_timestamp_time("ReloadCustomImages");
5828 UPDATE_BUSY_STATE();
5830 LoadCustomElementDescriptions();
5831 print_timestamp_time("LoadCustomElementDescriptions");
5833 UPDATE_BUSY_STATE();
5835 LoadMenuDesignSettings();
5836 print_timestamp_time("LoadMenuDesignSettings");
5838 UPDATE_BUSY_STATE();
5840 ReinitializeGraphics();
5841 print_timestamp_time("ReinitializeGraphics");
5843 LoadMenuDesignSettings_AfterGraphics();
5844 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5846 UPDATE_BUSY_STATE();
5848 print_timestamp_done("InitImages");
5851 static void InitSound(char *identifier)
5853 print_timestamp_init("InitSound");
5855 if (identifier == NULL)
5856 identifier = artwork.snd_current->identifier;
5858 // set artwork path to send it to the sound server process
5859 setLevelArtworkDir(artwork.snd_first);
5861 InitReloadCustomSounds(identifier);
5862 print_timestamp_time("InitReloadCustomSounds");
5864 ReinitializeSounds();
5865 print_timestamp_time("ReinitializeSounds");
5867 print_timestamp_done("InitSound");
5870 static void InitMusic(char *identifier)
5872 print_timestamp_init("InitMusic");
5874 if (identifier == NULL)
5875 identifier = artwork.mus_current->identifier;
5877 // set artwork path to send it to the sound server process
5878 setLevelArtworkDir(artwork.mus_first);
5880 InitReloadCustomMusic(identifier);
5881 print_timestamp_time("InitReloadCustomMusic");
5883 ReinitializeMusic();
5884 print_timestamp_time("ReinitializeMusic");
5886 print_timestamp_done("InitMusic");
5889 static void InitArtworkDone(void)
5891 if (program.headless)
5894 InitGlobalAnimations();
5897 static void InitNetworkSettings(void)
5899 boolean network_enabled = (options.network || setup.network_mode);
5900 char *network_server = (options.server_host != NULL ? options.server_host :
5901 setup.network_server_hostname);
5903 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5904 network_server = NULL;
5906 InitNetworkInfo(network_enabled,
5910 options.server_port);
5913 void InitNetworkServer(void)
5915 if (!network.enabled || network.connected)
5918 LimitScreenUpdates(FALSE);
5920 if (game_status == GAME_MODE_LOADING)
5923 if (!ConnectToServer(network.server_host, network.server_port))
5925 network.enabled = FALSE;
5927 setup.network_mode = FALSE;
5931 SendToServer_ProtocolVersion();
5932 SendToServer_PlayerName(setup.player_name);
5933 SendToServer_NrWanted(setup.network_player_nr + 1);
5935 network.connected = TRUE;
5938 // short time to recognize result of network initialization
5939 if (game_status == GAME_MODE_LOADING)
5940 Delay_WithScreenUpdates(1000);
5943 static boolean CheckArtworkConfigForCustomElements(char *filename)
5945 SetupFileHash *setup_file_hash;
5946 boolean redefined_ce_found = FALSE;
5948 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5950 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5952 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5954 char *token = HASH_ITERATION_TOKEN(itr);
5956 if (strPrefix(token, "custom_"))
5958 redefined_ce_found = TRUE;
5963 END_HASH_ITERATION(setup_file_hash, itr)
5965 freeSetupFileHash(setup_file_hash);
5968 return redefined_ce_found;
5971 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5973 char *filename_base, *filename_local;
5974 boolean redefined_ce_found = FALSE;
5976 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5979 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5980 "leveldir_current->identifier == '%s'",
5981 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5982 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5983 "leveldir_current->graphics_path == '%s'",
5984 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5985 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5986 "leveldir_current->graphics_set == '%s'",
5987 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5988 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5989 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5990 leveldir_current == NULL ? "[NULL]" :
5991 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5994 // first look for special artwork configured in level series config
5995 filename_base = getCustomArtworkLevelConfigFilename(type);
5998 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5999 "filename_base == '%s'", filename_base);
6002 if (fileExists(filename_base))
6003 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6005 filename_local = getCustomArtworkConfigFilename(type);
6008 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6009 "filename_local == '%s'", filename_local);
6012 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6013 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6016 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6017 "redefined_ce_found == %d", redefined_ce_found);
6020 return redefined_ce_found;
6023 static void InitOverrideArtwork(void)
6025 boolean redefined_ce_found = FALSE;
6027 // to check if this level set redefines any CEs, do not use overriding
6028 gfx.override_level_graphics = FALSE;
6029 gfx.override_level_sounds = FALSE;
6030 gfx.override_level_music = FALSE;
6032 // now check if this level set has definitions for custom elements
6033 if (setup.override_level_graphics == AUTO ||
6034 setup.override_level_sounds == AUTO ||
6035 setup.override_level_music == AUTO)
6036 redefined_ce_found =
6037 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6038 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6039 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6042 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6043 redefined_ce_found);
6046 if (redefined_ce_found)
6048 // this level set has CE definitions: change "AUTO" to "FALSE"
6049 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6050 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6051 gfx.override_level_music = (setup.override_level_music == TRUE);
6055 // this level set has no CE definitions: change "AUTO" to "TRUE"
6056 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6057 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6058 gfx.override_level_music = (setup.override_level_music != FALSE);
6062 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6063 gfx.override_level_graphics,
6064 gfx.override_level_sounds,
6065 gfx.override_level_music);
6069 static char *getNewArtworkIdentifier(int type)
6071 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6072 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6073 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6074 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6075 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6076 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6077 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6078 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6079 char *leveldir_identifier = leveldir_current->identifier;
6080 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6081 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6082 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6083 TreeInfo *custom_artwork_set =
6084 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6085 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6086 char *artwork_current_identifier;
6087 char *artwork_new_identifier = NULL; // default: nothing has changed
6089 // leveldir_current may be invalid (level group, parent link)
6090 if (!validLevelSeries(leveldir_current))
6093 /* 1st step: determine artwork set to be activated in descending order:
6094 --------------------------------------------------------------------
6095 1. setup artwork (when configured to override everything else)
6096 2. artwork set configured in "levelinfo.conf" of current level set
6097 (artwork in level directory will have priority when loading later)
6098 3. artwork in level directory (stored in artwork sub-directory)
6099 4. setup artwork (currently configured in setup menu) */
6101 if (setup_override_artwork)
6102 artwork_current_identifier = setup_artwork_set;
6103 else if (has_level_artwork_set)
6104 artwork_current_identifier = leveldir_artwork_set;
6105 else if (has_custom_artwork_set)
6106 artwork_current_identifier = leveldir_identifier;
6108 artwork_current_identifier = setup_artwork_set;
6110 /* 2nd step: check if it is really needed to reload artwork set
6111 ------------------------------------------------------------ */
6113 // ---------- reload if level set and also artwork set has changed ----------
6114 if (last_leveldir_identifier[type] != leveldir_identifier &&
6115 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6116 artwork_new_identifier = artwork_current_identifier;
6118 last_leveldir_identifier[type] = leveldir_identifier;
6119 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6121 // ---------- reload if "override artwork" setting has changed --------------
6122 if (last_override_level_artwork[type] != setup_override_artwork)
6123 artwork_new_identifier = artwork_current_identifier;
6125 last_override_level_artwork[type] = setup_override_artwork;
6127 // ---------- reload if current artwork identifier has changed --------------
6128 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6129 artwork_new_identifier = artwork_current_identifier;
6131 // (we cannot compare string pointers here, so copy string content itself)
6132 setString(&last_artwork_identifier[type], artwork_current_identifier);
6134 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6136 // ---------- do not reload directly after starting -------------------------
6137 if (!initialized[type])
6138 artwork_new_identifier = NULL;
6140 initialized[type] = TRUE;
6142 return artwork_new_identifier;
6145 void ReloadCustomArtwork(int force_reload)
6147 int last_game_status = game_status; // save current game status
6148 char *gfx_new_identifier;
6149 char *snd_new_identifier;
6150 char *mus_new_identifier;
6151 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6152 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6153 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6154 boolean reload_needed;
6156 InitOverrideArtwork();
6158 AdjustGraphicsForEMC();
6159 AdjustSoundsForEMC();
6161 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6162 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6163 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6165 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6166 snd_new_identifier != NULL || force_reload_snd ||
6167 mus_new_identifier != NULL || force_reload_mus);
6172 print_timestamp_init("ReloadCustomArtwork");
6174 SetGameStatus(GAME_MODE_LOADING);
6176 FadeOut(REDRAW_ALL);
6178 SetLoadingBackgroundImage();
6180 ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6181 print_timestamp_time("ClearRectangleOnBackground");
6185 UPDATE_BUSY_STATE();
6187 if (gfx_new_identifier != NULL || force_reload_gfx)
6190 Debug("init:ReloadCustomArtwork",
6191 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6192 artwork.gfx_current_identifier,
6194 artwork.gfx_current->identifier,
6195 leveldir_current->graphics_set);
6199 print_timestamp_time("InitImages");
6202 if (snd_new_identifier != NULL || force_reload_snd)
6204 InitSound(snd_new_identifier);
6205 print_timestamp_time("InitSound");
6208 if (mus_new_identifier != NULL || force_reload_mus)
6210 InitMusic(mus_new_identifier);
6211 print_timestamp_time("InitMusic");
6216 SetGameStatus(last_game_status); // restore current game status
6218 FadeOut(REDRAW_ALL);
6220 RedrawGlobalBorder();
6222 // force redraw of (open or closed) door graphics
6223 SetDoorState(DOOR_OPEN_ALL);
6224 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6226 FadeSetEnterScreen();
6227 FadeSkipNextFadeOut();
6229 print_timestamp_done("ReloadCustomArtwork");
6231 LimitScreenUpdates(FALSE);
6234 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6236 if (global.autoplay_leveldir == NULL)
6237 KeyboardAutoRepeatOff();
6240 void DisplayExitMessage(char *format, va_list ap)
6242 // also check for initialized video (headless flag may be temporarily unset)
6243 if (program.headless || !video.initialized)
6246 // check if draw buffer and fonts for exit message are already available
6247 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6250 int font_1 = FC_RED;
6251 int font_2 = FC_YELLOW;
6252 int font_3 = FC_BLUE;
6253 int font_width = getFontWidth(font_2);
6254 int font_height = getFontHeight(font_2);
6257 int sxsize = WIN_XSIZE - 2 * sx;
6258 int sysize = WIN_YSIZE - 2 * sy;
6259 int line_length = sxsize / font_width;
6260 int max_lines = sysize / font_height;
6261 int num_lines_printed;
6265 gfx.sxsize = sxsize;
6266 gfx.sysize = sysize;
6270 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6272 DrawTextSCentered(sy, font_1, "Fatal error:");
6273 sy += 3 * font_height;;
6276 DrawTextBufferVA(sx, sy, format, ap, font_2,
6277 line_length, line_length, max_lines,
6278 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6279 sy += (num_lines_printed + 3) * font_height;
6281 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6282 sy += 3 * font_height;
6285 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6286 line_length, line_length, max_lines,
6287 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6289 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6291 redraw_mask = REDRAW_ALL;
6293 // force drawing exit message even if screen updates are currently limited
6294 LimitScreenUpdates(FALSE);
6298 // deactivate toons on error message screen
6299 setup.toons = FALSE;
6301 WaitForEventToContinue();
6305 // ============================================================================
6307 // ============================================================================
6311 print_timestamp_init("OpenAll");
6313 SetGameStatus(GAME_MODE_LOADING);
6317 InitGlobal(); // initialize some global variables
6319 InitRND(NEW_RANDOMIZE);
6320 InitSimpleRandom(NEW_RANDOMIZE);
6321 InitBetterRandom(NEW_RANDOMIZE);
6323 print_timestamp_time("[init global stuff]");
6327 print_timestamp_time("[init setup/config stuff (1)]");
6329 if (options.execute_command)
6330 Execute_Command(options.execute_command);
6332 InitNetworkSettings();
6336 if (network.serveronly)
6338 #if defined(PLATFORM_UNIX)
6339 NetworkServer(network.server_port, TRUE);
6341 Warn("networking only supported in Unix version");
6344 exit(0); // never reached, server loops forever
6348 print_timestamp_time("[init setup/config stuff (2)]");
6350 print_timestamp_time("[init setup/config stuff (3)]");
6351 InitArtworkInfo(); // needed before loading gfx, sound & music
6352 print_timestamp_time("[init setup/config stuff (4)]");
6353 InitArtworkConfig(); // needed before forking sound child process
6354 print_timestamp_time("[init setup/config stuff (5)]");
6356 print_timestamp_time("[init setup/config stuff (6)]");
6360 print_timestamp_time("[init setup/config stuff]");
6362 InitVideoDefaults();
6364 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6367 InitEventFilter(FilterMouseMotionEvents);
6369 print_timestamp_time("[init video stuff]");
6371 InitElementPropertiesStatic();
6372 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6373 InitElementPropertiesGfxElement();
6375 print_timestamp_time("[init element properties stuff]");
6379 print_timestamp_time("InitGfx");
6382 print_timestamp_time("InitLevelInfo");
6384 InitLevelArtworkInfo();
6385 print_timestamp_time("InitLevelArtworkInfo");
6387 InitOverrideArtwork(); // needs to know current level directory
6388 print_timestamp_time("InitOverrideArtwork");
6390 InitImages(); // needs to know current level directory
6391 print_timestamp_time("InitImages");
6393 InitSound(NULL); // needs to know current level directory
6394 print_timestamp_time("InitSound");
6396 InitMusic(NULL); // needs to know current level directory
6397 print_timestamp_time("InitMusic");
6401 InitGfxBackground();
6407 if (global.autoplay_leveldir)
6412 else if (global.patchtapes_leveldir)
6417 else if (global.convert_leveldir)
6422 else if (global.dumplevel_leveldir)
6427 else if (global.dumptape_leveldir)
6432 else if (global.create_sketch_images_dir)
6434 CreateLevelSketchImages();
6437 else if (global.create_collect_images_dir)
6439 CreateCollectElementImages();
6443 InitNetworkServer();
6445 SetGameStatus(GAME_MODE_MAIN);
6447 FadeSetEnterScreen();
6448 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6449 FadeSkipNextFadeOut();
6451 print_timestamp_time("[post-artwork]");
6453 print_timestamp_done("OpenAll");
6455 if (setup.ask_for_remaining_tapes)
6456 setup.ask_for_uploading_tapes = TRUE;
6461 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6463 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6464 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6465 #if defined(PLATFORM_ANDROID)
6466 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6467 SDL_AndroidGetInternalStoragePath());
6468 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6469 SDL_AndroidGetExternalStoragePath());
6470 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6471 (SDL_AndroidGetExternalStorageState() &
6472 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6473 SDL_AndroidGetExternalStorageState() &
6474 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6479 static boolean WaitForApiThreads(void)
6481 unsigned int thread_delay = 0;
6482 unsigned int thread_delay_value = 10000;
6484 if (program.api_thread_count == 0)
6487 // deactivate global animations (not accessible in game state "loading")
6488 setup.toons = FALSE;
6490 // set game state to "loading" to be able to show busy animation
6491 SetGameStatus(GAME_MODE_LOADING);
6493 ResetDelayCounter(&thread_delay);
6495 // wait for threads to finish (and fail on timeout)
6496 while (program.api_thread_count > 0)
6498 if (DelayReached(&thread_delay, thread_delay_value))
6500 Error("failed waiting for threads - TIMEOUT");
6505 UPDATE_BUSY_STATE();
6513 void CloseAllAndExit(int exit_value)
6515 WaitForApiThreads();
6520 CloseAudio(); // called after freeing sounds (needed for SDL)
6528 // set a flag to tell the network server thread to quit and wait for it
6529 // using SDL_WaitThread()
6531 // Code used with SDL 1.2:
6532 // if (network.server_thread) // terminate network server
6533 // SDL_KillThread(network.server_thread);
6535 CloseVideoDisplay();
6536 ClosePlatformDependentStuff();
6538 if (exit_value != 0 && !options.execute_command)
6540 // fall back to default level set (current set may have caused an error)
6541 SaveLevelSetup_LastSeries_Deactivate();
6543 // tell user where to find error log file which may contain more details
6544 // (error notification now directly displayed on screen inside R'n'D
6545 // NotifyUserAboutErrorFile(); // currently only works for Windows