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"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
82 EL_SPRING_LEFT, EL_SPRING_RIGHT,
83 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
92 // forward declaration for internal use
93 static int get_graphic_parameter_value(char *, char *, int);
96 static void DrawInitAnim(void)
98 struct GraphicInfo *graphic_info_last = graphic_info;
100 static unsigned int action_delay = 0;
101 unsigned int action_delay_value = GameFrameDelay;
102 int sync_frame = FrameCounter;
105 // prevent OS (Windows) from complaining about program not responding
108 if (game_status != GAME_MODE_LOADING)
111 if (anim_initial.bitmap == NULL || window == NULL)
114 if (!DelayReached(&action_delay, action_delay_value))
117 if (init_last.busy.x == -1)
118 init_last.busy.x = WIN_XSIZE / 2;
119 if (init_last.busy.y == -1)
120 init_last.busy.y = WIN_YSIZE / 2;
122 x = ALIGNED_TEXT_XPOS(&init_last.busy);
123 y = ALIGNED_TEXT_YPOS(&init_last.busy);
125 graphic_info = &anim_initial; // graphic == 0 => anim_initial
127 if (sync_frame % anim_initial.anim_delay == 0)
131 int width = graphic_info[graphic].width;
132 int height = graphic_info[graphic].height;
133 int frame = getGraphicAnimationFrame(graphic, sync_frame);
135 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
136 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
139 graphic_info = graphic_info_last;
144 static void DrawProgramInfo(void)
146 int font1_nr = FC_YELLOW;
147 int font2_nr = FC_RED;
148 int font2_height = getFontHeight(font2_nr);
151 int ypos3 = WIN_YSIZE - 20 - font2_height;
153 DrawInitText(getProgramInitString(), ypos1, font1_nr);
154 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
155 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
158 static void FreeGadgets(void)
160 FreeLevelEditorGadgets();
167 void InitGadgets(void)
169 static boolean gadgets_initialized = FALSE;
171 if (gadgets_initialized)
174 CreateLevelEditorGadgets();
178 CreateScreenGadgets();
180 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
182 gadgets_initialized = TRUE;
185 static void InitElementSmallImagesScaledUp(int graphic)
187 struct GraphicInfo *g = &graphic_info[graphic];
189 // create small and game tile sized bitmaps (and scale up, if needed)
190 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
193 static void InitElementSmallImages(void)
195 print_timestamp_init("InitElementSmallImages");
197 static int special_graphics[] =
211 IMG_EDITOR_ELEMENT_BORDER,
212 IMG_EDITOR_ELEMENT_BORDER_INPUT,
213 IMG_EDITOR_CASCADE_LIST,
214 IMG_EDITOR_CASCADE_LIST_ACTIVE,
217 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
218 int num_property_mappings = getImageListPropertyMappingSize();
221 print_timestamp_time("getImageListPropertyMapping/Size");
223 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
224 // initialize normal element images from static configuration
225 for (i = 0; element_to_graphic[i].element > -1; i++)
226 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
227 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
229 // initialize special element images from static configuration
230 for (i = 0; element_to_special_graphic[i].element > -1; i++)
231 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
232 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
234 // initialize element images from dynamic configuration
235 for (i = 0; i < num_property_mappings; i++)
236 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
237 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
238 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
240 // initialize special non-element images from above list
241 for (i = 0; special_graphics[i] > -1; i++)
242 InitElementSmallImagesScaledUp(special_graphics[i]);
243 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
245 print_timestamp_done("InitElementSmallImages");
248 static void InitScaledImagesScaledUp(int graphic)
250 struct GraphicInfo *g = &graphic_info[graphic];
252 ScaleImage(graphic, g->scale_up_factor);
255 static void InitScaledImages(void)
257 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
258 int num_property_mappings = getImageListPropertyMappingSize();
261 // scale normal images from static configuration, if not already scaled
262 for (i = 0; i < NUM_IMAGE_FILES; i++)
263 InitScaledImagesScaledUp(i);
265 // scale images from dynamic configuration, if not already scaled
266 for (i = 0; i < num_property_mappings; i++)
267 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
270 static void InitBitmapPointers(void)
272 int num_images = getImageListSize();
275 // standard size bitmap may have changed -- update default bitmap pointer
276 for (i = 0; i < num_images; i++)
277 if (graphic_info[i].bitmaps)
278 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
281 void InitImageTextures(void)
283 static int texture_graphics[] =
285 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
286 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
287 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
288 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
289 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
290 IMG_MENU_BUTTON_TOUCH_BACK,
291 IMG_MENU_BUTTON_TOUCH_NEXT,
292 IMG_MENU_BUTTON_TOUCH_BACK2,
293 IMG_MENU_BUTTON_TOUCH_NEXT2,
298 FreeAllImageTextures();
300 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
301 CreateImageTextures(i);
303 for (i = 0; i < MAX_NUM_TOONS; i++)
304 CreateImageTextures(IMG_TOON_1 + i);
306 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
308 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
310 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
312 int graphic = global_anim_info[i].graphic[j][k];
314 if (graphic == IMG_UNDEFINED)
317 CreateImageTextures(graphic);
322 for (i = 0; texture_graphics[i] > -1; i++)
323 CreateImageTextures(texture_graphics[i]);
326 static int getFontBitmapID(int font_nr)
330 // (special case: do not use special font for GAME_MODE_LOADING)
331 if (game_status >= GAME_MODE_TITLE_INITIAL &&
332 game_status <= GAME_MODE_PSEUDO_PREVIEW)
333 special = game_status;
334 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
335 special = GFX_SPECIAL_ARG_MAIN;
338 return font_info[font_nr].special_bitmap_id[special];
343 static int getFontFromToken(char *token)
345 char *value = getHashEntry(font_token_hash, token);
350 // if font not found, use reliable default value
351 return FONT_INITIAL_1;
354 static void InitFontGraphicInfo(void)
356 static struct FontBitmapInfo *font_bitmap_info = NULL;
357 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
358 int num_property_mappings = getImageListPropertyMappingSize();
359 int num_font_bitmaps = NUM_FONTS;
362 if (graphic_info == NULL) // still at startup phase
364 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
365 getFontBitmapID, getFontFromToken);
370 // ---------- initialize font graphic definitions ----------
372 // always start with reliable default values (normal font graphics)
373 for (i = 0; i < NUM_FONTS; i++)
374 font_info[i].graphic = IMG_FONT_INITIAL_1;
376 // initialize normal font/graphic mapping from static configuration
377 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
379 int font_nr = font_to_graphic[i].font_nr;
380 int special = font_to_graphic[i].special;
381 int graphic = font_to_graphic[i].graphic;
386 font_info[font_nr].graphic = graphic;
389 // always start with reliable default values (special font graphics)
390 for (i = 0; i < NUM_FONTS; i++)
392 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
394 font_info[i].special_graphic[j] = font_info[i].graphic;
395 font_info[i].special_bitmap_id[j] = i;
399 // initialize special font/graphic mapping from static configuration
400 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
402 int font_nr = font_to_graphic[i].font_nr;
403 int special = font_to_graphic[i].special;
404 int graphic = font_to_graphic[i].graphic;
405 int base_graphic = font2baseimg(font_nr);
407 if (IS_SPECIAL_GFX_ARG(special))
409 boolean base_redefined =
410 getImageListEntryFromImageID(base_graphic)->redefined;
411 boolean special_redefined =
412 getImageListEntryFromImageID(graphic)->redefined;
413 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
415 /* if the base font ("font.title_1", for example) has been redefined,
416 but not the special font ("font.title_1.LEVELS", for example), do not
417 use an existing (in this case considered obsolete) special font
418 anymore, but use the automatically determined default font */
419 /* special case: cloned special fonts must be explicitly redefined,
420 but are not automatically redefined by redefining base font */
421 if (base_redefined && !special_redefined && !special_cloned)
424 font_info[font_nr].special_graphic[special] = graphic;
425 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
430 // initialize special font/graphic mapping from dynamic configuration
431 for (i = 0; i < num_property_mappings; i++)
433 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
434 int special = property_mapping[i].ext3_index;
435 int graphic = property_mapping[i].artwork_index;
437 if (font_nr < 0 || font_nr >= NUM_FONTS)
440 if (IS_SPECIAL_GFX_ARG(special))
442 font_info[font_nr].special_graphic[special] = graphic;
443 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
448 /* correct special font/graphic mapping for cloned fonts for downwards
449 compatibility of PREVIEW fonts -- this is only needed for implicit
450 redefinition of special font by redefined base font, and only if other
451 fonts are cloned from this special font (like in the "Zelda" level set) */
452 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
454 int font_nr = font_to_graphic[i].font_nr;
455 int special = font_to_graphic[i].special;
456 int graphic = font_to_graphic[i].graphic;
458 if (IS_SPECIAL_GFX_ARG(special))
460 boolean special_redefined =
461 getImageListEntryFromImageID(graphic)->redefined;
462 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
464 if (special_cloned && !special_redefined)
468 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
470 int font_nr2 = font_to_graphic[j].font_nr;
471 int special2 = font_to_graphic[j].special;
472 int graphic2 = font_to_graphic[j].graphic;
474 if (IS_SPECIAL_GFX_ARG(special2) &&
475 graphic2 == graphic_info[graphic].clone_from)
477 font_info[font_nr].special_graphic[special] =
478 font_info[font_nr2].special_graphic[special2];
479 font_info[font_nr].special_bitmap_id[special] =
480 font_info[font_nr2].special_bitmap_id[special2];
487 // reset non-redefined ".active" font graphics if normal font is redefined
488 // (this different treatment is needed because normal and active fonts are
489 // independently defined ("active" is not a property of font definitions!)
490 for (i = 0; i < NUM_FONTS; i++)
492 int font_nr_base = i;
493 int font_nr_active = FONT_ACTIVE(font_nr_base);
495 // check only those fonts with exist as normal and ".active" variant
496 if (font_nr_base != font_nr_active)
498 int base_graphic = font_info[font_nr_base].graphic;
499 int active_graphic = font_info[font_nr_active].graphic;
500 boolean base_redefined =
501 getImageListEntryFromImageID(base_graphic)->redefined;
502 boolean active_redefined =
503 getImageListEntryFromImageID(active_graphic)->redefined;
505 /* if the base font ("font.menu_1", for example) has been redefined,
506 but not the active font ("font.menu_1.active", for example), do not
507 use an existing (in this case considered obsolete) active font
508 anymore, but use the automatically determined default font */
509 if (base_redefined && !active_redefined)
510 font_info[font_nr_active].graphic = base_graphic;
512 // now also check each "special" font (which may be the same as above)
513 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
515 int base_graphic = font_info[font_nr_base].special_graphic[j];
516 int active_graphic = font_info[font_nr_active].special_graphic[j];
517 boolean base_redefined =
518 getImageListEntryFromImageID(base_graphic)->redefined;
519 boolean active_redefined =
520 getImageListEntryFromImageID(active_graphic)->redefined;
522 // same as above, but check special graphic definitions, for example:
523 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
524 if (base_redefined && !active_redefined)
526 font_info[font_nr_active].special_graphic[j] =
527 font_info[font_nr_base].special_graphic[j];
528 font_info[font_nr_active].special_bitmap_id[j] =
529 font_info[font_nr_base].special_bitmap_id[j];
535 // ---------- initialize font bitmap array ----------
537 if (font_bitmap_info != NULL)
538 FreeFontInfo(font_bitmap_info);
541 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
543 // ---------- initialize font bitmap definitions ----------
545 for (i = 0; i < NUM_FONTS; i++)
547 if (i < NUM_INITIAL_FONTS)
549 font_bitmap_info[i] = font_initial[i];
553 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
555 int font_bitmap_id = font_info[i].special_bitmap_id[j];
556 int graphic = font_info[i].special_graphic[j];
558 // set 'graphic_info' for font entries, if uninitialized (guessed)
559 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
561 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
562 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
565 // copy font relevant information from graphics information
566 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
567 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
568 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
569 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
570 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
572 font_bitmap_info[font_bitmap_id].offset_x =
573 graphic_info[graphic].offset_x;
574 font_bitmap_info[font_bitmap_id].offset_y =
575 graphic_info[graphic].offset_y;
577 font_bitmap_info[font_bitmap_id].draw_xoffset =
578 graphic_info[graphic].draw_xoffset;
579 font_bitmap_info[font_bitmap_id].draw_yoffset =
580 graphic_info[graphic].draw_yoffset;
582 font_bitmap_info[font_bitmap_id].num_chars =
583 graphic_info[graphic].anim_frames;
584 font_bitmap_info[font_bitmap_id].num_chars_per_line =
585 graphic_info[graphic].anim_frames_per_line;
589 InitFontInfo(font_bitmap_info, num_font_bitmaps,
590 getFontBitmapID, getFontFromToken);
593 static void InitGlobalAnimGraphicInfo(void)
595 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
596 int num_property_mappings = getImageListPropertyMappingSize();
599 if (graphic_info == NULL) // still at startup phase
602 // always start with reliable default values (no global animations)
603 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
604 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
605 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
606 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
608 // initialize global animation definitions from static configuration
609 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
611 int j = GLOBAL_ANIM_ID_PART_BASE;
612 int k = GFX_SPECIAL_ARG_DEFAULT;
614 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
617 // initialize global animation definitions from dynamic configuration
618 for (i = 0; i < num_property_mappings; i++)
620 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
621 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
622 int special = property_mapping[i].ext3_index;
623 int graphic = property_mapping[i].artwork_index;
625 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
628 // set animation part to base part, if not specified
629 if (!IS_GLOBAL_ANIM_PART(part_nr))
630 part_nr = GLOBAL_ANIM_ID_PART_BASE;
632 // set animation screen to default, if not specified
633 if (!IS_SPECIAL_GFX_ARG(special))
634 special = GFX_SPECIAL_ARG_DEFAULT;
636 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
638 // fix default value for ".draw_masked" (for backward compatibility)
639 struct GraphicInfo *g = &graphic_info[graphic];
640 struct FileInfo *image = getImageListEntryFromImageID(graphic);
641 char **parameter_raw = image->parameter;
642 int p = GFX_ARG_DRAW_MASKED;
643 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
644 image_config_suffix[p].token,
645 image_config_suffix[p].type);
647 // if ".draw_masked" parameter is undefined, use default value "TRUE"
648 if (draw_masked == ARG_UNDEFINED_VALUE)
649 g->draw_masked = TRUE;
653 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
654 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
655 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
656 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
657 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
658 Debug("init:InitGlobalAnimGraphicInfo",
659 "anim %d, part %d, mode %d => %d",
660 i, j, k, global_anim_info[i].graphic[j][k]);
664 static void InitGlobalAnimSoundInfo(void)
666 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
667 int num_property_mappings = getSoundListPropertyMappingSize();
670 // always start with reliable default values (no global animation sounds)
671 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
672 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
673 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
674 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
676 // initialize global animation sound definitions from dynamic configuration
677 for (i = 0; i < num_property_mappings; i++)
679 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
680 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
681 int special = property_mapping[i].ext3_index;
682 int sound = property_mapping[i].artwork_index;
684 // sound uses control definition; map it to position of graphic (artwork)
685 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
687 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
690 // set animation part to base part, if not specified
691 if (!IS_GLOBAL_ANIM_PART(part_nr))
692 part_nr = GLOBAL_ANIM_ID_PART_BASE;
694 // set animation screen to default, if not specified
695 if (!IS_SPECIAL_GFX_ARG(special))
696 special = GFX_SPECIAL_ARG_DEFAULT;
698 global_anim_info[anim_nr].sound[part_nr][special] = sound;
702 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
703 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
704 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
705 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
706 Debug("init:InitGlobalAnimSoundInfo",
707 "anim %d, part %d, mode %d => %d",
708 i, j, k, global_anim_info[i].sound[j][k]);
712 static void InitGlobalAnimMusicInfo(void)
714 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
715 int num_property_mappings = getMusicListPropertyMappingSize();
718 // always start with reliable default values (no global animation music)
719 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
720 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
721 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
722 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
724 // initialize global animation music definitions from dynamic configuration
725 for (i = 0; i < num_property_mappings; i++)
727 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
728 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
729 int special = property_mapping[i].ext2_index;
730 int music = property_mapping[i].artwork_index;
732 // music uses control definition; map it to position of graphic (artwork)
733 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
735 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
738 // set animation part to base part, if not specified
739 if (!IS_GLOBAL_ANIM_PART(part_nr))
740 part_nr = GLOBAL_ANIM_ID_PART_BASE;
742 // set animation screen to default, if not specified
743 if (!IS_SPECIAL_GFX_ARG(special))
744 special = GFX_SPECIAL_ARG_DEFAULT;
746 global_anim_info[anim_nr].music[part_nr][special] = music;
750 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
754 Debug("init:InitGlobalAnimMusicInfo",
755 "anim %d, part %d, mode %d => %d",
756 i, j, k, global_anim_info[i].music[j][k]);
760 static void InitElementGraphicInfo(void)
762 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
763 int num_property_mappings = getImageListPropertyMappingSize();
766 if (graphic_info == NULL) // still at startup phase
769 // set values to -1 to identify later as "uninitialized" values
770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
772 for (act = 0; act < NUM_ACTIONS; act++)
774 element_info[i].graphic[act] = -1;
775 element_info[i].crumbled[act] = -1;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 element_info[i].direction_graphic[act][dir] = -1;
780 element_info[i].direction_crumbled[act][dir] = -1;
787 // initialize normal element/graphic mapping from static configuration
788 for (i = 0; element_to_graphic[i].element > -1; i++)
790 int element = element_to_graphic[i].element;
791 int action = element_to_graphic[i].action;
792 int direction = element_to_graphic[i].direction;
793 boolean crumbled = element_to_graphic[i].crumbled;
794 int graphic = element_to_graphic[i].graphic;
795 int base_graphic = el2baseimg(element);
797 if (graphic_info[graphic].bitmap == NULL)
800 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
803 boolean base_redefined =
804 getImageListEntryFromImageID(base_graphic)->redefined;
805 boolean act_dir_redefined =
806 getImageListEntryFromImageID(graphic)->redefined;
808 /* if the base graphic ("emerald", for example) has been redefined,
809 but not the action graphic ("emerald.falling", for example), do not
810 use an existing (in this case considered obsolete) action graphic
811 anymore, but use the automatically determined default graphic */
812 if (base_redefined && !act_dir_redefined)
817 action = ACTION_DEFAULT;
822 element_info[element].direction_crumbled[action][direction] = graphic;
824 element_info[element].crumbled[action] = graphic;
829 element_info[element].direction_graphic[action][direction] = graphic;
831 element_info[element].graphic[action] = graphic;
835 // initialize normal element/graphic mapping from dynamic configuration
836 for (i = 0; i < num_property_mappings; i++)
838 int element = property_mapping[i].base_index;
839 int action = property_mapping[i].ext1_index;
840 int direction = property_mapping[i].ext2_index;
841 int special = property_mapping[i].ext3_index;
842 int graphic = property_mapping[i].artwork_index;
843 boolean crumbled = FALSE;
845 if (special == GFX_SPECIAL_ARG_CRUMBLED)
851 if (graphic_info[graphic].bitmap == NULL)
854 if (element >= MAX_NUM_ELEMENTS || special != -1)
858 action = ACTION_DEFAULT;
863 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
864 element_info[element].direction_crumbled[action][dir] = -1;
867 element_info[element].direction_crumbled[action][direction] = graphic;
869 element_info[element].crumbled[action] = graphic;
874 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
875 element_info[element].direction_graphic[action][dir] = -1;
878 element_info[element].direction_graphic[action][direction] = graphic;
880 element_info[element].graphic[action] = graphic;
884 // now copy all graphics that are defined to be cloned from other graphics
885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
887 int graphic = element_info[i].graphic[ACTION_DEFAULT];
888 int crumbled_like, diggable_like;
893 crumbled_like = graphic_info[graphic].crumbled_like;
894 diggable_like = graphic_info[graphic].diggable_like;
896 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
898 for (act = 0; act < NUM_ACTIONS; act++)
899 element_info[i].crumbled[act] =
900 element_info[crumbled_like].crumbled[act];
901 for (act = 0; act < NUM_ACTIONS; act++)
902 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
903 element_info[i].direction_crumbled[act][dir] =
904 element_info[crumbled_like].direction_crumbled[act][dir];
907 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
909 element_info[i].graphic[ACTION_DIGGING] =
910 element_info[diggable_like].graphic[ACTION_DIGGING];
911 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
912 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
913 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
917 // set hardcoded definitions for some runtime elements without graphic
918 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
920 // set hardcoded definitions for some internal elements without graphic
921 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
923 if (IS_EDITOR_CASCADE_INACTIVE(i))
924 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
925 else if (IS_EDITOR_CASCADE_ACTIVE(i))
926 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
929 // now set all undefined/invalid graphics to -1 to set to default after it
930 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
932 for (act = 0; act < NUM_ACTIONS; act++)
936 graphic = element_info[i].graphic[act];
937 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
938 element_info[i].graphic[act] = -1;
940 graphic = element_info[i].crumbled[act];
941 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
942 element_info[i].crumbled[act] = -1;
944 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
946 graphic = element_info[i].direction_graphic[act][dir];
947 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
948 element_info[i].direction_graphic[act][dir] = -1;
950 graphic = element_info[i].direction_crumbled[act][dir];
951 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
952 element_info[i].direction_crumbled[act][dir] = -1;
959 // adjust graphics with 2nd tile for movement according to direction
960 // (do this before correcting '-1' values to minimize calculations)
961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
963 for (act = 0; act < NUM_ACTIONS; act++)
965 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
967 int graphic = element_info[i].direction_graphic[act][dir];
968 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
970 if (act == ACTION_FALLING) // special case
971 graphic = element_info[i].graphic[act];
974 graphic_info[graphic].double_movement &&
975 graphic_info[graphic].swap_double_tiles != 0)
977 struct GraphicInfo *g = &graphic_info[graphic];
978 int src_x_front = g->src_x;
979 int src_y_front = g->src_y;
980 int src_x_back = g->src_x + g->offset2_x;
981 int src_y_back = g->src_y + g->offset2_y;
982 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
984 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
985 src_y_front < src_y_back);
986 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
987 boolean swap_movement_tiles_autodetected =
988 (!frames_are_ordered_diagonally &&
989 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
990 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
991 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
992 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
994 // swap frontside and backside graphic tile coordinates, if needed
995 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
997 // get current (wrong) backside tile coordinates
998 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1000 // set frontside tile coordinates to backside tile coordinates
1001 g->src_x = src_x_back;
1002 g->src_y = src_y_back;
1004 // invert tile offset to point to new backside tile coordinates
1008 // do not swap front and backside tiles again after correction
1009 g->swap_double_tiles = 0;
1016 UPDATE_BUSY_STATE();
1018 // now set all '-1' values to element specific default values
1019 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1021 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1022 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1023 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1024 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1026 if (default_graphic == -1)
1027 default_graphic = IMG_UNKNOWN;
1029 if (default_crumbled == -1)
1030 default_crumbled = default_graphic;
1032 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1034 default_direction_graphic[dir] =
1035 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1036 default_direction_crumbled[dir] =
1037 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1039 if (default_direction_graphic[dir] == -1)
1040 default_direction_graphic[dir] = default_graphic;
1042 if (default_direction_crumbled[dir] == -1)
1043 default_direction_crumbled[dir] = default_direction_graphic[dir];
1046 for (act = 0; act < NUM_ACTIONS; act++)
1048 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1049 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1050 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1051 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1052 act == ACTION_TURNING_FROM_RIGHT ||
1053 act == ACTION_TURNING_FROM_UP ||
1054 act == ACTION_TURNING_FROM_DOWN);
1056 // generic default action graphic (defined by "[default]" directive)
1057 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1058 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1059 int default_remove_graphic = IMG_EMPTY;
1061 if (act_remove && default_action_graphic != -1)
1062 default_remove_graphic = default_action_graphic;
1064 // look for special default action graphic (classic game specific)
1065 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1066 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1067 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1068 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1069 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1070 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1071 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1072 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1074 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1075 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1076 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1077 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1078 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1079 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1080 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1081 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1083 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1084 // !!! make this better !!!
1085 if (i == EL_EMPTY_SPACE)
1087 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1088 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1091 if (default_action_graphic == -1)
1092 default_action_graphic = default_graphic;
1094 if (default_action_crumbled == -1)
1095 default_action_crumbled = default_action_graphic;
1097 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1099 // use action graphic as the default direction graphic, if undefined
1100 int default_action_direction_graphic = element_info[i].graphic[act];
1101 int default_action_direction_crumbled = element_info[i].crumbled[act];
1103 // no graphic for current action -- use default direction graphic
1104 if (default_action_direction_graphic == -1)
1105 default_action_direction_graphic =
1106 (act_remove ? default_remove_graphic :
1108 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1109 default_action_graphic != default_graphic ?
1110 default_action_graphic :
1111 default_direction_graphic[dir]);
1113 if (element_info[i].direction_graphic[act][dir] == -1)
1114 element_info[i].direction_graphic[act][dir] =
1115 default_action_direction_graphic;
1117 if (default_action_direction_crumbled == -1)
1118 default_action_direction_crumbled =
1119 element_info[i].direction_graphic[act][dir];
1121 if (element_info[i].direction_crumbled[act][dir] == -1)
1122 element_info[i].direction_crumbled[act][dir] =
1123 default_action_direction_crumbled;
1126 // no graphic for this specific action -- use default action graphic
1127 if (element_info[i].graphic[act] == -1)
1128 element_info[i].graphic[act] =
1129 (act_remove ? default_remove_graphic :
1130 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1131 default_action_graphic);
1133 if (element_info[i].crumbled[act] == -1)
1134 element_info[i].crumbled[act] = element_info[i].graphic[act];
1138 UPDATE_BUSY_STATE();
1141 static void InitElementSpecialGraphicInfo(void)
1143 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1144 int num_property_mappings = getImageListPropertyMappingSize();
1147 // always start with reliable default values
1148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1149 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1150 element_info[i].special_graphic[j] =
1151 element_info[i].graphic[ACTION_DEFAULT];
1153 // initialize special element/graphic mapping from static configuration
1154 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1156 int element = element_to_special_graphic[i].element;
1157 int special = element_to_special_graphic[i].special;
1158 int graphic = element_to_special_graphic[i].graphic;
1159 int base_graphic = el2baseimg(element);
1160 boolean base_redefined =
1161 getImageListEntryFromImageID(base_graphic)->redefined;
1162 boolean special_redefined =
1163 getImageListEntryFromImageID(graphic)->redefined;
1165 /* if the base graphic ("emerald", for example) has been redefined,
1166 but not the special graphic ("emerald.EDITOR", for example), do not
1167 use an existing (in this case considered obsolete) special graphic
1168 anymore, but use the automatically created (down-scaled) graphic */
1169 if (base_redefined && !special_redefined)
1172 element_info[element].special_graphic[special] = graphic;
1175 // initialize special element/graphic mapping from dynamic configuration
1176 for (i = 0; i < num_property_mappings; i++)
1178 int element = property_mapping[i].base_index;
1179 int action = property_mapping[i].ext1_index;
1180 int direction = property_mapping[i].ext2_index;
1181 int special = property_mapping[i].ext3_index;
1182 int graphic = property_mapping[i].artwork_index;
1184 // for action ".active", replace element with active element, if exists
1185 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1187 element = ELEMENT_ACTIVE(element);
1191 if (element >= MAX_NUM_ELEMENTS)
1194 // do not change special graphic if action or direction was specified
1195 if (action != -1 || direction != -1)
1198 if (IS_SPECIAL_GFX_ARG(special))
1199 element_info[element].special_graphic[special] = graphic;
1202 // now set all undefined/invalid graphics to default
1203 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1204 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1205 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1206 element_info[i].special_graphic[j] =
1207 element_info[i].graphic[ACTION_DEFAULT];
1210 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1212 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1213 return get_parameter_value(value_raw, suffix, type);
1215 if (strEqual(value_raw, ARG_UNDEFINED))
1216 return ARG_UNDEFINED_VALUE;
1218 if (type == TYPE_ELEMENT)
1220 char *value = getHashEntry(element_token_hash, value_raw);
1225 Warn("error found in config file:");
1226 Warn("- config file: '%s'", getImageConfigFilename());
1227 Warn("error: invalid element token '%s'", value_raw);
1228 Warn("custom graphic rejected for this element/action");
1229 Warn("fallback done to undefined element for this graphic");
1233 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1235 else if (type == TYPE_GRAPHIC)
1237 char *value = getHashEntry(graphic_token_hash, value_raw);
1238 int fallback_graphic = IMG_CHAR_EXCLAM;
1243 Warn("error found in config file:");
1244 Warn("- config file: '%s'", getImageConfigFilename());
1245 Warn("error: invalid graphic token '%s'", value_raw);
1246 Warn("custom graphic rejected for this element/action");
1247 Warn("fallback done to 'char_exclam' for this graphic");
1251 return (value != NULL ? atoi(value) : fallback_graphic);
1257 static int get_scaled_graphic_width(int graphic)
1259 int original_width = getOriginalImageWidthFromImageID(graphic);
1260 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1262 return original_width * scale_up_factor;
1265 static int get_scaled_graphic_height(int graphic)
1267 int original_height = getOriginalImageHeightFromImageID(graphic);
1268 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1270 return original_height * scale_up_factor;
1273 static void set_graphic_parameters_ext(int graphic, int *parameter,
1274 Bitmap **src_bitmaps)
1276 struct GraphicInfo *g = &graphic_info[graphic];
1277 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1278 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1279 int anim_frames_per_line = 1;
1281 // always start with reliable default values
1282 g->src_image_width = 0;
1283 g->src_image_height = 0;
1286 g->width = TILEX; // default for element graphics
1287 g->height = TILEY; // default for element graphics
1288 g->offset_x = 0; // one or both of these values ...
1289 g->offset_y = 0; // ... will be corrected later
1290 g->offset2_x = 0; // one or both of these values ...
1291 g->offset2_y = 0; // ... will be corrected later
1292 g->swap_double_tiles = -1; // auto-detect tile swapping
1293 g->crumbled_like = -1; // do not use clone element
1294 g->diggable_like = -1; // do not use clone element
1295 g->border_size = TILEX / 8; // "CRUMBLED" border size
1296 g->scale_up_factor = 1; // default: no scaling up
1297 g->tile_size = TILESIZE; // default: standard tile size
1298 g->clone_from = -1; // do not use clone graphic
1299 g->init_delay_fixed = 0;
1300 g->init_delay_random = 0;
1301 g->init_delay_action = -1;
1302 g->anim_delay_fixed = 0;
1303 g->anim_delay_random = 0;
1304 g->anim_delay_action = -1;
1305 g->post_delay_fixed = 0;
1306 g->post_delay_random = 0;
1307 g->post_delay_action = -1;
1308 g->init_event = ANIM_EVENT_UNDEFINED;
1309 g->anim_event = ANIM_EVENT_UNDEFINED;
1310 g->init_event_action = -1;
1311 g->anim_event_action = -1;
1312 g->draw_masked = FALSE;
1314 g->fade_mode = FADE_MODE_DEFAULT;
1318 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1319 g->align = ALIGN_CENTER; // default for title screens
1320 g->valign = VALIGN_MIDDLE; // default for title screens
1321 g->sort_priority = 0; // default for title screens
1323 g->style = STYLE_DEFAULT;
1325 g->bitmaps = src_bitmaps;
1326 g->bitmap = src_bitmap;
1328 // optional zoom factor for scaling up the image to a larger size
1329 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1330 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1331 if (g->scale_up_factor < 1)
1332 g->scale_up_factor = 1; // no scaling
1334 // optional tile size for using non-standard image size
1335 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1337 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1340 // CHECK: should tile sizes less than standard tile size be allowed?
1341 if (g->tile_size < TILESIZE)
1342 g->tile_size = TILESIZE; // standard tile size
1345 // when setting tile size, also set width and height accordingly
1346 g->width = g->tile_size;
1347 g->height = g->tile_size;
1350 if (g->use_image_size)
1352 // set new default bitmap size (with scaling, but without small images)
1353 g->width = get_scaled_graphic_width(graphic);
1354 g->height = get_scaled_graphic_height(graphic);
1357 // optional width and height of each animation frame
1358 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1359 g->width = parameter[GFX_ARG_WIDTH];
1360 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1361 g->height = parameter[GFX_ARG_HEIGHT];
1363 // optional x and y tile position of animation frame sequence
1364 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1365 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1366 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1367 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1369 // optional x and y pixel position of animation frame sequence
1370 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1371 g->src_x = parameter[GFX_ARG_X];
1372 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1373 g->src_y = parameter[GFX_ARG_Y];
1380 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1381 g->width, getTokenFromImageID(graphic), TILEX);
1384 g->width = TILEX; // will be checked to be inside bitmap later
1390 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1391 g->height, getTokenFromImageID(graphic), TILEY);
1394 g->height = TILEY; // will be checked to be inside bitmap later
1400 // get final bitmap size (with scaling, but without small images)
1401 int src_image_width = get_scaled_graphic_width(graphic);
1402 int src_image_height = get_scaled_graphic_height(graphic);
1404 if (src_image_width == 0 || src_image_height == 0)
1406 // only happens when loaded outside artwork system (like "global.busy")
1407 src_image_width = src_bitmap->width;
1408 src_image_height = src_bitmap->height;
1411 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1413 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1414 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1418 anim_frames_per_row = MAX(1, src_image_width / g->width);
1419 anim_frames_per_col = MAX(1, src_image_height / g->height);
1422 g->src_image_width = src_image_width;
1423 g->src_image_height = src_image_height;
1426 // correct x or y offset dependent of vertical or horizontal frame order
1427 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1429 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1430 parameter[GFX_ARG_OFFSET] : g->height);
1431 anim_frames_per_line = anim_frames_per_col;
1433 else // frames are ordered horizontally
1435 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_OFFSET] : g->width);
1437 anim_frames_per_line = anim_frames_per_row;
1440 // optionally, the x and y offset of frames can be specified directly
1441 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1442 g->offset_x = parameter[GFX_ARG_XOFFSET];
1443 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1444 g->offset_y = parameter[GFX_ARG_YOFFSET];
1446 // optionally, moving animations may have separate start and end graphics
1447 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1449 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1450 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1452 // correct x or y offset2 dependent of vertical or horizontal frame order
1453 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1454 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1455 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1456 else // frames are ordered horizontally
1457 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1458 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1460 // optionally, the x and y offset of 2nd graphic can be specified directly
1461 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1462 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1463 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1464 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1466 // optionally, the second movement tile can be specified as start tile
1467 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1468 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1470 // automatically determine correct number of frames, if not defined
1471 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1472 g->anim_frames = parameter[GFX_ARG_FRAMES];
1473 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1474 g->anim_frames = anim_frames_per_row;
1475 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1476 g->anim_frames = anim_frames_per_col;
1480 if (g->anim_frames < 1) // frames must be at least 1
1483 g->anim_frames_per_line =
1484 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1485 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1487 g->anim_delay = parameter[GFX_ARG_DELAY];
1488 if (g->anim_delay < 1) // delay must be at least 1
1491 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1493 // automatically determine correct start frame, if not defined
1494 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1495 g->anim_start_frame = 0;
1496 else if (g->anim_mode & ANIM_REVERSE)
1497 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1499 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1501 // animation synchronized with global frame counter, not move position
1502 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1504 // optional element for cloning crumble graphics
1505 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1506 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1508 // optional element for cloning digging graphics
1509 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1510 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1512 // optional border size for "crumbling" diggable graphics
1513 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1514 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1516 // used for global animations and player "boring" and "sleeping" actions
1517 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1518 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1519 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1520 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1521 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1522 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1523 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1524 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1525 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1526 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1527 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1528 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1530 // used for global animations
1531 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1532 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1533 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1534 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1535 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1536 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1537 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1538 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1539 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1540 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1541 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1543 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1544 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1546 // used for toon animations and global animations
1547 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1548 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1549 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1550 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1551 g->direction = parameter[GFX_ARG_DIRECTION];
1552 g->position = parameter[GFX_ARG_POSITION];
1553 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1554 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1556 if (g->step_delay < 1) // delay must be at least 1
1559 // this is only used for drawing font characters
1560 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1561 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1563 // use a different default value for global animations and toons
1564 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1565 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1566 g->draw_masked = TRUE;
1568 // this is used for drawing envelopes, global animations and toons
1569 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1570 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1572 // used for toon animations and global animations
1573 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1574 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1576 // optional graphic for cloning all graphics settings
1577 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1578 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1580 // optional settings for drawing title screens and title messages
1581 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1582 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1583 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1584 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1585 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1586 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1587 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1588 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1589 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1590 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1591 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1592 g->align = parameter[GFX_ARG_ALIGN];
1593 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1594 g->valign = parameter[GFX_ARG_VALIGN];
1595 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1596 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1598 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1599 g->class = parameter[GFX_ARG_CLASS];
1600 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1601 g->style = parameter[GFX_ARG_STYLE];
1603 // this is only used for drawing menu buttons and text
1604 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1605 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1606 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1607 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1610 static void set_graphic_parameters(int graphic)
1612 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1613 char **parameter_raw = image->parameter;
1614 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1615 int parameter[NUM_GFX_ARGS];
1618 // if fallback to default artwork is done, also use the default parameters
1619 if (image->fallback_to_default)
1620 parameter_raw = image->default_parameter;
1622 // get integer values from string parameters
1623 for (i = 0; i < NUM_GFX_ARGS; i++)
1624 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1625 image_config_suffix[i].token,
1626 image_config_suffix[i].type);
1628 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1630 UPDATE_BUSY_STATE();
1633 static void set_cloned_graphic_parameters(int graphic)
1635 int fallback_graphic = IMG_CHAR_EXCLAM;
1636 int max_num_images = getImageListSize();
1637 int clone_graphic = graphic_info[graphic].clone_from;
1638 int num_references_followed = 1;
1640 while (graphic_info[clone_graphic].clone_from != -1 &&
1641 num_references_followed < max_num_images)
1643 clone_graphic = graphic_info[clone_graphic].clone_from;
1645 num_references_followed++;
1648 if (num_references_followed >= max_num_images)
1651 Warn("error found in config file:");
1652 Warn("- config file: '%s'", getImageConfigFilename());
1653 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1654 Warn("error: loop discovered when resolving cloned graphics");
1655 Warn("custom graphic rejected for this element/action");
1657 if (graphic == fallback_graphic)
1658 Fail("no fallback graphic available");
1660 Warn("fallback done to 'char_exclam' for this graphic");
1663 graphic_info[graphic] = graphic_info[fallback_graphic];
1667 graphic_info[graphic] = graphic_info[clone_graphic];
1668 graphic_info[graphic].clone_from = clone_graphic;
1672 static void InitGraphicInfo(void)
1674 int fallback_graphic = IMG_CHAR_EXCLAM;
1675 int num_images = getImageListSize();
1678 // use image size as default values for width and height for these images
1679 static int full_size_graphics[] =
1682 IMG_GLOBAL_BORDER_MAIN,
1683 IMG_GLOBAL_BORDER_SCORES,
1684 IMG_GLOBAL_BORDER_EDITOR,
1685 IMG_GLOBAL_BORDER_PLAYING,
1688 IMG_BACKGROUND_ENVELOPE_1,
1689 IMG_BACKGROUND_ENVELOPE_2,
1690 IMG_BACKGROUND_ENVELOPE_3,
1691 IMG_BACKGROUND_ENVELOPE_4,
1692 IMG_BACKGROUND_REQUEST,
1695 IMG_BACKGROUND_TITLE_INITIAL,
1696 IMG_BACKGROUND_TITLE,
1697 IMG_BACKGROUND_MAIN,
1698 IMG_BACKGROUND_LEVELS,
1699 IMG_BACKGROUND_LEVELNR,
1700 IMG_BACKGROUND_SCORES,
1701 IMG_BACKGROUND_EDITOR,
1702 IMG_BACKGROUND_INFO,
1703 IMG_BACKGROUND_INFO_ELEMENTS,
1704 IMG_BACKGROUND_INFO_MUSIC,
1705 IMG_BACKGROUND_INFO_CREDITS,
1706 IMG_BACKGROUND_INFO_PROGRAM,
1707 IMG_BACKGROUND_INFO_VERSION,
1708 IMG_BACKGROUND_INFO_LEVELSET,
1709 IMG_BACKGROUND_SETUP,
1710 IMG_BACKGROUND_PLAYING,
1711 IMG_BACKGROUND_DOOR,
1712 IMG_BACKGROUND_TAPE,
1713 IMG_BACKGROUND_PANEL,
1714 IMG_BACKGROUND_PALETTE,
1715 IMG_BACKGROUND_TOOLBOX,
1717 IMG_TITLESCREEN_INITIAL_1,
1718 IMG_TITLESCREEN_INITIAL_2,
1719 IMG_TITLESCREEN_INITIAL_3,
1720 IMG_TITLESCREEN_INITIAL_4,
1721 IMG_TITLESCREEN_INITIAL_5,
1728 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1729 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1730 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1731 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1732 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1733 IMG_BACKGROUND_TITLEMESSAGE_1,
1734 IMG_BACKGROUND_TITLEMESSAGE_2,
1735 IMG_BACKGROUND_TITLEMESSAGE_3,
1736 IMG_BACKGROUND_TITLEMESSAGE_4,
1737 IMG_BACKGROUND_TITLEMESSAGE_5,
1742 FreeGlobalAnimEventInfo();
1744 checked_free(graphic_info);
1746 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1748 // initialize "use_image_size" flag with default value
1749 for (i = 0; i < num_images; i++)
1750 graphic_info[i].use_image_size = FALSE;
1752 // initialize "use_image_size" flag from static configuration above
1753 for (i = 0; full_size_graphics[i] != -1; i++)
1754 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1756 // first set all graphic paramaters ...
1757 for (i = 0; i < num_images; i++)
1758 set_graphic_parameters(i);
1760 // ... then copy these parameters for cloned graphics
1761 for (i = 0; i < num_images; i++)
1762 if (graphic_info[i].clone_from != -1)
1763 set_cloned_graphic_parameters(i);
1765 for (i = 0; i < num_images; i++)
1767 Bitmap *src_bitmap = graphic_info[i].bitmap;
1771 int src_bitmap_width, src_bitmap_height;
1773 // now check if no animation frames are outside of the loaded image
1775 if (graphic_info[i].bitmap == NULL)
1776 continue; // skip check for optional images that are undefined
1778 // get image size (this can differ from the standard element tile size!)
1779 width = graphic_info[i].width;
1780 height = graphic_info[i].height;
1782 // get final bitmap size (with scaling, but without small images)
1783 src_bitmap_width = graphic_info[i].src_image_width;
1784 src_bitmap_height = graphic_info[i].src_image_height;
1786 // check if first animation frame is inside specified bitmap
1788 // do not use getGraphicSourceXY() here to get position of first frame;
1789 // this avoids calculating wrong start position for out-of-bounds frame
1790 src_x = graphic_info[i].src_x;
1791 src_y = graphic_info[i].src_y;
1793 if (program.headless)
1796 if (src_x < 0 || src_y < 0 ||
1797 src_x + width > src_bitmap_width ||
1798 src_y + height > src_bitmap_height)
1801 Warn("error found in config file:");
1802 Warn("- config file: '%s'", getImageConfigFilename());
1803 Warn("- config token: '%s'", getTokenFromImageID(i));
1804 Warn("- image file: '%s'", src_bitmap->source_filename);
1805 Warn("- frame size: %d, %d", width, height);
1806 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1807 src_x, src_y, src_bitmap_width, src_bitmap_height);
1808 Warn("custom graphic rejected for this element/action");
1810 if (i == fallback_graphic)
1811 Fail("no fallback graphic available");
1813 Warn("fallback done to 'char_exclam' for this graphic");
1816 graphic_info[i] = graphic_info[fallback_graphic];
1818 // if first frame out of bounds, do not check last frame anymore
1822 // check if last animation frame is inside specified bitmap
1824 last_frame = graphic_info[i].anim_frames - 1;
1825 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1827 if (src_x < 0 || src_y < 0 ||
1828 src_x + width > src_bitmap_width ||
1829 src_y + height > src_bitmap_height)
1832 Warn("error found in config file:");
1833 Warn("- config file: '%s'", getImageConfigFilename());
1834 Warn("- config token: '%s'", getTokenFromImageID(i));
1835 Warn("- image file: '%s'", src_bitmap->source_filename);
1836 Warn("- frame size: %d, %d", width, height);
1837 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1838 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1839 Warn("custom graphic rejected for this element/action");
1841 if (i == fallback_graphic)
1842 Fail("no fallback graphic available");
1844 Warn("fallback done to 'char_exclam' for this graphic");
1847 graphic_info[i] = graphic_info[fallback_graphic];
1852 static void InitGraphicCompatibilityInfo(void)
1854 struct FileInfo *fi_global_door =
1855 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1856 int num_images = getImageListSize();
1859 /* the following compatibility handling is needed for the following case:
1860 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1861 graphics mainly used for door and panel graphics, like editor, tape and
1862 in-game buttons with hard-coded bitmap positions and button sizes; as
1863 these graphics now have individual definitions, redefining "global.door"
1864 to change all these graphics at once like before does not work anymore
1865 (because all those individual definitions still have their default values);
1866 to solve this, remap all those individual definitions that are not
1867 redefined to the new bitmap of "global.door" if it was redefined */
1869 // special compatibility handling if image "global.door" was redefined
1870 if (fi_global_door->redefined)
1872 for (i = 0; i < num_images; i++)
1874 struct FileInfo *fi = getImageListEntryFromImageID(i);
1876 // process only those images that still use the default settings
1879 // process all images which default to same image as "global.door"
1880 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1883 Debug("init:InitGraphicCompatibilityInfo",
1884 "special treatment needed for token '%s'", fi->token);
1887 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1888 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1894 InitGraphicCompatibilityInfo_Doors();
1897 static void InitElementSoundInfo(void)
1899 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1900 int num_property_mappings = getSoundListPropertyMappingSize();
1903 // set values to -1 to identify later as "uninitialized" values
1904 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1905 for (act = 0; act < NUM_ACTIONS; act++)
1906 element_info[i].sound[act] = -1;
1908 // initialize element/sound mapping from static configuration
1909 for (i = 0; element_to_sound[i].element > -1; i++)
1911 int element = element_to_sound[i].element;
1912 int action = element_to_sound[i].action;
1913 int sound = element_to_sound[i].sound;
1914 boolean is_class = element_to_sound[i].is_class;
1917 action = ACTION_DEFAULT;
1920 element_info[element].sound[action] = sound;
1922 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1923 if (strEqual(element_info[j].class_name,
1924 element_info[element].class_name))
1925 element_info[j].sound[action] = sound;
1928 // initialize element class/sound mapping from dynamic configuration
1929 for (i = 0; i < num_property_mappings; i++)
1931 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1932 int action = property_mapping[i].ext1_index;
1933 int sound = property_mapping[i].artwork_index;
1935 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1939 action = ACTION_DEFAULT;
1941 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1942 if (strEqual(element_info[j].class_name,
1943 element_info[element_class].class_name))
1944 element_info[j].sound[action] = sound;
1947 // initialize element/sound mapping from dynamic configuration
1948 for (i = 0; i < num_property_mappings; i++)
1950 int element = property_mapping[i].base_index;
1951 int action = property_mapping[i].ext1_index;
1952 int sound = property_mapping[i].artwork_index;
1954 if (element >= MAX_NUM_ELEMENTS)
1958 action = ACTION_DEFAULT;
1960 element_info[element].sound[action] = sound;
1963 // now set all '-1' values to element specific default values
1964 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1966 for (act = 0; act < NUM_ACTIONS; act++)
1968 // generic default action sound (defined by "[default]" directive)
1969 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1971 // look for special default action sound (classic game specific)
1972 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1973 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1974 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1975 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1976 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1977 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1978 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1979 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1981 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1982 // !!! make this better !!!
1983 if (i == EL_EMPTY_SPACE)
1984 default_action_sound = element_info[EL_DEFAULT].sound[act];
1986 // no sound for this specific action -- use default action sound
1987 if (element_info[i].sound[act] == -1)
1988 element_info[i].sound[act] = default_action_sound;
1992 // copy sound settings to some elements that are only stored in level file
1993 // in native R'n'D levels, but are used by game engine in native EM levels
1994 for (i = 0; copy_properties[i][0] != -1; i++)
1995 for (j = 1; j <= 4; j++)
1996 for (act = 0; act < NUM_ACTIONS; act++)
1997 element_info[copy_properties[i][j]].sound[act] =
1998 element_info[copy_properties[i][0]].sound[act];
2001 static void InitGameModeSoundInfo(void)
2005 // set values to -1 to identify later as "uninitialized" values
2006 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2009 // initialize gamemode/sound mapping from static configuration
2010 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2012 int gamemode = gamemode_to_sound[i].gamemode;
2013 int sound = gamemode_to_sound[i].sound;
2016 gamemode = GAME_MODE_DEFAULT;
2018 menu.sound[gamemode] = sound;
2021 // now set all '-1' values to levelset specific default values
2022 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2023 if (menu.sound[i] == -1)
2024 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2027 static void set_sound_parameters(int sound, char **parameter_raw)
2029 int parameter[NUM_SND_ARGS];
2032 // get integer values from string parameters
2033 for (i = 0; i < NUM_SND_ARGS; i++)
2035 get_parameter_value(parameter_raw[i],
2036 sound_config_suffix[i].token,
2037 sound_config_suffix[i].type);
2039 // explicit loop mode setting in configuration overrides default value
2040 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2041 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2043 // sound volume to change the original volume when loading the sound file
2044 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2046 // sound priority to give certain sounds a higher or lower priority
2047 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2050 static void InitSoundInfo(void)
2052 int *sound_effect_properties;
2053 int num_sounds = getSoundListSize();
2056 checked_free(sound_info);
2058 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2059 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2061 // initialize sound effect for all elements to "no sound"
2062 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2063 for (j = 0; j < NUM_ACTIONS; j++)
2064 element_info[i].sound[j] = SND_UNDEFINED;
2066 for (i = 0; i < num_sounds; i++)
2068 struct FileInfo *sound = getSoundListEntry(i);
2069 int len_effect_text = strlen(sound->token);
2071 sound_effect_properties[i] = ACTION_OTHER;
2072 sound_info[i].loop = FALSE; // default: play sound only once
2074 // determine all loop sounds and identify certain sound classes
2076 for (j = 0; element_action_info[j].suffix; j++)
2078 int len_action_text = strlen(element_action_info[j].suffix);
2080 if (len_action_text < len_effect_text &&
2081 strEqual(&sound->token[len_effect_text - len_action_text],
2082 element_action_info[j].suffix))
2084 sound_effect_properties[i] = element_action_info[j].value;
2085 sound_info[i].loop = element_action_info[j].is_loop_sound;
2091 // associate elements and some selected sound actions
2093 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2095 if (element_info[j].class_name)
2097 int len_class_text = strlen(element_info[j].class_name);
2099 if (len_class_text + 1 < len_effect_text &&
2100 strncmp(sound->token,
2101 element_info[j].class_name, len_class_text) == 0 &&
2102 sound->token[len_class_text] == '.')
2104 int sound_action_value = sound_effect_properties[i];
2106 element_info[j].sound[sound_action_value] = i;
2111 set_sound_parameters(i, sound->parameter);
2114 free(sound_effect_properties);
2117 static void InitGameModeMusicInfo(void)
2119 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2120 int num_property_mappings = getMusicListPropertyMappingSize();
2121 int default_levelset_music = -1;
2124 // set values to -1 to identify later as "uninitialized" values
2125 for (i = 0; i < MAX_LEVELS; i++)
2126 levelset.music[i] = -1;
2127 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2130 // initialize gamemode/music mapping from static configuration
2131 for (i = 0; gamemode_to_music[i].music > -1; i++)
2133 int gamemode = gamemode_to_music[i].gamemode;
2134 int music = gamemode_to_music[i].music;
2137 gamemode = GAME_MODE_DEFAULT;
2139 menu.music[gamemode] = music;
2142 // initialize gamemode/music mapping from dynamic configuration
2143 for (i = 0; i < num_property_mappings; i++)
2145 int prefix = property_mapping[i].base_index;
2146 int gamemode = property_mapping[i].ext2_index;
2147 int level = property_mapping[i].ext3_index;
2148 int music = property_mapping[i].artwork_index;
2150 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2154 gamemode = GAME_MODE_DEFAULT;
2156 // level specific music only allowed for in-game music
2157 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2158 gamemode = GAME_MODE_PLAYING;
2163 default_levelset_music = music;
2166 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2167 levelset.music[level] = music;
2168 if (gamemode != GAME_MODE_PLAYING)
2169 menu.music[gamemode] = music;
2172 // now set all '-1' values to menu specific default values
2173 // (undefined values of "levelset.music[]" might stay at "-1" to
2174 // allow dynamic selection of music files from music directory!)
2175 for (i = 0; i < MAX_LEVELS; i++)
2176 if (levelset.music[i] == -1)
2177 levelset.music[i] = default_levelset_music;
2178 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2179 if (menu.music[i] == -1)
2180 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2183 static void set_music_parameters(int music, char **parameter_raw)
2185 int parameter[NUM_MUS_ARGS];
2188 // get integer values from string parameters
2189 for (i = 0; i < NUM_MUS_ARGS; i++)
2191 get_parameter_value(parameter_raw[i],
2192 music_config_suffix[i].token,
2193 music_config_suffix[i].type);
2195 // explicit loop mode setting in configuration overrides default value
2196 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2197 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2200 static void InitMusicInfo(void)
2202 int num_music = getMusicListSize();
2205 checked_free(music_info);
2207 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2209 for (i = 0; i < num_music; i++)
2211 struct FileInfo *music = getMusicListEntry(i);
2212 int len_music_text = strlen(music->token);
2214 music_info[i].loop = TRUE; // default: play music in loop mode
2216 // determine all loop music
2218 for (j = 0; music_prefix_info[j].prefix; j++)
2220 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2222 if (len_prefix_text < len_music_text &&
2223 strncmp(music->token,
2224 music_prefix_info[j].prefix, len_prefix_text) == 0)
2226 music_info[i].loop = music_prefix_info[j].is_loop_music;
2232 set_music_parameters(i, music->parameter);
2236 static void ReinitializeGraphics(void)
2238 print_timestamp_init("ReinitializeGraphics");
2240 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2242 InitGraphicInfo(); // graphic properties mapping
2243 print_timestamp_time("InitGraphicInfo");
2244 InitElementGraphicInfo(); // element game graphic mapping
2245 print_timestamp_time("InitElementGraphicInfo");
2246 InitElementSpecialGraphicInfo(); // element special graphic mapping
2247 print_timestamp_time("InitElementSpecialGraphicInfo");
2249 InitElementSmallImages(); // scale elements to all needed sizes
2250 print_timestamp_time("InitElementSmallImages");
2251 InitScaledImages(); // scale all other images, if needed
2252 print_timestamp_time("InitScaledImages");
2253 InitBitmapPointers(); // set standard size bitmap pointers
2254 print_timestamp_time("InitBitmapPointers");
2255 InitFontGraphicInfo(); // initialize text drawing functions
2256 print_timestamp_time("InitFontGraphicInfo");
2257 InitGlobalAnimGraphicInfo(); // initialize global animation config
2258 print_timestamp_time("InitGlobalAnimGraphicInfo");
2260 InitImageTextures(); // create textures for certain images
2261 print_timestamp_time("InitImageTextures");
2263 InitGraphicInfo_EM(); // graphic mapping for EM engine
2264 print_timestamp_time("InitGraphicInfo_EM");
2266 InitGraphicCompatibilityInfo();
2267 print_timestamp_time("InitGraphicCompatibilityInfo");
2269 SetMainBackgroundImage(IMG_BACKGROUND);
2270 print_timestamp_time("SetMainBackgroundImage");
2271 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2272 print_timestamp_time("SetDoorBackgroundImage");
2275 print_timestamp_time("InitGadgets");
2277 print_timestamp_time("InitDoors");
2279 print_timestamp_done("ReinitializeGraphics");
2282 static void ReinitializeSounds(void)
2284 InitSoundInfo(); // sound properties mapping
2285 InitElementSoundInfo(); // element game sound mapping
2286 InitGameModeSoundInfo(); // game mode sound mapping
2287 InitGlobalAnimSoundInfo(); // global animation sound settings
2289 InitPlayLevelSound(); // internal game sound settings
2292 static void ReinitializeMusic(void)
2294 InitMusicInfo(); // music properties mapping
2295 InitGameModeMusicInfo(); // game mode music mapping
2296 InitGlobalAnimMusicInfo(); // global animation music settings
2299 static int get_special_property_bit(int element, int property_bit_nr)
2301 struct PropertyBitInfo
2307 static struct PropertyBitInfo pb_can_move_into_acid[] =
2309 // the player may be able fall into acid when gravity is activated
2314 { EL_SP_MURPHY, 0 },
2315 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2317 // all elements that can move may be able to also move into acid
2320 { EL_BUG_RIGHT, 1 },
2323 { EL_SPACESHIP, 2 },
2324 { EL_SPACESHIP_LEFT, 2 },
2325 { EL_SPACESHIP_RIGHT, 2 },
2326 { EL_SPACESHIP_UP, 2 },
2327 { EL_SPACESHIP_DOWN, 2 },
2328 { EL_BD_BUTTERFLY, 3 },
2329 { EL_BD_BUTTERFLY_LEFT, 3 },
2330 { EL_BD_BUTTERFLY_RIGHT, 3 },
2331 { EL_BD_BUTTERFLY_UP, 3 },
2332 { EL_BD_BUTTERFLY_DOWN, 3 },
2333 { EL_BD_FIREFLY, 4 },
2334 { EL_BD_FIREFLY_LEFT, 4 },
2335 { EL_BD_FIREFLY_RIGHT, 4 },
2336 { EL_BD_FIREFLY_UP, 4 },
2337 { EL_BD_FIREFLY_DOWN, 4 },
2339 { EL_YAMYAM_LEFT, 5 },
2340 { EL_YAMYAM_RIGHT, 5 },
2341 { EL_YAMYAM_UP, 5 },
2342 { EL_YAMYAM_DOWN, 5 },
2343 { EL_DARK_YAMYAM, 6 },
2346 { EL_PACMAN_LEFT, 8 },
2347 { EL_PACMAN_RIGHT, 8 },
2348 { EL_PACMAN_UP, 8 },
2349 { EL_PACMAN_DOWN, 8 },
2351 { EL_MOLE_LEFT, 9 },
2352 { EL_MOLE_RIGHT, 9 },
2354 { EL_MOLE_DOWN, 9 },
2358 { EL_SATELLITE, 13 },
2359 { EL_SP_SNIKSNAK, 14 },
2360 { EL_SP_ELECTRON, 15 },
2363 { EL_SPRING_LEFT, 17 },
2364 { EL_SPRING_RIGHT, 17 },
2365 { EL_EMC_ANDROID, 18 },
2370 static struct PropertyBitInfo pb_dont_collide_with[] =
2372 { EL_SP_SNIKSNAK, 0 },
2373 { EL_SP_ELECTRON, 1 },
2381 struct PropertyBitInfo *pb_info;
2384 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2385 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2390 struct PropertyBitInfo *pb_info = NULL;
2393 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2394 if (pb_definition[i].bit_nr == property_bit_nr)
2395 pb_info = pb_definition[i].pb_info;
2397 if (pb_info == NULL)
2400 for (i = 0; pb_info[i].element != -1; i++)
2401 if (pb_info[i].element == element)
2402 return pb_info[i].bit_nr;
2407 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2408 boolean property_value)
2410 int bit_nr = get_special_property_bit(element, property_bit_nr);
2415 *bitfield |= (1 << bit_nr);
2417 *bitfield &= ~(1 << bit_nr);
2421 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2423 int bit_nr = get_special_property_bit(element, property_bit_nr);
2426 return ((*bitfield & (1 << bit_nr)) != 0);
2431 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2433 static int group_nr;
2434 static struct ElementGroupInfo *group;
2435 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2438 if (actual_group == NULL) // not yet initialized
2441 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2443 Warn("recursion too deep when resolving group element %d",
2444 group_element - EL_GROUP_START + 1);
2446 // replace element which caused too deep recursion by question mark
2447 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2452 if (recursion_depth == 0) // initialization
2454 group = actual_group;
2455 group_nr = GROUP_NR(group_element);
2457 group->num_elements_resolved = 0;
2458 group->choice_pos = 0;
2460 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2461 element_info[i].in_group[group_nr] = FALSE;
2464 for (i = 0; i < actual_group->num_elements; i++)
2466 int element = actual_group->element[i];
2468 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2471 if (IS_GROUP_ELEMENT(element))
2472 ResolveGroupElementExt(element, recursion_depth + 1);
2475 group->element_resolved[group->num_elements_resolved++] = element;
2476 element_info[element].in_group[group_nr] = TRUE;
2481 void ResolveGroupElement(int group_element)
2483 ResolveGroupElementExt(group_element, 0);
2486 void InitElementPropertiesStatic(void)
2488 static boolean clipboard_elements_initialized = FALSE;
2490 static int ep_diggable[] =
2495 EL_SP_BUGGY_BASE_ACTIVATING,
2498 EL_INVISIBLE_SAND_ACTIVE,
2501 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2502 // (if amoeba can grow into anything diggable, maybe keep these out)
2507 EL_SP_BUGGY_BASE_ACTIVE,
2514 static int ep_collectible_only[] =
2536 EL_DYNABOMB_INCREASE_NUMBER,
2537 EL_DYNABOMB_INCREASE_SIZE,
2538 EL_DYNABOMB_INCREASE_POWER,
2556 // !!! handle separately !!!
2557 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2563 static int ep_dont_run_into[] =
2565 // same elements as in 'ep_dont_touch'
2571 // same elements as in 'ep_dont_collide_with'
2583 // !!! maybe this should better be handled by 'ep_diggable' !!!
2588 EL_SP_BUGGY_BASE_ACTIVE,
2595 static int ep_dont_collide_with[] =
2597 // same elements as in 'ep_dont_touch'
2614 static int ep_dont_touch[] =
2624 static int ep_indestructible[] =
2628 EL_ACID_POOL_TOPLEFT,
2629 EL_ACID_POOL_TOPRIGHT,
2630 EL_ACID_POOL_BOTTOMLEFT,
2631 EL_ACID_POOL_BOTTOM,
2632 EL_ACID_POOL_BOTTOMRIGHT,
2633 EL_SP_HARDWARE_GRAY,
2634 EL_SP_HARDWARE_GREEN,
2635 EL_SP_HARDWARE_BLUE,
2637 EL_SP_HARDWARE_YELLOW,
2638 EL_SP_HARDWARE_BASE_1,
2639 EL_SP_HARDWARE_BASE_2,
2640 EL_SP_HARDWARE_BASE_3,
2641 EL_SP_HARDWARE_BASE_4,
2642 EL_SP_HARDWARE_BASE_5,
2643 EL_SP_HARDWARE_BASE_6,
2644 EL_INVISIBLE_STEELWALL,
2645 EL_INVISIBLE_STEELWALL_ACTIVE,
2646 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2647 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2648 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2649 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2650 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2651 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2652 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2653 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2654 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2655 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2656 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2657 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2659 EL_LIGHT_SWITCH_ACTIVE,
2660 EL_SIGN_EXCLAMATION,
2661 EL_SIGN_RADIOACTIVITY,
2668 EL_SIGN_ENTRY_FORBIDDEN,
2669 EL_SIGN_EMERGENCY_EXIT,
2677 EL_STEEL_EXIT_CLOSED,
2679 EL_STEEL_EXIT_OPENING,
2680 EL_STEEL_EXIT_CLOSING,
2681 EL_EM_STEEL_EXIT_CLOSED,
2682 EL_EM_STEEL_EXIT_OPEN,
2683 EL_EM_STEEL_EXIT_OPENING,
2684 EL_EM_STEEL_EXIT_CLOSING,
2685 EL_DC_STEELWALL_1_LEFT,
2686 EL_DC_STEELWALL_1_RIGHT,
2687 EL_DC_STEELWALL_1_TOP,
2688 EL_DC_STEELWALL_1_BOTTOM,
2689 EL_DC_STEELWALL_1_HORIZONTAL,
2690 EL_DC_STEELWALL_1_VERTICAL,
2691 EL_DC_STEELWALL_1_TOPLEFT,
2692 EL_DC_STEELWALL_1_TOPRIGHT,
2693 EL_DC_STEELWALL_1_BOTTOMLEFT,
2694 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2695 EL_DC_STEELWALL_1_TOPLEFT_2,
2696 EL_DC_STEELWALL_1_TOPRIGHT_2,
2697 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2698 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2699 EL_DC_STEELWALL_2_LEFT,
2700 EL_DC_STEELWALL_2_RIGHT,
2701 EL_DC_STEELWALL_2_TOP,
2702 EL_DC_STEELWALL_2_BOTTOM,
2703 EL_DC_STEELWALL_2_HORIZONTAL,
2704 EL_DC_STEELWALL_2_VERTICAL,
2705 EL_DC_STEELWALL_2_MIDDLE,
2706 EL_DC_STEELWALL_2_SINGLE,
2707 EL_STEELWALL_SLIPPERY,
2721 EL_GATE_1_GRAY_ACTIVE,
2722 EL_GATE_2_GRAY_ACTIVE,
2723 EL_GATE_3_GRAY_ACTIVE,
2724 EL_GATE_4_GRAY_ACTIVE,
2733 EL_EM_GATE_1_GRAY_ACTIVE,
2734 EL_EM_GATE_2_GRAY_ACTIVE,
2735 EL_EM_GATE_3_GRAY_ACTIVE,
2736 EL_EM_GATE_4_GRAY_ACTIVE,
2745 EL_EMC_GATE_5_GRAY_ACTIVE,
2746 EL_EMC_GATE_6_GRAY_ACTIVE,
2747 EL_EMC_GATE_7_GRAY_ACTIVE,
2748 EL_EMC_GATE_8_GRAY_ACTIVE,
2750 EL_DC_GATE_WHITE_GRAY,
2751 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2752 EL_DC_GATE_FAKE_GRAY,
2754 EL_SWITCHGATE_OPENING,
2755 EL_SWITCHGATE_CLOSED,
2756 EL_SWITCHGATE_CLOSING,
2757 EL_DC_SWITCHGATE_SWITCH_UP,
2758 EL_DC_SWITCHGATE_SWITCH_DOWN,
2760 EL_TIMEGATE_OPENING,
2762 EL_TIMEGATE_CLOSING,
2763 EL_DC_TIMEGATE_SWITCH,
2764 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2768 EL_TUBE_VERTICAL_LEFT,
2769 EL_TUBE_VERTICAL_RIGHT,
2770 EL_TUBE_HORIZONTAL_UP,
2771 EL_TUBE_HORIZONTAL_DOWN,
2776 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2777 EL_EXPANDABLE_STEELWALL_VERTICAL,
2778 EL_EXPANDABLE_STEELWALL_ANY,
2783 static int ep_slippery[] =
2797 EL_ROBOT_WHEEL_ACTIVE,
2803 EL_ACID_POOL_TOPLEFT,
2804 EL_ACID_POOL_TOPRIGHT,
2814 EL_STEELWALL_SLIPPERY,
2817 EL_EMC_WALL_SLIPPERY_1,
2818 EL_EMC_WALL_SLIPPERY_2,
2819 EL_EMC_WALL_SLIPPERY_3,
2820 EL_EMC_WALL_SLIPPERY_4,
2822 EL_EMC_MAGIC_BALL_ACTIVE,
2827 static int ep_can_change[] =
2832 static int ep_can_move[] =
2834 // same elements as in 'pb_can_move_into_acid'
2857 static int ep_can_fall[] =
2872 EL_QUICKSAND_FAST_FULL,
2874 EL_BD_MAGIC_WALL_FULL,
2875 EL_DC_MAGIC_WALL_FULL,
2889 static int ep_can_smash_player[] =
2915 static int ep_can_smash_enemies[] =
2924 static int ep_can_smash_everything[] =
2933 static int ep_explodes_by_fire[] =
2935 // same elements as in 'ep_explodes_impact'
2940 // same elements as in 'ep_explodes_smashed'
2950 EL_EM_DYNAMITE_ACTIVE,
2951 EL_DYNABOMB_PLAYER_1_ACTIVE,
2952 EL_DYNABOMB_PLAYER_2_ACTIVE,
2953 EL_DYNABOMB_PLAYER_3_ACTIVE,
2954 EL_DYNABOMB_PLAYER_4_ACTIVE,
2955 EL_DYNABOMB_INCREASE_NUMBER,
2956 EL_DYNABOMB_INCREASE_SIZE,
2957 EL_DYNABOMB_INCREASE_POWER,
2958 EL_SP_DISK_RED_ACTIVE,
2972 static int ep_explodes_smashed[] =
2974 // same elements as in 'ep_explodes_impact'
2988 static int ep_explodes_impact[] =
2997 static int ep_walkable_over[] =
3001 EL_SOKOBAN_FIELD_EMPTY,
3008 EL_EM_STEEL_EXIT_OPEN,
3009 EL_EM_STEEL_EXIT_OPENING,
3018 EL_GATE_1_GRAY_ACTIVE,
3019 EL_GATE_2_GRAY_ACTIVE,
3020 EL_GATE_3_GRAY_ACTIVE,
3021 EL_GATE_4_GRAY_ACTIVE,
3029 static int ep_walkable_inside[] =
3034 EL_TUBE_VERTICAL_LEFT,
3035 EL_TUBE_VERTICAL_RIGHT,
3036 EL_TUBE_HORIZONTAL_UP,
3037 EL_TUBE_HORIZONTAL_DOWN,
3046 static int ep_walkable_under[] =
3051 static int ep_passable_over[] =
3061 EL_EM_GATE_1_GRAY_ACTIVE,
3062 EL_EM_GATE_2_GRAY_ACTIVE,
3063 EL_EM_GATE_3_GRAY_ACTIVE,
3064 EL_EM_GATE_4_GRAY_ACTIVE,
3073 EL_EMC_GATE_5_GRAY_ACTIVE,
3074 EL_EMC_GATE_6_GRAY_ACTIVE,
3075 EL_EMC_GATE_7_GRAY_ACTIVE,
3076 EL_EMC_GATE_8_GRAY_ACTIVE,
3078 EL_DC_GATE_WHITE_GRAY,
3079 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3086 static int ep_passable_inside[] =
3092 EL_SP_PORT_HORIZONTAL,
3093 EL_SP_PORT_VERTICAL,
3095 EL_SP_GRAVITY_PORT_LEFT,
3096 EL_SP_GRAVITY_PORT_RIGHT,
3097 EL_SP_GRAVITY_PORT_UP,
3098 EL_SP_GRAVITY_PORT_DOWN,
3099 EL_SP_GRAVITY_ON_PORT_LEFT,
3100 EL_SP_GRAVITY_ON_PORT_RIGHT,
3101 EL_SP_GRAVITY_ON_PORT_UP,
3102 EL_SP_GRAVITY_ON_PORT_DOWN,
3103 EL_SP_GRAVITY_OFF_PORT_LEFT,
3104 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3105 EL_SP_GRAVITY_OFF_PORT_UP,
3106 EL_SP_GRAVITY_OFF_PORT_DOWN,
3111 static int ep_passable_under[] =
3116 static int ep_droppable[] =
3121 static int ep_explodes_1x1_old[] =
3126 static int ep_pushable[] =
3138 EL_SOKOBAN_FIELD_FULL,
3147 static int ep_explodes_cross_old[] =
3152 static int ep_protected[] =
3154 // same elements as in 'ep_walkable_inside'
3158 EL_TUBE_VERTICAL_LEFT,
3159 EL_TUBE_VERTICAL_RIGHT,
3160 EL_TUBE_HORIZONTAL_UP,
3161 EL_TUBE_HORIZONTAL_DOWN,
3167 // same elements as in 'ep_passable_over'
3176 EL_EM_GATE_1_GRAY_ACTIVE,
3177 EL_EM_GATE_2_GRAY_ACTIVE,
3178 EL_EM_GATE_3_GRAY_ACTIVE,
3179 EL_EM_GATE_4_GRAY_ACTIVE,
3188 EL_EMC_GATE_5_GRAY_ACTIVE,
3189 EL_EMC_GATE_6_GRAY_ACTIVE,
3190 EL_EMC_GATE_7_GRAY_ACTIVE,
3191 EL_EMC_GATE_8_GRAY_ACTIVE,
3193 EL_DC_GATE_WHITE_GRAY,
3194 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3198 // same elements as in 'ep_passable_inside'
3203 EL_SP_PORT_HORIZONTAL,
3204 EL_SP_PORT_VERTICAL,
3206 EL_SP_GRAVITY_PORT_LEFT,
3207 EL_SP_GRAVITY_PORT_RIGHT,
3208 EL_SP_GRAVITY_PORT_UP,
3209 EL_SP_GRAVITY_PORT_DOWN,
3210 EL_SP_GRAVITY_ON_PORT_LEFT,
3211 EL_SP_GRAVITY_ON_PORT_RIGHT,
3212 EL_SP_GRAVITY_ON_PORT_UP,
3213 EL_SP_GRAVITY_ON_PORT_DOWN,
3214 EL_SP_GRAVITY_OFF_PORT_LEFT,
3215 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3216 EL_SP_GRAVITY_OFF_PORT_UP,
3217 EL_SP_GRAVITY_OFF_PORT_DOWN,
3222 static int ep_throwable[] =
3227 static int ep_can_explode[] =
3229 // same elements as in 'ep_explodes_impact'
3234 // same elements as in 'ep_explodes_smashed'
3240 // elements that can explode by explosion or by dragonfire
3244 EL_EM_DYNAMITE_ACTIVE,
3245 EL_DYNABOMB_PLAYER_1_ACTIVE,
3246 EL_DYNABOMB_PLAYER_2_ACTIVE,
3247 EL_DYNABOMB_PLAYER_3_ACTIVE,
3248 EL_DYNABOMB_PLAYER_4_ACTIVE,
3249 EL_DYNABOMB_INCREASE_NUMBER,
3250 EL_DYNABOMB_INCREASE_SIZE,
3251 EL_DYNABOMB_INCREASE_POWER,
3252 EL_SP_DISK_RED_ACTIVE,
3260 // elements that can explode only by explosion
3266 static int ep_gravity_reachable[] =
3272 EL_INVISIBLE_SAND_ACTIVE,
3277 EL_SP_PORT_HORIZONTAL,
3278 EL_SP_PORT_VERTICAL,
3280 EL_SP_GRAVITY_PORT_LEFT,
3281 EL_SP_GRAVITY_PORT_RIGHT,
3282 EL_SP_GRAVITY_PORT_UP,
3283 EL_SP_GRAVITY_PORT_DOWN,
3284 EL_SP_GRAVITY_ON_PORT_LEFT,
3285 EL_SP_GRAVITY_ON_PORT_RIGHT,
3286 EL_SP_GRAVITY_ON_PORT_UP,
3287 EL_SP_GRAVITY_ON_PORT_DOWN,
3288 EL_SP_GRAVITY_OFF_PORT_LEFT,
3289 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3290 EL_SP_GRAVITY_OFF_PORT_UP,
3291 EL_SP_GRAVITY_OFF_PORT_DOWN,
3297 static int ep_player[] =
3304 EL_SOKOBAN_FIELD_PLAYER,
3310 static int ep_can_pass_magic_wall[] =
3324 static int ep_can_pass_dc_magic_wall[] =
3340 static int ep_switchable[] =
3344 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3345 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3346 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3347 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3348 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3349 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3350 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3351 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3352 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3353 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3354 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3355 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3356 EL_SWITCHGATE_SWITCH_UP,
3357 EL_SWITCHGATE_SWITCH_DOWN,
3358 EL_DC_SWITCHGATE_SWITCH_UP,
3359 EL_DC_SWITCHGATE_SWITCH_DOWN,
3361 EL_LIGHT_SWITCH_ACTIVE,
3363 EL_DC_TIMEGATE_SWITCH,
3364 EL_BALLOON_SWITCH_LEFT,
3365 EL_BALLOON_SWITCH_RIGHT,
3366 EL_BALLOON_SWITCH_UP,
3367 EL_BALLOON_SWITCH_DOWN,
3368 EL_BALLOON_SWITCH_ANY,
3369 EL_BALLOON_SWITCH_NONE,
3372 EL_EMC_MAGIC_BALL_SWITCH,
3373 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3378 static int ep_bd_element[] =
3412 static int ep_sp_element[] =
3414 // should always be valid
3417 // standard classic Supaplex elements
3424 EL_SP_HARDWARE_GRAY,
3432 EL_SP_GRAVITY_PORT_RIGHT,
3433 EL_SP_GRAVITY_PORT_DOWN,
3434 EL_SP_GRAVITY_PORT_LEFT,
3435 EL_SP_GRAVITY_PORT_UP,
3440 EL_SP_PORT_VERTICAL,
3441 EL_SP_PORT_HORIZONTAL,
3447 EL_SP_HARDWARE_BASE_1,
3448 EL_SP_HARDWARE_GREEN,
3449 EL_SP_HARDWARE_BLUE,
3451 EL_SP_HARDWARE_YELLOW,
3452 EL_SP_HARDWARE_BASE_2,
3453 EL_SP_HARDWARE_BASE_3,
3454 EL_SP_HARDWARE_BASE_4,
3455 EL_SP_HARDWARE_BASE_5,
3456 EL_SP_HARDWARE_BASE_6,
3460 // additional elements that appeared in newer Supaplex levels
3463 // additional gravity port elements (not switching, but setting gravity)
3464 EL_SP_GRAVITY_ON_PORT_LEFT,
3465 EL_SP_GRAVITY_ON_PORT_RIGHT,
3466 EL_SP_GRAVITY_ON_PORT_UP,
3467 EL_SP_GRAVITY_ON_PORT_DOWN,
3468 EL_SP_GRAVITY_OFF_PORT_LEFT,
3469 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3470 EL_SP_GRAVITY_OFF_PORT_UP,
3471 EL_SP_GRAVITY_OFF_PORT_DOWN,
3473 // more than one Murphy in a level results in an inactive clone
3476 // runtime Supaplex elements
3477 EL_SP_DISK_RED_ACTIVE,
3478 EL_SP_TERMINAL_ACTIVE,
3479 EL_SP_BUGGY_BASE_ACTIVATING,
3480 EL_SP_BUGGY_BASE_ACTIVE,
3487 static int ep_sb_element[] =
3492 EL_SOKOBAN_FIELD_EMPTY,
3493 EL_SOKOBAN_FIELD_FULL,
3494 EL_SOKOBAN_FIELD_PLAYER,
3499 EL_INVISIBLE_STEELWALL,
3504 static int ep_gem[] =
3516 static int ep_food_dark_yamyam[] =
3544 static int ep_food_penguin[] =
3558 static int ep_food_pig[] =
3570 static int ep_historic_wall[] =
3581 EL_GATE_1_GRAY_ACTIVE,
3582 EL_GATE_2_GRAY_ACTIVE,
3583 EL_GATE_3_GRAY_ACTIVE,
3584 EL_GATE_4_GRAY_ACTIVE,
3593 EL_EM_GATE_1_GRAY_ACTIVE,
3594 EL_EM_GATE_2_GRAY_ACTIVE,
3595 EL_EM_GATE_3_GRAY_ACTIVE,
3596 EL_EM_GATE_4_GRAY_ACTIVE,
3603 EL_EXPANDABLE_WALL_HORIZONTAL,
3604 EL_EXPANDABLE_WALL_VERTICAL,
3605 EL_EXPANDABLE_WALL_ANY,
3606 EL_EXPANDABLE_WALL_GROWING,
3607 EL_BD_EXPANDABLE_WALL,
3614 EL_SP_HARDWARE_GRAY,
3615 EL_SP_HARDWARE_GREEN,
3616 EL_SP_HARDWARE_BLUE,
3618 EL_SP_HARDWARE_YELLOW,
3619 EL_SP_HARDWARE_BASE_1,
3620 EL_SP_HARDWARE_BASE_2,
3621 EL_SP_HARDWARE_BASE_3,
3622 EL_SP_HARDWARE_BASE_4,
3623 EL_SP_HARDWARE_BASE_5,
3624 EL_SP_HARDWARE_BASE_6,
3626 EL_SP_TERMINAL_ACTIVE,
3629 EL_INVISIBLE_STEELWALL,
3630 EL_INVISIBLE_STEELWALL_ACTIVE,
3632 EL_INVISIBLE_WALL_ACTIVE,
3633 EL_STEELWALL_SLIPPERY,
3650 static int ep_historic_solid[] =
3654 EL_EXPANDABLE_WALL_HORIZONTAL,
3655 EL_EXPANDABLE_WALL_VERTICAL,
3656 EL_EXPANDABLE_WALL_ANY,
3657 EL_BD_EXPANDABLE_WALL,
3670 EL_QUICKSAND_FILLING,
3671 EL_QUICKSAND_EMPTYING,
3673 EL_MAGIC_WALL_ACTIVE,
3674 EL_MAGIC_WALL_EMPTYING,
3675 EL_MAGIC_WALL_FILLING,
3679 EL_BD_MAGIC_WALL_ACTIVE,
3680 EL_BD_MAGIC_WALL_EMPTYING,
3681 EL_BD_MAGIC_WALL_FULL,
3682 EL_BD_MAGIC_WALL_FILLING,
3683 EL_BD_MAGIC_WALL_DEAD,
3692 EL_SP_TERMINAL_ACTIVE,
3696 EL_INVISIBLE_WALL_ACTIVE,
3697 EL_SWITCHGATE_SWITCH_UP,
3698 EL_SWITCHGATE_SWITCH_DOWN,
3700 EL_TIMEGATE_SWITCH_ACTIVE,
3712 // the following elements are a direct copy of "indestructible" elements,
3713 // except "EL_ACID", which is "indestructible", but not "solid"!
3718 EL_ACID_POOL_TOPLEFT,
3719 EL_ACID_POOL_TOPRIGHT,
3720 EL_ACID_POOL_BOTTOMLEFT,
3721 EL_ACID_POOL_BOTTOM,
3722 EL_ACID_POOL_BOTTOMRIGHT,
3723 EL_SP_HARDWARE_GRAY,
3724 EL_SP_HARDWARE_GREEN,
3725 EL_SP_HARDWARE_BLUE,
3727 EL_SP_HARDWARE_YELLOW,
3728 EL_SP_HARDWARE_BASE_1,
3729 EL_SP_HARDWARE_BASE_2,
3730 EL_SP_HARDWARE_BASE_3,
3731 EL_SP_HARDWARE_BASE_4,
3732 EL_SP_HARDWARE_BASE_5,
3733 EL_SP_HARDWARE_BASE_6,
3734 EL_INVISIBLE_STEELWALL,
3735 EL_INVISIBLE_STEELWALL_ACTIVE,
3736 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3737 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3738 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3739 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3740 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3741 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3742 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3743 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3744 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3745 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3746 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3747 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3749 EL_LIGHT_SWITCH_ACTIVE,
3750 EL_SIGN_EXCLAMATION,
3751 EL_SIGN_RADIOACTIVITY,
3758 EL_SIGN_ENTRY_FORBIDDEN,
3759 EL_SIGN_EMERGENCY_EXIT,
3767 EL_STEEL_EXIT_CLOSED,
3769 EL_STEEL_EXIT_OPENING,
3770 EL_STEEL_EXIT_CLOSING,
3771 EL_EM_STEEL_EXIT_CLOSED,
3772 EL_EM_STEEL_EXIT_OPEN,
3773 EL_EM_STEEL_EXIT_OPENING,
3774 EL_EM_STEEL_EXIT_CLOSING,
3775 EL_DC_STEELWALL_1_LEFT,
3776 EL_DC_STEELWALL_1_RIGHT,
3777 EL_DC_STEELWALL_1_TOP,
3778 EL_DC_STEELWALL_1_BOTTOM,
3779 EL_DC_STEELWALL_1_HORIZONTAL,
3780 EL_DC_STEELWALL_1_VERTICAL,
3781 EL_DC_STEELWALL_1_TOPLEFT,
3782 EL_DC_STEELWALL_1_TOPRIGHT,
3783 EL_DC_STEELWALL_1_BOTTOMLEFT,
3784 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3785 EL_DC_STEELWALL_1_TOPLEFT_2,
3786 EL_DC_STEELWALL_1_TOPRIGHT_2,
3787 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3788 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3789 EL_DC_STEELWALL_2_LEFT,
3790 EL_DC_STEELWALL_2_RIGHT,
3791 EL_DC_STEELWALL_2_TOP,
3792 EL_DC_STEELWALL_2_BOTTOM,
3793 EL_DC_STEELWALL_2_HORIZONTAL,
3794 EL_DC_STEELWALL_2_VERTICAL,
3795 EL_DC_STEELWALL_2_MIDDLE,
3796 EL_DC_STEELWALL_2_SINGLE,
3797 EL_STEELWALL_SLIPPERY,
3811 EL_GATE_1_GRAY_ACTIVE,
3812 EL_GATE_2_GRAY_ACTIVE,
3813 EL_GATE_3_GRAY_ACTIVE,
3814 EL_GATE_4_GRAY_ACTIVE,
3823 EL_EM_GATE_1_GRAY_ACTIVE,
3824 EL_EM_GATE_2_GRAY_ACTIVE,
3825 EL_EM_GATE_3_GRAY_ACTIVE,
3826 EL_EM_GATE_4_GRAY_ACTIVE,
3835 EL_EMC_GATE_5_GRAY_ACTIVE,
3836 EL_EMC_GATE_6_GRAY_ACTIVE,
3837 EL_EMC_GATE_7_GRAY_ACTIVE,
3838 EL_EMC_GATE_8_GRAY_ACTIVE,
3840 EL_DC_GATE_WHITE_GRAY,
3841 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3842 EL_DC_GATE_FAKE_GRAY,
3844 EL_SWITCHGATE_OPENING,
3845 EL_SWITCHGATE_CLOSED,
3846 EL_SWITCHGATE_CLOSING,
3847 EL_DC_SWITCHGATE_SWITCH_UP,
3848 EL_DC_SWITCHGATE_SWITCH_DOWN,
3850 EL_TIMEGATE_OPENING,
3852 EL_TIMEGATE_CLOSING,
3853 EL_DC_TIMEGATE_SWITCH,
3854 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3858 EL_TUBE_VERTICAL_LEFT,
3859 EL_TUBE_VERTICAL_RIGHT,
3860 EL_TUBE_HORIZONTAL_UP,
3861 EL_TUBE_HORIZONTAL_DOWN,
3866 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3867 EL_EXPANDABLE_STEELWALL_VERTICAL,
3868 EL_EXPANDABLE_STEELWALL_ANY,
3873 static int ep_classic_enemy[] =
3890 static int ep_belt[] =
3892 EL_CONVEYOR_BELT_1_LEFT,
3893 EL_CONVEYOR_BELT_1_MIDDLE,
3894 EL_CONVEYOR_BELT_1_RIGHT,
3895 EL_CONVEYOR_BELT_2_LEFT,
3896 EL_CONVEYOR_BELT_2_MIDDLE,
3897 EL_CONVEYOR_BELT_2_RIGHT,
3898 EL_CONVEYOR_BELT_3_LEFT,
3899 EL_CONVEYOR_BELT_3_MIDDLE,
3900 EL_CONVEYOR_BELT_3_RIGHT,
3901 EL_CONVEYOR_BELT_4_LEFT,
3902 EL_CONVEYOR_BELT_4_MIDDLE,
3903 EL_CONVEYOR_BELT_4_RIGHT,
3908 static int ep_belt_active[] =
3910 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3911 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3912 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3913 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3914 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3915 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3916 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3917 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3918 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3919 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3920 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3921 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3926 static int ep_belt_switch[] =
3928 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3929 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3930 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3931 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3932 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3933 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3934 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3935 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3936 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3937 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3938 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3939 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3944 static int ep_tube[] =
3951 EL_TUBE_HORIZONTAL_UP,
3952 EL_TUBE_HORIZONTAL_DOWN,
3954 EL_TUBE_VERTICAL_LEFT,
3955 EL_TUBE_VERTICAL_RIGHT,
3961 static int ep_acid_pool[] =
3963 EL_ACID_POOL_TOPLEFT,
3964 EL_ACID_POOL_TOPRIGHT,
3965 EL_ACID_POOL_BOTTOMLEFT,
3966 EL_ACID_POOL_BOTTOM,
3967 EL_ACID_POOL_BOTTOMRIGHT,
3972 static int ep_keygate[] =
3982 EL_GATE_1_GRAY_ACTIVE,
3983 EL_GATE_2_GRAY_ACTIVE,
3984 EL_GATE_3_GRAY_ACTIVE,
3985 EL_GATE_4_GRAY_ACTIVE,
3994 EL_EM_GATE_1_GRAY_ACTIVE,
3995 EL_EM_GATE_2_GRAY_ACTIVE,
3996 EL_EM_GATE_3_GRAY_ACTIVE,
3997 EL_EM_GATE_4_GRAY_ACTIVE,
4006 EL_EMC_GATE_5_GRAY_ACTIVE,
4007 EL_EMC_GATE_6_GRAY_ACTIVE,
4008 EL_EMC_GATE_7_GRAY_ACTIVE,
4009 EL_EMC_GATE_8_GRAY_ACTIVE,
4011 EL_DC_GATE_WHITE_GRAY,
4012 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4017 static int ep_amoeboid[] =
4029 static int ep_amoebalive[] =
4040 static int ep_has_editor_content[] =
4046 EL_SOKOBAN_FIELD_PLAYER,
4063 static int ep_can_turn_each_move[] =
4065 // !!! do something with this one !!!
4069 static int ep_can_grow[] =
4083 static int ep_active_bomb[] =
4086 EL_EM_DYNAMITE_ACTIVE,
4087 EL_DYNABOMB_PLAYER_1_ACTIVE,
4088 EL_DYNABOMB_PLAYER_2_ACTIVE,
4089 EL_DYNABOMB_PLAYER_3_ACTIVE,
4090 EL_DYNABOMB_PLAYER_4_ACTIVE,
4091 EL_SP_DISK_RED_ACTIVE,
4096 static int ep_inactive[] =
4106 EL_QUICKSAND_FAST_EMPTY,
4129 EL_GATE_1_GRAY_ACTIVE,
4130 EL_GATE_2_GRAY_ACTIVE,
4131 EL_GATE_3_GRAY_ACTIVE,
4132 EL_GATE_4_GRAY_ACTIVE,
4141 EL_EM_GATE_1_GRAY_ACTIVE,
4142 EL_EM_GATE_2_GRAY_ACTIVE,
4143 EL_EM_GATE_3_GRAY_ACTIVE,
4144 EL_EM_GATE_4_GRAY_ACTIVE,
4153 EL_EMC_GATE_5_GRAY_ACTIVE,
4154 EL_EMC_GATE_6_GRAY_ACTIVE,
4155 EL_EMC_GATE_7_GRAY_ACTIVE,
4156 EL_EMC_GATE_8_GRAY_ACTIVE,
4158 EL_DC_GATE_WHITE_GRAY,
4159 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4160 EL_DC_GATE_FAKE_GRAY,
4163 EL_INVISIBLE_STEELWALL,
4171 EL_WALL_EMERALD_YELLOW,
4172 EL_DYNABOMB_INCREASE_NUMBER,
4173 EL_DYNABOMB_INCREASE_SIZE,
4174 EL_DYNABOMB_INCREASE_POWER,
4178 EL_SOKOBAN_FIELD_EMPTY,
4179 EL_SOKOBAN_FIELD_FULL,
4180 EL_WALL_EMERALD_RED,
4181 EL_WALL_EMERALD_PURPLE,
4182 EL_ACID_POOL_TOPLEFT,
4183 EL_ACID_POOL_TOPRIGHT,
4184 EL_ACID_POOL_BOTTOMLEFT,
4185 EL_ACID_POOL_BOTTOM,
4186 EL_ACID_POOL_BOTTOMRIGHT,
4190 EL_BD_MAGIC_WALL_DEAD,
4192 EL_DC_MAGIC_WALL_DEAD,
4193 EL_AMOEBA_TO_DIAMOND,
4201 EL_SP_GRAVITY_PORT_RIGHT,
4202 EL_SP_GRAVITY_PORT_DOWN,
4203 EL_SP_GRAVITY_PORT_LEFT,
4204 EL_SP_GRAVITY_PORT_UP,
4205 EL_SP_PORT_HORIZONTAL,
4206 EL_SP_PORT_VERTICAL,
4217 EL_SP_HARDWARE_GRAY,
4218 EL_SP_HARDWARE_GREEN,
4219 EL_SP_HARDWARE_BLUE,
4221 EL_SP_HARDWARE_YELLOW,
4222 EL_SP_HARDWARE_BASE_1,
4223 EL_SP_HARDWARE_BASE_2,
4224 EL_SP_HARDWARE_BASE_3,
4225 EL_SP_HARDWARE_BASE_4,
4226 EL_SP_HARDWARE_BASE_5,
4227 EL_SP_HARDWARE_BASE_6,
4228 EL_SP_GRAVITY_ON_PORT_LEFT,
4229 EL_SP_GRAVITY_ON_PORT_RIGHT,
4230 EL_SP_GRAVITY_ON_PORT_UP,
4231 EL_SP_GRAVITY_ON_PORT_DOWN,
4232 EL_SP_GRAVITY_OFF_PORT_LEFT,
4233 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4234 EL_SP_GRAVITY_OFF_PORT_UP,
4235 EL_SP_GRAVITY_OFF_PORT_DOWN,
4236 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4237 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4238 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4239 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4240 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4241 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4242 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4243 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4244 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4245 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4246 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4247 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4248 EL_SIGN_EXCLAMATION,
4249 EL_SIGN_RADIOACTIVITY,
4256 EL_SIGN_ENTRY_FORBIDDEN,
4257 EL_SIGN_EMERGENCY_EXIT,
4265 EL_DC_STEELWALL_1_LEFT,
4266 EL_DC_STEELWALL_1_RIGHT,
4267 EL_DC_STEELWALL_1_TOP,
4268 EL_DC_STEELWALL_1_BOTTOM,
4269 EL_DC_STEELWALL_1_HORIZONTAL,
4270 EL_DC_STEELWALL_1_VERTICAL,
4271 EL_DC_STEELWALL_1_TOPLEFT,
4272 EL_DC_STEELWALL_1_TOPRIGHT,
4273 EL_DC_STEELWALL_1_BOTTOMLEFT,
4274 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4275 EL_DC_STEELWALL_1_TOPLEFT_2,
4276 EL_DC_STEELWALL_1_TOPRIGHT_2,
4277 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4278 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4279 EL_DC_STEELWALL_2_LEFT,
4280 EL_DC_STEELWALL_2_RIGHT,
4281 EL_DC_STEELWALL_2_TOP,
4282 EL_DC_STEELWALL_2_BOTTOM,
4283 EL_DC_STEELWALL_2_HORIZONTAL,
4284 EL_DC_STEELWALL_2_VERTICAL,
4285 EL_DC_STEELWALL_2_MIDDLE,
4286 EL_DC_STEELWALL_2_SINGLE,
4287 EL_STEELWALL_SLIPPERY,
4292 EL_EMC_WALL_SLIPPERY_1,
4293 EL_EMC_WALL_SLIPPERY_2,
4294 EL_EMC_WALL_SLIPPERY_3,
4295 EL_EMC_WALL_SLIPPERY_4,
4316 static int ep_em_slippery_wall[] =
4321 static int ep_gfx_crumbled[] =
4332 static int ep_editor_cascade_active[] =
4334 EL_INTERNAL_CASCADE_BD_ACTIVE,
4335 EL_INTERNAL_CASCADE_EM_ACTIVE,
4336 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4337 EL_INTERNAL_CASCADE_RND_ACTIVE,
4338 EL_INTERNAL_CASCADE_SB_ACTIVE,
4339 EL_INTERNAL_CASCADE_SP_ACTIVE,
4340 EL_INTERNAL_CASCADE_DC_ACTIVE,
4341 EL_INTERNAL_CASCADE_DX_ACTIVE,
4342 EL_INTERNAL_CASCADE_MM_ACTIVE,
4343 EL_INTERNAL_CASCADE_DF_ACTIVE,
4344 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4345 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4346 EL_INTERNAL_CASCADE_CE_ACTIVE,
4347 EL_INTERNAL_CASCADE_GE_ACTIVE,
4348 EL_INTERNAL_CASCADE_REF_ACTIVE,
4349 EL_INTERNAL_CASCADE_USER_ACTIVE,
4350 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4355 static int ep_editor_cascade_inactive[] =
4357 EL_INTERNAL_CASCADE_BD,
4358 EL_INTERNAL_CASCADE_EM,
4359 EL_INTERNAL_CASCADE_EMC,
4360 EL_INTERNAL_CASCADE_RND,
4361 EL_INTERNAL_CASCADE_SB,
4362 EL_INTERNAL_CASCADE_SP,
4363 EL_INTERNAL_CASCADE_DC,
4364 EL_INTERNAL_CASCADE_DX,
4365 EL_INTERNAL_CASCADE_MM,
4366 EL_INTERNAL_CASCADE_DF,
4367 EL_INTERNAL_CASCADE_CHARS,
4368 EL_INTERNAL_CASCADE_STEEL_CHARS,
4369 EL_INTERNAL_CASCADE_CE,
4370 EL_INTERNAL_CASCADE_GE,
4371 EL_INTERNAL_CASCADE_REF,
4372 EL_INTERNAL_CASCADE_USER,
4373 EL_INTERNAL_CASCADE_DYNAMIC,
4378 static int ep_obsolete[] =
4382 EL_EM_KEY_1_FILE_OBSOLETE,
4383 EL_EM_KEY_2_FILE_OBSOLETE,
4384 EL_EM_KEY_3_FILE_OBSOLETE,
4385 EL_EM_KEY_4_FILE_OBSOLETE,
4386 EL_ENVELOPE_OBSOLETE,
4395 } element_properties[] =
4397 { ep_diggable, EP_DIGGABLE },
4398 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4399 { ep_dont_run_into, EP_DONT_RUN_INTO },
4400 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4401 { ep_dont_touch, EP_DONT_TOUCH },
4402 { ep_indestructible, EP_INDESTRUCTIBLE },
4403 { ep_slippery, EP_SLIPPERY },
4404 { ep_can_change, EP_CAN_CHANGE },
4405 { ep_can_move, EP_CAN_MOVE },
4406 { ep_can_fall, EP_CAN_FALL },
4407 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4408 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4409 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4410 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4411 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4412 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4413 { ep_walkable_over, EP_WALKABLE_OVER },
4414 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4415 { ep_walkable_under, EP_WALKABLE_UNDER },
4416 { ep_passable_over, EP_PASSABLE_OVER },
4417 { ep_passable_inside, EP_PASSABLE_INSIDE },
4418 { ep_passable_under, EP_PASSABLE_UNDER },
4419 { ep_droppable, EP_DROPPABLE },
4420 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4421 { ep_pushable, EP_PUSHABLE },
4422 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4423 { ep_protected, EP_PROTECTED },
4424 { ep_throwable, EP_THROWABLE },
4425 { ep_can_explode, EP_CAN_EXPLODE },
4426 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4428 { ep_player, EP_PLAYER },
4429 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4430 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4431 { ep_switchable, EP_SWITCHABLE },
4432 { ep_bd_element, EP_BD_ELEMENT },
4433 { ep_sp_element, EP_SP_ELEMENT },
4434 { ep_sb_element, EP_SB_ELEMENT },
4436 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4437 { ep_food_penguin, EP_FOOD_PENGUIN },
4438 { ep_food_pig, EP_FOOD_PIG },
4439 { ep_historic_wall, EP_HISTORIC_WALL },
4440 { ep_historic_solid, EP_HISTORIC_SOLID },
4441 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4442 { ep_belt, EP_BELT },
4443 { ep_belt_active, EP_BELT_ACTIVE },
4444 { ep_belt_switch, EP_BELT_SWITCH },
4445 { ep_tube, EP_TUBE },
4446 { ep_acid_pool, EP_ACID_POOL },
4447 { ep_keygate, EP_KEYGATE },
4448 { ep_amoeboid, EP_AMOEBOID },
4449 { ep_amoebalive, EP_AMOEBALIVE },
4450 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4451 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4452 { ep_can_grow, EP_CAN_GROW },
4453 { ep_active_bomb, EP_ACTIVE_BOMB },
4454 { ep_inactive, EP_INACTIVE },
4456 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4458 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4460 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4461 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4463 { ep_obsolete, EP_OBSOLETE },
4470 // always start with reliable default values (element has no properties)
4471 // (but never initialize clipboard elements after the very first time)
4472 // (to be able to use clipboard elements between several levels)
4473 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4474 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4475 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4476 SET_PROPERTY(i, j, FALSE);
4478 // set all base element properties from above array definitions
4479 for (i = 0; element_properties[i].elements != NULL; i++)
4480 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4481 SET_PROPERTY((element_properties[i].elements)[j],
4482 element_properties[i].property, TRUE);
4484 // copy properties to some elements that are only stored in level file
4485 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4486 for (j = 0; copy_properties[j][0] != -1; j++)
4487 if (HAS_PROPERTY(copy_properties[j][0], i))
4488 for (k = 1; k <= 4; k++)
4489 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4491 // set static element properties that are not listed in array definitions
4492 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4493 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4495 clipboard_elements_initialized = TRUE;
4498 void InitElementPropertiesEngine(int engine_version)
4500 static int no_wall_properties[] =
4503 EP_COLLECTIBLE_ONLY,
4505 EP_DONT_COLLIDE_WITH,
4508 EP_CAN_SMASH_PLAYER,
4509 EP_CAN_SMASH_ENEMIES,
4510 EP_CAN_SMASH_EVERYTHING,
4515 EP_FOOD_DARK_YAMYAM,
4531 /* important: after initialization in InitElementPropertiesStatic(), the
4532 elements are not again initialized to a default value; therefore all
4533 changes have to make sure that they leave the element with a defined
4534 property (which means that conditional property changes must be set to
4535 a reliable default value before) */
4537 // resolve group elements
4538 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4539 ResolveGroupElement(EL_GROUP_START + i);
4541 // set all special, combined or engine dependent element properties
4542 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4544 // do not change (already initialized) clipboard elements here
4545 if (IS_CLIPBOARD_ELEMENT(i))
4548 // ---------- INACTIVE ----------------------------------------------------
4549 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4550 i <= EL_CHAR_END) ||
4551 (i >= EL_STEEL_CHAR_START &&
4552 i <= EL_STEEL_CHAR_END)));
4554 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4555 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4556 IS_WALKABLE_INSIDE(i) ||
4557 IS_WALKABLE_UNDER(i)));
4559 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4560 IS_PASSABLE_INSIDE(i) ||
4561 IS_PASSABLE_UNDER(i)));
4563 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4564 IS_PASSABLE_OVER(i)));
4566 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4567 IS_PASSABLE_INSIDE(i)));
4569 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4570 IS_PASSABLE_UNDER(i)));
4572 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4575 // ---------- COLLECTIBLE -------------------------------------------------
4576 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4580 // ---------- SNAPPABLE ---------------------------------------------------
4581 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4582 IS_COLLECTIBLE(i) ||
4586 // ---------- WALL --------------------------------------------------------
4587 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4589 for (j = 0; no_wall_properties[j] != -1; j++)
4590 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4591 i >= EL_FIRST_RUNTIME_UNREAL)
4592 SET_PROPERTY(i, EP_WALL, FALSE);
4594 if (IS_HISTORIC_WALL(i))
4595 SET_PROPERTY(i, EP_WALL, TRUE);
4597 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4598 if (engine_version < VERSION_IDENT(2,2,0,0))
4599 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4601 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4603 !IS_COLLECTIBLE(i)));
4605 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4606 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4607 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4609 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4612 // ---------- EXPLOSION_PROOF ---------------------------------------------
4614 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4615 else if (engine_version < VERSION_IDENT(2,2,0,0))
4616 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4618 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4622 if (IS_CUSTOM_ELEMENT(i))
4624 // these are additional properties which are initially false when set
4626 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4628 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4629 if (DONT_COLLIDE_WITH(i))
4630 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4632 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4633 if (CAN_SMASH_EVERYTHING(i))
4634 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4635 if (CAN_SMASH_ENEMIES(i))
4636 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4639 // ---------- CAN_SMASH ---------------------------------------------------
4640 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4641 CAN_SMASH_ENEMIES(i) ||
4642 CAN_SMASH_EVERYTHING(i)));
4644 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4645 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4646 EXPLODES_BY_FIRE(i)));
4648 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4649 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4650 EXPLODES_SMASHED(i)));
4652 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4653 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4654 EXPLODES_IMPACT(i)));
4656 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4657 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4659 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4660 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4661 i == EL_BLACK_ORB));
4663 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4664 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4666 IS_CUSTOM_ELEMENT(i)));
4668 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4669 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4670 i == EL_SP_ELECTRON));
4672 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4673 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4674 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4675 getMoveIntoAcidProperty(&level, i));
4677 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4678 if (MAYBE_DONT_COLLIDE_WITH(i))
4679 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4680 getDontCollideWithProperty(&level, i));
4682 // ---------- SP_PORT -----------------------------------------------------
4683 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4684 IS_PASSABLE_INSIDE(i)));
4686 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4687 for (j = 0; j < level.num_android_clone_elements; j++)
4688 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4690 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4692 // ---------- CAN_CHANGE --------------------------------------------------
4693 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4694 for (j = 0; j < element_info[i].num_change_pages; j++)
4695 if (element_info[i].change_page[j].can_change)
4696 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4698 // ---------- HAS_ACTION --------------------------------------------------
4699 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4700 for (j = 0; j < element_info[i].num_change_pages; j++)
4701 if (element_info[i].change_page[j].has_action)
4702 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4704 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4705 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4708 // ---------- GFX_CRUMBLED ------------------------------------------------
4709 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4710 element_info[i].crumbled[ACTION_DEFAULT] !=
4711 element_info[i].graphic[ACTION_DEFAULT]);
4713 // ---------- EDITOR_CASCADE ----------------------------------------------
4714 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4715 IS_EDITOR_CASCADE_INACTIVE(i)));
4718 // dynamically adjust element properties according to game engine version
4720 static int ep_em_slippery_wall[] =
4725 EL_EXPANDABLE_WALL_HORIZONTAL,
4726 EL_EXPANDABLE_WALL_VERTICAL,
4727 EL_EXPANDABLE_WALL_ANY,
4728 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4729 EL_EXPANDABLE_STEELWALL_VERTICAL,
4730 EL_EXPANDABLE_STEELWALL_ANY,
4731 EL_EXPANDABLE_STEELWALL_GROWING,
4735 static int ep_em_explodes_by_fire[] =
4738 EL_EM_DYNAMITE_ACTIVE,
4743 // special EM style gems behaviour
4744 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4745 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4746 level.em_slippery_gems);
4748 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4749 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4750 (level.em_slippery_gems &&
4751 engine_version > VERSION_IDENT(2,0,1,0)));
4753 // special EM style explosion behaviour regarding chain reactions
4754 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4755 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4756 level.em_explodes_by_fire);
4759 // this is needed because some graphics depend on element properties
4760 if (game_status == GAME_MODE_PLAYING)
4761 InitElementGraphicInfo();
4764 void InitElementPropertiesGfxElement(void)
4768 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4770 struct ElementInfo *ei = &element_info[i];
4772 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4776 static void InitGlobal(void)
4781 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4783 // check if element_name_info entry defined for each element in "main.h"
4784 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4785 Fail("undefined 'element_name_info' entry for element %d", i);
4787 element_info[i].token_name = element_name_info[i].token_name;
4788 element_info[i].class_name = element_name_info[i].class_name;
4789 element_info[i].editor_description= element_name_info[i].editor_description;
4792 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4794 // check if global_anim_name_info defined for each entry in "main.h"
4795 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4796 global_anim_name_info[i].token_name == NULL)
4797 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4799 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4802 // create hash from image config list
4803 image_config_hash = newSetupFileHash();
4804 for (i = 0; image_config[i].token != NULL; i++)
4805 setHashEntry(image_config_hash,
4806 image_config[i].token,
4807 image_config[i].value);
4809 // create hash from element token list
4810 element_token_hash = newSetupFileHash();
4811 for (i = 0; element_name_info[i].token_name != NULL; i++)
4812 setHashEntry(element_token_hash,
4813 element_name_info[i].token_name,
4816 // create hash from graphic token list
4817 graphic_token_hash = newSetupFileHash();
4818 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4819 if (strSuffix(image_config[i].value, ".png") ||
4820 strSuffix(image_config[i].value, ".pcx") ||
4821 strSuffix(image_config[i].value, ".wav") ||
4822 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4823 setHashEntry(graphic_token_hash,
4824 image_config[i].token,
4825 int2str(graphic++, 0));
4827 // create hash from font token list
4828 font_token_hash = newSetupFileHash();
4829 for (i = 0; font_info[i].token_name != NULL; i++)
4830 setHashEntry(font_token_hash,
4831 font_info[i].token_name,
4834 // set default filenames for all cloned graphics in static configuration
4835 for (i = 0; image_config[i].token != NULL; i++)
4837 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4839 char *token = image_config[i].token;
4840 char *token_clone_from = getStringCat2(token, ".clone_from");
4841 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4843 if (token_cloned != NULL)
4845 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4847 if (value_cloned != NULL)
4849 // set default filename in static configuration
4850 image_config[i].value = value_cloned;
4852 // set default filename in image config hash
4853 setHashEntry(image_config_hash, token, value_cloned);
4857 free(token_clone_from);
4861 // always start with reliable default values (all elements)
4862 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4863 ActiveElement[i] = i;
4865 // now add all entries that have an active state (active elements)
4866 for (i = 0; element_with_active_state[i].element != -1; i++)
4868 int element = element_with_active_state[i].element;
4869 int element_active = element_with_active_state[i].element_active;
4871 ActiveElement[element] = element_active;
4874 // always start with reliable default values (all buttons)
4875 for (i = 0; i < NUM_IMAGE_FILES; i++)
4876 ActiveButton[i] = i;
4878 // now add all entries that have an active state (active buttons)
4879 for (i = 0; button_with_active_state[i].button != -1; i++)
4881 int button = button_with_active_state[i].button;
4882 int button_active = button_with_active_state[i].button_active;
4884 ActiveButton[button] = button_active;
4887 // always start with reliable default values (all fonts)
4888 for (i = 0; i < NUM_FONTS; i++)
4891 // now add all entries that have an active state (active fonts)
4892 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4894 int font = font_with_active_state[i].font_nr;
4895 int font_active = font_with_active_state[i].font_nr_active;
4897 ActiveFont[font] = font_active;
4900 global.autoplay_leveldir = NULL;
4901 global.patchtapes_leveldir = NULL;
4902 global.convert_leveldir = NULL;
4903 global.create_images_dir = NULL;
4905 global.frames_per_second = 0;
4906 global.show_frames_per_second = FALSE;
4908 global.border_status = GAME_MODE_LOADING;
4909 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4911 global.use_envelope_request = FALSE;
4914 static void Execute_Command(char *command)
4918 if (strEqual(command, "print graphicsinfo.conf"))
4920 Print("# You can configure additional/alternative image files here.\n");
4921 Print("# (The entries below are default and therefore commented out.)\n");
4923 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4925 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4928 for (i = 0; image_config[i].token != NULL; i++)
4929 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4930 image_config[i].value));
4934 else if (strEqual(command, "print soundsinfo.conf"))
4936 Print("# You can configure additional/alternative sound files here.\n");
4937 Print("# (The entries below are default and therefore commented out.)\n");
4939 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4941 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4944 for (i = 0; sound_config[i].token != NULL; i++)
4945 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4946 sound_config[i].value));
4950 else if (strEqual(command, "print musicinfo.conf"))
4952 Print("# You can configure additional/alternative music files here.\n");
4953 Print("# (The entries below are default and therefore commented out.)\n");
4955 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4957 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4960 for (i = 0; music_config[i].token != NULL; i++)
4961 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4962 music_config[i].value));
4966 else if (strEqual(command, "print editorsetup.conf"))
4968 Print("# You can configure your personal editor element list here.\n");
4969 Print("# (The entries below are default and therefore commented out.)\n");
4972 // this is needed to be able to check element list for cascade elements
4973 InitElementPropertiesStatic();
4974 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4976 PrintEditorElementList();
4980 else if (strEqual(command, "print helpanim.conf"))
4982 Print("# You can configure different element help animations here.\n");
4983 Print("# (The entries below are default and therefore commented out.)\n");
4986 for (i = 0; helpanim_config[i].token != NULL; i++)
4988 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4989 helpanim_config[i].value));
4991 if (strEqual(helpanim_config[i].token, "end"))
4997 else if (strEqual(command, "print helptext.conf"))
4999 Print("# You can configure different element help text here.\n");
5000 Print("# (The entries below are default and therefore commented out.)\n");
5003 for (i = 0; helptext_config[i].token != NULL; i++)
5004 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5005 helptext_config[i].value));
5009 else if (strPrefix(command, "dump level "))
5011 char *filename = &command[11];
5013 if (!fileExists(filename))
5014 Fail("cannot open file '%s'", filename);
5016 LoadLevelFromFilename(&level, filename);
5021 else if (strPrefix(command, "dump tape "))
5023 char *filename = &command[10];
5025 if (!fileExists(filename))
5026 Fail("cannot open file '%s'", filename);
5028 LoadTapeFromFilename(filename);
5033 else if (strPrefix(command, "autoplay ") ||
5034 strPrefix(command, "autoffwd ") ||
5035 strPrefix(command, "autowarp ") ||
5036 strPrefix(command, "autotest ") ||
5037 strPrefix(command, "autofix "))
5039 char *str_ptr = getStringCopy(&command[8]); // read command parameters
5041 global.autoplay_mode =
5042 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5043 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5044 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5045 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5046 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5047 AUTOPLAY_MODE_NONE);
5049 while (*str_ptr != '\0') // continue parsing string
5051 // cut leading whitespace from string, replace it by string terminator
5052 while (*str_ptr == ' ' || *str_ptr == '\t')
5055 if (*str_ptr == '\0') // end of string reached
5058 if (global.autoplay_leveldir == NULL) // read level set string
5060 global.autoplay_leveldir = str_ptr;
5061 global.autoplay_all = TRUE; // default: play all tapes
5063 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5064 global.autoplay_level[i] = FALSE;
5066 else // read level number string
5068 int level_nr = atoi(str_ptr); // get level_nr value
5070 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5071 global.autoplay_level[level_nr] = TRUE;
5073 global.autoplay_all = FALSE;
5076 // advance string pointer to the next whitespace (or end of string)
5077 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5081 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5082 program.headless = TRUE;
5084 else if (strPrefix(command, "patch tapes "))
5086 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5088 // skip leading whitespace
5089 while (*str_ptr == ' ' || *str_ptr == '\t')
5092 if (*str_ptr == '\0')
5093 Fail("cannot find MODE in command '%s'", command);
5095 global.patchtapes_mode = str_ptr; // store patch mode
5097 // advance to next whitespace (or end of string)
5098 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5101 while (*str_ptr != '\0') // continue parsing string
5103 // cut leading whitespace from string, replace it by string terminator
5104 while (*str_ptr == ' ' || *str_ptr == '\t')
5107 if (*str_ptr == '\0') // end of string reached
5110 if (global.patchtapes_leveldir == NULL) // read level set string
5112 global.patchtapes_leveldir = str_ptr;
5113 global.patchtapes_all = TRUE; // default: patch all tapes
5115 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5116 global.patchtapes_level[i] = FALSE;
5118 else // read level number string
5120 int level_nr = atoi(str_ptr); // get level_nr value
5122 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5123 global.patchtapes_level[level_nr] = TRUE;
5125 global.patchtapes_all = FALSE;
5128 // advance string pointer to the next whitespace (or end of string)
5129 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5133 if (global.patchtapes_leveldir == NULL)
5135 if (strEqual(global.patchtapes_mode, "help"))
5136 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5138 Fail("cannot find LEVELDIR in command '%s'", command);
5141 program.headless = TRUE;
5143 else if (strPrefix(command, "convert "))
5145 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5146 char *str_ptr = strchr(str_copy, ' ');
5148 global.convert_leveldir = str_copy;
5149 global.convert_level_nr = -1;
5151 if (str_ptr != NULL) // level number follows
5153 *str_ptr++ = '\0'; // terminate leveldir string
5154 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5157 program.headless = TRUE;
5159 else if (strPrefix(command, "create images "))
5161 global.create_images_dir = getStringCopy(&command[14]);
5163 if (access(global.create_images_dir, W_OK) != 0)
5164 Fail("image target directory '%s' not found or not writable",
5165 global.create_images_dir);
5167 else if (strPrefix(command, "create CE image "))
5169 CreateCustomElementImages(&command[16]);
5175 FailWithHelp("unrecognized command '%s'", command);
5178 // disable networking if any valid command was recognized
5179 options.network = setup.network_mode = FALSE;
5182 static void InitSetup(void)
5184 LoadSetup(); // global setup info
5185 LoadSetup_AutoSetup(); // global auto setup info
5187 // set some options from setup file
5189 if (setup.options.verbose)
5190 options.verbose = TRUE;
5192 if (setup.debug.show_frames_per_second)
5193 global.show_frames_per_second = TRUE;
5196 static void InitGameInfo(void)
5198 game.restart_level = FALSE;
5199 game.restart_game_message = NULL;
5200 game.request_active = FALSE;
5203 static void InitPlayerInfo(void)
5207 // choose default local player
5208 local_player = &stored_player[0];
5210 for (i = 0; i < MAX_PLAYERS; i++)
5212 stored_player[i].connected_locally = FALSE;
5213 stored_player[i].connected_network = FALSE;
5216 local_player->connected_locally = TRUE;
5219 static void InitArtworkInfo(void)
5224 static char *get_string_in_brackets(char *string)
5226 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5228 sprintf(string_in_brackets, "[%s]", string);
5230 return string_in_brackets;
5233 static char *get_level_id_suffix(int id_nr)
5235 char *id_suffix = checked_malloc(1 + 3 + 1);
5237 if (id_nr < 0 || id_nr > 999)
5240 sprintf(id_suffix, ".%03d", id_nr);
5245 static void InitArtworkConfig(void)
5247 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5249 NUM_GLOBAL_ANIM_TOKENS + 1];
5250 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5251 NUM_GLOBAL_ANIM_TOKENS + 1];
5252 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5253 NUM_GLOBAL_ANIM_TOKENS + 1];
5254 static char *action_id_suffix[NUM_ACTIONS + 1];
5255 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5256 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5257 static char *level_id_suffix[MAX_LEVELS + 1];
5258 static char *dummy[1] = { NULL };
5259 static char *ignore_generic_tokens[] =
5264 "program_copyright",
5269 static char **ignore_image_tokens;
5270 static char **ignore_sound_tokens;
5271 static char **ignore_music_tokens;
5272 int num_ignore_generic_tokens;
5273 int num_ignore_image_tokens;
5274 int num_ignore_sound_tokens;
5275 int num_ignore_music_tokens;
5278 // dynamically determine list of generic tokens to be ignored
5279 num_ignore_generic_tokens = 0;
5280 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5281 num_ignore_generic_tokens++;
5283 // dynamically determine list of image tokens to be ignored
5284 num_ignore_image_tokens = num_ignore_generic_tokens;
5285 for (i = 0; image_config_vars[i].token != NULL; i++)
5286 num_ignore_image_tokens++;
5287 ignore_image_tokens =
5288 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5289 for (i = 0; i < num_ignore_generic_tokens; i++)
5290 ignore_image_tokens[i] = ignore_generic_tokens[i];
5291 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5292 ignore_image_tokens[num_ignore_generic_tokens + i] =
5293 image_config_vars[i].token;
5294 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5296 // dynamically determine list of sound tokens to be ignored
5297 num_ignore_sound_tokens = num_ignore_generic_tokens;
5298 ignore_sound_tokens =
5299 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5300 for (i = 0; i < num_ignore_generic_tokens; i++)
5301 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5302 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5304 // dynamically determine list of music tokens to be ignored
5305 num_ignore_music_tokens = num_ignore_generic_tokens;
5306 ignore_music_tokens =
5307 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5308 for (i = 0; i < num_ignore_generic_tokens; i++)
5309 ignore_music_tokens[i] = ignore_generic_tokens[i];
5310 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5312 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5313 image_id_prefix[i] = element_info[i].token_name;
5314 for (i = 0; i < NUM_FONTS; i++)
5315 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5316 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5317 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5318 global_anim_info[i].token_name;
5319 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5321 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5322 sound_id_prefix[i] = element_info[i].token_name;
5323 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5324 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5325 get_string_in_brackets(element_info[i].class_name);
5326 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5327 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5328 global_anim_info[i].token_name;
5329 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5331 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5332 music_id_prefix[i] = music_prefix_info[i].prefix;
5333 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5334 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5335 global_anim_info[i].token_name;
5336 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5338 for (i = 0; i < NUM_ACTIONS; i++)
5339 action_id_suffix[i] = element_action_info[i].suffix;
5340 action_id_suffix[NUM_ACTIONS] = NULL;
5342 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5343 direction_id_suffix[i] = element_direction_info[i].suffix;
5344 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5346 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5347 special_id_suffix[i] = special_suffix_info[i].suffix;
5348 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5350 for (i = 0; i < MAX_LEVELS; i++)
5351 level_id_suffix[i] = get_level_id_suffix(i);
5352 level_id_suffix[MAX_LEVELS] = NULL;
5354 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5355 image_id_prefix, action_id_suffix, direction_id_suffix,
5356 special_id_suffix, ignore_image_tokens);
5357 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5358 sound_id_prefix, action_id_suffix, dummy,
5359 special_id_suffix, ignore_sound_tokens);
5360 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5361 music_id_prefix, action_id_suffix, special_id_suffix,
5362 level_id_suffix, ignore_music_tokens);
5365 static void InitMixer(void)
5372 static void InitVideoOverlay(void)
5374 // if virtual buttons are not loaded from setup file, repeat initializing
5375 // virtual buttons grid with default values now that video is initialized
5376 if (!setup.touch.grid_initialized)
5379 InitTileCursorInfo();
5383 void InitGfxBuffers(void)
5385 static int win_xsize_last = -1;
5386 static int win_ysize_last = -1;
5388 // create additional image buffers for double-buffering and cross-fading
5390 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5392 // used to temporarily store the backbuffer -- only re-create if changed
5393 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5394 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5396 win_xsize_last = WIN_XSIZE;
5397 win_ysize_last = WIN_YSIZE;
5400 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5401 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5402 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5403 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5405 // initialize screen properties
5406 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5407 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5409 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5410 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5411 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5412 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5413 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5414 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5416 // required if door size definitions have changed
5417 InitGraphicCompatibilityInfo_Doors();
5419 InitGfxBuffers_EM();
5420 InitGfxBuffers_SP();
5423 static void InitGfx(void)
5425 struct GraphicInfo *graphic_info_last = graphic_info;
5426 char *filename_font_initial = NULL;
5427 char *filename_anim_initial = NULL;
5428 Bitmap *bitmap_font_initial = NULL;
5431 // determine settings for initial font (for displaying startup messages)
5432 for (i = 0; image_config[i].token != NULL; i++)
5434 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5436 char font_token[128];
5439 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5440 len_font_token = strlen(font_token);
5442 if (strEqual(image_config[i].token, font_token))
5443 filename_font_initial = image_config[i].value;
5444 else if (strlen(image_config[i].token) > len_font_token &&
5445 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5447 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5448 font_initial[j].src_x = atoi(image_config[i].value);
5449 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5450 font_initial[j].src_y = atoi(image_config[i].value);
5451 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5452 font_initial[j].width = atoi(image_config[i].value);
5453 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5454 font_initial[j].height = atoi(image_config[i].value);
5459 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5461 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5462 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5465 if (filename_font_initial == NULL) // should not happen
5466 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5469 InitGfxCustomArtworkInfo();
5470 InitGfxOtherSettings();
5472 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5474 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5475 font_initial[j].bitmap = bitmap_font_initial;
5477 InitFontGraphicInfo();
5481 DrawInitText("Loading graphics", 120, FC_GREEN);
5483 // initialize settings for busy animation with default values
5484 int parameter[NUM_GFX_ARGS];
5485 for (i = 0; i < NUM_GFX_ARGS; i++)
5486 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5487 image_config_suffix[i].token,
5488 image_config_suffix[i].type);
5490 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5491 int len_anim_token = strlen(anim_token);
5493 // read settings for busy animation from default custom artwork config
5494 char *gfx_config_filename = getPath3(options.graphics_directory,
5496 GRAPHICSINFO_FILENAME);
5498 if (fileExists(gfx_config_filename))
5500 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5502 if (setup_file_hash)
5504 char *filename = getHashEntry(setup_file_hash, anim_token);
5508 filename_anim_initial = getStringCopy(filename);
5510 for (j = 0; image_config_suffix[j].token != NULL; j++)
5512 int type = image_config_suffix[j].type;
5513 char *suffix = image_config_suffix[j].token;
5514 char *token = getStringCat2(anim_token, suffix);
5515 char *value = getHashEntry(setup_file_hash, token);
5517 checked_free(token);
5520 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5524 freeSetupFileHash(setup_file_hash);
5528 if (filename_anim_initial == NULL)
5530 // read settings for busy animation from static default artwork config
5531 for (i = 0; image_config[i].token != NULL; i++)
5533 if (strEqual(image_config[i].token, anim_token))
5534 filename_anim_initial = getStringCopy(image_config[i].value);
5535 else if (strlen(image_config[i].token) > len_anim_token &&
5536 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5538 for (j = 0; image_config_suffix[j].token != NULL; j++)
5540 if (strEqual(&image_config[i].token[len_anim_token],
5541 image_config_suffix[j].token))
5543 get_graphic_parameter_value(image_config[i].value,
5544 image_config_suffix[j].token,
5545 image_config_suffix[j].type);
5551 if (filename_anim_initial == NULL) // should not happen
5552 Fail("cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5554 anim_initial.bitmaps =
5555 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5557 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5558 LoadCustomImage(filename_anim_initial);
5560 checked_free(filename_anim_initial);
5562 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5564 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5566 graphic_info = graphic_info_last;
5568 init.busy.width = anim_initial.width;
5569 init.busy.height = anim_initial.height;
5571 InitMenuDesignSettings_Static();
5573 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5574 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5575 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5576 InitGfxDrawTileCursorFunction(DrawTileCursor);
5578 gfx.fade_border_source_status = global.border_status;
5579 gfx.fade_border_target_status = global.border_status;
5580 gfx.masked_border_bitmap_ptr = backbuffer;
5582 // use copy of busy animation to prevent change while reloading artwork
5586 static void InitGfxBackground(void)
5588 fieldbuffer = bitmap_db_field;
5589 SetDrawtoField(DRAW_TO_BACKBUFFER);
5591 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5593 redraw_mask = REDRAW_ALL;
5596 static void InitLevelInfo(void)
5598 LoadLevelInfo(); // global level info
5599 LoadLevelSetup_LastSeries(); // last played series info
5600 LoadLevelSetup_SeriesInfo(); // last played level info
5602 if (global.autoplay_leveldir &&
5603 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5605 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5606 global.autoplay_leveldir);
5607 if (leveldir_current == NULL)
5608 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5611 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5614 static void InitLevelArtworkInfo(void)
5616 LoadLevelArtworkInfo();
5619 static void InitImages(void)
5621 print_timestamp_init("InitImages");
5624 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5625 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5626 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5627 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5628 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5629 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5630 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5631 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5634 setLevelArtworkDir(artwork.gfx_first);
5637 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5638 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5639 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5640 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5641 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5642 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5643 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5644 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5648 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5649 leveldir_current->identifier,
5650 artwork.gfx_current_identifier,
5651 artwork.gfx_current->identifier,
5652 leveldir_current->graphics_set,
5653 leveldir_current->graphics_path);
5656 UPDATE_BUSY_STATE();
5658 ReloadCustomImages();
5659 print_timestamp_time("ReloadCustomImages");
5661 UPDATE_BUSY_STATE();
5663 LoadCustomElementDescriptions();
5664 print_timestamp_time("LoadCustomElementDescriptions");
5666 UPDATE_BUSY_STATE();
5668 LoadMenuDesignSettings();
5669 print_timestamp_time("LoadMenuDesignSettings");
5671 UPDATE_BUSY_STATE();
5673 ReinitializeGraphics();
5674 print_timestamp_time("ReinitializeGraphics");
5676 LoadMenuDesignSettings_AfterGraphics();
5677 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5679 UPDATE_BUSY_STATE();
5681 print_timestamp_done("InitImages");
5684 static void InitSound(char *identifier)
5686 print_timestamp_init("InitSound");
5688 if (identifier == NULL)
5689 identifier = artwork.snd_current->identifier;
5691 // set artwork path to send it to the sound server process
5692 setLevelArtworkDir(artwork.snd_first);
5694 InitReloadCustomSounds(identifier);
5695 print_timestamp_time("InitReloadCustomSounds");
5697 ReinitializeSounds();
5698 print_timestamp_time("ReinitializeSounds");
5700 print_timestamp_done("InitSound");
5703 static void InitMusic(char *identifier)
5705 print_timestamp_init("InitMusic");
5707 if (identifier == NULL)
5708 identifier = artwork.mus_current->identifier;
5710 // set artwork path to send it to the sound server process
5711 setLevelArtworkDir(artwork.mus_first);
5713 InitReloadCustomMusic(identifier);
5714 print_timestamp_time("InitReloadCustomMusic");
5716 ReinitializeMusic();
5717 print_timestamp_time("ReinitializeMusic");
5719 print_timestamp_done("InitMusic");
5722 static void InitArtworkDone(void)
5724 if (program.headless)
5727 InitGlobalAnimations();
5730 static void InitNetworkSettings(void)
5732 boolean network_enabled = (options.network || setup.network_mode);
5733 char *network_server = (options.server_host != NULL ? options.server_host :
5734 setup.network_server_hostname);
5736 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5737 network_server = NULL;
5739 InitNetworkInfo(network_enabled,
5743 options.server_port);
5746 void InitNetworkServer(void)
5748 if (!network.enabled || network.connected)
5751 LimitScreenUpdates(FALSE);
5753 if (game_status == GAME_MODE_LOADING)
5756 if (!ConnectToServer(network.server_host, network.server_port))
5758 network.enabled = FALSE;
5760 setup.network_mode = FALSE;
5764 SendToServer_ProtocolVersion();
5765 SendToServer_PlayerName(setup.player_name);
5766 SendToServer_NrWanted(setup.network_player_nr + 1);
5768 network.connected = TRUE;
5771 // short time to recognize result of network initialization
5772 if (game_status == GAME_MODE_LOADING)
5773 Delay_WithScreenUpdates(1000);
5776 static boolean CheckArtworkConfigForCustomElements(char *filename)
5778 SetupFileHash *setup_file_hash;
5779 boolean redefined_ce_found = FALSE;
5781 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5783 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5785 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5787 char *token = HASH_ITERATION_TOKEN(itr);
5789 if (strPrefix(token, "custom_"))
5791 redefined_ce_found = TRUE;
5796 END_HASH_ITERATION(setup_file_hash, itr)
5798 freeSetupFileHash(setup_file_hash);
5801 return redefined_ce_found;
5804 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5806 char *filename_base, *filename_local;
5807 boolean redefined_ce_found = FALSE;
5809 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5812 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5813 "leveldir_current->identifier == '%s'",
5814 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5815 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5816 "leveldir_current->graphics_path == '%s'",
5817 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5818 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5819 "leveldir_current->graphics_set == '%s'",
5820 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5821 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5822 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5823 leveldir_current == NULL ? "[NULL]" :
5824 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5827 // first look for special artwork configured in level series config
5828 filename_base = getCustomArtworkLevelConfigFilename(type);
5831 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5832 "filename_base == '%s'", filename_base);
5835 if (fileExists(filename_base))
5836 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5838 filename_local = getCustomArtworkConfigFilename(type);
5841 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5842 "filename_local == '%s'", filename_local);
5845 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5846 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5849 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5850 "redefined_ce_found == %d", redefined_ce_found);
5853 return redefined_ce_found;
5856 static void InitOverrideArtwork(void)
5858 boolean redefined_ce_found = FALSE;
5860 // to check if this level set redefines any CEs, do not use overriding
5861 gfx.override_level_graphics = FALSE;
5862 gfx.override_level_sounds = FALSE;
5863 gfx.override_level_music = FALSE;
5865 // now check if this level set has definitions for custom elements
5866 if (setup.override_level_graphics == AUTO ||
5867 setup.override_level_sounds == AUTO ||
5868 setup.override_level_music == AUTO)
5869 redefined_ce_found =
5870 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5871 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5872 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5875 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
5876 redefined_ce_found);
5879 if (redefined_ce_found)
5881 // this level set has CE definitions: change "AUTO" to "FALSE"
5882 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5883 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5884 gfx.override_level_music = (setup.override_level_music == TRUE);
5888 // this level set has no CE definitions: change "AUTO" to "TRUE"
5889 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5890 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5891 gfx.override_level_music = (setup.override_level_music != FALSE);
5895 Debug("init:InitOverrideArtwork", "%d, %d, %d",
5896 gfx.override_level_graphics,
5897 gfx.override_level_sounds,
5898 gfx.override_level_music);
5902 static char *getNewArtworkIdentifier(int type)
5904 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5905 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5906 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5907 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5908 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5909 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5910 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5911 char *leveldir_identifier = leveldir_current->identifier;
5912 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5913 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5914 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5915 char *artwork_current_identifier;
5916 char *artwork_new_identifier = NULL; // default: nothing has changed
5918 // leveldir_current may be invalid (level group, parent link)
5919 if (!validLevelSeries(leveldir_current))
5922 /* 1st step: determine artwork set to be activated in descending order:
5923 --------------------------------------------------------------------
5924 1. setup artwork (when configured to override everything else)
5925 2. artwork set configured in "levelinfo.conf" of current level set
5926 (artwork in level directory will have priority when loading later)
5927 3. artwork in level directory (stored in artwork sub-directory)
5928 4. setup artwork (currently configured in setup menu) */
5930 if (setup_override_artwork)
5931 artwork_current_identifier = setup_artwork_set;
5932 else if (leveldir_artwork_set != NULL)
5933 artwork_current_identifier = leveldir_artwork_set;
5934 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5935 artwork_current_identifier = leveldir_identifier;
5937 artwork_current_identifier = setup_artwork_set;
5940 /* 2nd step: check if it is really needed to reload artwork set
5941 ------------------------------------------------------------ */
5943 // ---------- reload if level set and also artwork set has changed ----------
5944 if (leveldir_current_identifier[type] != leveldir_identifier &&
5945 (last_has_level_artwork_set[type] || has_level_artwork_set))
5946 artwork_new_identifier = artwork_current_identifier;
5948 leveldir_current_identifier[type] = leveldir_identifier;
5949 last_has_level_artwork_set[type] = has_level_artwork_set;
5951 // ---------- reload if "override artwork" setting has changed --------------
5952 if (last_override_level_artwork[type] != setup_override_artwork)
5953 artwork_new_identifier = artwork_current_identifier;
5955 last_override_level_artwork[type] = setup_override_artwork;
5957 // ---------- reload if current artwork identifier has changed --------------
5958 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5959 artwork_current_identifier))
5960 artwork_new_identifier = artwork_current_identifier;
5962 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5964 // ---------- do not reload directly after starting -------------------------
5965 if (!initialized[type])
5966 artwork_new_identifier = NULL;
5968 initialized[type] = TRUE;
5970 return artwork_new_identifier;
5973 void ReloadCustomArtwork(int force_reload)
5975 int last_game_status = game_status; // save current game status
5976 char *gfx_new_identifier;
5977 char *snd_new_identifier;
5978 char *mus_new_identifier;
5979 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5980 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5981 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5982 boolean reload_needed;
5984 InitOverrideArtwork();
5986 force_reload_gfx |= AdjustGraphicsForEMC();
5987 force_reload_snd |= AdjustSoundsForEMC();
5989 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5990 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5991 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5993 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5994 snd_new_identifier != NULL || force_reload_snd ||
5995 mus_new_identifier != NULL || force_reload_mus);
6000 print_timestamp_init("ReloadCustomArtwork");
6002 SetGameStatus(GAME_MODE_LOADING);
6004 FadeOut(REDRAW_ALL);
6006 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6007 print_timestamp_time("ClearRectangle");
6011 if (gfx_new_identifier != NULL || force_reload_gfx)
6014 Debug("init:ReloadCustomArtwork",
6015 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6016 artwork.gfx_current_identifier,
6018 artwork.gfx_current->identifier,
6019 leveldir_current->graphics_set);
6023 print_timestamp_time("InitImages");
6026 if (snd_new_identifier != NULL || force_reload_snd)
6028 InitSound(snd_new_identifier);
6029 print_timestamp_time("InitSound");
6032 if (mus_new_identifier != NULL || force_reload_mus)
6034 InitMusic(mus_new_identifier);
6035 print_timestamp_time("InitMusic");
6040 SetGameStatus(last_game_status); // restore current game status
6042 init_last = init; // switch to new busy animation
6044 FadeOut(REDRAW_ALL);
6046 RedrawGlobalBorder();
6048 // force redraw of (open or closed) door graphics
6049 SetDoorState(DOOR_OPEN_ALL);
6050 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6052 FadeSetEnterScreen();
6053 FadeSkipNextFadeOut();
6055 print_timestamp_done("ReloadCustomArtwork");
6057 LimitScreenUpdates(FALSE);
6060 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6062 if (global.autoplay_leveldir == NULL)
6063 KeyboardAutoRepeatOff();
6066 void DisplayExitMessage(char *format, va_list ap)
6068 // also check for initialized video (headless flag may be temporarily unset)
6069 if (program.headless || !video.initialized)
6072 // check if draw buffer and fonts for exit message are already available
6073 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6076 int font_1 = FC_RED;
6077 int font_2 = FC_YELLOW;
6078 int font_3 = FC_BLUE;
6079 int font_width = getFontWidth(font_2);
6080 int font_height = getFontHeight(font_2);
6083 int sxsize = WIN_XSIZE - 2 * sx;
6084 int sysize = WIN_YSIZE - 2 * sy;
6085 int line_length = sxsize / font_width;
6086 int max_lines = sysize / font_height;
6087 int num_lines_printed;
6091 gfx.sxsize = sxsize;
6092 gfx.sysize = sysize;
6096 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6098 DrawTextSCentered(sy, font_1, "Fatal error:");
6099 sy += 3 * font_height;;
6102 DrawTextBufferVA(sx, sy, format, ap, font_2,
6103 line_length, line_length, max_lines,
6104 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6105 sy += (num_lines_printed + 3) * font_height;
6107 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6108 sy += 3 * font_height;
6111 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6112 line_length, line_length, max_lines,
6113 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6115 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6117 redraw_mask = REDRAW_ALL;
6119 // force drawing exit message even if screen updates are currently limited
6120 LimitScreenUpdates(FALSE);
6124 // deactivate toons on error message screen
6125 setup.toons = FALSE;
6127 WaitForEventToContinue();
6131 // ============================================================================
6133 // ============================================================================
6137 print_timestamp_init("OpenAll");
6139 SetGameStatus(GAME_MODE_LOADING);
6143 InitGlobal(); // initialize some global variables
6145 print_timestamp_time("[init global stuff]");
6149 print_timestamp_time("[init setup/config stuff (1)]");
6153 if (options.execute_command)
6154 Execute_Command(options.execute_command);
6156 InitNetworkSettings();
6160 if (network.serveronly)
6162 #if defined(PLATFORM_UNIX)
6163 NetworkServer(network.server_port, TRUE);
6165 Warn("networking only supported in Unix version");
6168 exit(0); // never reached, server loops forever
6172 print_timestamp_time("[init setup/config stuff (2)]");
6174 print_timestamp_time("[init setup/config stuff (3)]");
6175 InitArtworkInfo(); // needed before loading gfx, sound & music
6176 print_timestamp_time("[init setup/config stuff (4)]");
6177 InitArtworkConfig(); // needed before forking sound child process
6178 print_timestamp_time("[init setup/config stuff (5)]");
6180 print_timestamp_time("[init setup/config stuff (6)]");
6182 InitRND(NEW_RANDOMIZE);
6183 InitSimpleRandom(NEW_RANDOMIZE);
6187 print_timestamp_time("[init setup/config stuff]");
6189 InitVideoDefaults();
6191 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6194 InitEventFilter(FilterMouseMotionEvents);
6196 print_timestamp_time("[init video stuff]");
6198 InitElementPropertiesStatic();
6199 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6200 InitElementPropertiesGfxElement();
6202 print_timestamp_time("[init element properties stuff]");
6206 print_timestamp_time("InitGfx");
6209 print_timestamp_time("InitLevelInfo");
6211 InitLevelArtworkInfo();
6212 print_timestamp_time("InitLevelArtworkInfo");
6214 InitOverrideArtwork(); // needs to know current level directory
6215 print_timestamp_time("InitOverrideArtwork");
6217 InitImages(); // needs to know current level directory
6218 print_timestamp_time("InitImages");
6220 InitSound(NULL); // needs to know current level directory
6221 print_timestamp_time("InitSound");
6223 InitMusic(NULL); // needs to know current level directory
6224 print_timestamp_time("InitMusic");
6228 InitGfxBackground();
6234 if (global.autoplay_leveldir)
6239 else if (global.patchtapes_leveldir)
6244 else if (global.convert_leveldir)
6249 else if (global.create_images_dir)
6251 CreateLevelSketchImages();
6255 InitNetworkServer();
6257 SetGameStatus(GAME_MODE_MAIN);
6259 FadeSetEnterScreen();
6260 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6261 FadeSkipNextFadeOut();
6263 print_timestamp_time("[post-artwork]");
6265 print_timestamp_done("OpenAll");
6270 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6272 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6273 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6274 #if defined(PLATFORM_ANDROID)
6275 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6276 SDL_AndroidGetInternalStoragePath());
6277 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6278 SDL_AndroidGetExternalStoragePath());
6279 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6280 (SDL_AndroidGetExternalStorageState() &
6281 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6282 SDL_AndroidGetExternalStorageState() &
6283 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6288 void CloseAllAndExit(int exit_value)
6293 CloseAudio(); // called after freeing sounds (needed for SDL)
6301 // set a flag to tell the network server thread to quit and wait for it
6302 // using SDL_WaitThread()
6304 // Code used with SDL 1.2:
6305 // if (network.server_thread) // terminate network server
6306 // SDL_KillThread(network.server_thread);
6308 CloseVideoDisplay();
6309 ClosePlatformDependentStuff();
6311 if (exit_value != 0 && !options.execute_command)
6313 // fall back to default level set (current set may have caused an error)
6314 SaveLevelSetup_LastSeries_Deactivate();
6316 // tell user where to find error log file which may contain more details
6317 // (error notification now directly displayed on screen inside R'n'D
6318 // NotifyUserAboutErrorFile(); // currently only works for Windows