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"
39 #define INITIAL_IMG_GLOBAL_BUSY 0
41 #define NUM_INITIAL_IMAGES 1
44 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
45 static struct GraphicInfo image_initial[NUM_INITIAL_IMAGES];
47 static int copy_properties[][5] =
51 EL_BUG_LEFT, EL_BUG_RIGHT,
52 EL_BUG_UP, EL_BUG_DOWN
56 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
57 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
61 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
62 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
66 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
67 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
71 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
72 EL_PACMAN_UP, EL_PACMAN_DOWN
76 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
77 EL_YAMYAM_UP, EL_YAMYAM_DOWN
81 EL_MOLE_LEFT, EL_MOLE_RIGHT,
82 EL_MOLE_UP, EL_MOLE_DOWN
86 EL_SPRING_LEFT, EL_SPRING_RIGHT,
87 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
96 // forward declaration for internal use
97 static int get_graphic_parameter_value(char *, char *, int);
100 static void DrawInitAnim(void)
102 struct GraphicInfo *graphic_info_last = graphic_info;
104 static unsigned int action_delay = 0;
105 unsigned int action_delay_value = GameFrameDelay;
106 int sync_frame = FrameCounter;
109 // prevent OS (Windows) from complaining about program not responding
112 if (game_status != GAME_MODE_LOADING)
115 if (image_initial[INITIAL_IMG_GLOBAL_BUSY].bitmap == NULL || window == NULL)
118 if (!DelayReached(&action_delay, action_delay_value))
121 if (init_last.busy.x == -1)
122 init_last.busy.x = WIN_XSIZE / 2;
123 if (init_last.busy.y == -1)
124 init_last.busy.y = WIN_YSIZE / 2;
126 x = ALIGNED_TEXT_XPOS(&init_last.busy);
127 y = ALIGNED_TEXT_YPOS(&init_last.busy);
129 graphic_info = image_initial; // graphic == 0 => image_initial
131 if (sync_frame % image_initial[INITIAL_IMG_GLOBAL_BUSY].anim_delay == 0)
135 int width = graphic_info[graphic].width;
136 int height = graphic_info[graphic].height;
137 int frame = getGraphicAnimationFrame(graphic, sync_frame);
139 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
140 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
143 graphic_info = graphic_info_last;
148 static void DrawProgramInfo(void)
150 int font1_nr = FC_YELLOW;
151 int font2_nr = FC_RED;
152 int font2_height = getFontHeight(font2_nr);
155 int ypos3 = WIN_YSIZE - 20 - font2_height;
157 DrawInitText(getProgramInitString(), ypos1, font1_nr);
158 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
159 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
162 static void FreeGadgets(void)
164 FreeLevelEditorGadgets();
171 void InitGadgets(void)
173 static boolean gadgets_initialized = FALSE;
175 if (gadgets_initialized)
178 CreateLevelEditorGadgets();
182 CreateScreenGadgets();
184 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
186 gadgets_initialized = TRUE;
189 static void InitElementSmallImagesScaledUp(int graphic)
191 struct GraphicInfo *g = &graphic_info[graphic];
193 // create small and game tile sized bitmaps (and scale up, if needed)
194 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
197 static void InitElementSmallImages(void)
199 print_timestamp_init("InitElementSmallImages");
201 static int special_graphics[] =
215 IMG_EDITOR_ELEMENT_BORDER,
216 IMG_EDITOR_ELEMENT_BORDER_INPUT,
217 IMG_EDITOR_CASCADE_LIST,
218 IMG_EDITOR_CASCADE_LIST_ACTIVE,
221 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
222 int num_property_mappings = getImageListPropertyMappingSize();
225 print_timestamp_time("getImageListPropertyMapping/Size");
227 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
228 // initialize normal element images from static configuration
229 for (i = 0; element_to_graphic[i].element > -1; i++)
230 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
231 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
233 // initialize special element images from static configuration
234 for (i = 0; element_to_special_graphic[i].element > -1; i++)
235 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
236 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
238 // initialize element images from dynamic configuration
239 for (i = 0; i < num_property_mappings; i++)
240 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
241 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
242 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
244 // initialize special non-element images from above list
245 for (i = 0; special_graphics[i] > -1; i++)
246 InitElementSmallImagesScaledUp(special_graphics[i]);
247 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
249 print_timestamp_done("InitElementSmallImages");
252 static void InitScaledImagesScaledUp(int graphic)
254 struct GraphicInfo *g = &graphic_info[graphic];
256 ScaleImage(graphic, g->scale_up_factor);
259 static void InitScaledImages(void)
261 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
262 int num_property_mappings = getImageListPropertyMappingSize();
265 // scale normal images from static configuration, if not already scaled
266 for (i = 0; i < NUM_IMAGE_FILES; i++)
267 InitScaledImagesScaledUp(i);
269 // scale images from dynamic configuration, if not already scaled
270 for (i = 0; i < num_property_mappings; i++)
271 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
274 static void InitBitmapPointers(void)
276 int num_images = getImageListSize();
279 // standard size bitmap may have changed -- update default bitmap pointer
280 for (i = 0; i < num_images; i++)
281 if (graphic_info[i].bitmaps)
282 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
285 void InitImageTextures(void)
287 static int texture_graphics[] =
289 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
290 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
291 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
292 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
293 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
294 IMG_MENU_BUTTON_TOUCH_BACK,
295 IMG_MENU_BUTTON_TOUCH_NEXT,
296 IMG_MENU_BUTTON_TOUCH_BACK2,
297 IMG_MENU_BUTTON_TOUCH_NEXT2,
302 FreeAllImageTextures();
304 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
305 CreateImageTextures(i);
307 for (i = 0; i < MAX_NUM_TOONS; i++)
308 CreateImageTextures(IMG_TOON_1 + i);
310 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
312 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
314 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
316 int graphic = global_anim_info[i].graphic[j][k];
318 if (graphic == IMG_UNDEFINED)
321 CreateImageTextures(graphic);
326 for (i = 0; texture_graphics[i] > -1; i++)
327 CreateImageTextures(texture_graphics[i]);
330 static int getFontBitmapID(int font_nr)
334 // (special case: do not use special font for GAME_MODE_LOADING)
335 if (game_status >= GAME_MODE_TITLE_INITIAL &&
336 game_status <= GAME_MODE_PSEUDO_PREVIEW)
337 special = game_status;
338 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
339 special = GFX_SPECIAL_ARG_MAIN;
340 else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
341 special = GFX_SPECIAL_ARG_NAMES;
344 return font_info[font_nr].special_bitmap_id[special];
349 static int getFontFromToken(char *token)
351 char *value = getHashEntry(font_token_hash, token);
356 // if font not found, use reliable default value
357 return FONT_INITIAL_1;
360 static void InitFontGraphicInfo(void)
362 static struct FontBitmapInfo *font_bitmap_info = NULL;
363 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
364 int num_property_mappings = getImageListPropertyMappingSize();
365 int num_font_bitmaps = NUM_FONTS;
368 if (graphic_info == NULL) // still at startup phase
370 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
371 getFontBitmapID, getFontFromToken);
376 // ---------- initialize font graphic definitions ----------
378 // always start with reliable default values (normal font graphics)
379 for (i = 0; i < NUM_FONTS; i++)
380 font_info[i].graphic = IMG_FONT_INITIAL_1;
382 // initialize normal font/graphic mapping from static configuration
383 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
385 int font_nr = font_to_graphic[i].font_nr;
386 int special = font_to_graphic[i].special;
387 int graphic = font_to_graphic[i].graphic;
392 font_info[font_nr].graphic = graphic;
395 // always start with reliable default values (special font graphics)
396 for (i = 0; i < NUM_FONTS; i++)
398 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
400 font_info[i].special_graphic[j] = font_info[i].graphic;
401 font_info[i].special_bitmap_id[j] = i;
405 // initialize special font/graphic mapping from static configuration
406 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
408 int font_nr = font_to_graphic[i].font_nr;
409 int special = font_to_graphic[i].special;
410 int graphic = font_to_graphic[i].graphic;
411 int base_graphic = font2baseimg(font_nr);
413 if (IS_SPECIAL_GFX_ARG(special))
415 boolean base_redefined =
416 getImageListEntryFromImageID(base_graphic)->redefined;
417 boolean special_redefined =
418 getImageListEntryFromImageID(graphic)->redefined;
419 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
421 /* if the base font ("font.title_1", for example) has been redefined,
422 but not the special font ("font.title_1.LEVELS", for example), do not
423 use an existing (in this case considered obsolete) special font
424 anymore, but use the automatically determined default font */
425 /* special case: cloned special fonts must be explicitly redefined,
426 but are not automatically redefined by redefining base font */
427 if (base_redefined && !special_redefined && !special_cloned)
430 font_info[font_nr].special_graphic[special] = graphic;
431 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
436 // initialize special font/graphic mapping from dynamic configuration
437 for (i = 0; i < num_property_mappings; i++)
439 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
440 int special = property_mapping[i].ext3_index;
441 int graphic = property_mapping[i].artwork_index;
443 if (font_nr < 0 || font_nr >= NUM_FONTS)
446 if (IS_SPECIAL_GFX_ARG(special))
448 font_info[font_nr].special_graphic[special] = graphic;
449 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
454 /* correct special font/graphic mapping for cloned fonts for downwards
455 compatibility of PREVIEW fonts -- this is only needed for implicit
456 redefinition of special font by redefined base font, and only if other
457 fonts are cloned from this special font (like in the "Zelda" level set) */
458 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
460 int font_nr = font_to_graphic[i].font_nr;
461 int special = font_to_graphic[i].special;
462 int graphic = font_to_graphic[i].graphic;
464 if (IS_SPECIAL_GFX_ARG(special))
466 boolean special_redefined =
467 getImageListEntryFromImageID(graphic)->redefined;
468 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
470 if (special_cloned && !special_redefined)
474 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
476 int font_nr2 = font_to_graphic[j].font_nr;
477 int special2 = font_to_graphic[j].special;
478 int graphic2 = font_to_graphic[j].graphic;
480 if (IS_SPECIAL_GFX_ARG(special2) &&
481 graphic2 == graphic_info[graphic].clone_from)
483 font_info[font_nr].special_graphic[special] =
484 font_info[font_nr2].special_graphic[special2];
485 font_info[font_nr].special_bitmap_id[special] =
486 font_info[font_nr2].special_bitmap_id[special2];
493 // reset non-redefined ".active" font graphics if normal font is redefined
494 // (this different treatment is needed because normal and active fonts are
495 // independently defined ("active" is not a property of font definitions!)
496 for (i = 0; i < NUM_FONTS; i++)
498 int font_nr_base = i;
499 int font_nr_active = FONT_ACTIVE(font_nr_base);
501 // check only those fonts with exist as normal and ".active" variant
502 if (font_nr_base != font_nr_active)
504 int base_graphic = font_info[font_nr_base].graphic;
505 int active_graphic = font_info[font_nr_active].graphic;
506 boolean base_redefined =
507 getImageListEntryFromImageID(base_graphic)->redefined;
508 boolean active_redefined =
509 getImageListEntryFromImageID(active_graphic)->redefined;
511 /* if the base font ("font.menu_1", for example) has been redefined,
512 but not the active font ("font.menu_1.active", for example), do not
513 use an existing (in this case considered obsolete) active font
514 anymore, but use the automatically determined default font */
515 if (base_redefined && !active_redefined)
516 font_info[font_nr_active].graphic = base_graphic;
518 // now also check each "special" font (which may be the same as above)
519 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
521 int base_graphic = font_info[font_nr_base].special_graphic[j];
522 int active_graphic = font_info[font_nr_active].special_graphic[j];
523 boolean base_redefined =
524 getImageListEntryFromImageID(base_graphic)->redefined;
525 boolean active_redefined =
526 getImageListEntryFromImageID(active_graphic)->redefined;
528 // same as above, but check special graphic definitions, for example:
529 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
530 if (base_redefined && !active_redefined)
532 font_info[font_nr_active].special_graphic[j] =
533 font_info[font_nr_base].special_graphic[j];
534 font_info[font_nr_active].special_bitmap_id[j] =
535 font_info[font_nr_base].special_bitmap_id[j];
541 // ---------- initialize font bitmap array ----------
543 if (font_bitmap_info != NULL)
544 FreeFontInfo(font_bitmap_info);
547 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
549 // ---------- initialize font bitmap definitions ----------
551 for (i = 0; i < NUM_FONTS; i++)
553 if (i < NUM_INITIAL_FONTS)
555 font_bitmap_info[i] = font_initial[i];
559 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
561 int font_bitmap_id = font_info[i].special_bitmap_id[j];
562 int graphic = font_info[i].special_graphic[j];
564 // set 'graphic_info' for font entries, if uninitialized (guessed)
565 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
567 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
568 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
571 // copy font relevant information from graphics information
572 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
573 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
574 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
575 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
576 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
578 font_bitmap_info[font_bitmap_id].offset_x =
579 graphic_info[graphic].offset_x;
580 font_bitmap_info[font_bitmap_id].offset_y =
581 graphic_info[graphic].offset_y;
583 font_bitmap_info[font_bitmap_id].draw_xoffset =
584 graphic_info[graphic].draw_xoffset;
585 font_bitmap_info[font_bitmap_id].draw_yoffset =
586 graphic_info[graphic].draw_yoffset;
588 font_bitmap_info[font_bitmap_id].num_chars =
589 graphic_info[graphic].anim_frames;
590 font_bitmap_info[font_bitmap_id].num_chars_per_line =
591 graphic_info[graphic].anim_frames_per_line;
595 InitFontInfo(font_bitmap_info, num_font_bitmaps,
596 getFontBitmapID, getFontFromToken);
599 static void InitGlobalAnimGraphicInfo(void)
601 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
602 int num_property_mappings = getImageListPropertyMappingSize();
605 if (graphic_info == NULL) // still at startup phase
608 // always start with reliable default values (no global animations)
609 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
610 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
611 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
612 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
614 // initialize global animation definitions from static configuration
615 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
617 int j = GLOBAL_ANIM_ID_PART_BASE;
618 int k = GFX_SPECIAL_ARG_DEFAULT;
620 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
623 // initialize global animation definitions from dynamic configuration
624 for (i = 0; i < num_property_mappings; i++)
626 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
627 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
628 int special = property_mapping[i].ext3_index;
629 int graphic = property_mapping[i].artwork_index;
631 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
634 // set animation part to base part, if not specified
635 if (!IS_GLOBAL_ANIM_PART(part_nr))
636 part_nr = GLOBAL_ANIM_ID_PART_BASE;
638 // set animation screen to default, if not specified
639 if (!IS_SPECIAL_GFX_ARG(special))
640 special = GFX_SPECIAL_ARG_DEFAULT;
642 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
644 // fix default value for ".draw_masked" (for backward compatibility)
645 struct GraphicInfo *g = &graphic_info[graphic];
646 struct FileInfo *image = getImageListEntryFromImageID(graphic);
647 char **parameter_raw = image->parameter;
648 int p = GFX_ARG_DRAW_MASKED;
649 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
650 image_config_suffix[p].token,
651 image_config_suffix[p].type);
653 // if ".draw_masked" parameter is undefined, use default value "TRUE"
654 if (draw_masked == ARG_UNDEFINED_VALUE)
655 g->draw_masked = TRUE;
659 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
660 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
661 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
662 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
663 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
664 Debug("init:InitGlobalAnimGraphicInfo",
665 "anim %d, part %d, mode %d => %d",
666 i, j, k, global_anim_info[i].graphic[j][k]);
670 static void InitGlobalAnimSoundInfo(void)
672 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
673 int num_property_mappings = getSoundListPropertyMappingSize();
676 // always start with reliable default values (no global animation sounds)
677 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
678 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
679 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
680 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
682 // initialize global animation sound definitions from dynamic configuration
683 for (i = 0; i < num_property_mappings; i++)
685 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
686 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
687 int special = property_mapping[i].ext3_index;
688 int sound = property_mapping[i].artwork_index;
690 // sound uses control definition; map it to position of graphic (artwork)
691 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
693 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
696 // set animation part to base part, if not specified
697 if (!IS_GLOBAL_ANIM_PART(part_nr))
698 part_nr = GLOBAL_ANIM_ID_PART_BASE;
700 // set animation screen to default, if not specified
701 if (!IS_SPECIAL_GFX_ARG(special))
702 special = GFX_SPECIAL_ARG_DEFAULT;
704 global_anim_info[anim_nr].sound[part_nr][special] = sound;
708 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
709 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
710 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
711 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
712 Debug("init:InitGlobalAnimSoundInfo",
713 "anim %d, part %d, mode %d => %d",
714 i, j, k, global_anim_info[i].sound[j][k]);
718 static void InitGlobalAnimMusicInfo(void)
720 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
721 int num_property_mappings = getMusicListPropertyMappingSize();
724 // always start with reliable default values (no global animation music)
725 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
726 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
727 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
728 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
730 // initialize global animation music definitions from dynamic configuration
731 for (i = 0; i < num_property_mappings; i++)
733 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
734 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
735 int special = property_mapping[i].ext2_index;
736 int music = property_mapping[i].artwork_index;
738 // music uses control definition; map it to position of graphic (artwork)
739 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
741 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
744 // set animation part to base part, if not specified
745 if (!IS_GLOBAL_ANIM_PART(part_nr))
746 part_nr = GLOBAL_ANIM_ID_PART_BASE;
748 // set animation screen to default, if not specified
749 if (!IS_SPECIAL_GFX_ARG(special))
750 special = GFX_SPECIAL_ARG_DEFAULT;
752 global_anim_info[anim_nr].music[part_nr][special] = music;
756 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
757 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
758 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
759 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
760 Debug("init:InitGlobalAnimMusicInfo",
761 "anim %d, part %d, mode %d => %d",
762 i, j, k, global_anim_info[i].music[j][k]);
766 static void InitElementGraphicInfo(void)
768 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
769 int num_property_mappings = getImageListPropertyMappingSize();
772 if (graphic_info == NULL) // still at startup phase
775 // set values to -1 to identify later as "uninitialized" values
776 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
778 for (act = 0; act < NUM_ACTIONS; act++)
780 element_info[i].graphic[act] = -1;
781 element_info[i].crumbled[act] = -1;
783 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
785 element_info[i].direction_graphic[act][dir] = -1;
786 element_info[i].direction_crumbled[act][dir] = -1;
793 // initialize normal element/graphic mapping from static configuration
794 for (i = 0; element_to_graphic[i].element > -1; i++)
796 int element = element_to_graphic[i].element;
797 int action = element_to_graphic[i].action;
798 int direction = element_to_graphic[i].direction;
799 boolean crumbled = element_to_graphic[i].crumbled;
800 int graphic = element_to_graphic[i].graphic;
801 int base_graphic = el2baseimg(element);
803 if (graphic_info[graphic].bitmap == NULL)
806 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
809 boolean base_redefined =
810 getImageListEntryFromImageID(base_graphic)->redefined;
811 boolean act_dir_redefined =
812 getImageListEntryFromImageID(graphic)->redefined;
814 /* if the base graphic ("emerald", for example) has been redefined,
815 but not the action graphic ("emerald.falling", for example), do not
816 use an existing (in this case considered obsolete) action graphic
817 anymore, but use the automatically determined default graphic */
818 if (base_redefined && !act_dir_redefined)
823 action = ACTION_DEFAULT;
828 element_info[element].direction_crumbled[action][direction] = graphic;
830 element_info[element].crumbled[action] = graphic;
835 element_info[element].direction_graphic[action][direction] = graphic;
837 element_info[element].graphic[action] = graphic;
841 // initialize normal element/graphic mapping from dynamic configuration
842 for (i = 0; i < num_property_mappings; i++)
844 int element = property_mapping[i].base_index;
845 int action = property_mapping[i].ext1_index;
846 int direction = property_mapping[i].ext2_index;
847 int special = property_mapping[i].ext3_index;
848 int graphic = property_mapping[i].artwork_index;
849 boolean crumbled = FALSE;
851 if (special == GFX_SPECIAL_ARG_CRUMBLED)
857 if (graphic_info[graphic].bitmap == NULL)
860 if (element >= MAX_NUM_ELEMENTS || special != -1)
864 action = ACTION_DEFAULT;
869 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
870 element_info[element].direction_crumbled[action][dir] = -1;
873 element_info[element].direction_crumbled[action][direction] = graphic;
875 element_info[element].crumbled[action] = graphic;
880 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
881 element_info[element].direction_graphic[action][dir] = -1;
884 element_info[element].direction_graphic[action][direction] = graphic;
886 element_info[element].graphic[action] = graphic;
890 // now copy all graphics that are defined to be cloned from other graphics
891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
893 int graphic = element_info[i].graphic[ACTION_DEFAULT];
894 int crumbled_like, diggable_like;
899 crumbled_like = graphic_info[graphic].crumbled_like;
900 diggable_like = graphic_info[graphic].diggable_like;
902 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
904 for (act = 0; act < NUM_ACTIONS; act++)
905 element_info[i].crumbled[act] =
906 element_info[crumbled_like].crumbled[act];
907 for (act = 0; act < NUM_ACTIONS; act++)
908 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
909 element_info[i].direction_crumbled[act][dir] =
910 element_info[crumbled_like].direction_crumbled[act][dir];
913 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
915 element_info[i].graphic[ACTION_DIGGING] =
916 element_info[diggable_like].graphic[ACTION_DIGGING];
917 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
918 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
919 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
923 // set hardcoded definitions for some runtime elements without graphic
924 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
926 // set hardcoded definitions for some internal elements without graphic
927 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
929 if (IS_EDITOR_CASCADE_INACTIVE(i))
930 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
931 else if (IS_EDITOR_CASCADE_ACTIVE(i))
932 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
935 // now set all undefined/invalid graphics to -1 to set to default after it
936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 for (act = 0; act < NUM_ACTIONS; act++)
942 graphic = element_info[i].graphic[act];
943 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
944 element_info[i].graphic[act] = -1;
946 graphic = element_info[i].crumbled[act];
947 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
948 element_info[i].crumbled[act] = -1;
950 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
952 graphic = element_info[i].direction_graphic[act][dir];
953 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
954 element_info[i].direction_graphic[act][dir] = -1;
956 graphic = element_info[i].direction_crumbled[act][dir];
957 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
958 element_info[i].direction_crumbled[act][dir] = -1;
965 // adjust graphics with 2nd tile for movement according to direction
966 // (do this before correcting '-1' values to minimize calculations)
967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
969 for (act = 0; act < NUM_ACTIONS; act++)
971 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
973 int graphic = element_info[i].direction_graphic[act][dir];
974 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
976 if (act == ACTION_FALLING) // special case
977 graphic = element_info[i].graphic[act];
980 graphic_info[graphic].double_movement &&
981 graphic_info[graphic].swap_double_tiles != 0)
983 struct GraphicInfo *g = &graphic_info[graphic];
984 int src_x_front = g->src_x;
985 int src_y_front = g->src_y;
986 int src_x_back = g->src_x + g->offset2_x;
987 int src_y_back = g->src_y + g->offset2_y;
988 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
990 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
991 src_y_front < src_y_back);
992 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
993 boolean swap_movement_tiles_autodetected =
994 (!frames_are_ordered_diagonally &&
995 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
996 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
997 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
998 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1000 // swap frontside and backside graphic tile coordinates, if needed
1001 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1003 // get current (wrong) backside tile coordinates
1004 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1006 // set frontside tile coordinates to backside tile coordinates
1007 g->src_x = src_x_back;
1008 g->src_y = src_y_back;
1010 // invert tile offset to point to new backside tile coordinates
1014 // do not swap front and backside tiles again after correction
1015 g->swap_double_tiles = 0;
1022 UPDATE_BUSY_STATE();
1024 // now set all '-1' values to element specific default values
1025 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1027 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1028 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1029 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1030 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1032 if (default_graphic == -1)
1033 default_graphic = IMG_UNKNOWN;
1035 if (default_crumbled == -1)
1036 default_crumbled = default_graphic;
1038 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1040 default_direction_graphic[dir] =
1041 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1042 default_direction_crumbled[dir] =
1043 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1045 if (default_direction_graphic[dir] == -1)
1046 default_direction_graphic[dir] = default_graphic;
1048 if (default_direction_crumbled[dir] == -1)
1049 default_direction_crumbled[dir] = default_direction_graphic[dir];
1052 for (act = 0; act < NUM_ACTIONS; act++)
1054 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1055 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1056 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1057 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1058 act == ACTION_TURNING_FROM_RIGHT ||
1059 act == ACTION_TURNING_FROM_UP ||
1060 act == ACTION_TURNING_FROM_DOWN);
1062 // generic default action graphic (defined by "[default]" directive)
1063 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1064 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1065 int default_remove_graphic = IMG_EMPTY;
1067 if (act_remove && default_action_graphic != -1)
1068 default_remove_graphic = default_action_graphic;
1070 // look for special default action graphic (classic game specific)
1071 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1072 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1073 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1074 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1075 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1076 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1077 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1078 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1080 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1081 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1082 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1083 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1084 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1085 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1086 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1087 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1089 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1090 // !!! make this better !!!
1091 if (i == EL_EMPTY_SPACE)
1093 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1094 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1097 if (default_action_graphic == -1)
1098 default_action_graphic = default_graphic;
1100 if (default_action_crumbled == -1)
1101 default_action_crumbled = default_action_graphic;
1103 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1105 // use action graphic as the default direction graphic, if undefined
1106 int default_action_direction_graphic = element_info[i].graphic[act];
1107 int default_action_direction_crumbled = element_info[i].crumbled[act];
1109 // no graphic for current action -- use default direction graphic
1110 if (default_action_direction_graphic == -1)
1111 default_action_direction_graphic =
1112 (act_remove ? default_remove_graphic :
1114 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1115 default_action_graphic != default_graphic ?
1116 default_action_graphic :
1117 default_direction_graphic[dir]);
1119 if (element_info[i].direction_graphic[act][dir] == -1)
1120 element_info[i].direction_graphic[act][dir] =
1121 default_action_direction_graphic;
1123 if (default_action_direction_crumbled == -1)
1124 default_action_direction_crumbled =
1125 element_info[i].direction_graphic[act][dir];
1127 if (element_info[i].direction_crumbled[act][dir] == -1)
1128 element_info[i].direction_crumbled[act][dir] =
1129 default_action_direction_crumbled;
1132 // no graphic for this specific action -- use default action graphic
1133 if (element_info[i].graphic[act] == -1)
1134 element_info[i].graphic[act] =
1135 (act_remove ? default_remove_graphic :
1136 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1137 default_action_graphic);
1139 if (element_info[i].crumbled[act] == -1)
1140 element_info[i].crumbled[act] = element_info[i].graphic[act];
1144 UPDATE_BUSY_STATE();
1147 static void InitElementSpecialGraphicInfo(void)
1149 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1150 int num_property_mappings = getImageListPropertyMappingSize();
1153 // always start with reliable default values
1154 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1155 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1156 element_info[i].special_graphic[j] =
1157 element_info[i].graphic[ACTION_DEFAULT];
1159 // initialize special element/graphic mapping from static configuration
1160 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1162 int element = element_to_special_graphic[i].element;
1163 int special = element_to_special_graphic[i].special;
1164 int graphic = element_to_special_graphic[i].graphic;
1165 int base_graphic = el2baseimg(element);
1166 boolean base_redefined =
1167 getImageListEntryFromImageID(base_graphic)->redefined;
1168 boolean special_redefined =
1169 getImageListEntryFromImageID(graphic)->redefined;
1171 /* if the base graphic ("emerald", for example) has been redefined,
1172 but not the special graphic ("emerald.EDITOR", for example), do not
1173 use an existing (in this case considered obsolete) special graphic
1174 anymore, but use the automatically created (down-scaled) graphic */
1175 if (base_redefined && !special_redefined)
1178 element_info[element].special_graphic[special] = graphic;
1181 // initialize special element/graphic mapping from dynamic configuration
1182 for (i = 0; i < num_property_mappings; i++)
1184 int element = property_mapping[i].base_index;
1185 int action = property_mapping[i].ext1_index;
1186 int direction = property_mapping[i].ext2_index;
1187 int special = property_mapping[i].ext3_index;
1188 int graphic = property_mapping[i].artwork_index;
1190 // for action ".active", replace element with active element, if exists
1191 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1193 element = ELEMENT_ACTIVE(element);
1197 if (element >= MAX_NUM_ELEMENTS)
1200 // do not change special graphic if action or direction was specified
1201 if (action != -1 || direction != -1)
1204 if (IS_SPECIAL_GFX_ARG(special))
1205 element_info[element].special_graphic[special] = graphic;
1208 // now set all undefined/invalid graphics to default
1209 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1210 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1211 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1212 element_info[i].special_graphic[j] =
1213 element_info[i].graphic[ACTION_DEFAULT];
1216 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1218 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1219 return get_parameter_value(value_raw, suffix, type);
1221 if (strEqual(value_raw, ARG_UNDEFINED))
1222 return ARG_UNDEFINED_VALUE;
1224 if (type == TYPE_ELEMENT)
1226 char *value = getHashEntry(element_token_hash, value_raw);
1231 Warn("error found in config file:");
1232 Warn("- config file: '%s'", getImageConfigFilename());
1233 Warn("error: invalid element token '%s'", value_raw);
1234 Warn("custom graphic rejected for this element/action");
1235 Warn("fallback done to undefined element for this graphic");
1239 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1241 else if (type == TYPE_GRAPHIC)
1243 char *value = getHashEntry(graphic_token_hash, value_raw);
1244 int fallback_graphic = IMG_CHAR_EXCLAM;
1249 Warn("error found in config file:");
1250 Warn("- config file: '%s'", getImageConfigFilename());
1251 Warn("error: invalid graphic token '%s'", value_raw);
1252 Warn("custom graphic rejected for this element/action");
1253 Warn("fallback done to 'char_exclam' for this graphic");
1257 return (value != NULL ? atoi(value) : fallback_graphic);
1263 static int get_scaled_graphic_width(int graphic)
1265 int original_width = getOriginalImageWidthFromImageID(graphic);
1266 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1268 return original_width * scale_up_factor;
1271 static int get_scaled_graphic_height(int graphic)
1273 int original_height = getOriginalImageHeightFromImageID(graphic);
1274 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1276 return original_height * scale_up_factor;
1279 static void set_graphic_parameters_ext(int graphic, int *parameter,
1280 Bitmap **src_bitmaps)
1282 struct GraphicInfo *g = &graphic_info[graphic];
1283 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1284 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1285 int anim_frames_per_line = 1;
1287 // always start with reliable default values
1288 g->src_image_width = 0;
1289 g->src_image_height = 0;
1292 g->width = TILEX; // default for element graphics
1293 g->height = TILEY; // default for element graphics
1294 g->offset_x = 0; // one or both of these values ...
1295 g->offset_y = 0; // ... will be corrected later
1296 g->offset2_x = 0; // one or both of these values ...
1297 g->offset2_y = 0; // ... will be corrected later
1298 g->swap_double_tiles = -1; // auto-detect tile swapping
1299 g->crumbled_like = -1; // do not use clone element
1300 g->diggable_like = -1; // do not use clone element
1301 g->border_size = TILEX / 8; // "CRUMBLED" border size
1302 g->scale_up_factor = 1; // default: no scaling up
1303 g->tile_size = TILESIZE; // default: standard tile size
1304 g->clone_from = -1; // do not use clone graphic
1305 g->init_delay_fixed = 0;
1306 g->init_delay_random = 0;
1307 g->init_delay_action = -1;
1308 g->anim_delay_fixed = 0;
1309 g->anim_delay_random = 0;
1310 g->anim_delay_action = -1;
1311 g->post_delay_fixed = 0;
1312 g->post_delay_random = 0;
1313 g->post_delay_action = -1;
1314 g->init_event = ANIM_EVENT_UNDEFINED;
1315 g->anim_event = ANIM_EVENT_UNDEFINED;
1316 g->init_event_action = -1;
1317 g->anim_event_action = -1;
1318 g->draw_masked = FALSE;
1320 g->fade_mode = FADE_MODE_DEFAULT;
1324 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1325 g->align = ALIGN_CENTER; // default for title screens
1326 g->valign = VALIGN_MIDDLE; // default for title screens
1327 g->sort_priority = 0; // default for title screens
1329 g->style = STYLE_DEFAULT;
1331 g->bitmaps = src_bitmaps;
1332 g->bitmap = src_bitmap;
1334 // optional zoom factor for scaling up the image to a larger size
1335 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1336 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1337 if (g->scale_up_factor < 1)
1338 g->scale_up_factor = 1; // no scaling
1340 // optional tile size for using non-standard image size
1341 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1343 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1346 // CHECK: should tile sizes less than standard tile size be allowed?
1347 if (g->tile_size < TILESIZE)
1348 g->tile_size = TILESIZE; // standard tile size
1351 // when setting tile size, also set width and height accordingly
1352 g->width = g->tile_size;
1353 g->height = g->tile_size;
1356 if (g->use_image_size)
1358 // set new default bitmap size (with scaling, but without small images)
1359 g->width = get_scaled_graphic_width(graphic);
1360 g->height = get_scaled_graphic_height(graphic);
1363 // optional width and height of each animation frame
1364 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1365 g->width = parameter[GFX_ARG_WIDTH];
1366 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1367 g->height = parameter[GFX_ARG_HEIGHT];
1369 // optional x and y tile position of animation frame sequence
1370 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1371 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1372 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1373 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1375 // optional x and y pixel position of animation frame sequence
1376 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1377 g->src_x = parameter[GFX_ARG_X];
1378 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1379 g->src_y = parameter[GFX_ARG_Y];
1386 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1387 g->width, getTokenFromImageID(graphic), TILEX);
1390 g->width = TILEX; // will be checked to be inside bitmap later
1396 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1397 g->height, getTokenFromImageID(graphic), TILEY);
1400 g->height = TILEY; // will be checked to be inside bitmap later
1406 // get final bitmap size (with scaling, but without small images)
1407 int src_image_width = get_scaled_graphic_width(graphic);
1408 int src_image_height = get_scaled_graphic_height(graphic);
1410 if (src_image_width == 0 || src_image_height == 0)
1412 // only happens when loaded outside artwork system (like "global.busy")
1413 src_image_width = src_bitmap->width;
1414 src_image_height = src_bitmap->height;
1417 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1419 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1420 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1424 anim_frames_per_row = MAX(1, src_image_width / g->width);
1425 anim_frames_per_col = MAX(1, src_image_height / g->height);
1428 g->src_image_width = src_image_width;
1429 g->src_image_height = src_image_height;
1432 // correct x or y offset dependent of vertical or horizontal frame order
1433 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1435 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_OFFSET] : g->height);
1437 anim_frames_per_line = anim_frames_per_col;
1439 else // frames are ordered horizontally
1441 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1442 parameter[GFX_ARG_OFFSET] : g->width);
1443 anim_frames_per_line = anim_frames_per_row;
1446 // optionally, the x and y offset of frames can be specified directly
1447 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1448 g->offset_x = parameter[GFX_ARG_XOFFSET];
1449 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1450 g->offset_y = parameter[GFX_ARG_YOFFSET];
1452 // optionally, moving animations may have separate start and end graphics
1453 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1455 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1456 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1458 // correct x or y offset2 dependent of vertical or horizontal frame order
1459 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1460 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1461 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1462 else // frames are ordered horizontally
1463 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1464 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1466 // optionally, the x and y offset of 2nd graphic can be specified directly
1467 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1468 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1469 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1470 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1472 // optionally, the second movement tile can be specified as start tile
1473 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1474 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1476 // automatically determine correct number of frames, if not defined
1477 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1478 g->anim_frames = parameter[GFX_ARG_FRAMES];
1479 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1480 g->anim_frames = anim_frames_per_row;
1481 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1482 g->anim_frames = anim_frames_per_col;
1486 if (g->anim_frames < 1) // frames must be at least 1
1489 g->anim_frames_per_line =
1490 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1491 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1493 g->anim_delay = parameter[GFX_ARG_DELAY];
1494 if (g->anim_delay < 1) // delay must be at least 1
1497 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1499 // automatically determine correct start frame, if not defined
1500 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1501 g->anim_start_frame = 0;
1502 else if (g->anim_mode & ANIM_REVERSE)
1503 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1505 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1507 // animation synchronized with global frame counter, not move position
1508 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1510 // optional element for cloning crumble graphics
1511 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1512 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1514 // optional element for cloning digging graphics
1515 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1516 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1518 // optional border size for "crumbling" diggable graphics
1519 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1520 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1522 // used for global animations and player "boring" and "sleeping" actions
1523 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1524 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1525 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1526 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1527 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1528 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1529 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1530 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1531 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1532 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1533 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1534 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1536 // used for global animations
1537 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1538 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1539 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1540 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1541 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1543 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1544 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1545 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1546 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1547 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1548 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1549 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1550 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1552 // used for toon animations and global animations
1553 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1554 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1555 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1556 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1557 g->direction = parameter[GFX_ARG_DIRECTION];
1558 g->position = parameter[GFX_ARG_POSITION];
1559 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1560 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1562 if (g->step_delay < 1) // delay must be at least 1
1565 // this is only used for drawing font characters
1566 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1567 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1569 // use a different default value for global animations and toons
1570 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1571 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1572 g->draw_masked = TRUE;
1574 // this is used for drawing envelopes, global animations and toons
1575 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1576 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1578 // used for toon animations and global animations
1579 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1580 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1582 // optional graphic for cloning all graphics settings
1583 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1584 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1586 // optional settings for drawing title screens and title messages
1587 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1588 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1589 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1590 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1591 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1592 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1593 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1594 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1595 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1596 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1597 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1598 g->align = parameter[GFX_ARG_ALIGN];
1599 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1600 g->valign = parameter[GFX_ARG_VALIGN];
1601 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1602 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1604 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1605 g->class = parameter[GFX_ARG_CLASS];
1606 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1607 g->style = parameter[GFX_ARG_STYLE];
1609 // this is only used for drawing menu buttons and text
1610 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1611 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1612 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1613 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1616 static void set_graphic_parameters(int graphic)
1618 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1619 char **parameter_raw = image->parameter;
1620 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1621 int parameter[NUM_GFX_ARGS];
1624 // if fallback to default artwork is done, also use the default parameters
1625 if (image->fallback_to_default)
1626 parameter_raw = image->default_parameter;
1628 // get integer values from string parameters
1629 for (i = 0; i < NUM_GFX_ARGS; i++)
1630 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1631 image_config_suffix[i].token,
1632 image_config_suffix[i].type);
1634 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1636 UPDATE_BUSY_STATE();
1639 static void set_cloned_graphic_parameters(int graphic)
1641 int fallback_graphic = IMG_CHAR_EXCLAM;
1642 int max_num_images = getImageListSize();
1643 int clone_graphic = graphic_info[graphic].clone_from;
1644 int num_references_followed = 1;
1646 while (graphic_info[clone_graphic].clone_from != -1 &&
1647 num_references_followed < max_num_images)
1649 clone_graphic = graphic_info[clone_graphic].clone_from;
1651 num_references_followed++;
1654 if (num_references_followed >= max_num_images)
1657 Warn("error found in config file:");
1658 Warn("- config file: '%s'", getImageConfigFilename());
1659 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1660 Warn("error: loop discovered when resolving cloned graphics");
1661 Warn("custom graphic rejected for this element/action");
1663 if (graphic == fallback_graphic)
1664 Fail("no fallback graphic available");
1666 Warn("fallback done to 'char_exclam' for this graphic");
1669 graphic_info[graphic] = graphic_info[fallback_graphic];
1673 graphic_info[graphic] = graphic_info[clone_graphic];
1674 graphic_info[graphic].clone_from = clone_graphic;
1678 static void InitGraphicInfo(void)
1680 int fallback_graphic = IMG_CHAR_EXCLAM;
1681 int num_images = getImageListSize();
1684 // use image size as default values for width and height for these images
1685 static int full_size_graphics[] =
1688 IMG_GLOBAL_BORDER_MAIN,
1689 IMG_GLOBAL_BORDER_SCORES,
1690 IMG_GLOBAL_BORDER_EDITOR,
1691 IMG_GLOBAL_BORDER_PLAYING,
1694 IMG_BACKGROUND_ENVELOPE_1,
1695 IMG_BACKGROUND_ENVELOPE_2,
1696 IMG_BACKGROUND_ENVELOPE_3,
1697 IMG_BACKGROUND_ENVELOPE_4,
1698 IMG_BACKGROUND_REQUEST,
1701 IMG_BACKGROUND_TITLE_INITIAL,
1702 IMG_BACKGROUND_TITLE,
1703 IMG_BACKGROUND_MAIN,
1704 IMG_BACKGROUND_NAMES,
1705 IMG_BACKGROUND_LEVELS,
1706 IMG_BACKGROUND_LEVELNR,
1707 IMG_BACKGROUND_SCORES,
1708 IMG_BACKGROUND_EDITOR,
1709 IMG_BACKGROUND_INFO,
1710 IMG_BACKGROUND_INFO_ELEMENTS,
1711 IMG_BACKGROUND_INFO_MUSIC,
1712 IMG_BACKGROUND_INFO_CREDITS,
1713 IMG_BACKGROUND_INFO_PROGRAM,
1714 IMG_BACKGROUND_INFO_VERSION,
1715 IMG_BACKGROUND_INFO_LEVELSET,
1716 IMG_BACKGROUND_SETUP,
1717 IMG_BACKGROUND_PLAYING,
1718 IMG_BACKGROUND_DOOR,
1719 IMG_BACKGROUND_TAPE,
1720 IMG_BACKGROUND_PANEL,
1721 IMG_BACKGROUND_PALETTE,
1722 IMG_BACKGROUND_TOOLBOX,
1724 IMG_TITLESCREEN_INITIAL_1,
1725 IMG_TITLESCREEN_INITIAL_2,
1726 IMG_TITLESCREEN_INITIAL_3,
1727 IMG_TITLESCREEN_INITIAL_4,
1728 IMG_TITLESCREEN_INITIAL_5,
1735 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1736 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1737 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1738 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1739 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1740 IMG_BACKGROUND_TITLEMESSAGE_1,
1741 IMG_BACKGROUND_TITLEMESSAGE_2,
1742 IMG_BACKGROUND_TITLEMESSAGE_3,
1743 IMG_BACKGROUND_TITLEMESSAGE_4,
1744 IMG_BACKGROUND_TITLEMESSAGE_5,
1749 FreeGlobalAnimEventInfo();
1751 checked_free(graphic_info);
1753 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1755 // initialize "use_image_size" flag with default value
1756 for (i = 0; i < num_images; i++)
1757 graphic_info[i].use_image_size = FALSE;
1759 // initialize "use_image_size" flag from static configuration above
1760 for (i = 0; full_size_graphics[i] != -1; i++)
1761 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1763 // first set all graphic paramaters ...
1764 for (i = 0; i < num_images; i++)
1765 set_graphic_parameters(i);
1767 // ... then copy these parameters for cloned graphics
1768 for (i = 0; i < num_images; i++)
1769 if (graphic_info[i].clone_from != -1)
1770 set_cloned_graphic_parameters(i);
1772 for (i = 0; i < num_images; i++)
1774 Bitmap *src_bitmap = graphic_info[i].bitmap;
1778 int src_bitmap_width, src_bitmap_height;
1780 // now check if no animation frames are outside of the loaded image
1782 if (graphic_info[i].bitmap == NULL)
1783 continue; // skip check for optional images that are undefined
1785 // get image size (this can differ from the standard element tile size!)
1786 width = graphic_info[i].width;
1787 height = graphic_info[i].height;
1789 // get final bitmap size (with scaling, but without small images)
1790 src_bitmap_width = graphic_info[i].src_image_width;
1791 src_bitmap_height = graphic_info[i].src_image_height;
1793 // check if first animation frame is inside specified bitmap
1795 // do not use getGraphicSourceXY() here to get position of first frame;
1796 // this avoids calculating wrong start position for out-of-bounds frame
1797 src_x = graphic_info[i].src_x;
1798 src_y = graphic_info[i].src_y;
1800 if (program.headless)
1803 if (src_x < 0 || src_y < 0 ||
1804 src_x + width > src_bitmap_width ||
1805 src_y + height > src_bitmap_height)
1808 Warn("error found in config file:");
1809 Warn("- config file: '%s'", getImageConfigFilename());
1810 Warn("- config token: '%s'", getTokenFromImageID(i));
1811 Warn("- image file: '%s'", src_bitmap->source_filename);
1812 Warn("- frame size: %d, %d", width, height);
1813 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1814 src_x, src_y, src_bitmap_width, src_bitmap_height);
1815 Warn("custom graphic rejected for this element/action");
1817 if (i == fallback_graphic)
1818 Fail("no fallback graphic available");
1820 Warn("fallback done to 'char_exclam' for this graphic");
1823 graphic_info[i] = graphic_info[fallback_graphic];
1825 // if first frame out of bounds, do not check last frame anymore
1829 // check if last animation frame is inside specified bitmap
1831 last_frame = graphic_info[i].anim_frames - 1;
1832 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1834 if (src_x < 0 || src_y < 0 ||
1835 src_x + width > src_bitmap_width ||
1836 src_y + height > src_bitmap_height)
1839 Warn("error found in config file:");
1840 Warn("- config file: '%s'", getImageConfigFilename());
1841 Warn("- config token: '%s'", getTokenFromImageID(i));
1842 Warn("- image file: '%s'", src_bitmap->source_filename);
1843 Warn("- frame size: %d, %d", width, height);
1844 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1845 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1846 Warn("custom graphic rejected for this element/action");
1848 if (i == fallback_graphic)
1849 Fail("no fallback graphic available");
1851 Warn("fallback done to 'char_exclam' for this graphic");
1854 graphic_info[i] = graphic_info[fallback_graphic];
1859 static void InitGraphicCompatibilityInfo(void)
1861 struct FileInfo *fi_global_door =
1862 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1863 int num_images = getImageListSize();
1866 /* the following compatibility handling is needed for the following case:
1867 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1868 graphics mainly used for door and panel graphics, like editor, tape and
1869 in-game buttons with hard-coded bitmap positions and button sizes; as
1870 these graphics now have individual definitions, redefining "global.door"
1871 to change all these graphics at once like before does not work anymore
1872 (because all those individual definitions still have their default values);
1873 to solve this, remap all those individual definitions that are not
1874 redefined to the new bitmap of "global.door" if it was redefined */
1876 // special compatibility handling if image "global.door" was redefined
1877 if (fi_global_door->redefined)
1879 for (i = 0; i < num_images; i++)
1881 struct FileInfo *fi = getImageListEntryFromImageID(i);
1883 // process only those images that still use the default settings
1886 // process all images which default to same image as "global.door"
1887 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1890 Debug("init:InitGraphicCompatibilityInfo",
1891 "special treatment needed for token '%s'", fi->token);
1894 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1895 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1901 InitGraphicCompatibilityInfo_Doors();
1904 static void InitElementSoundInfo(void)
1906 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1907 int num_property_mappings = getSoundListPropertyMappingSize();
1910 // set values to -1 to identify later as "uninitialized" values
1911 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1912 for (act = 0; act < NUM_ACTIONS; act++)
1913 element_info[i].sound[act] = -1;
1915 // initialize element/sound mapping from static configuration
1916 for (i = 0; element_to_sound[i].element > -1; i++)
1918 int element = element_to_sound[i].element;
1919 int action = element_to_sound[i].action;
1920 int sound = element_to_sound[i].sound;
1921 boolean is_class = element_to_sound[i].is_class;
1924 action = ACTION_DEFAULT;
1927 element_info[element].sound[action] = sound;
1929 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1930 if (strEqual(element_info[j].class_name,
1931 element_info[element].class_name))
1932 element_info[j].sound[action] = sound;
1935 // initialize element class/sound mapping from dynamic configuration
1936 for (i = 0; i < num_property_mappings; i++)
1938 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1939 int action = property_mapping[i].ext1_index;
1940 int sound = property_mapping[i].artwork_index;
1942 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1946 action = ACTION_DEFAULT;
1948 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1949 if (strEqual(element_info[j].class_name,
1950 element_info[element_class].class_name))
1951 element_info[j].sound[action] = sound;
1954 // initialize element/sound mapping from dynamic configuration
1955 for (i = 0; i < num_property_mappings; i++)
1957 int element = property_mapping[i].base_index;
1958 int action = property_mapping[i].ext1_index;
1959 int sound = property_mapping[i].artwork_index;
1961 if (element >= MAX_NUM_ELEMENTS)
1965 action = ACTION_DEFAULT;
1967 element_info[element].sound[action] = sound;
1970 // now set all '-1' values to element specific default values
1971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1973 for (act = 0; act < NUM_ACTIONS; act++)
1975 // generic default action sound (defined by "[default]" directive)
1976 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1978 // look for special default action sound (classic game specific)
1979 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1980 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1981 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1982 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1983 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1984 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1985 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1986 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1988 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1989 // !!! make this better !!!
1990 if (i == EL_EMPTY_SPACE)
1991 default_action_sound = element_info[EL_DEFAULT].sound[act];
1993 // no sound for this specific action -- use default action sound
1994 if (element_info[i].sound[act] == -1)
1995 element_info[i].sound[act] = default_action_sound;
1999 // copy sound settings to some elements that are only stored in level file
2000 // in native R'n'D levels, but are used by game engine in native EM levels
2001 for (i = 0; copy_properties[i][0] != -1; i++)
2002 for (j = 1; j <= 4; j++)
2003 for (act = 0; act < NUM_ACTIONS; act++)
2004 element_info[copy_properties[i][j]].sound[act] =
2005 element_info[copy_properties[i][0]].sound[act];
2008 static void InitGameModeSoundInfo(void)
2012 // set values to -1 to identify later as "uninitialized" values
2013 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2016 // initialize gamemode/sound mapping from static configuration
2017 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2019 int gamemode = gamemode_to_sound[i].gamemode;
2020 int sound = gamemode_to_sound[i].sound;
2023 gamemode = GAME_MODE_DEFAULT;
2025 menu.sound[gamemode] = sound;
2028 // now set all '-1' values to levelset specific default values
2029 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2030 if (menu.sound[i] == -1)
2031 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2034 static void set_sound_parameters(int sound, char **parameter_raw)
2036 int parameter[NUM_SND_ARGS];
2039 // get integer values from string parameters
2040 for (i = 0; i < NUM_SND_ARGS; i++)
2042 get_parameter_value(parameter_raw[i],
2043 sound_config_suffix[i].token,
2044 sound_config_suffix[i].type);
2046 // explicit loop mode setting in configuration overrides default value
2047 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2048 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2050 // sound volume to change the original volume when loading the sound file
2051 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2053 // sound priority to give certain sounds a higher or lower priority
2054 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2057 static void InitSoundInfo(void)
2059 int *sound_effect_properties;
2060 int num_sounds = getSoundListSize();
2063 checked_free(sound_info);
2065 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2066 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2068 // initialize sound effect for all elements to "no sound"
2069 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2070 for (j = 0; j < NUM_ACTIONS; j++)
2071 element_info[i].sound[j] = SND_UNDEFINED;
2073 for (i = 0; i < num_sounds; i++)
2075 struct FileInfo *sound = getSoundListEntry(i);
2076 int len_effect_text = strlen(sound->token);
2078 sound_effect_properties[i] = ACTION_OTHER;
2079 sound_info[i].loop = FALSE; // default: play sound only once
2081 // determine all loop sounds and identify certain sound classes
2083 for (j = 0; element_action_info[j].suffix; j++)
2085 int len_action_text = strlen(element_action_info[j].suffix);
2087 if (len_action_text < len_effect_text &&
2088 strEqual(&sound->token[len_effect_text - len_action_text],
2089 element_action_info[j].suffix))
2091 sound_effect_properties[i] = element_action_info[j].value;
2092 sound_info[i].loop = element_action_info[j].is_loop_sound;
2098 // associate elements and some selected sound actions
2100 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2102 if (element_info[j].class_name)
2104 int len_class_text = strlen(element_info[j].class_name);
2106 if (len_class_text + 1 < len_effect_text &&
2107 strncmp(sound->token,
2108 element_info[j].class_name, len_class_text) == 0 &&
2109 sound->token[len_class_text] == '.')
2111 int sound_action_value = sound_effect_properties[i];
2113 element_info[j].sound[sound_action_value] = i;
2118 set_sound_parameters(i, sound->parameter);
2121 free(sound_effect_properties);
2124 static void InitGameModeMusicInfo(void)
2126 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2127 int num_property_mappings = getMusicListPropertyMappingSize();
2128 int default_levelset_music = -1;
2131 // set values to -1 to identify later as "uninitialized" values
2132 for (i = 0; i < MAX_LEVELS; i++)
2133 levelset.music[i] = -1;
2134 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2137 // initialize gamemode/music mapping from static configuration
2138 for (i = 0; gamemode_to_music[i].music > -1; i++)
2140 int gamemode = gamemode_to_music[i].gamemode;
2141 int music = gamemode_to_music[i].music;
2144 gamemode = GAME_MODE_DEFAULT;
2146 menu.music[gamemode] = music;
2149 // initialize gamemode/music mapping from dynamic configuration
2150 for (i = 0; i < num_property_mappings; i++)
2152 int prefix = property_mapping[i].base_index;
2153 int gamemode = property_mapping[i].ext2_index;
2154 int level = property_mapping[i].ext3_index;
2155 int music = property_mapping[i].artwork_index;
2157 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2161 gamemode = GAME_MODE_DEFAULT;
2163 // level specific music only allowed for in-game music
2164 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2165 gamemode = GAME_MODE_PLAYING;
2170 default_levelset_music = music;
2173 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2174 levelset.music[level] = music;
2175 if (gamemode != GAME_MODE_PLAYING)
2176 menu.music[gamemode] = music;
2179 // now set all '-1' values to menu specific default values
2180 // (undefined values of "levelset.music[]" might stay at "-1" to
2181 // allow dynamic selection of music files from music directory!)
2182 for (i = 0; i < MAX_LEVELS; i++)
2183 if (levelset.music[i] == -1)
2184 levelset.music[i] = default_levelset_music;
2185 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2186 if (menu.music[i] == -1)
2187 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2190 static void set_music_parameters(int music, char **parameter_raw)
2192 int parameter[NUM_MUS_ARGS];
2195 // get integer values from string parameters
2196 for (i = 0; i < NUM_MUS_ARGS; i++)
2198 get_parameter_value(parameter_raw[i],
2199 music_config_suffix[i].token,
2200 music_config_suffix[i].type);
2202 // explicit loop mode setting in configuration overrides default value
2203 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2204 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2207 static void InitMusicInfo(void)
2209 int num_music = getMusicListSize();
2212 checked_free(music_info);
2214 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2216 for (i = 0; i < num_music; i++)
2218 struct FileInfo *music = getMusicListEntry(i);
2219 int len_music_text = strlen(music->token);
2221 music_info[i].loop = TRUE; // default: play music in loop mode
2223 // determine all loop music
2225 for (j = 0; music_prefix_info[j].prefix; j++)
2227 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2229 if (len_prefix_text < len_music_text &&
2230 strncmp(music->token,
2231 music_prefix_info[j].prefix, len_prefix_text) == 0)
2233 music_info[i].loop = music_prefix_info[j].is_loop_music;
2239 set_music_parameters(i, music->parameter);
2244 static void InitGameInfoFromArtworkInfo(void)
2246 // special case: store initial value of custom artwork setting
2247 game.use_masked_elements_initial = game.use_masked_elements;
2250 static void ReinitializeGraphics(void)
2252 print_timestamp_init("ReinitializeGraphics");
2254 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2256 InitGraphicInfo(); // graphic properties mapping
2257 print_timestamp_time("InitGraphicInfo");
2258 InitElementGraphicInfo(); // element game graphic mapping
2259 print_timestamp_time("InitElementGraphicInfo");
2260 InitElementSpecialGraphicInfo(); // element special graphic mapping
2261 print_timestamp_time("InitElementSpecialGraphicInfo");
2263 InitElementSmallImages(); // scale elements to all needed sizes
2264 print_timestamp_time("InitElementSmallImages");
2265 InitScaledImages(); // scale all other images, if needed
2266 print_timestamp_time("InitScaledImages");
2267 InitBitmapPointers(); // set standard size bitmap pointers
2268 print_timestamp_time("InitBitmapPointers");
2269 InitFontGraphicInfo(); // initialize text drawing functions
2270 print_timestamp_time("InitFontGraphicInfo");
2271 InitGlobalAnimGraphicInfo(); // initialize global animation config
2272 print_timestamp_time("InitGlobalAnimGraphicInfo");
2274 InitImageTextures(); // create textures for certain images
2275 print_timestamp_time("InitImageTextures");
2277 InitGraphicInfo_EM(); // graphic mapping for EM engine
2278 print_timestamp_time("InitGraphicInfo_EM");
2280 InitGraphicCompatibilityInfo();
2281 print_timestamp_time("InitGraphicCompatibilityInfo");
2283 SetMainBackgroundImage(IMG_BACKGROUND);
2284 print_timestamp_time("SetMainBackgroundImage");
2285 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2286 print_timestamp_time("SetDoorBackgroundImage");
2289 print_timestamp_time("InitGadgets");
2291 print_timestamp_time("InitDoors");
2293 InitGameInfoFromArtworkInfo();
2295 print_timestamp_done("ReinitializeGraphics");
2298 static void ReinitializeSounds(void)
2300 InitSoundInfo(); // sound properties mapping
2301 InitElementSoundInfo(); // element game sound mapping
2302 InitGameModeSoundInfo(); // game mode sound mapping
2303 InitGlobalAnimSoundInfo(); // global animation sound settings
2305 InitPlayLevelSound(); // internal game sound settings
2308 static void ReinitializeMusic(void)
2310 InitMusicInfo(); // music properties mapping
2311 InitGameModeMusicInfo(); // game mode music mapping
2312 InitGlobalAnimMusicInfo(); // global animation music settings
2315 static int get_special_property_bit(int element, int property_bit_nr)
2317 struct PropertyBitInfo
2323 static struct PropertyBitInfo pb_can_move_into_acid[] =
2325 // the player may be able fall into acid when gravity is activated
2330 { EL_SP_MURPHY, 0 },
2331 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2333 // all elements that can move may be able to also move into acid
2336 { EL_BUG_RIGHT, 1 },
2339 { EL_SPACESHIP, 2 },
2340 { EL_SPACESHIP_LEFT, 2 },
2341 { EL_SPACESHIP_RIGHT, 2 },
2342 { EL_SPACESHIP_UP, 2 },
2343 { EL_SPACESHIP_DOWN, 2 },
2344 { EL_BD_BUTTERFLY, 3 },
2345 { EL_BD_BUTTERFLY_LEFT, 3 },
2346 { EL_BD_BUTTERFLY_RIGHT, 3 },
2347 { EL_BD_BUTTERFLY_UP, 3 },
2348 { EL_BD_BUTTERFLY_DOWN, 3 },
2349 { EL_BD_FIREFLY, 4 },
2350 { EL_BD_FIREFLY_LEFT, 4 },
2351 { EL_BD_FIREFLY_RIGHT, 4 },
2352 { EL_BD_FIREFLY_UP, 4 },
2353 { EL_BD_FIREFLY_DOWN, 4 },
2355 { EL_YAMYAM_LEFT, 5 },
2356 { EL_YAMYAM_RIGHT, 5 },
2357 { EL_YAMYAM_UP, 5 },
2358 { EL_YAMYAM_DOWN, 5 },
2359 { EL_DARK_YAMYAM, 6 },
2362 { EL_PACMAN_LEFT, 8 },
2363 { EL_PACMAN_RIGHT, 8 },
2364 { EL_PACMAN_UP, 8 },
2365 { EL_PACMAN_DOWN, 8 },
2367 { EL_MOLE_LEFT, 9 },
2368 { EL_MOLE_RIGHT, 9 },
2370 { EL_MOLE_DOWN, 9 },
2374 { EL_SATELLITE, 13 },
2375 { EL_SP_SNIKSNAK, 14 },
2376 { EL_SP_ELECTRON, 15 },
2379 { EL_SPRING_LEFT, 17 },
2380 { EL_SPRING_RIGHT, 17 },
2381 { EL_EMC_ANDROID, 18 },
2386 static struct PropertyBitInfo pb_dont_collide_with[] =
2388 { EL_SP_SNIKSNAK, 0 },
2389 { EL_SP_ELECTRON, 1 },
2397 struct PropertyBitInfo *pb_info;
2400 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2401 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2406 struct PropertyBitInfo *pb_info = NULL;
2409 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2410 if (pb_definition[i].bit_nr == property_bit_nr)
2411 pb_info = pb_definition[i].pb_info;
2413 if (pb_info == NULL)
2416 for (i = 0; pb_info[i].element != -1; i++)
2417 if (pb_info[i].element == element)
2418 return pb_info[i].bit_nr;
2423 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2424 boolean property_value)
2426 int bit_nr = get_special_property_bit(element, property_bit_nr);
2431 *bitfield |= (1 << bit_nr);
2433 *bitfield &= ~(1 << bit_nr);
2437 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2439 int bit_nr = get_special_property_bit(element, property_bit_nr);
2442 return ((*bitfield & (1 << bit_nr)) != 0);
2447 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2449 static int group_nr;
2450 static struct ElementGroupInfo *group;
2451 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2454 if (actual_group == NULL) // not yet initialized
2457 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2459 Warn("recursion too deep when resolving group element %d",
2460 group_element - EL_GROUP_START + 1);
2462 // replace element which caused too deep recursion by question mark
2463 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2468 if (recursion_depth == 0) // initialization
2470 group = actual_group;
2471 group_nr = GROUP_NR(group_element);
2473 group->num_elements_resolved = 0;
2474 group->choice_pos = 0;
2476 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2477 element_info[i].in_group[group_nr] = FALSE;
2480 for (i = 0; i < actual_group->num_elements; i++)
2482 int element = actual_group->element[i];
2484 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2487 if (IS_GROUP_ELEMENT(element))
2488 ResolveGroupElementExt(element, recursion_depth + 1);
2491 group->element_resolved[group->num_elements_resolved++] = element;
2492 element_info[element].in_group[group_nr] = TRUE;
2497 void ResolveGroupElement(int group_element)
2499 ResolveGroupElementExt(group_element, 0);
2502 void InitElementPropertiesStatic(void)
2504 static boolean clipboard_elements_initialized = FALSE;
2506 static int ep_diggable[] =
2511 EL_SP_BUGGY_BASE_ACTIVATING,
2514 EL_INVISIBLE_SAND_ACTIVE,
2517 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2518 // (if amoeba can grow into anything diggable, maybe keep these out)
2523 EL_SP_BUGGY_BASE_ACTIVE,
2530 static int ep_collectible_only[] =
2552 EL_DYNABOMB_INCREASE_NUMBER,
2553 EL_DYNABOMB_INCREASE_SIZE,
2554 EL_DYNABOMB_INCREASE_POWER,
2572 // !!! handle separately !!!
2573 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2579 static int ep_dont_run_into[] =
2581 // same elements as in 'ep_dont_touch'
2587 // same elements as in 'ep_dont_collide_with'
2599 // !!! maybe this should better be handled by 'ep_diggable' !!!
2604 EL_SP_BUGGY_BASE_ACTIVE,
2611 static int ep_dont_collide_with[] =
2613 // same elements as in 'ep_dont_touch'
2630 static int ep_dont_touch[] =
2640 static int ep_indestructible[] =
2644 EL_ACID_POOL_TOPLEFT,
2645 EL_ACID_POOL_TOPRIGHT,
2646 EL_ACID_POOL_BOTTOMLEFT,
2647 EL_ACID_POOL_BOTTOM,
2648 EL_ACID_POOL_BOTTOMRIGHT,
2649 EL_SP_HARDWARE_GRAY,
2650 EL_SP_HARDWARE_GREEN,
2651 EL_SP_HARDWARE_BLUE,
2653 EL_SP_HARDWARE_YELLOW,
2654 EL_SP_HARDWARE_BASE_1,
2655 EL_SP_HARDWARE_BASE_2,
2656 EL_SP_HARDWARE_BASE_3,
2657 EL_SP_HARDWARE_BASE_4,
2658 EL_SP_HARDWARE_BASE_5,
2659 EL_SP_HARDWARE_BASE_6,
2660 EL_INVISIBLE_STEELWALL,
2661 EL_INVISIBLE_STEELWALL_ACTIVE,
2662 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2663 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2664 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2665 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2666 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2667 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2668 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2669 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2670 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2671 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2672 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2673 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2675 EL_LIGHT_SWITCH_ACTIVE,
2676 EL_SIGN_EXCLAMATION,
2677 EL_SIGN_RADIOACTIVITY,
2684 EL_SIGN_ENTRY_FORBIDDEN,
2685 EL_SIGN_EMERGENCY_EXIT,
2693 EL_STEEL_EXIT_CLOSED,
2695 EL_STEEL_EXIT_OPENING,
2696 EL_STEEL_EXIT_CLOSING,
2697 EL_EM_STEEL_EXIT_CLOSED,
2698 EL_EM_STEEL_EXIT_OPEN,
2699 EL_EM_STEEL_EXIT_OPENING,
2700 EL_EM_STEEL_EXIT_CLOSING,
2701 EL_DC_STEELWALL_1_LEFT,
2702 EL_DC_STEELWALL_1_RIGHT,
2703 EL_DC_STEELWALL_1_TOP,
2704 EL_DC_STEELWALL_1_BOTTOM,
2705 EL_DC_STEELWALL_1_HORIZONTAL,
2706 EL_DC_STEELWALL_1_VERTICAL,
2707 EL_DC_STEELWALL_1_TOPLEFT,
2708 EL_DC_STEELWALL_1_TOPRIGHT,
2709 EL_DC_STEELWALL_1_BOTTOMLEFT,
2710 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2711 EL_DC_STEELWALL_1_TOPLEFT_2,
2712 EL_DC_STEELWALL_1_TOPRIGHT_2,
2713 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2714 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2715 EL_DC_STEELWALL_2_LEFT,
2716 EL_DC_STEELWALL_2_RIGHT,
2717 EL_DC_STEELWALL_2_TOP,
2718 EL_DC_STEELWALL_2_BOTTOM,
2719 EL_DC_STEELWALL_2_HORIZONTAL,
2720 EL_DC_STEELWALL_2_VERTICAL,
2721 EL_DC_STEELWALL_2_MIDDLE,
2722 EL_DC_STEELWALL_2_SINGLE,
2723 EL_STEELWALL_SLIPPERY,
2737 EL_GATE_1_GRAY_ACTIVE,
2738 EL_GATE_2_GRAY_ACTIVE,
2739 EL_GATE_3_GRAY_ACTIVE,
2740 EL_GATE_4_GRAY_ACTIVE,
2749 EL_EM_GATE_1_GRAY_ACTIVE,
2750 EL_EM_GATE_2_GRAY_ACTIVE,
2751 EL_EM_GATE_3_GRAY_ACTIVE,
2752 EL_EM_GATE_4_GRAY_ACTIVE,
2761 EL_EMC_GATE_5_GRAY_ACTIVE,
2762 EL_EMC_GATE_6_GRAY_ACTIVE,
2763 EL_EMC_GATE_7_GRAY_ACTIVE,
2764 EL_EMC_GATE_8_GRAY_ACTIVE,
2766 EL_DC_GATE_WHITE_GRAY,
2767 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2768 EL_DC_GATE_FAKE_GRAY,
2770 EL_SWITCHGATE_OPENING,
2771 EL_SWITCHGATE_CLOSED,
2772 EL_SWITCHGATE_CLOSING,
2773 EL_DC_SWITCHGATE_SWITCH_UP,
2774 EL_DC_SWITCHGATE_SWITCH_DOWN,
2776 EL_TIMEGATE_OPENING,
2778 EL_TIMEGATE_CLOSING,
2779 EL_DC_TIMEGATE_SWITCH,
2780 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2784 EL_TUBE_VERTICAL_LEFT,
2785 EL_TUBE_VERTICAL_RIGHT,
2786 EL_TUBE_HORIZONTAL_UP,
2787 EL_TUBE_HORIZONTAL_DOWN,
2792 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2793 EL_EXPANDABLE_STEELWALL_VERTICAL,
2794 EL_EXPANDABLE_STEELWALL_ANY,
2799 static int ep_slippery[] =
2813 EL_ROBOT_WHEEL_ACTIVE,
2819 EL_ACID_POOL_TOPLEFT,
2820 EL_ACID_POOL_TOPRIGHT,
2830 EL_STEELWALL_SLIPPERY,
2833 EL_EMC_WALL_SLIPPERY_1,
2834 EL_EMC_WALL_SLIPPERY_2,
2835 EL_EMC_WALL_SLIPPERY_3,
2836 EL_EMC_WALL_SLIPPERY_4,
2838 EL_EMC_MAGIC_BALL_ACTIVE,
2843 static int ep_can_change[] =
2848 static int ep_can_move[] =
2850 // same elements as in 'pb_can_move_into_acid'
2873 static int ep_can_fall[] =
2888 EL_QUICKSAND_FAST_FULL,
2890 EL_BD_MAGIC_WALL_FULL,
2891 EL_DC_MAGIC_WALL_FULL,
2905 static int ep_can_smash_player[] =
2931 static int ep_can_smash_enemies[] =
2940 static int ep_can_smash_everything[] =
2949 static int ep_explodes_by_fire[] =
2951 // same elements as in 'ep_explodes_impact'
2956 // same elements as in 'ep_explodes_smashed'
2966 EL_EM_DYNAMITE_ACTIVE,
2967 EL_DYNABOMB_PLAYER_1_ACTIVE,
2968 EL_DYNABOMB_PLAYER_2_ACTIVE,
2969 EL_DYNABOMB_PLAYER_3_ACTIVE,
2970 EL_DYNABOMB_PLAYER_4_ACTIVE,
2971 EL_DYNABOMB_INCREASE_NUMBER,
2972 EL_DYNABOMB_INCREASE_SIZE,
2973 EL_DYNABOMB_INCREASE_POWER,
2974 EL_SP_DISK_RED_ACTIVE,
2988 static int ep_explodes_smashed[] =
2990 // same elements as in 'ep_explodes_impact'
3004 static int ep_explodes_impact[] =
3013 static int ep_walkable_over[] =
3033 EL_SOKOBAN_FIELD_EMPTY,
3040 EL_EM_STEEL_EXIT_OPEN,
3041 EL_EM_STEEL_EXIT_OPENING,
3050 EL_GATE_1_GRAY_ACTIVE,
3051 EL_GATE_2_GRAY_ACTIVE,
3052 EL_GATE_3_GRAY_ACTIVE,
3053 EL_GATE_4_GRAY_ACTIVE,
3061 static int ep_walkable_inside[] =
3066 EL_TUBE_VERTICAL_LEFT,
3067 EL_TUBE_VERTICAL_RIGHT,
3068 EL_TUBE_HORIZONTAL_UP,
3069 EL_TUBE_HORIZONTAL_DOWN,
3078 static int ep_walkable_under[] =
3083 static int ep_passable_over[] =
3093 EL_EM_GATE_1_GRAY_ACTIVE,
3094 EL_EM_GATE_2_GRAY_ACTIVE,
3095 EL_EM_GATE_3_GRAY_ACTIVE,
3096 EL_EM_GATE_4_GRAY_ACTIVE,
3105 EL_EMC_GATE_5_GRAY_ACTIVE,
3106 EL_EMC_GATE_6_GRAY_ACTIVE,
3107 EL_EMC_GATE_7_GRAY_ACTIVE,
3108 EL_EMC_GATE_8_GRAY_ACTIVE,
3110 EL_DC_GATE_WHITE_GRAY,
3111 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3118 static int ep_passable_inside[] =
3124 EL_SP_PORT_HORIZONTAL,
3125 EL_SP_PORT_VERTICAL,
3127 EL_SP_GRAVITY_PORT_LEFT,
3128 EL_SP_GRAVITY_PORT_RIGHT,
3129 EL_SP_GRAVITY_PORT_UP,
3130 EL_SP_GRAVITY_PORT_DOWN,
3131 EL_SP_GRAVITY_ON_PORT_LEFT,
3132 EL_SP_GRAVITY_ON_PORT_RIGHT,
3133 EL_SP_GRAVITY_ON_PORT_UP,
3134 EL_SP_GRAVITY_ON_PORT_DOWN,
3135 EL_SP_GRAVITY_OFF_PORT_LEFT,
3136 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3137 EL_SP_GRAVITY_OFF_PORT_UP,
3138 EL_SP_GRAVITY_OFF_PORT_DOWN,
3143 static int ep_passable_under[] =
3148 static int ep_droppable[] =
3153 static int ep_explodes_1x1_old[] =
3158 static int ep_pushable[] =
3170 EL_SOKOBAN_FIELD_FULL,
3179 static int ep_explodes_cross_old[] =
3184 static int ep_protected[] =
3186 // same elements as in 'ep_walkable_inside'
3190 EL_TUBE_VERTICAL_LEFT,
3191 EL_TUBE_VERTICAL_RIGHT,
3192 EL_TUBE_HORIZONTAL_UP,
3193 EL_TUBE_HORIZONTAL_DOWN,
3199 // same elements as in 'ep_passable_over'
3208 EL_EM_GATE_1_GRAY_ACTIVE,
3209 EL_EM_GATE_2_GRAY_ACTIVE,
3210 EL_EM_GATE_3_GRAY_ACTIVE,
3211 EL_EM_GATE_4_GRAY_ACTIVE,
3220 EL_EMC_GATE_5_GRAY_ACTIVE,
3221 EL_EMC_GATE_6_GRAY_ACTIVE,
3222 EL_EMC_GATE_7_GRAY_ACTIVE,
3223 EL_EMC_GATE_8_GRAY_ACTIVE,
3225 EL_DC_GATE_WHITE_GRAY,
3226 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3230 // same elements as in 'ep_passable_inside'
3235 EL_SP_PORT_HORIZONTAL,
3236 EL_SP_PORT_VERTICAL,
3238 EL_SP_GRAVITY_PORT_LEFT,
3239 EL_SP_GRAVITY_PORT_RIGHT,
3240 EL_SP_GRAVITY_PORT_UP,
3241 EL_SP_GRAVITY_PORT_DOWN,
3242 EL_SP_GRAVITY_ON_PORT_LEFT,
3243 EL_SP_GRAVITY_ON_PORT_RIGHT,
3244 EL_SP_GRAVITY_ON_PORT_UP,
3245 EL_SP_GRAVITY_ON_PORT_DOWN,
3246 EL_SP_GRAVITY_OFF_PORT_LEFT,
3247 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3248 EL_SP_GRAVITY_OFF_PORT_UP,
3249 EL_SP_GRAVITY_OFF_PORT_DOWN,
3254 static int ep_throwable[] =
3259 static int ep_can_explode[] =
3261 // same elements as in 'ep_explodes_impact'
3266 // same elements as in 'ep_explodes_smashed'
3272 // elements that can explode by explosion or by dragonfire
3276 EL_EM_DYNAMITE_ACTIVE,
3277 EL_DYNABOMB_PLAYER_1_ACTIVE,
3278 EL_DYNABOMB_PLAYER_2_ACTIVE,
3279 EL_DYNABOMB_PLAYER_3_ACTIVE,
3280 EL_DYNABOMB_PLAYER_4_ACTIVE,
3281 EL_DYNABOMB_INCREASE_NUMBER,
3282 EL_DYNABOMB_INCREASE_SIZE,
3283 EL_DYNABOMB_INCREASE_POWER,
3284 EL_SP_DISK_RED_ACTIVE,
3292 // elements that can explode only by explosion
3298 static int ep_gravity_reachable[] =
3304 EL_INVISIBLE_SAND_ACTIVE,
3309 EL_SP_PORT_HORIZONTAL,
3310 EL_SP_PORT_VERTICAL,
3312 EL_SP_GRAVITY_PORT_LEFT,
3313 EL_SP_GRAVITY_PORT_RIGHT,
3314 EL_SP_GRAVITY_PORT_UP,
3315 EL_SP_GRAVITY_PORT_DOWN,
3316 EL_SP_GRAVITY_ON_PORT_LEFT,
3317 EL_SP_GRAVITY_ON_PORT_RIGHT,
3318 EL_SP_GRAVITY_ON_PORT_UP,
3319 EL_SP_GRAVITY_ON_PORT_DOWN,
3320 EL_SP_GRAVITY_OFF_PORT_LEFT,
3321 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3322 EL_SP_GRAVITY_OFF_PORT_UP,
3323 EL_SP_GRAVITY_OFF_PORT_DOWN,
3329 static int ep_empty_space[] =
3352 static int ep_player[] =
3359 EL_SOKOBAN_FIELD_PLAYER,
3365 static int ep_can_pass_magic_wall[] =
3379 static int ep_can_pass_dc_magic_wall[] =
3395 static int ep_switchable[] =
3399 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3400 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3401 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3402 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3403 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3404 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3405 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3406 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3407 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3408 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3409 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3410 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3411 EL_SWITCHGATE_SWITCH_UP,
3412 EL_SWITCHGATE_SWITCH_DOWN,
3413 EL_DC_SWITCHGATE_SWITCH_UP,
3414 EL_DC_SWITCHGATE_SWITCH_DOWN,
3416 EL_LIGHT_SWITCH_ACTIVE,
3418 EL_DC_TIMEGATE_SWITCH,
3419 EL_BALLOON_SWITCH_LEFT,
3420 EL_BALLOON_SWITCH_RIGHT,
3421 EL_BALLOON_SWITCH_UP,
3422 EL_BALLOON_SWITCH_DOWN,
3423 EL_BALLOON_SWITCH_ANY,
3424 EL_BALLOON_SWITCH_NONE,
3427 EL_EMC_MAGIC_BALL_SWITCH,
3428 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3433 static int ep_bd_element[] =
3467 static int ep_sp_element[] =
3469 // should always be valid
3472 // standard classic Supaplex elements
3479 EL_SP_HARDWARE_GRAY,
3487 EL_SP_GRAVITY_PORT_RIGHT,
3488 EL_SP_GRAVITY_PORT_DOWN,
3489 EL_SP_GRAVITY_PORT_LEFT,
3490 EL_SP_GRAVITY_PORT_UP,
3495 EL_SP_PORT_VERTICAL,
3496 EL_SP_PORT_HORIZONTAL,
3502 EL_SP_HARDWARE_BASE_1,
3503 EL_SP_HARDWARE_GREEN,
3504 EL_SP_HARDWARE_BLUE,
3506 EL_SP_HARDWARE_YELLOW,
3507 EL_SP_HARDWARE_BASE_2,
3508 EL_SP_HARDWARE_BASE_3,
3509 EL_SP_HARDWARE_BASE_4,
3510 EL_SP_HARDWARE_BASE_5,
3511 EL_SP_HARDWARE_BASE_6,
3515 // additional elements that appeared in newer Supaplex levels
3518 // additional gravity port elements (not switching, but setting gravity)
3519 EL_SP_GRAVITY_ON_PORT_LEFT,
3520 EL_SP_GRAVITY_ON_PORT_RIGHT,
3521 EL_SP_GRAVITY_ON_PORT_UP,
3522 EL_SP_GRAVITY_ON_PORT_DOWN,
3523 EL_SP_GRAVITY_OFF_PORT_LEFT,
3524 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3525 EL_SP_GRAVITY_OFF_PORT_UP,
3526 EL_SP_GRAVITY_OFF_PORT_DOWN,
3528 // more than one Murphy in a level results in an inactive clone
3531 // runtime Supaplex elements
3532 EL_SP_DISK_RED_ACTIVE,
3533 EL_SP_TERMINAL_ACTIVE,
3534 EL_SP_BUGGY_BASE_ACTIVATING,
3535 EL_SP_BUGGY_BASE_ACTIVE,
3542 static int ep_sb_element[] =
3547 EL_SOKOBAN_FIELD_EMPTY,
3548 EL_SOKOBAN_FIELD_FULL,
3549 EL_SOKOBAN_FIELD_PLAYER,
3554 EL_INVISIBLE_STEELWALL,
3559 static int ep_gem[] =
3571 static int ep_food_dark_yamyam[] =
3599 static int ep_food_penguin[] =
3613 static int ep_food_pig[] =
3625 static int ep_historic_wall[] =
3636 EL_GATE_1_GRAY_ACTIVE,
3637 EL_GATE_2_GRAY_ACTIVE,
3638 EL_GATE_3_GRAY_ACTIVE,
3639 EL_GATE_4_GRAY_ACTIVE,
3648 EL_EM_GATE_1_GRAY_ACTIVE,
3649 EL_EM_GATE_2_GRAY_ACTIVE,
3650 EL_EM_GATE_3_GRAY_ACTIVE,
3651 EL_EM_GATE_4_GRAY_ACTIVE,
3658 EL_EXPANDABLE_WALL_HORIZONTAL,
3659 EL_EXPANDABLE_WALL_VERTICAL,
3660 EL_EXPANDABLE_WALL_ANY,
3661 EL_EXPANDABLE_WALL_GROWING,
3662 EL_BD_EXPANDABLE_WALL,
3669 EL_SP_HARDWARE_GRAY,
3670 EL_SP_HARDWARE_GREEN,
3671 EL_SP_HARDWARE_BLUE,
3673 EL_SP_HARDWARE_YELLOW,
3674 EL_SP_HARDWARE_BASE_1,
3675 EL_SP_HARDWARE_BASE_2,
3676 EL_SP_HARDWARE_BASE_3,
3677 EL_SP_HARDWARE_BASE_4,
3678 EL_SP_HARDWARE_BASE_5,
3679 EL_SP_HARDWARE_BASE_6,
3681 EL_SP_TERMINAL_ACTIVE,
3684 EL_INVISIBLE_STEELWALL,
3685 EL_INVISIBLE_STEELWALL_ACTIVE,
3687 EL_INVISIBLE_WALL_ACTIVE,
3688 EL_STEELWALL_SLIPPERY,
3705 static int ep_historic_solid[] =
3709 EL_EXPANDABLE_WALL_HORIZONTAL,
3710 EL_EXPANDABLE_WALL_VERTICAL,
3711 EL_EXPANDABLE_WALL_ANY,
3712 EL_BD_EXPANDABLE_WALL,
3725 EL_QUICKSAND_FILLING,
3726 EL_QUICKSAND_EMPTYING,
3728 EL_MAGIC_WALL_ACTIVE,
3729 EL_MAGIC_WALL_EMPTYING,
3730 EL_MAGIC_WALL_FILLING,
3734 EL_BD_MAGIC_WALL_ACTIVE,
3735 EL_BD_MAGIC_WALL_EMPTYING,
3736 EL_BD_MAGIC_WALL_FULL,
3737 EL_BD_MAGIC_WALL_FILLING,
3738 EL_BD_MAGIC_WALL_DEAD,
3747 EL_SP_TERMINAL_ACTIVE,
3751 EL_INVISIBLE_WALL_ACTIVE,
3752 EL_SWITCHGATE_SWITCH_UP,
3753 EL_SWITCHGATE_SWITCH_DOWN,
3755 EL_TIMEGATE_SWITCH_ACTIVE,
3767 // the following elements are a direct copy of "indestructible" elements,
3768 // except "EL_ACID", which is "indestructible", but not "solid"!
3773 EL_ACID_POOL_TOPLEFT,
3774 EL_ACID_POOL_TOPRIGHT,
3775 EL_ACID_POOL_BOTTOMLEFT,
3776 EL_ACID_POOL_BOTTOM,
3777 EL_ACID_POOL_BOTTOMRIGHT,
3778 EL_SP_HARDWARE_GRAY,
3779 EL_SP_HARDWARE_GREEN,
3780 EL_SP_HARDWARE_BLUE,
3782 EL_SP_HARDWARE_YELLOW,
3783 EL_SP_HARDWARE_BASE_1,
3784 EL_SP_HARDWARE_BASE_2,
3785 EL_SP_HARDWARE_BASE_3,
3786 EL_SP_HARDWARE_BASE_4,
3787 EL_SP_HARDWARE_BASE_5,
3788 EL_SP_HARDWARE_BASE_6,
3789 EL_INVISIBLE_STEELWALL,
3790 EL_INVISIBLE_STEELWALL_ACTIVE,
3791 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3792 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3793 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3794 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3795 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3796 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3797 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3798 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3799 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3800 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3801 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3802 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3804 EL_LIGHT_SWITCH_ACTIVE,
3805 EL_SIGN_EXCLAMATION,
3806 EL_SIGN_RADIOACTIVITY,
3813 EL_SIGN_ENTRY_FORBIDDEN,
3814 EL_SIGN_EMERGENCY_EXIT,
3822 EL_STEEL_EXIT_CLOSED,
3824 EL_STEEL_EXIT_OPENING,
3825 EL_STEEL_EXIT_CLOSING,
3826 EL_EM_STEEL_EXIT_CLOSED,
3827 EL_EM_STEEL_EXIT_OPEN,
3828 EL_EM_STEEL_EXIT_OPENING,
3829 EL_EM_STEEL_EXIT_CLOSING,
3830 EL_DC_STEELWALL_1_LEFT,
3831 EL_DC_STEELWALL_1_RIGHT,
3832 EL_DC_STEELWALL_1_TOP,
3833 EL_DC_STEELWALL_1_BOTTOM,
3834 EL_DC_STEELWALL_1_HORIZONTAL,
3835 EL_DC_STEELWALL_1_VERTICAL,
3836 EL_DC_STEELWALL_1_TOPLEFT,
3837 EL_DC_STEELWALL_1_TOPRIGHT,
3838 EL_DC_STEELWALL_1_BOTTOMLEFT,
3839 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3840 EL_DC_STEELWALL_1_TOPLEFT_2,
3841 EL_DC_STEELWALL_1_TOPRIGHT_2,
3842 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3843 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3844 EL_DC_STEELWALL_2_LEFT,
3845 EL_DC_STEELWALL_2_RIGHT,
3846 EL_DC_STEELWALL_2_TOP,
3847 EL_DC_STEELWALL_2_BOTTOM,
3848 EL_DC_STEELWALL_2_HORIZONTAL,
3849 EL_DC_STEELWALL_2_VERTICAL,
3850 EL_DC_STEELWALL_2_MIDDLE,
3851 EL_DC_STEELWALL_2_SINGLE,
3852 EL_STEELWALL_SLIPPERY,
3866 EL_GATE_1_GRAY_ACTIVE,
3867 EL_GATE_2_GRAY_ACTIVE,
3868 EL_GATE_3_GRAY_ACTIVE,
3869 EL_GATE_4_GRAY_ACTIVE,
3878 EL_EM_GATE_1_GRAY_ACTIVE,
3879 EL_EM_GATE_2_GRAY_ACTIVE,
3880 EL_EM_GATE_3_GRAY_ACTIVE,
3881 EL_EM_GATE_4_GRAY_ACTIVE,
3890 EL_EMC_GATE_5_GRAY_ACTIVE,
3891 EL_EMC_GATE_6_GRAY_ACTIVE,
3892 EL_EMC_GATE_7_GRAY_ACTIVE,
3893 EL_EMC_GATE_8_GRAY_ACTIVE,
3895 EL_DC_GATE_WHITE_GRAY,
3896 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3897 EL_DC_GATE_FAKE_GRAY,
3899 EL_SWITCHGATE_OPENING,
3900 EL_SWITCHGATE_CLOSED,
3901 EL_SWITCHGATE_CLOSING,
3902 EL_DC_SWITCHGATE_SWITCH_UP,
3903 EL_DC_SWITCHGATE_SWITCH_DOWN,
3905 EL_TIMEGATE_OPENING,
3907 EL_TIMEGATE_CLOSING,
3908 EL_DC_TIMEGATE_SWITCH,
3909 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3913 EL_TUBE_VERTICAL_LEFT,
3914 EL_TUBE_VERTICAL_RIGHT,
3915 EL_TUBE_HORIZONTAL_UP,
3916 EL_TUBE_HORIZONTAL_DOWN,
3921 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3922 EL_EXPANDABLE_STEELWALL_VERTICAL,
3923 EL_EXPANDABLE_STEELWALL_ANY,
3928 static int ep_classic_enemy[] =
3945 static int ep_belt[] =
3947 EL_CONVEYOR_BELT_1_LEFT,
3948 EL_CONVEYOR_BELT_1_MIDDLE,
3949 EL_CONVEYOR_BELT_1_RIGHT,
3950 EL_CONVEYOR_BELT_2_LEFT,
3951 EL_CONVEYOR_BELT_2_MIDDLE,
3952 EL_CONVEYOR_BELT_2_RIGHT,
3953 EL_CONVEYOR_BELT_3_LEFT,
3954 EL_CONVEYOR_BELT_3_MIDDLE,
3955 EL_CONVEYOR_BELT_3_RIGHT,
3956 EL_CONVEYOR_BELT_4_LEFT,
3957 EL_CONVEYOR_BELT_4_MIDDLE,
3958 EL_CONVEYOR_BELT_4_RIGHT,
3963 static int ep_belt_active[] =
3965 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3966 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3967 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3968 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3969 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3970 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3971 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3972 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3973 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3974 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3975 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3976 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3981 static int ep_belt_switch[] =
3983 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3984 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3985 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3986 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3987 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3988 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3989 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3990 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3991 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3992 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3993 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3994 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3999 static int ep_tube[] =
4006 EL_TUBE_HORIZONTAL_UP,
4007 EL_TUBE_HORIZONTAL_DOWN,
4009 EL_TUBE_VERTICAL_LEFT,
4010 EL_TUBE_VERTICAL_RIGHT,
4016 static int ep_acid_pool[] =
4018 EL_ACID_POOL_TOPLEFT,
4019 EL_ACID_POOL_TOPRIGHT,
4020 EL_ACID_POOL_BOTTOMLEFT,
4021 EL_ACID_POOL_BOTTOM,
4022 EL_ACID_POOL_BOTTOMRIGHT,
4027 static int ep_keygate[] =
4037 EL_GATE_1_GRAY_ACTIVE,
4038 EL_GATE_2_GRAY_ACTIVE,
4039 EL_GATE_3_GRAY_ACTIVE,
4040 EL_GATE_4_GRAY_ACTIVE,
4049 EL_EM_GATE_1_GRAY_ACTIVE,
4050 EL_EM_GATE_2_GRAY_ACTIVE,
4051 EL_EM_GATE_3_GRAY_ACTIVE,
4052 EL_EM_GATE_4_GRAY_ACTIVE,
4061 EL_EMC_GATE_5_GRAY_ACTIVE,
4062 EL_EMC_GATE_6_GRAY_ACTIVE,
4063 EL_EMC_GATE_7_GRAY_ACTIVE,
4064 EL_EMC_GATE_8_GRAY_ACTIVE,
4066 EL_DC_GATE_WHITE_GRAY,
4067 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4072 static int ep_amoeboid[] =
4084 static int ep_amoebalive[] =
4095 static int ep_has_editor_content[] =
4101 EL_SOKOBAN_FIELD_PLAYER,
4118 static int ep_can_turn_each_move[] =
4120 // !!! do something with this one !!!
4124 static int ep_can_grow[] =
4138 static int ep_active_bomb[] =
4141 EL_EM_DYNAMITE_ACTIVE,
4142 EL_DYNABOMB_PLAYER_1_ACTIVE,
4143 EL_DYNABOMB_PLAYER_2_ACTIVE,
4144 EL_DYNABOMB_PLAYER_3_ACTIVE,
4145 EL_DYNABOMB_PLAYER_4_ACTIVE,
4146 EL_SP_DISK_RED_ACTIVE,
4151 static int ep_inactive[] =
4177 EL_QUICKSAND_FAST_EMPTY,
4200 EL_GATE_1_GRAY_ACTIVE,
4201 EL_GATE_2_GRAY_ACTIVE,
4202 EL_GATE_3_GRAY_ACTIVE,
4203 EL_GATE_4_GRAY_ACTIVE,
4212 EL_EM_GATE_1_GRAY_ACTIVE,
4213 EL_EM_GATE_2_GRAY_ACTIVE,
4214 EL_EM_GATE_3_GRAY_ACTIVE,
4215 EL_EM_GATE_4_GRAY_ACTIVE,
4224 EL_EMC_GATE_5_GRAY_ACTIVE,
4225 EL_EMC_GATE_6_GRAY_ACTIVE,
4226 EL_EMC_GATE_7_GRAY_ACTIVE,
4227 EL_EMC_GATE_8_GRAY_ACTIVE,
4229 EL_DC_GATE_WHITE_GRAY,
4230 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4231 EL_DC_GATE_FAKE_GRAY,
4234 EL_INVISIBLE_STEELWALL,
4242 EL_WALL_EMERALD_YELLOW,
4243 EL_DYNABOMB_INCREASE_NUMBER,
4244 EL_DYNABOMB_INCREASE_SIZE,
4245 EL_DYNABOMB_INCREASE_POWER,
4249 EL_SOKOBAN_FIELD_EMPTY,
4250 EL_SOKOBAN_FIELD_FULL,
4251 EL_WALL_EMERALD_RED,
4252 EL_WALL_EMERALD_PURPLE,
4253 EL_ACID_POOL_TOPLEFT,
4254 EL_ACID_POOL_TOPRIGHT,
4255 EL_ACID_POOL_BOTTOMLEFT,
4256 EL_ACID_POOL_BOTTOM,
4257 EL_ACID_POOL_BOTTOMRIGHT,
4261 EL_BD_MAGIC_WALL_DEAD,
4263 EL_DC_MAGIC_WALL_DEAD,
4264 EL_AMOEBA_TO_DIAMOND,
4272 EL_SP_GRAVITY_PORT_RIGHT,
4273 EL_SP_GRAVITY_PORT_DOWN,
4274 EL_SP_GRAVITY_PORT_LEFT,
4275 EL_SP_GRAVITY_PORT_UP,
4276 EL_SP_PORT_HORIZONTAL,
4277 EL_SP_PORT_VERTICAL,
4288 EL_SP_HARDWARE_GRAY,
4289 EL_SP_HARDWARE_GREEN,
4290 EL_SP_HARDWARE_BLUE,
4292 EL_SP_HARDWARE_YELLOW,
4293 EL_SP_HARDWARE_BASE_1,
4294 EL_SP_HARDWARE_BASE_2,
4295 EL_SP_HARDWARE_BASE_3,
4296 EL_SP_HARDWARE_BASE_4,
4297 EL_SP_HARDWARE_BASE_5,
4298 EL_SP_HARDWARE_BASE_6,
4299 EL_SP_GRAVITY_ON_PORT_LEFT,
4300 EL_SP_GRAVITY_ON_PORT_RIGHT,
4301 EL_SP_GRAVITY_ON_PORT_UP,
4302 EL_SP_GRAVITY_ON_PORT_DOWN,
4303 EL_SP_GRAVITY_OFF_PORT_LEFT,
4304 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4305 EL_SP_GRAVITY_OFF_PORT_UP,
4306 EL_SP_GRAVITY_OFF_PORT_DOWN,
4307 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4308 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4309 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4310 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4311 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4312 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4313 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4314 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4315 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4316 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4317 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4318 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4319 EL_SIGN_EXCLAMATION,
4320 EL_SIGN_RADIOACTIVITY,
4327 EL_SIGN_ENTRY_FORBIDDEN,
4328 EL_SIGN_EMERGENCY_EXIT,
4336 EL_DC_STEELWALL_1_LEFT,
4337 EL_DC_STEELWALL_1_RIGHT,
4338 EL_DC_STEELWALL_1_TOP,
4339 EL_DC_STEELWALL_1_BOTTOM,
4340 EL_DC_STEELWALL_1_HORIZONTAL,
4341 EL_DC_STEELWALL_1_VERTICAL,
4342 EL_DC_STEELWALL_1_TOPLEFT,
4343 EL_DC_STEELWALL_1_TOPRIGHT,
4344 EL_DC_STEELWALL_1_BOTTOMLEFT,
4345 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4346 EL_DC_STEELWALL_1_TOPLEFT_2,
4347 EL_DC_STEELWALL_1_TOPRIGHT_2,
4348 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4349 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4350 EL_DC_STEELWALL_2_LEFT,
4351 EL_DC_STEELWALL_2_RIGHT,
4352 EL_DC_STEELWALL_2_TOP,
4353 EL_DC_STEELWALL_2_BOTTOM,
4354 EL_DC_STEELWALL_2_HORIZONTAL,
4355 EL_DC_STEELWALL_2_VERTICAL,
4356 EL_DC_STEELWALL_2_MIDDLE,
4357 EL_DC_STEELWALL_2_SINGLE,
4358 EL_STEELWALL_SLIPPERY,
4363 EL_EMC_WALL_SLIPPERY_1,
4364 EL_EMC_WALL_SLIPPERY_2,
4365 EL_EMC_WALL_SLIPPERY_3,
4366 EL_EMC_WALL_SLIPPERY_4,
4387 static int ep_em_slippery_wall[] =
4392 static int ep_gfx_crumbled[] =
4403 static int ep_editor_cascade_active[] =
4405 EL_INTERNAL_CASCADE_BD_ACTIVE,
4406 EL_INTERNAL_CASCADE_EM_ACTIVE,
4407 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4408 EL_INTERNAL_CASCADE_RND_ACTIVE,
4409 EL_INTERNAL_CASCADE_SB_ACTIVE,
4410 EL_INTERNAL_CASCADE_SP_ACTIVE,
4411 EL_INTERNAL_CASCADE_DC_ACTIVE,
4412 EL_INTERNAL_CASCADE_DX_ACTIVE,
4413 EL_INTERNAL_CASCADE_MM_ACTIVE,
4414 EL_INTERNAL_CASCADE_DF_ACTIVE,
4415 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4416 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4417 EL_INTERNAL_CASCADE_CE_ACTIVE,
4418 EL_INTERNAL_CASCADE_GE_ACTIVE,
4419 EL_INTERNAL_CASCADE_ES_ACTIVE,
4420 EL_INTERNAL_CASCADE_REF_ACTIVE,
4421 EL_INTERNAL_CASCADE_USER_ACTIVE,
4422 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4427 static int ep_editor_cascade_inactive[] =
4429 EL_INTERNAL_CASCADE_BD,
4430 EL_INTERNAL_CASCADE_EM,
4431 EL_INTERNAL_CASCADE_EMC,
4432 EL_INTERNAL_CASCADE_RND,
4433 EL_INTERNAL_CASCADE_SB,
4434 EL_INTERNAL_CASCADE_SP,
4435 EL_INTERNAL_CASCADE_DC,
4436 EL_INTERNAL_CASCADE_DX,
4437 EL_INTERNAL_CASCADE_MM,
4438 EL_INTERNAL_CASCADE_DF,
4439 EL_INTERNAL_CASCADE_CHARS,
4440 EL_INTERNAL_CASCADE_STEEL_CHARS,
4441 EL_INTERNAL_CASCADE_CE,
4442 EL_INTERNAL_CASCADE_GE,
4443 EL_INTERNAL_CASCADE_ES,
4444 EL_INTERNAL_CASCADE_REF,
4445 EL_INTERNAL_CASCADE_USER,
4446 EL_INTERNAL_CASCADE_DYNAMIC,
4451 static int ep_obsolete[] =
4455 EL_EM_KEY_1_FILE_OBSOLETE,
4456 EL_EM_KEY_2_FILE_OBSOLETE,
4457 EL_EM_KEY_3_FILE_OBSOLETE,
4458 EL_EM_KEY_4_FILE_OBSOLETE,
4459 EL_ENVELOPE_OBSOLETE,
4468 } element_properties[] =
4470 { ep_diggable, EP_DIGGABLE },
4471 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4472 { ep_dont_run_into, EP_DONT_RUN_INTO },
4473 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4474 { ep_dont_touch, EP_DONT_TOUCH },
4475 { ep_indestructible, EP_INDESTRUCTIBLE },
4476 { ep_slippery, EP_SLIPPERY },
4477 { ep_can_change, EP_CAN_CHANGE },
4478 { ep_can_move, EP_CAN_MOVE },
4479 { ep_can_fall, EP_CAN_FALL },
4480 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4481 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4482 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4483 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4484 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4485 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4486 { ep_walkable_over, EP_WALKABLE_OVER },
4487 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4488 { ep_walkable_under, EP_WALKABLE_UNDER },
4489 { ep_passable_over, EP_PASSABLE_OVER },
4490 { ep_passable_inside, EP_PASSABLE_INSIDE },
4491 { ep_passable_under, EP_PASSABLE_UNDER },
4492 { ep_droppable, EP_DROPPABLE },
4493 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4494 { ep_pushable, EP_PUSHABLE },
4495 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4496 { ep_protected, EP_PROTECTED },
4497 { ep_throwable, EP_THROWABLE },
4498 { ep_can_explode, EP_CAN_EXPLODE },
4499 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4501 { ep_empty_space, EP_EMPTY_SPACE },
4502 { ep_player, EP_PLAYER },
4503 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4504 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4505 { ep_switchable, EP_SWITCHABLE },
4506 { ep_bd_element, EP_BD_ELEMENT },
4507 { ep_sp_element, EP_SP_ELEMENT },
4508 { ep_sb_element, EP_SB_ELEMENT },
4510 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4511 { ep_food_penguin, EP_FOOD_PENGUIN },
4512 { ep_food_pig, EP_FOOD_PIG },
4513 { ep_historic_wall, EP_HISTORIC_WALL },
4514 { ep_historic_solid, EP_HISTORIC_SOLID },
4515 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4516 { ep_belt, EP_BELT },
4517 { ep_belt_active, EP_BELT_ACTIVE },
4518 { ep_belt_switch, EP_BELT_SWITCH },
4519 { ep_tube, EP_TUBE },
4520 { ep_acid_pool, EP_ACID_POOL },
4521 { ep_keygate, EP_KEYGATE },
4522 { ep_amoeboid, EP_AMOEBOID },
4523 { ep_amoebalive, EP_AMOEBALIVE },
4524 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4525 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4526 { ep_can_grow, EP_CAN_GROW },
4527 { ep_active_bomb, EP_ACTIVE_BOMB },
4528 { ep_inactive, EP_INACTIVE },
4530 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4532 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4534 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4535 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4537 { ep_obsolete, EP_OBSOLETE },
4544 // always start with reliable default values (element has no properties)
4545 // (but never initialize clipboard elements after the very first time)
4546 // (to be able to use clipboard elements between several levels)
4547 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4548 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4549 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4550 SET_PROPERTY(i, j, FALSE);
4552 // set all base element properties from above array definitions
4553 for (i = 0; element_properties[i].elements != NULL; i++)
4554 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4555 SET_PROPERTY((element_properties[i].elements)[j],
4556 element_properties[i].property, TRUE);
4558 // copy properties to some elements that are only stored in level file
4559 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4560 for (j = 0; copy_properties[j][0] != -1; j++)
4561 if (HAS_PROPERTY(copy_properties[j][0], i))
4562 for (k = 1; k <= 4; k++)
4563 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4565 // set static element properties that are not listed in array definitions
4566 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4567 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4569 clipboard_elements_initialized = TRUE;
4572 void InitElementPropertiesEngine(int engine_version)
4574 static int no_wall_properties[] =
4577 EP_COLLECTIBLE_ONLY,
4579 EP_DONT_COLLIDE_WITH,
4582 EP_CAN_SMASH_PLAYER,
4583 EP_CAN_SMASH_ENEMIES,
4584 EP_CAN_SMASH_EVERYTHING,
4589 EP_FOOD_DARK_YAMYAM,
4605 /* important: after initialization in InitElementPropertiesStatic(), the
4606 elements are not again initialized to a default value; therefore all
4607 changes have to make sure that they leave the element with a defined
4608 property (which means that conditional property changes must be set to
4609 a reliable default value before) */
4611 // resolve group elements
4612 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4613 ResolveGroupElement(EL_GROUP_START + i);
4615 // set all special, combined or engine dependent element properties
4616 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4618 // do not change (already initialized) clipboard elements here
4619 if (IS_CLIPBOARD_ELEMENT(i))
4622 // ---------- INACTIVE ----------------------------------------------------
4623 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4624 i <= EL_CHAR_END) ||
4625 (i >= EL_STEEL_CHAR_START &&
4626 i <= EL_STEEL_CHAR_END)));
4628 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4629 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4630 IS_WALKABLE_INSIDE(i) ||
4631 IS_WALKABLE_UNDER(i)));
4633 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4634 IS_PASSABLE_INSIDE(i) ||
4635 IS_PASSABLE_UNDER(i)));
4637 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4638 IS_PASSABLE_OVER(i)));
4640 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4641 IS_PASSABLE_INSIDE(i)));
4643 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4644 IS_PASSABLE_UNDER(i)));
4646 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4649 // ---------- COLLECTIBLE -------------------------------------------------
4650 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4654 // ---------- SNAPPABLE ---------------------------------------------------
4655 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4656 IS_COLLECTIBLE(i) ||
4660 // ---------- WALL --------------------------------------------------------
4661 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4663 for (j = 0; no_wall_properties[j] != -1; j++)
4664 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4665 i >= EL_FIRST_RUNTIME_UNREAL)
4666 SET_PROPERTY(i, EP_WALL, FALSE);
4668 if (IS_HISTORIC_WALL(i))
4669 SET_PROPERTY(i, EP_WALL, TRUE);
4671 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4672 if (engine_version < VERSION_IDENT(2,2,0,0))
4673 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4675 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4677 !IS_COLLECTIBLE(i)));
4679 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4680 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4681 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4683 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4686 // ---------- EXPLOSION_PROOF ---------------------------------------------
4688 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4689 else if (engine_version < VERSION_IDENT(2,2,0,0))
4690 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4692 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4696 if (IS_CUSTOM_ELEMENT(i))
4698 // these are additional properties which are initially false when set
4700 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4702 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4703 if (DONT_COLLIDE_WITH(i))
4704 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4706 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4707 if (CAN_SMASH_EVERYTHING(i))
4708 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4709 if (CAN_SMASH_ENEMIES(i))
4710 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4713 // ---------- CAN_SMASH ---------------------------------------------------
4714 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4715 CAN_SMASH_ENEMIES(i) ||
4716 CAN_SMASH_EVERYTHING(i)));
4718 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4719 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4720 EXPLODES_BY_FIRE(i)));
4722 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4723 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4724 EXPLODES_SMASHED(i)));
4726 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4727 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4728 EXPLODES_IMPACT(i)));
4730 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4731 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4733 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4734 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4735 i == EL_BLACK_ORB));
4737 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4738 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4740 IS_CUSTOM_ELEMENT(i)));
4742 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4743 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4744 i == EL_SP_ELECTRON));
4746 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4747 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4748 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4749 getMoveIntoAcidProperty(&level, i));
4751 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4752 if (MAYBE_DONT_COLLIDE_WITH(i))
4753 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4754 getDontCollideWithProperty(&level, i));
4756 // ---------- SP_PORT -----------------------------------------------------
4757 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4758 IS_PASSABLE_INSIDE(i)));
4760 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4761 for (j = 0; j < level.num_android_clone_elements; j++)
4762 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4764 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4766 // ---------- CAN_CHANGE --------------------------------------------------
4767 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4768 for (j = 0; j < element_info[i].num_change_pages; j++)
4769 if (element_info[i].change_page[j].can_change)
4770 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4772 // ---------- HAS_ACTION --------------------------------------------------
4773 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4774 for (j = 0; j < element_info[i].num_change_pages; j++)
4775 if (element_info[i].change_page[j].has_action)
4776 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4778 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4779 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4782 // ---------- GFX_CRUMBLED ------------------------------------------------
4783 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4784 element_info[i].crumbled[ACTION_DEFAULT] !=
4785 element_info[i].graphic[ACTION_DEFAULT]);
4787 // ---------- EDITOR_CASCADE ----------------------------------------------
4788 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4789 IS_EDITOR_CASCADE_INACTIVE(i)));
4792 // dynamically adjust element properties according to game engine version
4794 static int ep_em_slippery_wall[] =
4799 EL_EXPANDABLE_WALL_HORIZONTAL,
4800 EL_EXPANDABLE_WALL_VERTICAL,
4801 EL_EXPANDABLE_WALL_ANY,
4802 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4803 EL_EXPANDABLE_STEELWALL_VERTICAL,
4804 EL_EXPANDABLE_STEELWALL_ANY,
4805 EL_EXPANDABLE_STEELWALL_GROWING,
4809 static int ep_em_explodes_by_fire[] =
4812 EL_EM_DYNAMITE_ACTIVE,
4817 // special EM style gems behaviour
4818 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4819 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4820 level.em_slippery_gems);
4822 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4823 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4824 (level.em_slippery_gems &&
4825 engine_version > VERSION_IDENT(2,0,1,0)));
4827 // special EM style explosion behaviour regarding chain reactions
4828 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4829 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4830 level.em_explodes_by_fire);
4833 // this is needed because some graphics depend on element properties
4834 if (game_status == GAME_MODE_PLAYING)
4835 InitElementGraphicInfo();
4838 void InitElementPropertiesGfxElement(void)
4842 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4844 struct ElementInfo *ei = &element_info[i];
4846 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4850 static void InitGlobal(void)
4855 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4857 // check if element_name_info entry defined for each element in "main.h"
4858 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4859 Fail("undefined 'element_name_info' entry for element %d", i);
4861 element_info[i].token_name = element_name_info[i].token_name;
4862 element_info[i].class_name = element_name_info[i].class_name;
4863 element_info[i].editor_description= element_name_info[i].editor_description;
4866 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4868 // check if global_anim_name_info defined for each entry in "main.h"
4869 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4870 global_anim_name_info[i].token_name == NULL)
4871 Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4873 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4876 // create hash from image config list
4877 image_config_hash = newSetupFileHash();
4878 for (i = 0; image_config[i].token != NULL; i++)
4879 setHashEntry(image_config_hash,
4880 image_config[i].token,
4881 image_config[i].value);
4883 // create hash from element token list
4884 element_token_hash = newSetupFileHash();
4885 for (i = 0; element_name_info[i].token_name != NULL; i++)
4886 setHashEntry(element_token_hash,
4887 element_name_info[i].token_name,
4890 // create hash from graphic token list
4891 graphic_token_hash = newSetupFileHash();
4892 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4893 if (strSuffix(image_config[i].value, ".png") ||
4894 strSuffix(image_config[i].value, ".pcx") ||
4895 strSuffix(image_config[i].value, ".wav") ||
4896 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4897 setHashEntry(graphic_token_hash,
4898 image_config[i].token,
4899 int2str(graphic++, 0));
4901 // create hash from font token list
4902 font_token_hash = newSetupFileHash();
4903 for (i = 0; font_info[i].token_name != NULL; i++)
4904 setHashEntry(font_token_hash,
4905 font_info[i].token_name,
4908 // set default filenames for all cloned graphics in static configuration
4909 for (i = 0; image_config[i].token != NULL; i++)
4911 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4913 char *token = image_config[i].token;
4914 char *token_clone_from = getStringCat2(token, ".clone_from");
4915 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4917 if (token_cloned != NULL)
4919 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4921 if (value_cloned != NULL)
4923 // set default filename in static configuration
4924 image_config[i].value = value_cloned;
4926 // set default filename in image config hash
4927 setHashEntry(image_config_hash, token, value_cloned);
4931 free(token_clone_from);
4935 // always start with reliable default values (all elements)
4936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4937 ActiveElement[i] = i;
4939 // now add all entries that have an active state (active elements)
4940 for (i = 0; element_with_active_state[i].element != -1; i++)
4942 int element = element_with_active_state[i].element;
4943 int element_active = element_with_active_state[i].element_active;
4945 ActiveElement[element] = element_active;
4948 // always start with reliable default values (all buttons)
4949 for (i = 0; i < NUM_IMAGE_FILES; i++)
4950 ActiveButton[i] = i;
4952 // now add all entries that have an active state (active buttons)
4953 for (i = 0; button_with_active_state[i].button != -1; i++)
4955 int button = button_with_active_state[i].button;
4956 int button_active = button_with_active_state[i].button_active;
4958 ActiveButton[button] = button_active;
4961 // always start with reliable default values (all fonts)
4962 for (i = 0; i < NUM_FONTS; i++)
4965 // now add all entries that have an active state (active fonts)
4966 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4968 int font = font_with_active_state[i].font_nr;
4969 int font_active = font_with_active_state[i].font_nr_active;
4971 ActiveFont[font] = font_active;
4974 global.autoplay_leveldir = NULL;
4975 global.patchtapes_leveldir = NULL;
4976 global.convert_leveldir = NULL;
4977 global.dumplevel_leveldir = NULL;
4978 global.dumptape_leveldir = NULL;
4979 global.create_sketch_images_dir = NULL;
4980 global.create_collect_images_dir = NULL;
4982 global.frames_per_second = 0;
4983 global.show_frames_per_second = FALSE;
4985 global.border_status = GAME_MODE_LOADING;
4986 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4988 global.use_envelope_request = FALSE;
4990 global.user_names = NULL;
4993 static void Execute_Command(char *command)
4997 if (strEqual(command, "print graphicsinfo.conf"))
4999 Print("# You can configure additional/alternative image files here.\n");
5000 Print("# (The entries below are default and therefore commented out.)\n");
5002 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5004 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5007 for (i = 0; image_config[i].token != NULL; i++)
5008 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5009 image_config[i].value));
5013 else if (strEqual(command, "print soundsinfo.conf"))
5015 Print("# You can configure additional/alternative sound files here.\n");
5016 Print("# (The entries below are default and therefore commented out.)\n");
5018 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5020 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5023 for (i = 0; sound_config[i].token != NULL; i++)
5024 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5025 sound_config[i].value));
5029 else if (strEqual(command, "print musicinfo.conf"))
5031 Print("# You can configure additional/alternative music files here.\n");
5032 Print("# (The entries below are default and therefore commented out.)\n");
5034 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5036 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5039 for (i = 0; music_config[i].token != NULL; i++)
5040 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5041 music_config[i].value));
5045 else if (strEqual(command, "print editorsetup.conf"))
5047 Print("# You can configure your personal editor element list here.\n");
5048 Print("# (The entries below are default and therefore commented out.)\n");
5051 // this is needed to be able to check element list for cascade elements
5052 InitElementPropertiesStatic();
5053 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5055 PrintEditorElementList();
5059 else if (strEqual(command, "print helpanim.conf"))
5061 Print("# You can configure different element help animations here.\n");
5062 Print("# (The entries below are default and therefore commented out.)\n");
5065 for (i = 0; helpanim_config[i].token != NULL; i++)
5067 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5068 helpanim_config[i].value));
5070 if (strEqual(helpanim_config[i].token, "end"))
5076 else if (strEqual(command, "print helptext.conf"))
5078 Print("# You can configure different element help text here.\n");
5079 Print("# (The entries below are default and therefore commented out.)\n");
5082 for (i = 0; helptext_config[i].token != NULL; i++)
5083 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5084 helptext_config[i].value));
5088 else if (strPrefix(command, "dump level "))
5090 char *filename = &command[11];
5092 if (fileExists(filename))
5094 LoadLevelFromFilename(&level, filename);
5100 char *leveldir = getStringCopy(filename); // read command parameters
5101 char *level_nr = strchr(leveldir, ' ');
5103 if (level_nr == NULL)
5104 Fail("cannot open file '%s'", filename);
5108 global.dumplevel_leveldir = leveldir;
5109 global.dumplevel_level_nr = atoi(level_nr);
5111 program.headless = TRUE;
5113 else if (strPrefix(command, "dump tape "))
5115 char *filename = &command[10];
5117 if (fileExists(filename))
5119 LoadTapeFromFilename(filename);
5125 char *leveldir = getStringCopy(filename); // read command parameters
5126 char *level_nr = strchr(leveldir, ' ');
5128 if (level_nr == NULL)
5129 Fail("cannot open file '%s'", filename);
5133 global.dumptape_leveldir = leveldir;
5134 global.dumptape_level_nr = atoi(level_nr);
5136 program.headless = TRUE;
5138 else if (strPrefix(command, "autoplay ") ||
5139 strPrefix(command, "autoffwd ") ||
5140 strPrefix(command, "autowarp ") ||
5141 strPrefix(command, "autotest ") ||
5142 strPrefix(command, "autosave ") ||
5143 strPrefix(command, "autoupload ") ||
5144 strPrefix(command, "autofix "))
5146 char *arg_ptr = strchr(command, ' ');
5147 char *str_ptr = getStringCopy(arg_ptr); // read command parameters
5149 global.autoplay_mode =
5150 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5151 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5152 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5153 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5154 strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5155 strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5156 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5157 AUTOPLAY_MODE_NONE);
5159 while (*str_ptr != '\0') // continue parsing string
5161 // cut leading whitespace from string, replace it by string terminator
5162 while (*str_ptr == ' ' || *str_ptr == '\t')
5165 if (*str_ptr == '\0') // end of string reached
5168 if (global.autoplay_leveldir == NULL) // read level set string
5170 global.autoplay_leveldir = str_ptr;
5171 global.autoplay_all = TRUE; // default: play all tapes
5173 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5174 global.autoplay_level[i] = FALSE;
5176 else // read level number string
5178 int level_nr = atoi(str_ptr); // get level_nr value
5180 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5181 global.autoplay_level[level_nr] = TRUE;
5183 global.autoplay_all = FALSE;
5186 // advance string pointer to the next whitespace (or end of string)
5187 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5191 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5192 program.headless = TRUE;
5194 else if (strPrefix(command, "patch tapes "))
5196 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5198 // skip leading whitespace
5199 while (*str_ptr == ' ' || *str_ptr == '\t')
5202 if (*str_ptr == '\0')
5203 Fail("cannot find MODE in command '%s'", command);
5205 global.patchtapes_mode = str_ptr; // store patch mode
5207 // advance to next whitespace (or end of string)
5208 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5211 while (*str_ptr != '\0') // continue parsing string
5213 // cut leading whitespace from string, replace it by string terminator
5214 while (*str_ptr == ' ' || *str_ptr == '\t')
5217 if (*str_ptr == '\0') // end of string reached
5220 if (global.patchtapes_leveldir == NULL) // read level set string
5222 global.patchtapes_leveldir = str_ptr;
5223 global.patchtapes_all = TRUE; // default: patch all tapes
5225 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5226 global.patchtapes_level[i] = FALSE;
5228 else // read level number string
5230 int level_nr = atoi(str_ptr); // get level_nr value
5232 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5233 global.patchtapes_level[level_nr] = TRUE;
5235 global.patchtapes_all = FALSE;
5238 // advance string pointer to the next whitespace (or end of string)
5239 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5243 if (global.patchtapes_leveldir == NULL)
5245 if (strEqual(global.patchtapes_mode, "help"))
5246 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5248 Fail("cannot find LEVELDIR in command '%s'", command);
5251 program.headless = TRUE;
5253 else if (strPrefix(command, "convert "))
5255 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5256 char *str_ptr = strchr(str_copy, ' ');
5258 global.convert_leveldir = str_copy;
5259 global.convert_level_nr = -1;
5261 if (str_ptr != NULL) // level number follows
5263 *str_ptr++ = '\0'; // terminate leveldir string
5264 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5267 program.headless = TRUE;
5269 else if (strPrefix(command, "create sketch images "))
5271 global.create_sketch_images_dir = getStringCopy(&command[21]);
5273 if (access(global.create_sketch_images_dir, W_OK) != 0)
5274 Fail("image target directory '%s' not found or not writable",
5275 global.create_sketch_images_dir);
5277 else if (strPrefix(command, "create collect image "))
5279 global.create_collect_images_dir = getStringCopy(&command[21]);
5281 if (access(global.create_collect_images_dir, W_OK) != 0)
5282 Fail("image target directory '%s' not found or not writable",
5283 global.create_collect_images_dir);
5285 else if (strPrefix(command, "create CE image "))
5287 CreateCustomElementImages(&command[16]);
5293 FailWithHelp("unrecognized command '%s'", command);
5296 // disable networking if any valid command was recognized
5297 options.network = setup.network_mode = FALSE;
5300 static void InitSetup(void)
5302 LoadUserNames(); // global user names
5303 LoadUserSetup(); // global user number
5305 LoadSetup(); // global setup info
5307 // set some options from setup file
5309 if (setup.options.verbose)
5310 options.verbose = TRUE;
5312 if (setup.debug.show_frames_per_second)
5313 global.show_frames_per_second = TRUE;
5316 static void InitGameInfo(void)
5318 game.restart_level = FALSE;
5319 game.restart_game_message = NULL;
5321 game.request_active = FALSE;
5322 game.request_active_or_moving = FALSE;
5324 game.use_masked_elements_initial = FALSE;
5327 static void InitPlayerInfo(void)
5331 // choose default local player
5332 local_player = &stored_player[0];
5334 for (i = 0; i < MAX_PLAYERS; i++)
5336 stored_player[i].connected_locally = FALSE;
5337 stored_player[i].connected_network = FALSE;
5340 local_player->connected_locally = TRUE;
5343 static void InitArtworkInfo(void)
5348 static char *get_string_in_brackets(char *string)
5350 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5352 sprintf(string_in_brackets, "[%s]", string);
5354 return string_in_brackets;
5357 static char *get_level_id_suffix(int id_nr)
5359 char *id_suffix = checked_malloc(1 + 3 + 1);
5361 if (id_nr < 0 || id_nr > 999)
5364 sprintf(id_suffix, ".%03d", id_nr);
5369 static void InitArtworkConfig(void)
5371 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5373 NUM_GLOBAL_ANIM_TOKENS + 1];
5374 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5375 NUM_GLOBAL_ANIM_TOKENS + 1];
5376 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5377 NUM_GLOBAL_ANIM_TOKENS + 1];
5378 static char *action_id_suffix[NUM_ACTIONS + 1];
5379 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5380 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5381 static char *level_id_suffix[MAX_LEVELS + 1];
5382 static char *dummy[1] = { NULL };
5383 static char *ignore_generic_tokens[] =
5388 "program_copyright",
5393 static char **ignore_image_tokens;
5394 static char **ignore_sound_tokens;
5395 static char **ignore_music_tokens;
5396 int num_ignore_generic_tokens;
5397 int num_ignore_image_tokens;
5398 int num_ignore_sound_tokens;
5399 int num_ignore_music_tokens;
5402 // dynamically determine list of generic tokens to be ignored
5403 num_ignore_generic_tokens = 0;
5404 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5405 num_ignore_generic_tokens++;
5407 // dynamically determine list of image tokens to be ignored
5408 num_ignore_image_tokens = num_ignore_generic_tokens;
5409 for (i = 0; image_config_vars[i].token != NULL; i++)
5410 num_ignore_image_tokens++;
5411 ignore_image_tokens =
5412 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5413 for (i = 0; i < num_ignore_generic_tokens; i++)
5414 ignore_image_tokens[i] = ignore_generic_tokens[i];
5415 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5416 ignore_image_tokens[num_ignore_generic_tokens + i] =
5417 image_config_vars[i].token;
5418 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5420 // dynamically determine list of sound tokens to be ignored
5421 num_ignore_sound_tokens = num_ignore_generic_tokens;
5422 ignore_sound_tokens =
5423 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5424 for (i = 0; i < num_ignore_generic_tokens; i++)
5425 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5426 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5428 // dynamically determine list of music tokens to be ignored
5429 num_ignore_music_tokens = num_ignore_generic_tokens;
5430 ignore_music_tokens =
5431 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5432 for (i = 0; i < num_ignore_generic_tokens; i++)
5433 ignore_music_tokens[i] = ignore_generic_tokens[i];
5434 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5436 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5437 image_id_prefix[i] = element_info[i].token_name;
5438 for (i = 0; i < NUM_FONTS; i++)
5439 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5440 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5441 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5442 global_anim_info[i].token_name;
5443 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5445 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5446 sound_id_prefix[i] = element_info[i].token_name;
5447 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5448 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5449 get_string_in_brackets(element_info[i].class_name);
5450 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5451 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5452 global_anim_info[i].token_name;
5453 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5455 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5456 music_id_prefix[i] = music_prefix_info[i].prefix;
5457 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5458 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5459 global_anim_info[i].token_name;
5460 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5462 for (i = 0; i < NUM_ACTIONS; i++)
5463 action_id_suffix[i] = element_action_info[i].suffix;
5464 action_id_suffix[NUM_ACTIONS] = NULL;
5466 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5467 direction_id_suffix[i] = element_direction_info[i].suffix;
5468 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5470 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5471 special_id_suffix[i] = special_suffix_info[i].suffix;
5472 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5474 for (i = 0; i < MAX_LEVELS; i++)
5475 level_id_suffix[i] = get_level_id_suffix(i);
5476 level_id_suffix[MAX_LEVELS] = NULL;
5478 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5479 image_id_prefix, action_id_suffix, direction_id_suffix,
5480 special_id_suffix, ignore_image_tokens);
5481 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5482 sound_id_prefix, action_id_suffix, dummy,
5483 special_id_suffix, ignore_sound_tokens);
5484 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5485 music_id_prefix, action_id_suffix, special_id_suffix,
5486 level_id_suffix, ignore_music_tokens);
5489 static void InitMixer(void)
5496 static void InitVideoOverlay(void)
5498 // if virtual buttons are not loaded from setup file, repeat initializing
5499 // virtual buttons grid with default values now that video is initialized
5500 if (!setup.touch.grid_initialized)
5503 InitTileCursorInfo();
5507 void InitGfxBuffers(void)
5509 static int win_xsize_last = -1;
5510 static int win_ysize_last = -1;
5512 // create additional image buffers for double-buffering and cross-fading
5514 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5516 // used to temporarily store the backbuffer -- only re-create if changed
5517 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5518 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5520 win_xsize_last = WIN_XSIZE;
5521 win_ysize_last = WIN_YSIZE;
5524 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5525 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5526 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5527 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5529 // initialize screen properties
5530 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5531 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5533 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5534 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5535 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5536 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5537 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5538 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5540 // required if door size definitions have changed
5541 InitGraphicCompatibilityInfo_Doors();
5543 InitGfxBuffers_EM();
5544 InitGfxBuffers_SP();
5547 static void InitGfx(void)
5549 struct GraphicInfo *graphic_info_last = graphic_info;
5550 char *filename_font_initial = NULL;
5551 char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5552 char *image_token[NUM_INITIAL_IMAGES] =
5554 CONFIG_TOKEN_GLOBAL_BUSY
5556 Bitmap *bitmap_font_initial = NULL;
5557 int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5560 // determine settings for initial font (for displaying startup messages)
5561 for (i = 0; image_config[i].token != NULL; i++)
5563 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5565 char font_token[128];
5568 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5569 len_font_token = strlen(font_token);
5571 if (strEqual(image_config[i].token, font_token))
5573 filename_font_initial = image_config[i].value;
5575 else if (strlen(image_config[i].token) > len_font_token &&
5576 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5578 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5579 font_initial[j].src_x = atoi(image_config[i].value);
5580 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5581 font_initial[j].src_y = atoi(image_config[i].value);
5582 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5583 font_initial[j].width = atoi(image_config[i].value);
5584 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5585 font_initial[j].height = atoi(image_config[i].value);
5590 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5592 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5593 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5596 if (filename_font_initial == NULL) // should not happen
5597 Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5600 InitGfxCustomArtworkInfo();
5601 InitGfxOtherSettings();
5603 InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5605 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5607 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5608 font_initial[j].bitmap = bitmap_font_initial;
5610 InitFontGraphicInfo();
5614 DrawInitTextHead("Loading graphics");
5616 InitMenuDesignSettings_Static();
5618 // initialize settings for initial images with default values
5619 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5620 for (j = 0; j < NUM_GFX_ARGS; j++)
5622 get_graphic_parameter_value(image_config_suffix[j].value,
5623 image_config_suffix[j].token,
5624 image_config_suffix[j].type);
5626 // read settings for initial images from default custom artwork config
5627 char *gfx_config_filename = getPath3(options.graphics_directory,
5629 GRAPHICSINFO_FILENAME);
5631 if (fileExists(gfx_config_filename))
5633 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5635 if (setup_file_hash)
5637 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5639 char *filename = getHashEntry(setup_file_hash, image_token[i]);
5643 filename_image_initial[i] = getStringCopy(filename);
5645 for (j = 0; image_config_suffix[j].token != NULL; j++)
5647 int type = image_config_suffix[j].type;
5648 char *suffix = image_config_suffix[j].token;
5649 char *token = getStringCat2(image_token[i], suffix);
5650 char *value = getHashEntry(setup_file_hash, token);
5652 checked_free(token);
5656 get_graphic_parameter_value(value, suffix, type);
5661 // read values from custom graphics config file
5662 InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5664 freeSetupFileHash(setup_file_hash);
5668 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5670 if (filename_image_initial[i] == NULL)
5672 int len_token = strlen(image_token[i]);
5674 // read settings for initial images from static default artwork config
5675 for (j = 0; image_config[j].token != NULL; j++)
5677 if (strEqual(image_config[j].token, image_token[i]))
5679 filename_image_initial[i] = getStringCopy(image_config[j].value);
5681 else if (strlen(image_config[j].token) > len_token &&
5682 strncmp(image_config[j].token, image_token[i], len_token) == 0)
5684 for (k = 0; image_config_suffix[k].token != NULL; k++)
5686 if (strEqual(&image_config[j].token[len_token],
5687 image_config_suffix[k].token))
5689 get_graphic_parameter_value(image_config[j].value,
5690 image_config_suffix[k].token,
5691 image_config_suffix[k].type);
5698 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5700 if (filename_image_initial[i] == NULL) // should not happen
5701 Fail("cannot get filename for '%s'", image_token[i]);
5703 image_initial[i].bitmaps =
5704 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5706 if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5707 image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5708 LoadCustomImage(filename_image_initial[i]);
5710 checked_free(filename_image_initial[i]);
5713 graphic_info = image_initial; // graphic == 0 => image_initial
5715 for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5716 set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5718 graphic_info = graphic_info_last;
5720 init.busy.width = image_initial[INITIAL_IMG_GLOBAL_BUSY].width;
5721 init.busy.height = image_initial[INITIAL_IMG_GLOBAL_BUSY].height;
5723 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5724 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5725 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5726 InitGfxDrawTileCursorFunction(DrawTileCursor);
5728 gfx.fade_border_source_status = global.border_status;
5729 gfx.fade_border_target_status = global.border_status;
5730 gfx.masked_border_bitmap_ptr = backbuffer;
5732 // use copy of busy animation to prevent change while reloading artwork
5736 static void InitGfxBackground(void)
5738 fieldbuffer = bitmap_db_field;
5739 SetDrawtoField(DRAW_TO_BACKBUFFER);
5741 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5743 redraw_mask = REDRAW_ALL;
5746 static void InitLevelInfo(void)
5748 LoadLevelInfo(); // global level info
5749 LoadLevelSetup_LastSeries(); // last played series info
5750 LoadLevelSetup_SeriesInfo(); // last played level info
5752 if (global.autoplay_leveldir &&
5753 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5755 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5756 global.autoplay_leveldir);
5757 if (leveldir_current == NULL)
5758 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5761 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5764 static void InitLevelArtworkInfo(void)
5766 LoadLevelArtworkInfo();
5769 static void InitImages(void)
5771 print_timestamp_init("InitImages");
5774 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5775 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5776 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5777 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5778 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5779 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5780 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5781 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5784 setLevelArtworkDir(artwork.gfx_first);
5787 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5788 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5789 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5790 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5791 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5792 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5793 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5794 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5798 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5799 leveldir_current->identifier,
5800 artwork.gfx_current_identifier,
5801 artwork.gfx_current->identifier,
5802 leveldir_current->graphics_set,
5803 leveldir_current->graphics_path);
5806 UPDATE_BUSY_STATE();
5808 ReloadCustomImages();
5809 print_timestamp_time("ReloadCustomImages");
5811 UPDATE_BUSY_STATE();
5813 LoadCustomElementDescriptions();
5814 print_timestamp_time("LoadCustomElementDescriptions");
5816 UPDATE_BUSY_STATE();
5818 LoadMenuDesignSettings();
5819 print_timestamp_time("LoadMenuDesignSettings");
5821 UPDATE_BUSY_STATE();
5823 ReinitializeGraphics();
5824 print_timestamp_time("ReinitializeGraphics");
5826 LoadMenuDesignSettings_AfterGraphics();
5827 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5829 UPDATE_BUSY_STATE();
5831 print_timestamp_done("InitImages");
5834 static void InitSound(char *identifier)
5836 print_timestamp_init("InitSound");
5838 if (identifier == NULL)
5839 identifier = artwork.snd_current->identifier;
5841 // set artwork path to send it to the sound server process
5842 setLevelArtworkDir(artwork.snd_first);
5844 InitReloadCustomSounds(identifier);
5845 print_timestamp_time("InitReloadCustomSounds");
5847 ReinitializeSounds();
5848 print_timestamp_time("ReinitializeSounds");
5850 print_timestamp_done("InitSound");
5853 static void InitMusic(char *identifier)
5855 print_timestamp_init("InitMusic");
5857 if (identifier == NULL)
5858 identifier = artwork.mus_current->identifier;
5860 // set artwork path to send it to the sound server process
5861 setLevelArtworkDir(artwork.mus_first);
5863 InitReloadCustomMusic(identifier);
5864 print_timestamp_time("InitReloadCustomMusic");
5866 ReinitializeMusic();
5867 print_timestamp_time("ReinitializeMusic");
5869 print_timestamp_done("InitMusic");
5872 static void InitArtworkDone(void)
5874 if (program.headless)
5877 InitGlobalAnimations();
5880 static void InitNetworkSettings(void)
5882 boolean network_enabled = (options.network || setup.network_mode);
5883 char *network_server = (options.server_host != NULL ? options.server_host :
5884 setup.network_server_hostname);
5886 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5887 network_server = NULL;
5889 InitNetworkInfo(network_enabled,
5893 options.server_port);
5896 void InitNetworkServer(void)
5898 if (!network.enabled || network.connected)
5901 LimitScreenUpdates(FALSE);
5903 if (game_status == GAME_MODE_LOADING)
5906 if (!ConnectToServer(network.server_host, network.server_port))
5908 network.enabled = FALSE;
5910 setup.network_mode = FALSE;
5914 SendToServer_ProtocolVersion();
5915 SendToServer_PlayerName(setup.player_name);
5916 SendToServer_NrWanted(setup.network_player_nr + 1);
5918 network.connected = TRUE;
5921 // short time to recognize result of network initialization
5922 if (game_status == GAME_MODE_LOADING)
5923 Delay_WithScreenUpdates(1000);
5926 static boolean CheckArtworkConfigForCustomElements(char *filename)
5928 SetupFileHash *setup_file_hash;
5929 boolean redefined_ce_found = FALSE;
5931 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5933 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5935 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5937 char *token = HASH_ITERATION_TOKEN(itr);
5939 if (strPrefix(token, "custom_"))
5941 redefined_ce_found = TRUE;
5946 END_HASH_ITERATION(setup_file_hash, itr)
5948 freeSetupFileHash(setup_file_hash);
5951 return redefined_ce_found;
5954 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5956 char *filename_base, *filename_local;
5957 boolean redefined_ce_found = FALSE;
5959 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5962 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5963 "leveldir_current->identifier == '%s'",
5964 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5965 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5966 "leveldir_current->graphics_path == '%s'",
5967 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5968 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5969 "leveldir_current->graphics_set == '%s'",
5970 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5971 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5972 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5973 leveldir_current == NULL ? "[NULL]" :
5974 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5977 // first look for special artwork configured in level series config
5978 filename_base = getCustomArtworkLevelConfigFilename(type);
5981 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5982 "filename_base == '%s'", filename_base);
5985 if (fileExists(filename_base))
5986 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5988 filename_local = getCustomArtworkConfigFilename(type);
5991 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5992 "filename_local == '%s'", filename_local);
5995 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5996 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5999 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6000 "redefined_ce_found == %d", redefined_ce_found);
6003 return redefined_ce_found;
6006 static void InitOverrideArtwork(void)
6008 boolean redefined_ce_found = FALSE;
6010 // to check if this level set redefines any CEs, do not use overriding
6011 gfx.override_level_graphics = FALSE;
6012 gfx.override_level_sounds = FALSE;
6013 gfx.override_level_music = FALSE;
6015 // now check if this level set has definitions for custom elements
6016 if (setup.override_level_graphics == AUTO ||
6017 setup.override_level_sounds == AUTO ||
6018 setup.override_level_music == AUTO)
6019 redefined_ce_found =
6020 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6021 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6022 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6025 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6026 redefined_ce_found);
6029 if (redefined_ce_found)
6031 // this level set has CE definitions: change "AUTO" to "FALSE"
6032 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6033 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6034 gfx.override_level_music = (setup.override_level_music == TRUE);
6038 // this level set has no CE definitions: change "AUTO" to "TRUE"
6039 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6040 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6041 gfx.override_level_music = (setup.override_level_music != FALSE);
6045 Debug("init:InitOverrideArtwork", "%d, %d, %d",
6046 gfx.override_level_graphics,
6047 gfx.override_level_sounds,
6048 gfx.override_level_music);
6052 static char *getNewArtworkIdentifier(int type)
6054 static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6055 static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6056 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6057 static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6058 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6059 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6060 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6061 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6062 char *leveldir_identifier = leveldir_current->identifier;
6063 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6064 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6065 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6066 TreeInfo *custom_artwork_set =
6067 getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6068 boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6069 char *artwork_current_identifier;
6070 char *artwork_new_identifier = NULL; // default: nothing has changed
6072 // leveldir_current may be invalid (level group, parent link)
6073 if (!validLevelSeries(leveldir_current))
6076 /* 1st step: determine artwork set to be activated in descending order:
6077 --------------------------------------------------------------------
6078 1. setup artwork (when configured to override everything else)
6079 2. artwork set configured in "levelinfo.conf" of current level set
6080 (artwork in level directory will have priority when loading later)
6081 3. artwork in level directory (stored in artwork sub-directory)
6082 4. setup artwork (currently configured in setup menu) */
6084 if (setup_override_artwork)
6085 artwork_current_identifier = setup_artwork_set;
6086 else if (has_level_artwork_set)
6087 artwork_current_identifier = leveldir_artwork_set;
6088 else if (has_custom_artwork_set)
6089 artwork_current_identifier = leveldir_identifier;
6091 artwork_current_identifier = setup_artwork_set;
6093 /* 2nd step: check if it is really needed to reload artwork set
6094 ------------------------------------------------------------ */
6096 // ---------- reload if level set and also artwork set has changed ----------
6097 if (last_leveldir_identifier[type] != leveldir_identifier &&
6098 (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6099 artwork_new_identifier = artwork_current_identifier;
6101 last_leveldir_identifier[type] = leveldir_identifier;
6102 last_has_custom_artwork_set[type] = has_custom_artwork_set;
6104 // ---------- reload if "override artwork" setting has changed --------------
6105 if (last_override_level_artwork[type] != setup_override_artwork)
6106 artwork_new_identifier = artwork_current_identifier;
6108 last_override_level_artwork[type] = setup_override_artwork;
6110 // ---------- reload if current artwork identifier has changed --------------
6111 if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6112 artwork_new_identifier = artwork_current_identifier;
6114 // (we cannot compare string pointers here, so copy string content itself)
6115 setString(&last_artwork_identifier[type], artwork_current_identifier);
6117 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6119 // ---------- do not reload directly after starting -------------------------
6120 if (!initialized[type])
6121 artwork_new_identifier = NULL;
6123 initialized[type] = TRUE;
6125 return artwork_new_identifier;
6128 void ReloadCustomArtwork(int force_reload)
6130 int last_game_status = game_status; // save current game status
6131 char *gfx_new_identifier;
6132 char *snd_new_identifier;
6133 char *mus_new_identifier;
6134 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6135 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6136 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6137 boolean reload_needed;
6139 InitOverrideArtwork();
6141 AdjustGraphicsForEMC();
6142 AdjustSoundsForEMC();
6144 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6145 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6146 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6148 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6149 snd_new_identifier != NULL || force_reload_snd ||
6150 mus_new_identifier != NULL || force_reload_mus);
6155 print_timestamp_init("ReloadCustomArtwork");
6157 SetGameStatus(GAME_MODE_LOADING);
6159 FadeOut(REDRAW_ALL);
6161 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6162 print_timestamp_time("ClearRectangle");
6166 if (gfx_new_identifier != NULL || force_reload_gfx)
6169 Debug("init:ReloadCustomArtwork",
6170 "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6171 artwork.gfx_current_identifier,
6173 artwork.gfx_current->identifier,
6174 leveldir_current->graphics_set);
6178 print_timestamp_time("InitImages");
6181 if (snd_new_identifier != NULL || force_reload_snd)
6183 InitSound(snd_new_identifier);
6184 print_timestamp_time("InitSound");
6187 if (mus_new_identifier != NULL || force_reload_mus)
6189 InitMusic(mus_new_identifier);
6190 print_timestamp_time("InitMusic");
6195 SetGameStatus(last_game_status); // restore current game status
6197 init_last = init; // switch to new busy animation
6199 FadeOut(REDRAW_ALL);
6201 RedrawGlobalBorder();
6203 // force redraw of (open or closed) door graphics
6204 SetDoorState(DOOR_OPEN_ALL);
6205 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6207 FadeSetEnterScreen();
6208 FadeSkipNextFadeOut();
6210 print_timestamp_done("ReloadCustomArtwork");
6212 LimitScreenUpdates(FALSE);
6215 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6217 if (global.autoplay_leveldir == NULL)
6218 KeyboardAutoRepeatOff();
6221 void DisplayExitMessage(char *format, va_list ap)
6223 // also check for initialized video (headless flag may be temporarily unset)
6224 if (program.headless || !video.initialized)
6227 // check if draw buffer and fonts for exit message are already available
6228 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6231 int font_1 = FC_RED;
6232 int font_2 = FC_YELLOW;
6233 int font_3 = FC_BLUE;
6234 int font_width = getFontWidth(font_2);
6235 int font_height = getFontHeight(font_2);
6238 int sxsize = WIN_XSIZE - 2 * sx;
6239 int sysize = WIN_YSIZE - 2 * sy;
6240 int line_length = sxsize / font_width;
6241 int max_lines = sysize / font_height;
6242 int num_lines_printed;
6246 gfx.sxsize = sxsize;
6247 gfx.sysize = sysize;
6251 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6253 DrawTextSCentered(sy, font_1, "Fatal error:");
6254 sy += 3 * font_height;;
6257 DrawTextBufferVA(sx, sy, format, ap, font_2,
6258 line_length, line_length, max_lines,
6259 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6260 sy += (num_lines_printed + 3) * font_height;
6262 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6263 sy += 3 * font_height;
6266 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6267 line_length, line_length, max_lines,
6268 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6270 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6272 redraw_mask = REDRAW_ALL;
6274 // force drawing exit message even if screen updates are currently limited
6275 LimitScreenUpdates(FALSE);
6279 // deactivate toons on error message screen
6280 setup.toons = FALSE;
6282 WaitForEventToContinue();
6286 // ============================================================================
6288 // ============================================================================
6292 print_timestamp_init("OpenAll");
6294 SetGameStatus(GAME_MODE_LOADING);
6298 InitGlobal(); // initialize some global variables
6300 InitRND(NEW_RANDOMIZE);
6301 InitSimpleRandom(NEW_RANDOMIZE);
6302 InitBetterRandom(NEW_RANDOMIZE);
6304 print_timestamp_time("[init global stuff]");
6308 print_timestamp_time("[init setup/config stuff (1)]");
6310 if (options.execute_command)
6311 Execute_Command(options.execute_command);
6313 InitNetworkSettings();
6317 if (network.serveronly)
6319 #if defined(PLATFORM_UNIX)
6320 NetworkServer(network.server_port, TRUE);
6322 Warn("networking only supported in Unix version");
6325 exit(0); // never reached, server loops forever
6329 print_timestamp_time("[init setup/config stuff (2)]");
6331 print_timestamp_time("[init setup/config stuff (3)]");
6332 InitArtworkInfo(); // needed before loading gfx, sound & music
6333 print_timestamp_time("[init setup/config stuff (4)]");
6334 InitArtworkConfig(); // needed before forking sound child process
6335 print_timestamp_time("[init setup/config stuff (5)]");
6337 print_timestamp_time("[init setup/config stuff (6)]");
6341 print_timestamp_time("[init setup/config stuff]");
6343 InitVideoDefaults();
6345 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6348 InitEventFilter(FilterMouseMotionEvents);
6350 print_timestamp_time("[init video stuff]");
6352 InitElementPropertiesStatic();
6353 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6354 InitElementPropertiesGfxElement();
6356 print_timestamp_time("[init element properties stuff]");
6360 print_timestamp_time("InitGfx");
6363 print_timestamp_time("InitLevelInfo");
6365 InitLevelArtworkInfo();
6366 print_timestamp_time("InitLevelArtworkInfo");
6368 InitOverrideArtwork(); // needs to know current level directory
6369 print_timestamp_time("InitOverrideArtwork");
6371 InitImages(); // needs to know current level directory
6372 print_timestamp_time("InitImages");
6374 InitSound(NULL); // needs to know current level directory
6375 print_timestamp_time("InitSound");
6377 InitMusic(NULL); // needs to know current level directory
6378 print_timestamp_time("InitMusic");
6382 InitGfxBackground();
6388 if (global.autoplay_leveldir)
6393 else if (global.patchtapes_leveldir)
6398 else if (global.convert_leveldir)
6403 else if (global.dumplevel_leveldir)
6408 else if (global.dumptape_leveldir)
6413 else if (global.create_sketch_images_dir)
6415 CreateLevelSketchImages();
6418 else if (global.create_collect_images_dir)
6420 CreateCollectElementImages();
6424 InitNetworkServer();
6426 SetGameStatus(GAME_MODE_MAIN);
6428 FadeSetEnterScreen();
6429 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6430 FadeSkipNextFadeOut();
6432 print_timestamp_time("[post-artwork]");
6434 print_timestamp_done("OpenAll");
6436 if (setup.ask_for_remaining_tapes)
6437 setup.ask_for_uploading_tapes = TRUE;
6442 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6444 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6445 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6446 #if defined(PLATFORM_ANDROID)
6447 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6448 SDL_AndroidGetInternalStoragePath());
6449 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6450 SDL_AndroidGetExternalStoragePath());
6451 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6452 (SDL_AndroidGetExternalStorageState() &
6453 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6454 SDL_AndroidGetExternalStorageState() &
6455 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6460 static boolean WaitForApiThreads(void)
6462 unsigned int thread_delay = 0;
6463 unsigned int thread_delay_value = 10000;
6465 if (program.api_thread_count == 0)
6468 // deactivate global animations (not accessible in game state "loading")
6469 setup.toons = FALSE;
6471 // set game state to "loading" to be able to show busy animation
6472 SetGameStatus(GAME_MODE_LOADING);
6474 ResetDelayCounter(&thread_delay);
6476 // wait for threads to finish (and fail on timeout)
6477 while (program.api_thread_count > 0)
6479 if (DelayReached(&thread_delay, thread_delay_value))
6481 Error("failed waiting for threads - TIMEOUT");
6486 UPDATE_BUSY_STATE();
6494 void CloseAllAndExit(int exit_value)
6496 WaitForApiThreads();
6501 CloseAudio(); // called after freeing sounds (needed for SDL)
6509 // set a flag to tell the network server thread to quit and wait for it
6510 // using SDL_WaitThread()
6512 // Code used with SDL 1.2:
6513 // if (network.server_thread) // terminate network server
6514 // SDL_KillThread(network.server_thread);
6516 CloseVideoDisplay();
6517 ClosePlatformDependentStuff();
6519 if (exit_value != 0 && !options.execute_command)
6521 // fall back to default level set (current set may have caused an error)
6522 SaveLevelSetup_LastSeries_Deactivate();
6524 // tell user where to find error log file which may contain more details
6525 // (error notification now directly displayed on screen inside R'n'D
6526 // NotifyUserAboutErrorFile(); // currently only works for Windows