1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
87 // forward declaration for internal use
88 static int get_graphic_parameter_value(char *, char *, int);
91 static void DrawInitAnim(void)
93 struct GraphicInfo *graphic_info_last = graphic_info;
95 static unsigned int action_delay = 0;
96 unsigned int action_delay_value = GameFrameDelay;
97 int sync_frame = FrameCounter;
100 // prevent OS (Windows) from complaining about program not responding
103 if (game_status != GAME_MODE_LOADING)
106 if (anim_initial.bitmap == NULL || window == NULL)
109 if (!DelayReached(&action_delay, action_delay_value))
112 if (init_last.busy.x == -1)
113 init_last.busy.x = WIN_XSIZE / 2;
114 if (init_last.busy.y == -1)
115 init_last.busy.y = WIN_YSIZE / 2;
117 x = ALIGNED_TEXT_XPOS(&init_last.busy);
118 y = ALIGNED_TEXT_YPOS(&init_last.busy);
120 graphic_info = &anim_initial; // graphic == 0 => anim_initial
122 if (sync_frame % anim_initial.anim_delay == 0)
126 int width = graphic_info[graphic].width;
127 int height = graphic_info[graphic].height;
128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
130 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
131 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
134 graphic_info = graphic_info_last;
139 static void DrawProgramInfo(void)
141 int font1_nr = FC_YELLOW;
142 int font2_nr = FC_RED;
143 int font2_height = getFontHeight(font2_nr);
146 int ypos3 = WIN_YSIZE - 20 - font2_height;
148 DrawInitText(getProgramInitString(), ypos1, font1_nr);
149 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
150 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
153 static void FreeGadgets(void)
155 FreeLevelEditorGadgets();
162 void InitGadgets(void)
164 static boolean gadgets_initialized = FALSE;
166 if (gadgets_initialized)
169 CreateLevelEditorGadgets();
173 CreateScreenGadgets();
175 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
177 gadgets_initialized = TRUE;
180 static void InitElementSmallImagesScaledUp(int graphic)
182 struct GraphicInfo *g = &graphic_info[graphic];
184 // create small and game tile sized bitmaps (and scale up, if needed)
185 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
188 static void InitElementSmallImages(void)
190 print_timestamp_init("InitElementSmallImages");
192 static int special_graphics[] =
206 IMG_EDITOR_ELEMENT_BORDER,
207 IMG_EDITOR_ELEMENT_BORDER_INPUT,
208 IMG_EDITOR_CASCADE_LIST,
209 IMG_EDITOR_CASCADE_LIST_ACTIVE,
212 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
213 int num_property_mappings = getImageListPropertyMappingSize();
216 print_timestamp_time("getImageListPropertyMapping/Size");
218 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
219 // initialize normal element images from static configuration
220 for (i = 0; element_to_graphic[i].element > -1; i++)
221 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
222 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
224 // initialize special element images from static configuration
225 for (i = 0; element_to_special_graphic[i].element > -1; i++)
226 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
227 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
229 // initialize element images from dynamic configuration
230 for (i = 0; i < num_property_mappings; i++)
231 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
232 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
233 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
235 // initialize special non-element images from above list
236 for (i = 0; special_graphics[i] > -1; i++)
237 InitElementSmallImagesScaledUp(special_graphics[i]);
238 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
240 print_timestamp_done("InitElementSmallImages");
243 static void InitScaledImagesScaledUp(int graphic)
245 struct GraphicInfo *g = &graphic_info[graphic];
247 ScaleImage(graphic, g->scale_up_factor);
250 static void InitScaledImages(void)
252 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
253 int num_property_mappings = getImageListPropertyMappingSize();
256 // scale normal images from static configuration, if not already scaled
257 for (i = 0; i < NUM_IMAGE_FILES; i++)
258 InitScaledImagesScaledUp(i);
260 // scale images from dynamic configuration, if not already scaled
261 for (i = 0; i < num_property_mappings; i++)
262 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
265 static void InitBitmapPointers(void)
267 int num_images = getImageListSize();
270 // standard size bitmap may have changed -- update default bitmap pointer
271 for (i = 0; i < num_images; i++)
272 if (graphic_info[i].bitmaps)
273 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
276 void InitImageTextures(void)
278 static int texture_graphics[] =
280 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
281 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
282 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
283 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
284 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
285 IMG_MENU_BUTTON_TOUCH_BACK,
286 IMG_MENU_BUTTON_TOUCH_NEXT,
287 IMG_MENU_BUTTON_TOUCH_BACK2,
288 IMG_MENU_BUTTON_TOUCH_NEXT2,
293 FreeAllImageTextures();
295 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
296 CreateImageTextures(i);
298 for (i = 0; i < MAX_NUM_TOONS; i++)
299 CreateImageTextures(IMG_TOON_1 + i);
301 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
303 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
305 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
307 int graphic = global_anim_info[i].graphic[j][k];
309 if (graphic == IMG_UNDEFINED)
312 CreateImageTextures(graphic);
317 for (i = 0; texture_graphics[i] > -1; i++)
318 CreateImageTextures(texture_graphics[i]);
321 static int getFontBitmapID(int font_nr)
325 // (special case: do not use special font for GAME_MODE_LOADING)
326 if (game_status >= GAME_MODE_TITLE_INITIAL &&
327 game_status <= GAME_MODE_PSEUDO_PREVIEW)
328 special = game_status;
329 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
330 special = GFX_SPECIAL_ARG_MAIN;
333 return font_info[font_nr].special_bitmap_id[special];
338 static int getFontFromToken(char *token)
340 char *value = getHashEntry(font_token_hash, token);
345 // if font not found, use reliable default value
346 return FONT_INITIAL_1;
349 static void InitFontGraphicInfo(void)
351 static struct FontBitmapInfo *font_bitmap_info = NULL;
352 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
353 int num_property_mappings = getImageListPropertyMappingSize();
354 int num_font_bitmaps = NUM_FONTS;
357 if (graphic_info == NULL) // still at startup phase
359 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
360 getFontBitmapID, getFontFromToken);
365 // ---------- initialize font graphic definitions ----------
367 // always start with reliable default values (normal font graphics)
368 for (i = 0; i < NUM_FONTS; i++)
369 font_info[i].graphic = IMG_FONT_INITIAL_1;
371 // initialize normal font/graphic mapping from static configuration
372 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
374 int font_nr = font_to_graphic[i].font_nr;
375 int special = font_to_graphic[i].special;
376 int graphic = font_to_graphic[i].graphic;
381 font_info[font_nr].graphic = graphic;
384 // always start with reliable default values (special font graphics)
385 for (i = 0; i < NUM_FONTS; i++)
387 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
389 font_info[i].special_graphic[j] = font_info[i].graphic;
390 font_info[i].special_bitmap_id[j] = i;
394 // initialize special font/graphic mapping from static configuration
395 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
397 int font_nr = font_to_graphic[i].font_nr;
398 int special = font_to_graphic[i].special;
399 int graphic = font_to_graphic[i].graphic;
400 int base_graphic = font2baseimg(font_nr);
402 if (IS_SPECIAL_GFX_ARG(special))
404 boolean base_redefined =
405 getImageListEntryFromImageID(base_graphic)->redefined;
406 boolean special_redefined =
407 getImageListEntryFromImageID(graphic)->redefined;
408 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
410 /* if the base font ("font.title_1", for example) has been redefined,
411 but not the special font ("font.title_1.LEVELS", for example), do not
412 use an existing (in this case considered obsolete) special font
413 anymore, but use the automatically determined default font */
414 /* special case: cloned special fonts must be explicitly redefined,
415 but are not automatically redefined by redefining base font */
416 if (base_redefined && !special_redefined && !special_cloned)
419 font_info[font_nr].special_graphic[special] = graphic;
420 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
425 // initialize special font/graphic mapping from dynamic configuration
426 for (i = 0; i < num_property_mappings; i++)
428 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
429 int special = property_mapping[i].ext3_index;
430 int graphic = property_mapping[i].artwork_index;
432 if (font_nr < 0 || font_nr >= NUM_FONTS)
435 if (IS_SPECIAL_GFX_ARG(special))
437 font_info[font_nr].special_graphic[special] = graphic;
438 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
443 /* correct special font/graphic mapping for cloned fonts for downwards
444 compatibility of PREVIEW fonts -- this is only needed for implicit
445 redefinition of special font by redefined base font, and only if other
446 fonts are cloned from this special font (like in the "Zelda" level set) */
447 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
449 int font_nr = font_to_graphic[i].font_nr;
450 int special = font_to_graphic[i].special;
451 int graphic = font_to_graphic[i].graphic;
453 if (IS_SPECIAL_GFX_ARG(special))
455 boolean special_redefined =
456 getImageListEntryFromImageID(graphic)->redefined;
457 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
459 if (special_cloned && !special_redefined)
463 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
465 int font_nr2 = font_to_graphic[j].font_nr;
466 int special2 = font_to_graphic[j].special;
467 int graphic2 = font_to_graphic[j].graphic;
469 if (IS_SPECIAL_GFX_ARG(special2) &&
470 graphic2 == graphic_info[graphic].clone_from)
472 font_info[font_nr].special_graphic[special] =
473 font_info[font_nr2].special_graphic[special2];
474 font_info[font_nr].special_bitmap_id[special] =
475 font_info[font_nr2].special_bitmap_id[special2];
482 // reset non-redefined ".active" font graphics if normal font is redefined
483 // (this different treatment is needed because normal and active fonts are
484 // independently defined ("active" is not a property of font definitions!)
485 for (i = 0; i < NUM_FONTS; i++)
487 int font_nr_base = i;
488 int font_nr_active = FONT_ACTIVE(font_nr_base);
490 // check only those fonts with exist as normal and ".active" variant
491 if (font_nr_base != font_nr_active)
493 int base_graphic = font_info[font_nr_base].graphic;
494 int active_graphic = font_info[font_nr_active].graphic;
495 boolean base_redefined =
496 getImageListEntryFromImageID(base_graphic)->redefined;
497 boolean active_redefined =
498 getImageListEntryFromImageID(active_graphic)->redefined;
500 /* if the base font ("font.menu_1", for example) has been redefined,
501 but not the active font ("font.menu_1.active", for example), do not
502 use an existing (in this case considered obsolete) active font
503 anymore, but use the automatically determined default font */
504 if (base_redefined && !active_redefined)
505 font_info[font_nr_active].graphic = base_graphic;
507 // now also check each "special" font (which may be the same as above)
508 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
510 int base_graphic = font_info[font_nr_base].special_graphic[j];
511 int active_graphic = font_info[font_nr_active].special_graphic[j];
512 boolean base_redefined =
513 getImageListEntryFromImageID(base_graphic)->redefined;
514 boolean active_redefined =
515 getImageListEntryFromImageID(active_graphic)->redefined;
517 // same as above, but check special graphic definitions, for example:
518 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
519 if (base_redefined && !active_redefined)
521 font_info[font_nr_active].special_graphic[j] =
522 font_info[font_nr_base].special_graphic[j];
523 font_info[font_nr_active].special_bitmap_id[j] =
524 font_info[font_nr_base].special_bitmap_id[j];
530 // ---------- initialize font bitmap array ----------
532 if (font_bitmap_info != NULL)
533 FreeFontInfo(font_bitmap_info);
536 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
538 // ---------- initialize font bitmap definitions ----------
540 for (i = 0; i < NUM_FONTS; i++)
542 if (i < NUM_INITIAL_FONTS)
544 font_bitmap_info[i] = font_initial[i];
548 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
550 int font_bitmap_id = font_info[i].special_bitmap_id[j];
551 int graphic = font_info[i].special_graphic[j];
553 // set 'graphic_info' for font entries, if uninitialized (guessed)
554 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
556 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
557 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
560 // copy font relevant information from graphics information
561 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
562 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
563 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
564 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
565 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
567 font_bitmap_info[font_bitmap_id].offset_x =
568 graphic_info[graphic].offset_x;
569 font_bitmap_info[font_bitmap_id].offset_y =
570 graphic_info[graphic].offset_y;
572 font_bitmap_info[font_bitmap_id].draw_xoffset =
573 graphic_info[graphic].draw_xoffset;
574 font_bitmap_info[font_bitmap_id].draw_yoffset =
575 graphic_info[graphic].draw_yoffset;
577 font_bitmap_info[font_bitmap_id].num_chars =
578 graphic_info[graphic].anim_frames;
579 font_bitmap_info[font_bitmap_id].num_chars_per_line =
580 graphic_info[graphic].anim_frames_per_line;
584 InitFontInfo(font_bitmap_info, num_font_bitmaps,
585 getFontBitmapID, getFontFromToken);
588 static void InitGlobalAnimGraphicInfo(void)
590 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
591 int num_property_mappings = getImageListPropertyMappingSize();
594 if (graphic_info == NULL) // still at startup phase
597 // always start with reliable default values (no global animations)
598 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
599 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
600 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
601 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
603 // initialize global animation definitions from static configuration
604 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
606 int j = GLOBAL_ANIM_ID_PART_BASE;
607 int k = GFX_SPECIAL_ARG_DEFAULT;
609 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
612 // initialize global animation definitions from dynamic configuration
613 for (i = 0; i < num_property_mappings; i++)
615 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
616 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
617 int special = property_mapping[i].ext3_index;
618 int graphic = property_mapping[i].artwork_index;
620 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
623 // set animation part to base part, if not specified
624 if (!IS_GLOBAL_ANIM_PART(part_nr))
625 part_nr = GLOBAL_ANIM_ID_PART_BASE;
627 // set animation screen to default, if not specified
628 if (!IS_SPECIAL_GFX_ARG(special))
629 special = GFX_SPECIAL_ARG_DEFAULT;
631 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
633 // fix default value for ".draw_masked" (for backward compatibility)
634 struct GraphicInfo *g = &graphic_info[graphic];
635 struct FileInfo *image = getImageListEntryFromImageID(graphic);
636 char **parameter_raw = image->parameter;
637 int p = GFX_ARG_DRAW_MASKED;
638 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
639 image_config_suffix[p].token,
640 image_config_suffix[p].type);
642 // if ".draw_masked" parameter is undefined, use default value "TRUE"
643 if (draw_masked == ARG_UNDEFINED_VALUE)
644 g->draw_masked = TRUE;
648 printf("::: InitGlobalAnimGraphicInfo\n");
650 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
651 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
652 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
653 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
654 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
655 printf("::: - anim %d, part %d, mode %d => %d\n",
656 i, j, k, global_anim_info[i].graphic[j][k]);
660 static void InitGlobalAnimSoundInfo(void)
662 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
663 int num_property_mappings = getSoundListPropertyMappingSize();
666 // always start with reliable default values (no global animation sounds)
667 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
668 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
669 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
670 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
672 // initialize global animation sound definitions from dynamic configuration
673 for (i = 0; i < num_property_mappings; i++)
675 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
676 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
677 int special = property_mapping[i].ext3_index;
678 int sound = property_mapping[i].artwork_index;
680 // sound uses control definition; map it to position of graphic (artwork)
681 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
683 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
686 // set animation part to base part, if not specified
687 if (!IS_GLOBAL_ANIM_PART(part_nr))
688 part_nr = GLOBAL_ANIM_ID_PART_BASE;
690 // set animation screen to default, if not specified
691 if (!IS_SPECIAL_GFX_ARG(special))
692 special = GFX_SPECIAL_ARG_DEFAULT;
694 global_anim_info[anim_nr].sound[part_nr][special] = sound;
698 printf("::: InitGlobalAnimSoundInfo\n");
700 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
701 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
702 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
703 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
704 printf("::: - anim %d, part %d, mode %d => %d\n",
705 i, j, k, global_anim_info[i].sound[j][k]);
709 static void InitGlobalAnimMusicInfo(void)
711 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
712 int num_property_mappings = getMusicListPropertyMappingSize();
715 // always start with reliable default values (no global animation music)
716 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
717 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
718 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
719 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
721 // initialize global animation music definitions from dynamic configuration
722 for (i = 0; i < num_property_mappings; i++)
724 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
725 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
726 int special = property_mapping[i].ext2_index;
727 int music = property_mapping[i].artwork_index;
729 // music uses control definition; map it to position of graphic (artwork)
730 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
732 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
735 // set animation part to base part, if not specified
736 if (!IS_GLOBAL_ANIM_PART(part_nr))
737 part_nr = GLOBAL_ANIM_ID_PART_BASE;
739 // set animation screen to default, if not specified
740 if (!IS_SPECIAL_GFX_ARG(special))
741 special = GFX_SPECIAL_ARG_DEFAULT;
743 global_anim_info[anim_nr].music[part_nr][special] = music;
747 printf("::: InitGlobalAnimMusicInfo\n");
749 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
750 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
751 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
752 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
753 printf("::: - anim %d, part %d, mode %d => %d\n",
754 i, j, k, global_anim_info[i].music[j][k]);
758 static void InitElementGraphicInfo(void)
760 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
761 int num_property_mappings = getImageListPropertyMappingSize();
764 if (graphic_info == NULL) // still at startup phase
767 // set values to -1 to identify later as "uninitialized" values
768 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
770 for (act = 0; act < NUM_ACTIONS; act++)
772 element_info[i].graphic[act] = -1;
773 element_info[i].crumbled[act] = -1;
775 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
777 element_info[i].direction_graphic[act][dir] = -1;
778 element_info[i].direction_crumbled[act][dir] = -1;
785 // initialize normal element/graphic mapping from static configuration
786 for (i = 0; element_to_graphic[i].element > -1; i++)
788 int element = element_to_graphic[i].element;
789 int action = element_to_graphic[i].action;
790 int direction = element_to_graphic[i].direction;
791 boolean crumbled = element_to_graphic[i].crumbled;
792 int graphic = element_to_graphic[i].graphic;
793 int base_graphic = el2baseimg(element);
795 if (graphic_info[graphic].bitmap == NULL)
798 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
801 boolean base_redefined =
802 getImageListEntryFromImageID(base_graphic)->redefined;
803 boolean act_dir_redefined =
804 getImageListEntryFromImageID(graphic)->redefined;
806 /* if the base graphic ("emerald", for example) has been redefined,
807 but not the action graphic ("emerald.falling", for example), do not
808 use an existing (in this case considered obsolete) action graphic
809 anymore, but use the automatically determined default graphic */
810 if (base_redefined && !act_dir_redefined)
815 action = ACTION_DEFAULT;
820 element_info[element].direction_crumbled[action][direction] = graphic;
822 element_info[element].crumbled[action] = graphic;
827 element_info[element].direction_graphic[action][direction] = graphic;
829 element_info[element].graphic[action] = graphic;
833 // initialize normal element/graphic mapping from dynamic configuration
834 for (i = 0; i < num_property_mappings; i++)
836 int element = property_mapping[i].base_index;
837 int action = property_mapping[i].ext1_index;
838 int direction = property_mapping[i].ext2_index;
839 int special = property_mapping[i].ext3_index;
840 int graphic = property_mapping[i].artwork_index;
841 boolean crumbled = FALSE;
843 if (special == GFX_SPECIAL_ARG_CRUMBLED)
849 if (graphic_info[graphic].bitmap == NULL)
852 if (element >= MAX_NUM_ELEMENTS || special != -1)
856 action = ACTION_DEFAULT;
861 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
862 element_info[element].direction_crumbled[action][dir] = -1;
865 element_info[element].direction_crumbled[action][direction] = graphic;
867 element_info[element].crumbled[action] = graphic;
872 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
873 element_info[element].direction_graphic[action][dir] = -1;
876 element_info[element].direction_graphic[action][direction] = graphic;
878 element_info[element].graphic[action] = graphic;
882 // now copy all graphics that are defined to be cloned from other graphics
883 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
885 int graphic = element_info[i].graphic[ACTION_DEFAULT];
886 int crumbled_like, diggable_like;
891 crumbled_like = graphic_info[graphic].crumbled_like;
892 diggable_like = graphic_info[graphic].diggable_like;
894 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
896 for (act = 0; act < NUM_ACTIONS; act++)
897 element_info[i].crumbled[act] =
898 element_info[crumbled_like].crumbled[act];
899 for (act = 0; act < NUM_ACTIONS; act++)
900 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
901 element_info[i].direction_crumbled[act][dir] =
902 element_info[crumbled_like].direction_crumbled[act][dir];
905 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
907 element_info[i].graphic[ACTION_DIGGING] =
908 element_info[diggable_like].graphic[ACTION_DIGGING];
909 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
910 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
911 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
915 // set hardcoded definitions for some runtime elements without graphic
916 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
918 // set hardcoded definitions for some internal elements without graphic
919 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
921 if (IS_EDITOR_CASCADE_INACTIVE(i))
922 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
923 else if (IS_EDITOR_CASCADE_ACTIVE(i))
924 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
927 // now set all undefined/invalid graphics to -1 to set to default after it
928 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
930 for (act = 0; act < NUM_ACTIONS; act++)
934 graphic = element_info[i].graphic[act];
935 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
936 element_info[i].graphic[act] = -1;
938 graphic = element_info[i].crumbled[act];
939 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
940 element_info[i].crumbled[act] = -1;
942 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
944 graphic = element_info[i].direction_graphic[act][dir];
945 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
946 element_info[i].direction_graphic[act][dir] = -1;
948 graphic = element_info[i].direction_crumbled[act][dir];
949 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
950 element_info[i].direction_crumbled[act][dir] = -1;
957 // adjust graphics with 2nd tile for movement according to direction
958 // (do this before correcting '-1' values to minimize calculations)
959 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
961 for (act = 0; act < NUM_ACTIONS; act++)
963 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
965 int graphic = element_info[i].direction_graphic[act][dir];
966 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
968 if (act == ACTION_FALLING) // special case
969 graphic = element_info[i].graphic[act];
972 graphic_info[graphic].double_movement &&
973 graphic_info[graphic].swap_double_tiles != 0)
975 struct GraphicInfo *g = &graphic_info[graphic];
976 int src_x_front = g->src_x;
977 int src_y_front = g->src_y;
978 int src_x_back = g->src_x + g->offset2_x;
979 int src_y_back = g->src_y + g->offset2_y;
980 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
982 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
983 src_y_front < src_y_back);
984 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
985 boolean swap_movement_tiles_autodetected =
986 (!frames_are_ordered_diagonally &&
987 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
988 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
989 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
990 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
992 // swap frontside and backside graphic tile coordinates, if needed
993 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
995 // get current (wrong) backside tile coordinates
996 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
998 // set frontside tile coordinates to backside tile coordinates
999 g->src_x = src_x_back;
1000 g->src_y = src_y_back;
1002 // invert tile offset to point to new backside tile coordinates
1006 // do not swap front and backside tiles again after correction
1007 g->swap_double_tiles = 0;
1014 UPDATE_BUSY_STATE();
1016 // now set all '-1' values to element specific default values
1017 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1019 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1020 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1021 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1022 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1024 if (default_graphic == -1)
1025 default_graphic = IMG_UNKNOWN;
1027 if (default_crumbled == -1)
1028 default_crumbled = default_graphic;
1030 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1032 default_direction_graphic[dir] =
1033 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1034 default_direction_crumbled[dir] =
1035 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1037 if (default_direction_graphic[dir] == -1)
1038 default_direction_graphic[dir] = default_graphic;
1040 if (default_direction_crumbled[dir] == -1)
1041 default_direction_crumbled[dir] = default_direction_graphic[dir];
1044 for (act = 0; act < NUM_ACTIONS; act++)
1046 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1047 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1048 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1049 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1050 act == ACTION_TURNING_FROM_RIGHT ||
1051 act == ACTION_TURNING_FROM_UP ||
1052 act == ACTION_TURNING_FROM_DOWN);
1054 // generic default action graphic (defined by "[default]" directive)
1055 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1056 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1057 int default_remove_graphic = IMG_EMPTY;
1059 if (act_remove && default_action_graphic != -1)
1060 default_remove_graphic = default_action_graphic;
1062 // look for special default action graphic (classic game specific)
1063 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1064 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1065 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1066 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1067 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1068 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1069 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1070 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1072 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1073 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1074 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1075 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1076 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1077 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1078 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1079 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1081 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1082 // !!! make this better !!!
1083 if (i == EL_EMPTY_SPACE)
1085 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1086 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1089 if (default_action_graphic == -1)
1090 default_action_graphic = default_graphic;
1092 if (default_action_crumbled == -1)
1093 default_action_crumbled = default_action_graphic;
1095 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1097 // use action graphic as the default direction graphic, if undefined
1098 int default_action_direction_graphic = element_info[i].graphic[act];
1099 int default_action_direction_crumbled = element_info[i].crumbled[act];
1101 // no graphic for current action -- use default direction graphic
1102 if (default_action_direction_graphic == -1)
1103 default_action_direction_graphic =
1104 (act_remove ? default_remove_graphic :
1106 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1107 default_action_graphic != default_graphic ?
1108 default_action_graphic :
1109 default_direction_graphic[dir]);
1111 if (element_info[i].direction_graphic[act][dir] == -1)
1112 element_info[i].direction_graphic[act][dir] =
1113 default_action_direction_graphic;
1115 if (default_action_direction_crumbled == -1)
1116 default_action_direction_crumbled =
1117 element_info[i].direction_graphic[act][dir];
1119 if (element_info[i].direction_crumbled[act][dir] == -1)
1120 element_info[i].direction_crumbled[act][dir] =
1121 default_action_direction_crumbled;
1124 // no graphic for this specific action -- use default action graphic
1125 if (element_info[i].graphic[act] == -1)
1126 element_info[i].graphic[act] =
1127 (act_remove ? default_remove_graphic :
1128 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1129 default_action_graphic);
1131 if (element_info[i].crumbled[act] == -1)
1132 element_info[i].crumbled[act] = element_info[i].graphic[act];
1136 UPDATE_BUSY_STATE();
1139 static void InitElementSpecialGraphicInfo(void)
1141 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1142 int num_property_mappings = getImageListPropertyMappingSize();
1145 // always start with reliable default values
1146 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1147 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1148 element_info[i].special_graphic[j] =
1149 element_info[i].graphic[ACTION_DEFAULT];
1151 // initialize special element/graphic mapping from static configuration
1152 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1154 int element = element_to_special_graphic[i].element;
1155 int special = element_to_special_graphic[i].special;
1156 int graphic = element_to_special_graphic[i].graphic;
1157 int base_graphic = el2baseimg(element);
1158 boolean base_redefined =
1159 getImageListEntryFromImageID(base_graphic)->redefined;
1160 boolean special_redefined =
1161 getImageListEntryFromImageID(graphic)->redefined;
1163 /* if the base graphic ("emerald", for example) has been redefined,
1164 but not the special graphic ("emerald.EDITOR", for example), do not
1165 use an existing (in this case considered obsolete) special graphic
1166 anymore, but use the automatically created (down-scaled) graphic */
1167 if (base_redefined && !special_redefined)
1170 element_info[element].special_graphic[special] = graphic;
1173 // initialize special element/graphic mapping from dynamic configuration
1174 for (i = 0; i < num_property_mappings; i++)
1176 int element = property_mapping[i].base_index;
1177 int action = property_mapping[i].ext1_index;
1178 int direction = property_mapping[i].ext2_index;
1179 int special = property_mapping[i].ext3_index;
1180 int graphic = property_mapping[i].artwork_index;
1182 // for action ".active", replace element with active element, if exists
1183 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1185 element = ELEMENT_ACTIVE(element);
1189 if (element >= MAX_NUM_ELEMENTS)
1192 // do not change special graphic if action or direction was specified
1193 if (action != -1 || direction != -1)
1196 if (IS_SPECIAL_GFX_ARG(special))
1197 element_info[element].special_graphic[special] = graphic;
1200 // now set all undefined/invalid graphics to default
1201 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1202 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1203 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1204 element_info[i].special_graphic[j] =
1205 element_info[i].graphic[ACTION_DEFAULT];
1208 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1210 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1211 return get_parameter_value(value_raw, suffix, type);
1213 if (strEqual(value_raw, ARG_UNDEFINED))
1214 return ARG_UNDEFINED_VALUE;
1216 if (type == TYPE_ELEMENT)
1218 char *value = getHashEntry(element_token_hash, value_raw);
1222 Error(ERR_INFO_LINE, "-");
1223 Error(ERR_INFO, "warning: error found in config file:");
1224 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1225 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1226 Error(ERR_INFO, "custom graphic rejected for this element/action");
1227 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1228 Error(ERR_INFO_LINE, "-");
1231 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1233 else if (type == TYPE_GRAPHIC)
1235 char *value = getHashEntry(graphic_token_hash, value_raw);
1236 int fallback_graphic = IMG_CHAR_EXCLAM;
1240 Error(ERR_INFO_LINE, "-");
1241 Error(ERR_INFO, "warning: error found in config file:");
1242 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1243 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1244 Error(ERR_INFO, "custom graphic rejected for this element/action");
1245 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1246 Error(ERR_INFO_LINE, "-");
1249 return (value != NULL ? atoi(value) : fallback_graphic);
1255 static int get_scaled_graphic_width(int graphic)
1257 int original_width = getOriginalImageWidthFromImageID(graphic);
1258 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1260 return original_width * scale_up_factor;
1263 static int get_scaled_graphic_height(int graphic)
1265 int original_height = getOriginalImageHeightFromImageID(graphic);
1266 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1268 return original_height * scale_up_factor;
1271 static void set_graphic_parameters_ext(int graphic, int *parameter,
1272 Bitmap **src_bitmaps)
1274 struct GraphicInfo *g = &graphic_info[graphic];
1275 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1276 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1277 int anim_frames_per_line = 1;
1279 // always start with reliable default values
1280 g->src_image_width = 0;
1281 g->src_image_height = 0;
1284 g->width = TILEX; // default for element graphics
1285 g->height = TILEY; // default for element graphics
1286 g->offset_x = 0; // one or both of these values ...
1287 g->offset_y = 0; // ... will be corrected later
1288 g->offset2_x = 0; // one or both of these values ...
1289 g->offset2_y = 0; // ... will be corrected later
1290 g->swap_double_tiles = -1; // auto-detect tile swapping
1291 g->crumbled_like = -1; // do not use clone element
1292 g->diggable_like = -1; // do not use clone element
1293 g->border_size = TILEX / 8; // "CRUMBLED" border size
1294 g->scale_up_factor = 1; // default: no scaling up
1295 g->tile_size = TILESIZE; // default: standard tile size
1296 g->clone_from = -1; // do not use clone graphic
1297 g->init_delay_fixed = 0;
1298 g->init_delay_random = 0;
1299 g->init_delay_action = -1;
1300 g->anim_delay_fixed = 0;
1301 g->anim_delay_random = 0;
1302 g->anim_delay_action = -1;
1303 g->post_delay_fixed = 0;
1304 g->post_delay_random = 0;
1305 g->post_delay_action = -1;
1306 g->init_event = ANIM_EVENT_UNDEFINED;
1307 g->anim_event = ANIM_EVENT_UNDEFINED;
1308 g->init_event_action = -1;
1309 g->anim_event_action = -1;
1310 g->draw_masked = FALSE;
1312 g->fade_mode = FADE_MODE_DEFAULT;
1316 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1317 g->align = ALIGN_CENTER; // default for title screens
1318 g->valign = VALIGN_MIDDLE; // default for title screens
1319 g->sort_priority = 0; // default for title screens
1321 g->style = STYLE_DEFAULT;
1323 g->bitmaps = src_bitmaps;
1324 g->bitmap = src_bitmap;
1326 // optional zoom factor for scaling up the image to a larger size
1327 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1328 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1329 if (g->scale_up_factor < 1)
1330 g->scale_up_factor = 1; // no scaling
1332 // optional tile size for using non-standard image size
1333 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1335 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1338 // CHECK: should tile sizes less than standard tile size be allowed?
1339 if (g->tile_size < TILESIZE)
1340 g->tile_size = TILESIZE; // standard tile size
1343 // when setting tile size, also set width and height accordingly
1344 g->width = g->tile_size;
1345 g->height = g->tile_size;
1348 if (g->use_image_size)
1350 // set new default bitmap size (with scaling, but without small images)
1351 g->width = get_scaled_graphic_width(graphic);
1352 g->height = get_scaled_graphic_height(graphic);
1355 // optional width and height of each animation frame
1356 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1357 g->width = parameter[GFX_ARG_WIDTH];
1358 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1359 g->height = parameter[GFX_ARG_HEIGHT];
1361 // optional x and y tile position of animation frame sequence
1362 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1363 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1364 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1365 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1367 // optional x and y pixel position of animation frame sequence
1368 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1369 g->src_x = parameter[GFX_ARG_X];
1370 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1371 g->src_y = parameter[GFX_ARG_Y];
1377 Error(ERR_INFO_LINE, "-");
1378 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1379 g->width, getTokenFromImageID(graphic), TILEX);
1380 Error(ERR_INFO_LINE, "-");
1382 g->width = TILEX; // will be checked to be inside bitmap later
1387 Error(ERR_INFO_LINE, "-");
1388 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1389 g->height, getTokenFromImageID(graphic), TILEY);
1390 Error(ERR_INFO_LINE, "-");
1392 g->height = TILEY; // will be checked to be inside bitmap later
1398 // get final bitmap size (with scaling, but without small images)
1399 int src_image_width = get_scaled_graphic_width(graphic);
1400 int src_image_height = get_scaled_graphic_height(graphic);
1402 if (src_image_width == 0 || src_image_height == 0)
1404 // only happens when loaded outside artwork system (like "global.busy")
1405 src_image_width = src_bitmap->width;
1406 src_image_height = src_bitmap->height;
1409 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1411 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1412 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1416 anim_frames_per_row = MAX(1, src_image_width / g->width);
1417 anim_frames_per_col = MAX(1, src_image_height / g->height);
1420 g->src_image_width = src_image_width;
1421 g->src_image_height = src_image_height;
1424 // correct x or y offset dependent of vertical or horizontal frame order
1425 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1427 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1428 parameter[GFX_ARG_OFFSET] : g->height);
1429 anim_frames_per_line = anim_frames_per_col;
1431 else // frames are ordered horizontally
1433 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1434 parameter[GFX_ARG_OFFSET] : g->width);
1435 anim_frames_per_line = anim_frames_per_row;
1438 // optionally, the x and y offset of frames can be specified directly
1439 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1440 g->offset_x = parameter[GFX_ARG_XOFFSET];
1441 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1442 g->offset_y = parameter[GFX_ARG_YOFFSET];
1444 // optionally, moving animations may have separate start and end graphics
1445 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1447 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1448 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1450 // correct x or y offset2 dependent of vertical or horizontal frame order
1451 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1452 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1453 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1454 else // frames are ordered horizontally
1455 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1456 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1458 // optionally, the x and y offset of 2nd graphic can be specified directly
1459 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1460 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1461 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1462 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1464 // optionally, the second movement tile can be specified as start tile
1465 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1466 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1468 // automatically determine correct number of frames, if not defined
1469 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1470 g->anim_frames = parameter[GFX_ARG_FRAMES];
1471 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1472 g->anim_frames = anim_frames_per_row;
1473 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1474 g->anim_frames = anim_frames_per_col;
1478 if (g->anim_frames < 1) // frames must be at least 1
1481 g->anim_frames_per_line =
1482 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1483 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1485 g->anim_delay = parameter[GFX_ARG_DELAY];
1486 if (g->anim_delay < 1) // delay must be at least 1
1489 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1491 // automatically determine correct start frame, if not defined
1492 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1493 g->anim_start_frame = 0;
1494 else if (g->anim_mode & ANIM_REVERSE)
1495 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1497 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1499 // animation synchronized with global frame counter, not move position
1500 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1502 // optional element for cloning crumble graphics
1503 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1504 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1506 // optional element for cloning digging graphics
1507 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1508 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1510 // optional border size for "crumbling" diggable graphics
1511 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1512 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1514 // used for global animations and player "boring" and "sleeping" actions
1515 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1516 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1517 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1518 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1519 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1520 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1521 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1522 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1523 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1524 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1525 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1526 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1528 // used for global animations
1529 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1530 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1531 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1532 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1533 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1534 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1535 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1536 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1537 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1538 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1539 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1540 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1541 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1544 // used for toon animations and global animations
1545 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1546 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1547 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1548 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1549 g->direction = parameter[GFX_ARG_DIRECTION];
1550 g->position = parameter[GFX_ARG_POSITION];
1551 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1552 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1554 if (g->step_delay < 1) // delay must be at least 1
1557 // this is only used for drawing font characters
1558 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1559 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1561 // use a different default value for global animations and toons
1562 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1563 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1564 g->draw_masked = TRUE;
1566 // this is used for drawing envelopes, global animations and toons
1567 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1568 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1570 // used for toon animations and global animations
1571 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1572 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1574 // optional graphic for cloning all graphics settings
1575 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1576 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1578 // optional settings for drawing title screens and title messages
1579 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1580 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1581 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1582 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1583 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1584 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1585 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1586 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1587 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1588 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1589 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1590 g->align = parameter[GFX_ARG_ALIGN];
1591 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1592 g->valign = parameter[GFX_ARG_VALIGN];
1593 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1594 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1596 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1597 g->class = parameter[GFX_ARG_CLASS];
1598 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1599 g->style = parameter[GFX_ARG_STYLE];
1601 // this is only used for drawing menu buttons and text
1602 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1603 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1604 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1605 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1608 static void set_graphic_parameters(int graphic)
1610 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1611 char **parameter_raw = image->parameter;
1612 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1613 int parameter[NUM_GFX_ARGS];
1616 // if fallback to default artwork is done, also use the default parameters
1617 if (image->fallback_to_default)
1618 parameter_raw = image->default_parameter;
1620 // get integer values from string parameters
1621 for (i = 0; i < NUM_GFX_ARGS; i++)
1622 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1623 image_config_suffix[i].token,
1624 image_config_suffix[i].type);
1626 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1628 UPDATE_BUSY_STATE();
1631 static void set_cloned_graphic_parameters(int graphic)
1633 int fallback_graphic = IMG_CHAR_EXCLAM;
1634 int max_num_images = getImageListSize();
1635 int clone_graphic = graphic_info[graphic].clone_from;
1636 int num_references_followed = 1;
1638 while (graphic_info[clone_graphic].clone_from != -1 &&
1639 num_references_followed < max_num_images)
1641 clone_graphic = graphic_info[clone_graphic].clone_from;
1643 num_references_followed++;
1646 if (num_references_followed >= max_num_images)
1648 Error(ERR_INFO_LINE, "-");
1649 Error(ERR_INFO, "warning: error found in config file:");
1650 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1651 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1652 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1653 Error(ERR_INFO, "custom graphic rejected for this element/action");
1655 if (graphic == fallback_graphic)
1656 Error(ERR_EXIT, "no fallback graphic available");
1658 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1659 Error(ERR_INFO_LINE, "-");
1661 graphic_info[graphic] = graphic_info[fallback_graphic];
1665 graphic_info[graphic] = graphic_info[clone_graphic];
1666 graphic_info[graphic].clone_from = clone_graphic;
1670 static void InitGraphicInfo(void)
1672 int fallback_graphic = IMG_CHAR_EXCLAM;
1673 int num_images = getImageListSize();
1676 // use image size as default values for width and height for these images
1677 static int full_size_graphics[] =
1680 IMG_GLOBAL_BORDER_MAIN,
1681 IMG_GLOBAL_BORDER_SCORES,
1682 IMG_GLOBAL_BORDER_EDITOR,
1683 IMG_GLOBAL_BORDER_PLAYING,
1686 IMG_BACKGROUND_ENVELOPE_1,
1687 IMG_BACKGROUND_ENVELOPE_2,
1688 IMG_BACKGROUND_ENVELOPE_3,
1689 IMG_BACKGROUND_ENVELOPE_4,
1690 IMG_BACKGROUND_REQUEST,
1693 IMG_BACKGROUND_TITLE_INITIAL,
1694 IMG_BACKGROUND_TITLE,
1695 IMG_BACKGROUND_MAIN,
1696 IMG_BACKGROUND_LEVELS,
1697 IMG_BACKGROUND_LEVELNR,
1698 IMG_BACKGROUND_SCORES,
1699 IMG_BACKGROUND_EDITOR,
1700 IMG_BACKGROUND_INFO,
1701 IMG_BACKGROUND_INFO_ELEMENTS,
1702 IMG_BACKGROUND_INFO_MUSIC,
1703 IMG_BACKGROUND_INFO_CREDITS,
1704 IMG_BACKGROUND_INFO_PROGRAM,
1705 IMG_BACKGROUND_INFO_VERSION,
1706 IMG_BACKGROUND_INFO_LEVELSET,
1707 IMG_BACKGROUND_SETUP,
1708 IMG_BACKGROUND_PLAYING,
1709 IMG_BACKGROUND_DOOR,
1710 IMG_BACKGROUND_TAPE,
1711 IMG_BACKGROUND_PANEL,
1712 IMG_BACKGROUND_PALETTE,
1713 IMG_BACKGROUND_TOOLBOX,
1715 IMG_TITLESCREEN_INITIAL_1,
1716 IMG_TITLESCREEN_INITIAL_2,
1717 IMG_TITLESCREEN_INITIAL_3,
1718 IMG_TITLESCREEN_INITIAL_4,
1719 IMG_TITLESCREEN_INITIAL_5,
1726 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1727 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1728 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1729 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1730 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1731 IMG_BACKGROUND_TITLEMESSAGE_1,
1732 IMG_BACKGROUND_TITLEMESSAGE_2,
1733 IMG_BACKGROUND_TITLEMESSAGE_3,
1734 IMG_BACKGROUND_TITLEMESSAGE_4,
1735 IMG_BACKGROUND_TITLEMESSAGE_5,
1740 FreeGlobalAnimEventInfo();
1742 checked_free(graphic_info);
1744 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1746 // initialize "use_image_size" flag with default value
1747 for (i = 0; i < num_images; i++)
1748 graphic_info[i].use_image_size = FALSE;
1750 // initialize "use_image_size" flag from static configuration above
1751 for (i = 0; full_size_graphics[i] != -1; i++)
1752 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1754 // first set all graphic paramaters ...
1755 for (i = 0; i < num_images; i++)
1756 set_graphic_parameters(i);
1758 // ... then copy these parameters for cloned graphics
1759 for (i = 0; i < num_images; i++)
1760 if (graphic_info[i].clone_from != -1)
1761 set_cloned_graphic_parameters(i);
1763 for (i = 0; i < num_images; i++)
1765 Bitmap *src_bitmap = graphic_info[i].bitmap;
1769 int src_bitmap_width, src_bitmap_height;
1771 // now check if no animation frames are outside of the loaded image
1773 if (graphic_info[i].bitmap == NULL)
1774 continue; // skip check for optional images that are undefined
1776 // get image size (this can differ from the standard element tile size!)
1777 width = graphic_info[i].width;
1778 height = graphic_info[i].height;
1780 // get final bitmap size (with scaling, but without small images)
1781 src_bitmap_width = graphic_info[i].src_image_width;
1782 src_bitmap_height = graphic_info[i].src_image_height;
1784 // check if first animation frame is inside specified bitmap
1786 // do not use getGraphicSourceXY() here to get position of first frame;
1787 // this avoids calculating wrong start position for out-of-bounds frame
1788 src_x = graphic_info[i].src_x;
1789 src_y = graphic_info[i].src_y;
1791 if (program.headless)
1794 if (src_x < 0 || src_y < 0 ||
1795 src_x + width > src_bitmap_width ||
1796 src_y + height > src_bitmap_height)
1798 Error(ERR_INFO_LINE, "-");
1799 Error(ERR_INFO, "warning: error found in config file:");
1800 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1801 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1802 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1803 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1805 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1806 src_x, src_y, src_bitmap_width, src_bitmap_height);
1807 Error(ERR_INFO, "custom graphic rejected for this element/action");
1809 if (i == fallback_graphic)
1810 Error(ERR_EXIT, "no fallback graphic available");
1812 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1813 Error(ERR_INFO_LINE, "-");
1815 graphic_info[i] = graphic_info[fallback_graphic];
1817 // if first frame out of bounds, do not check last frame anymore
1821 // check if last animation frame is inside specified bitmap
1823 last_frame = graphic_info[i].anim_frames - 1;
1824 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1826 if (src_x < 0 || src_y < 0 ||
1827 src_x + width > src_bitmap_width ||
1828 src_y + height > src_bitmap_height)
1830 Error(ERR_INFO_LINE, "-");
1831 Error(ERR_INFO, "warning: error found in config file:");
1832 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1833 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1834 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1835 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1837 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1838 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1839 Error(ERR_INFO, "custom graphic rejected for this element/action");
1841 if (i == fallback_graphic)
1842 Error(ERR_EXIT, "no fallback graphic available");
1844 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1845 Error(ERR_INFO_LINE, "-");
1847 graphic_info[i] = graphic_info[fallback_graphic];
1852 static void InitGraphicCompatibilityInfo(void)
1854 struct FileInfo *fi_global_door =
1855 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1856 int num_images = getImageListSize();
1859 /* the following compatibility handling is needed for the following case:
1860 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1861 graphics mainly used for door and panel graphics, like editor, tape and
1862 in-game buttons with hard-coded bitmap positions and button sizes; as
1863 these graphics now have individual definitions, redefining "global.door"
1864 to change all these graphics at once like before does not work anymore
1865 (because all those individual definitions still have their default values);
1866 to solve this, remap all those individual definitions that are not
1867 redefined to the new bitmap of "global.door" if it was redefined */
1869 // special compatibility handling if image "global.door" was redefined
1870 if (fi_global_door->redefined)
1872 for (i = 0; i < num_images; i++)
1874 struct FileInfo *fi = getImageListEntryFromImageID(i);
1876 // process only those images that still use the default settings
1879 // process all images which default to same image as "global.door"
1880 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1882 // printf("::: special treatment needed for token '%s'\n", fi->token);
1884 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1885 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1891 InitGraphicCompatibilityInfo_Doors();
1894 static void InitElementSoundInfo(void)
1896 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1897 int num_property_mappings = getSoundListPropertyMappingSize();
1900 // set values to -1 to identify later as "uninitialized" values
1901 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1902 for (act = 0; act < NUM_ACTIONS; act++)
1903 element_info[i].sound[act] = -1;
1905 // initialize element/sound mapping from static configuration
1906 for (i = 0; element_to_sound[i].element > -1; i++)
1908 int element = element_to_sound[i].element;
1909 int action = element_to_sound[i].action;
1910 int sound = element_to_sound[i].sound;
1911 boolean is_class = element_to_sound[i].is_class;
1914 action = ACTION_DEFAULT;
1917 element_info[element].sound[action] = sound;
1919 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1920 if (strEqual(element_info[j].class_name,
1921 element_info[element].class_name))
1922 element_info[j].sound[action] = sound;
1925 // initialize element class/sound mapping from dynamic configuration
1926 for (i = 0; i < num_property_mappings; i++)
1928 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1929 int action = property_mapping[i].ext1_index;
1930 int sound = property_mapping[i].artwork_index;
1932 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1936 action = ACTION_DEFAULT;
1938 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1939 if (strEqual(element_info[j].class_name,
1940 element_info[element_class].class_name))
1941 element_info[j].sound[action] = sound;
1944 // initialize element/sound mapping from dynamic configuration
1945 for (i = 0; i < num_property_mappings; i++)
1947 int element = property_mapping[i].base_index;
1948 int action = property_mapping[i].ext1_index;
1949 int sound = property_mapping[i].artwork_index;
1951 if (element >= MAX_NUM_ELEMENTS)
1955 action = ACTION_DEFAULT;
1957 element_info[element].sound[action] = sound;
1960 // now set all '-1' values to element specific default values
1961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1963 for (act = 0; act < NUM_ACTIONS; act++)
1965 // generic default action sound (defined by "[default]" directive)
1966 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1968 // look for special default action sound (classic game specific)
1969 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1970 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1971 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1972 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1973 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1974 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1975 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1976 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1978 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1979 // !!! make this better !!!
1980 if (i == EL_EMPTY_SPACE)
1981 default_action_sound = element_info[EL_DEFAULT].sound[act];
1983 // no sound for this specific action -- use default action sound
1984 if (element_info[i].sound[act] == -1)
1985 element_info[i].sound[act] = default_action_sound;
1989 // copy sound settings to some elements that are only stored in level file
1990 // in native R'n'D levels, but are used by game engine in native EM levels
1991 for (i = 0; copy_properties[i][0] != -1; i++)
1992 for (j = 1; j <= 4; j++)
1993 for (act = 0; act < NUM_ACTIONS; act++)
1994 element_info[copy_properties[i][j]].sound[act] =
1995 element_info[copy_properties[i][0]].sound[act];
1998 static void InitGameModeSoundInfo(void)
2002 // set values to -1 to identify later as "uninitialized" values
2003 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2006 // initialize gamemode/sound mapping from static configuration
2007 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2009 int gamemode = gamemode_to_sound[i].gamemode;
2010 int sound = gamemode_to_sound[i].sound;
2013 gamemode = GAME_MODE_DEFAULT;
2015 menu.sound[gamemode] = sound;
2018 // now set all '-1' values to levelset specific default values
2019 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2020 if (menu.sound[i] == -1)
2021 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2024 static void set_sound_parameters(int sound, char **parameter_raw)
2026 int parameter[NUM_SND_ARGS];
2029 // get integer values from string parameters
2030 for (i = 0; i < NUM_SND_ARGS; i++)
2032 get_parameter_value(parameter_raw[i],
2033 sound_config_suffix[i].token,
2034 sound_config_suffix[i].type);
2036 // explicit loop mode setting in configuration overrides default value
2037 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2038 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2040 // sound volume to change the original volume when loading the sound file
2041 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2043 // sound priority to give certain sounds a higher or lower priority
2044 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2047 static void InitSoundInfo(void)
2049 int *sound_effect_properties;
2050 int num_sounds = getSoundListSize();
2053 checked_free(sound_info);
2055 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2056 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2058 // initialize sound effect for all elements to "no sound"
2059 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2060 for (j = 0; j < NUM_ACTIONS; j++)
2061 element_info[i].sound[j] = SND_UNDEFINED;
2063 for (i = 0; i < num_sounds; i++)
2065 struct FileInfo *sound = getSoundListEntry(i);
2066 int len_effect_text = strlen(sound->token);
2068 sound_effect_properties[i] = ACTION_OTHER;
2069 sound_info[i].loop = FALSE; // default: play sound only once
2071 // determine all loop sounds and identify certain sound classes
2073 for (j = 0; element_action_info[j].suffix; j++)
2075 int len_action_text = strlen(element_action_info[j].suffix);
2077 if (len_action_text < len_effect_text &&
2078 strEqual(&sound->token[len_effect_text - len_action_text],
2079 element_action_info[j].suffix))
2081 sound_effect_properties[i] = element_action_info[j].value;
2082 sound_info[i].loop = element_action_info[j].is_loop_sound;
2088 // associate elements and some selected sound actions
2090 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2092 if (element_info[j].class_name)
2094 int len_class_text = strlen(element_info[j].class_name);
2096 if (len_class_text + 1 < len_effect_text &&
2097 strncmp(sound->token,
2098 element_info[j].class_name, len_class_text) == 0 &&
2099 sound->token[len_class_text] == '.')
2101 int sound_action_value = sound_effect_properties[i];
2103 element_info[j].sound[sound_action_value] = i;
2108 set_sound_parameters(i, sound->parameter);
2111 free(sound_effect_properties);
2114 static void InitGameModeMusicInfo(void)
2116 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2117 int num_property_mappings = getMusicListPropertyMappingSize();
2118 int default_levelset_music = -1;
2121 // set values to -1 to identify later as "uninitialized" values
2122 for (i = 0; i < MAX_LEVELS; i++)
2123 levelset.music[i] = -1;
2124 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2127 // initialize gamemode/music mapping from static configuration
2128 for (i = 0; gamemode_to_music[i].music > -1; i++)
2130 int gamemode = gamemode_to_music[i].gamemode;
2131 int music = gamemode_to_music[i].music;
2134 gamemode = GAME_MODE_DEFAULT;
2136 menu.music[gamemode] = music;
2139 // initialize gamemode/music mapping from dynamic configuration
2140 for (i = 0; i < num_property_mappings; i++)
2142 int prefix = property_mapping[i].base_index;
2143 int gamemode = property_mapping[i].ext2_index;
2144 int level = property_mapping[i].ext3_index;
2145 int music = property_mapping[i].artwork_index;
2147 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2151 gamemode = GAME_MODE_DEFAULT;
2153 // level specific music only allowed for in-game music
2154 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2155 gamemode = GAME_MODE_PLAYING;
2160 default_levelset_music = music;
2163 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2164 levelset.music[level] = music;
2165 if (gamemode != GAME_MODE_PLAYING)
2166 menu.music[gamemode] = music;
2169 // now set all '-1' values to menu specific default values
2170 // (undefined values of "levelset.music[]" might stay at "-1" to
2171 // allow dynamic selection of music files from music directory!)
2172 for (i = 0; i < MAX_LEVELS; i++)
2173 if (levelset.music[i] == -1)
2174 levelset.music[i] = default_levelset_music;
2175 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2176 if (menu.music[i] == -1)
2177 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2180 static void set_music_parameters(int music, char **parameter_raw)
2182 int parameter[NUM_MUS_ARGS];
2185 // get integer values from string parameters
2186 for (i = 0; i < NUM_MUS_ARGS; i++)
2188 get_parameter_value(parameter_raw[i],
2189 music_config_suffix[i].token,
2190 music_config_suffix[i].type);
2192 // explicit loop mode setting in configuration overrides default value
2193 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2194 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2197 static void InitMusicInfo(void)
2199 int num_music = getMusicListSize();
2202 checked_free(music_info);
2204 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2206 for (i = 0; i < num_music; i++)
2208 struct FileInfo *music = getMusicListEntry(i);
2209 int len_music_text = strlen(music->token);
2211 music_info[i].loop = TRUE; // default: play music in loop mode
2213 // determine all loop music
2215 for (j = 0; music_prefix_info[j].prefix; j++)
2217 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2219 if (len_prefix_text < len_music_text &&
2220 strncmp(music->token,
2221 music_prefix_info[j].prefix, len_prefix_text) == 0)
2223 music_info[i].loop = music_prefix_info[j].is_loop_music;
2229 set_music_parameters(i, music->parameter);
2233 static void ReinitializeGraphics(void)
2235 print_timestamp_init("ReinitializeGraphics");
2237 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2239 InitGraphicInfo(); // graphic properties mapping
2240 print_timestamp_time("InitGraphicInfo");
2241 InitElementGraphicInfo(); // element game graphic mapping
2242 print_timestamp_time("InitElementGraphicInfo");
2243 InitElementSpecialGraphicInfo(); // element special graphic mapping
2244 print_timestamp_time("InitElementSpecialGraphicInfo");
2246 InitElementSmallImages(); // scale elements to all needed sizes
2247 print_timestamp_time("InitElementSmallImages");
2248 InitScaledImages(); // scale all other images, if needed
2249 print_timestamp_time("InitScaledImages");
2250 InitBitmapPointers(); // set standard size bitmap pointers
2251 print_timestamp_time("InitBitmapPointers");
2252 InitFontGraphicInfo(); // initialize text drawing functions
2253 print_timestamp_time("InitFontGraphicInfo");
2254 InitGlobalAnimGraphicInfo(); // initialize global animation config
2255 print_timestamp_time("InitGlobalAnimGraphicInfo");
2257 InitImageTextures(); // create textures for certain images
2258 print_timestamp_time("InitImageTextures");
2260 InitGraphicInfo_EM(); // graphic mapping for EM engine
2261 print_timestamp_time("InitGraphicInfo_EM");
2263 InitGraphicCompatibilityInfo();
2264 print_timestamp_time("InitGraphicCompatibilityInfo");
2266 SetMainBackgroundImage(IMG_BACKGROUND);
2267 print_timestamp_time("SetMainBackgroundImage");
2268 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2269 print_timestamp_time("SetDoorBackgroundImage");
2272 print_timestamp_time("InitGadgets");
2274 print_timestamp_time("InitDoors");
2276 print_timestamp_done("ReinitializeGraphics");
2279 static void ReinitializeSounds(void)
2281 InitSoundInfo(); // sound properties mapping
2282 InitElementSoundInfo(); // element game sound mapping
2283 InitGameModeSoundInfo(); // game mode sound mapping
2284 InitGlobalAnimSoundInfo(); // global animation sound settings
2286 InitPlayLevelSound(); // internal game sound settings
2289 static void ReinitializeMusic(void)
2291 InitMusicInfo(); // music properties mapping
2292 InitGameModeMusicInfo(); // game mode music mapping
2293 InitGlobalAnimMusicInfo(); // global animation music settings
2296 static int get_special_property_bit(int element, int property_bit_nr)
2298 struct PropertyBitInfo
2304 static struct PropertyBitInfo pb_can_move_into_acid[] =
2306 // the player may be able fall into acid when gravity is activated
2311 { EL_SP_MURPHY, 0 },
2312 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2314 // all elements that can move may be able to also move into acid
2317 { EL_BUG_RIGHT, 1 },
2320 { EL_SPACESHIP, 2 },
2321 { EL_SPACESHIP_LEFT, 2 },
2322 { EL_SPACESHIP_RIGHT, 2 },
2323 { EL_SPACESHIP_UP, 2 },
2324 { EL_SPACESHIP_DOWN, 2 },
2325 { EL_BD_BUTTERFLY, 3 },
2326 { EL_BD_BUTTERFLY_LEFT, 3 },
2327 { EL_BD_BUTTERFLY_RIGHT, 3 },
2328 { EL_BD_BUTTERFLY_UP, 3 },
2329 { EL_BD_BUTTERFLY_DOWN, 3 },
2330 { EL_BD_FIREFLY, 4 },
2331 { EL_BD_FIREFLY_LEFT, 4 },
2332 { EL_BD_FIREFLY_RIGHT, 4 },
2333 { EL_BD_FIREFLY_UP, 4 },
2334 { EL_BD_FIREFLY_DOWN, 4 },
2336 { EL_YAMYAM_LEFT, 5 },
2337 { EL_YAMYAM_RIGHT, 5 },
2338 { EL_YAMYAM_UP, 5 },
2339 { EL_YAMYAM_DOWN, 5 },
2340 { EL_DARK_YAMYAM, 6 },
2343 { EL_PACMAN_LEFT, 8 },
2344 { EL_PACMAN_RIGHT, 8 },
2345 { EL_PACMAN_UP, 8 },
2346 { EL_PACMAN_DOWN, 8 },
2348 { EL_MOLE_LEFT, 9 },
2349 { EL_MOLE_RIGHT, 9 },
2351 { EL_MOLE_DOWN, 9 },
2355 { EL_SATELLITE, 13 },
2356 { EL_SP_SNIKSNAK, 14 },
2357 { EL_SP_ELECTRON, 15 },
2360 { EL_EMC_ANDROID, 18 },
2365 static struct PropertyBitInfo pb_dont_collide_with[] =
2367 { EL_SP_SNIKSNAK, 0 },
2368 { EL_SP_ELECTRON, 1 },
2376 struct PropertyBitInfo *pb_info;
2379 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2380 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2385 struct PropertyBitInfo *pb_info = NULL;
2388 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2389 if (pb_definition[i].bit_nr == property_bit_nr)
2390 pb_info = pb_definition[i].pb_info;
2392 if (pb_info == NULL)
2395 for (i = 0; pb_info[i].element != -1; i++)
2396 if (pb_info[i].element == element)
2397 return pb_info[i].bit_nr;
2402 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2403 boolean property_value)
2405 int bit_nr = get_special_property_bit(element, property_bit_nr);
2410 *bitfield |= (1 << bit_nr);
2412 *bitfield &= ~(1 << bit_nr);
2416 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2418 int bit_nr = get_special_property_bit(element, property_bit_nr);
2421 return ((*bitfield & (1 << bit_nr)) != 0);
2426 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2428 static int group_nr;
2429 static struct ElementGroupInfo *group;
2430 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2433 if (actual_group == NULL) // not yet initialized
2436 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2438 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2439 group_element - EL_GROUP_START + 1);
2441 // replace element which caused too deep recursion by question mark
2442 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2447 if (recursion_depth == 0) // initialization
2449 group = actual_group;
2450 group_nr = GROUP_NR(group_element);
2452 group->num_elements_resolved = 0;
2453 group->choice_pos = 0;
2455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2456 element_info[i].in_group[group_nr] = FALSE;
2459 for (i = 0; i < actual_group->num_elements; i++)
2461 int element = actual_group->element[i];
2463 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2466 if (IS_GROUP_ELEMENT(element))
2467 ResolveGroupElementExt(element, recursion_depth + 1);
2470 group->element_resolved[group->num_elements_resolved++] = element;
2471 element_info[element].in_group[group_nr] = TRUE;
2476 void ResolveGroupElement(int group_element)
2478 ResolveGroupElementExt(group_element, 0);
2481 void InitElementPropertiesStatic(void)
2483 static boolean clipboard_elements_initialized = FALSE;
2485 static int ep_diggable[] =
2490 EL_SP_BUGGY_BASE_ACTIVATING,
2493 EL_INVISIBLE_SAND_ACTIVE,
2496 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2497 // (if amoeba can grow into anything diggable, maybe keep these out)
2502 EL_SP_BUGGY_BASE_ACTIVE,
2509 static int ep_collectible_only[] =
2531 EL_DYNABOMB_INCREASE_NUMBER,
2532 EL_DYNABOMB_INCREASE_SIZE,
2533 EL_DYNABOMB_INCREASE_POWER,
2551 // !!! handle separately !!!
2552 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2558 static int ep_dont_run_into[] =
2560 // same elements as in 'ep_dont_touch'
2566 // same elements as in 'ep_dont_collide_with'
2578 // !!! maybe this should better be handled by 'ep_diggable' !!!
2583 EL_SP_BUGGY_BASE_ACTIVE,
2590 static int ep_dont_collide_with[] =
2592 // same elements as in 'ep_dont_touch'
2609 static int ep_dont_touch[] =
2619 static int ep_indestructible[] =
2623 EL_ACID_POOL_TOPLEFT,
2624 EL_ACID_POOL_TOPRIGHT,
2625 EL_ACID_POOL_BOTTOMLEFT,
2626 EL_ACID_POOL_BOTTOM,
2627 EL_ACID_POOL_BOTTOMRIGHT,
2628 EL_SP_HARDWARE_GRAY,
2629 EL_SP_HARDWARE_GREEN,
2630 EL_SP_HARDWARE_BLUE,
2632 EL_SP_HARDWARE_YELLOW,
2633 EL_SP_HARDWARE_BASE_1,
2634 EL_SP_HARDWARE_BASE_2,
2635 EL_SP_HARDWARE_BASE_3,
2636 EL_SP_HARDWARE_BASE_4,
2637 EL_SP_HARDWARE_BASE_5,
2638 EL_SP_HARDWARE_BASE_6,
2639 EL_INVISIBLE_STEELWALL,
2640 EL_INVISIBLE_STEELWALL_ACTIVE,
2641 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2642 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2643 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2644 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2645 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2646 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2647 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2648 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2649 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2650 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2651 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2652 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2654 EL_LIGHT_SWITCH_ACTIVE,
2655 EL_SIGN_EXCLAMATION,
2656 EL_SIGN_RADIOACTIVITY,
2663 EL_SIGN_ENTRY_FORBIDDEN,
2664 EL_SIGN_EMERGENCY_EXIT,
2672 EL_STEEL_EXIT_CLOSED,
2674 EL_STEEL_EXIT_OPENING,
2675 EL_STEEL_EXIT_CLOSING,
2676 EL_EM_STEEL_EXIT_CLOSED,
2677 EL_EM_STEEL_EXIT_OPEN,
2678 EL_EM_STEEL_EXIT_OPENING,
2679 EL_EM_STEEL_EXIT_CLOSING,
2680 EL_DC_STEELWALL_1_LEFT,
2681 EL_DC_STEELWALL_1_RIGHT,
2682 EL_DC_STEELWALL_1_TOP,
2683 EL_DC_STEELWALL_1_BOTTOM,
2684 EL_DC_STEELWALL_1_HORIZONTAL,
2685 EL_DC_STEELWALL_1_VERTICAL,
2686 EL_DC_STEELWALL_1_TOPLEFT,
2687 EL_DC_STEELWALL_1_TOPRIGHT,
2688 EL_DC_STEELWALL_1_BOTTOMLEFT,
2689 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2690 EL_DC_STEELWALL_1_TOPLEFT_2,
2691 EL_DC_STEELWALL_1_TOPRIGHT_2,
2692 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2693 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2694 EL_DC_STEELWALL_2_LEFT,
2695 EL_DC_STEELWALL_2_RIGHT,
2696 EL_DC_STEELWALL_2_TOP,
2697 EL_DC_STEELWALL_2_BOTTOM,
2698 EL_DC_STEELWALL_2_HORIZONTAL,
2699 EL_DC_STEELWALL_2_VERTICAL,
2700 EL_DC_STEELWALL_2_MIDDLE,
2701 EL_DC_STEELWALL_2_SINGLE,
2702 EL_STEELWALL_SLIPPERY,
2716 EL_GATE_1_GRAY_ACTIVE,
2717 EL_GATE_2_GRAY_ACTIVE,
2718 EL_GATE_3_GRAY_ACTIVE,
2719 EL_GATE_4_GRAY_ACTIVE,
2728 EL_EM_GATE_1_GRAY_ACTIVE,
2729 EL_EM_GATE_2_GRAY_ACTIVE,
2730 EL_EM_GATE_3_GRAY_ACTIVE,
2731 EL_EM_GATE_4_GRAY_ACTIVE,
2740 EL_EMC_GATE_5_GRAY_ACTIVE,
2741 EL_EMC_GATE_6_GRAY_ACTIVE,
2742 EL_EMC_GATE_7_GRAY_ACTIVE,
2743 EL_EMC_GATE_8_GRAY_ACTIVE,
2745 EL_DC_GATE_WHITE_GRAY,
2746 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2747 EL_DC_GATE_FAKE_GRAY,
2749 EL_SWITCHGATE_OPENING,
2750 EL_SWITCHGATE_CLOSED,
2751 EL_SWITCHGATE_CLOSING,
2752 EL_DC_SWITCHGATE_SWITCH_UP,
2753 EL_DC_SWITCHGATE_SWITCH_DOWN,
2755 EL_TIMEGATE_OPENING,
2757 EL_TIMEGATE_CLOSING,
2758 EL_DC_TIMEGATE_SWITCH,
2759 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2763 EL_TUBE_VERTICAL_LEFT,
2764 EL_TUBE_VERTICAL_RIGHT,
2765 EL_TUBE_HORIZONTAL_UP,
2766 EL_TUBE_HORIZONTAL_DOWN,
2771 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2772 EL_EXPANDABLE_STEELWALL_VERTICAL,
2773 EL_EXPANDABLE_STEELWALL_ANY,
2778 static int ep_slippery[] =
2792 EL_ROBOT_WHEEL_ACTIVE,
2798 EL_ACID_POOL_TOPLEFT,
2799 EL_ACID_POOL_TOPRIGHT,
2809 EL_STEELWALL_SLIPPERY,
2812 EL_EMC_WALL_SLIPPERY_1,
2813 EL_EMC_WALL_SLIPPERY_2,
2814 EL_EMC_WALL_SLIPPERY_3,
2815 EL_EMC_WALL_SLIPPERY_4,
2817 EL_EMC_MAGIC_BALL_ACTIVE,
2822 static int ep_can_change[] =
2827 static int ep_can_move[] =
2829 // same elements as in 'pb_can_move_into_acid'
2852 static int ep_can_fall[] =
2866 EL_QUICKSAND_FAST_FULL,
2868 EL_BD_MAGIC_WALL_FULL,
2869 EL_DC_MAGIC_WALL_FULL,
2883 static int ep_can_smash_player[] =
2909 static int ep_can_smash_enemies[] =
2918 static int ep_can_smash_everything[] =
2927 static int ep_explodes_by_fire[] =
2929 // same elements as in 'ep_explodes_impact'
2934 // same elements as in 'ep_explodes_smashed'
2944 EL_EM_DYNAMITE_ACTIVE,
2945 EL_DYNABOMB_PLAYER_1_ACTIVE,
2946 EL_DYNABOMB_PLAYER_2_ACTIVE,
2947 EL_DYNABOMB_PLAYER_3_ACTIVE,
2948 EL_DYNABOMB_PLAYER_4_ACTIVE,
2949 EL_DYNABOMB_INCREASE_NUMBER,
2950 EL_DYNABOMB_INCREASE_SIZE,
2951 EL_DYNABOMB_INCREASE_POWER,
2952 EL_SP_DISK_RED_ACTIVE,
2966 static int ep_explodes_smashed[] =
2968 // same elements as in 'ep_explodes_impact'
2982 static int ep_explodes_impact[] =
2991 static int ep_walkable_over[] =
2995 EL_SOKOBAN_FIELD_EMPTY,
3002 EL_EM_STEEL_EXIT_OPEN,
3003 EL_EM_STEEL_EXIT_OPENING,
3012 EL_GATE_1_GRAY_ACTIVE,
3013 EL_GATE_2_GRAY_ACTIVE,
3014 EL_GATE_3_GRAY_ACTIVE,
3015 EL_GATE_4_GRAY_ACTIVE,
3023 static int ep_walkable_inside[] =
3028 EL_TUBE_VERTICAL_LEFT,
3029 EL_TUBE_VERTICAL_RIGHT,
3030 EL_TUBE_HORIZONTAL_UP,
3031 EL_TUBE_HORIZONTAL_DOWN,
3040 static int ep_walkable_under[] =
3045 static int ep_passable_over[] =
3055 EL_EM_GATE_1_GRAY_ACTIVE,
3056 EL_EM_GATE_2_GRAY_ACTIVE,
3057 EL_EM_GATE_3_GRAY_ACTIVE,
3058 EL_EM_GATE_4_GRAY_ACTIVE,
3067 EL_EMC_GATE_5_GRAY_ACTIVE,
3068 EL_EMC_GATE_6_GRAY_ACTIVE,
3069 EL_EMC_GATE_7_GRAY_ACTIVE,
3070 EL_EMC_GATE_8_GRAY_ACTIVE,
3072 EL_DC_GATE_WHITE_GRAY,
3073 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3080 static int ep_passable_inside[] =
3086 EL_SP_PORT_HORIZONTAL,
3087 EL_SP_PORT_VERTICAL,
3089 EL_SP_GRAVITY_PORT_LEFT,
3090 EL_SP_GRAVITY_PORT_RIGHT,
3091 EL_SP_GRAVITY_PORT_UP,
3092 EL_SP_GRAVITY_PORT_DOWN,
3093 EL_SP_GRAVITY_ON_PORT_LEFT,
3094 EL_SP_GRAVITY_ON_PORT_RIGHT,
3095 EL_SP_GRAVITY_ON_PORT_UP,
3096 EL_SP_GRAVITY_ON_PORT_DOWN,
3097 EL_SP_GRAVITY_OFF_PORT_LEFT,
3098 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3099 EL_SP_GRAVITY_OFF_PORT_UP,
3100 EL_SP_GRAVITY_OFF_PORT_DOWN,
3105 static int ep_passable_under[] =
3110 static int ep_droppable[] =
3115 static int ep_explodes_1x1_old[] =
3120 static int ep_pushable[] =
3132 EL_SOKOBAN_FIELD_FULL,
3141 static int ep_explodes_cross_old[] =
3146 static int ep_protected[] =
3148 // same elements as in 'ep_walkable_inside'
3152 EL_TUBE_VERTICAL_LEFT,
3153 EL_TUBE_VERTICAL_RIGHT,
3154 EL_TUBE_HORIZONTAL_UP,
3155 EL_TUBE_HORIZONTAL_DOWN,
3161 // same elements as in 'ep_passable_over'
3170 EL_EM_GATE_1_GRAY_ACTIVE,
3171 EL_EM_GATE_2_GRAY_ACTIVE,
3172 EL_EM_GATE_3_GRAY_ACTIVE,
3173 EL_EM_GATE_4_GRAY_ACTIVE,
3182 EL_EMC_GATE_5_GRAY_ACTIVE,
3183 EL_EMC_GATE_6_GRAY_ACTIVE,
3184 EL_EMC_GATE_7_GRAY_ACTIVE,
3185 EL_EMC_GATE_8_GRAY_ACTIVE,
3187 EL_DC_GATE_WHITE_GRAY,
3188 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3192 // same elements as in 'ep_passable_inside'
3197 EL_SP_PORT_HORIZONTAL,
3198 EL_SP_PORT_VERTICAL,
3200 EL_SP_GRAVITY_PORT_LEFT,
3201 EL_SP_GRAVITY_PORT_RIGHT,
3202 EL_SP_GRAVITY_PORT_UP,
3203 EL_SP_GRAVITY_PORT_DOWN,
3204 EL_SP_GRAVITY_ON_PORT_LEFT,
3205 EL_SP_GRAVITY_ON_PORT_RIGHT,
3206 EL_SP_GRAVITY_ON_PORT_UP,
3207 EL_SP_GRAVITY_ON_PORT_DOWN,
3208 EL_SP_GRAVITY_OFF_PORT_LEFT,
3209 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3210 EL_SP_GRAVITY_OFF_PORT_UP,
3211 EL_SP_GRAVITY_OFF_PORT_DOWN,
3216 static int ep_throwable[] =
3221 static int ep_can_explode[] =
3223 // same elements as in 'ep_explodes_impact'
3228 // same elements as in 'ep_explodes_smashed'
3234 // elements that can explode by explosion or by dragonfire
3238 EL_EM_DYNAMITE_ACTIVE,
3239 EL_DYNABOMB_PLAYER_1_ACTIVE,
3240 EL_DYNABOMB_PLAYER_2_ACTIVE,
3241 EL_DYNABOMB_PLAYER_3_ACTIVE,
3242 EL_DYNABOMB_PLAYER_4_ACTIVE,
3243 EL_DYNABOMB_INCREASE_NUMBER,
3244 EL_DYNABOMB_INCREASE_SIZE,
3245 EL_DYNABOMB_INCREASE_POWER,
3246 EL_SP_DISK_RED_ACTIVE,
3254 // elements that can explode only by explosion
3260 static int ep_gravity_reachable[] =
3266 EL_INVISIBLE_SAND_ACTIVE,
3271 EL_SP_PORT_HORIZONTAL,
3272 EL_SP_PORT_VERTICAL,
3274 EL_SP_GRAVITY_PORT_LEFT,
3275 EL_SP_GRAVITY_PORT_RIGHT,
3276 EL_SP_GRAVITY_PORT_UP,
3277 EL_SP_GRAVITY_PORT_DOWN,
3278 EL_SP_GRAVITY_ON_PORT_LEFT,
3279 EL_SP_GRAVITY_ON_PORT_RIGHT,
3280 EL_SP_GRAVITY_ON_PORT_UP,
3281 EL_SP_GRAVITY_ON_PORT_DOWN,
3282 EL_SP_GRAVITY_OFF_PORT_LEFT,
3283 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3284 EL_SP_GRAVITY_OFF_PORT_UP,
3285 EL_SP_GRAVITY_OFF_PORT_DOWN,
3291 static int ep_player[] =
3298 EL_SOKOBAN_FIELD_PLAYER,
3304 static int ep_can_pass_magic_wall[] =
3318 static int ep_can_pass_dc_magic_wall[] =
3334 static int ep_switchable[] =
3338 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3339 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3340 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3341 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3342 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3343 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3344 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3345 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3346 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3347 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3348 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3349 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3350 EL_SWITCHGATE_SWITCH_UP,
3351 EL_SWITCHGATE_SWITCH_DOWN,
3352 EL_DC_SWITCHGATE_SWITCH_UP,
3353 EL_DC_SWITCHGATE_SWITCH_DOWN,
3355 EL_LIGHT_SWITCH_ACTIVE,
3357 EL_DC_TIMEGATE_SWITCH,
3358 EL_BALLOON_SWITCH_LEFT,
3359 EL_BALLOON_SWITCH_RIGHT,
3360 EL_BALLOON_SWITCH_UP,
3361 EL_BALLOON_SWITCH_DOWN,
3362 EL_BALLOON_SWITCH_ANY,
3363 EL_BALLOON_SWITCH_NONE,
3366 EL_EMC_MAGIC_BALL_SWITCH,
3367 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3372 static int ep_bd_element[] =
3406 static int ep_sp_element[] =
3408 // should always be valid
3411 // standard classic Supaplex elements
3418 EL_SP_HARDWARE_GRAY,
3426 EL_SP_GRAVITY_PORT_RIGHT,
3427 EL_SP_GRAVITY_PORT_DOWN,
3428 EL_SP_GRAVITY_PORT_LEFT,
3429 EL_SP_GRAVITY_PORT_UP,
3434 EL_SP_PORT_VERTICAL,
3435 EL_SP_PORT_HORIZONTAL,
3441 EL_SP_HARDWARE_BASE_1,
3442 EL_SP_HARDWARE_GREEN,
3443 EL_SP_HARDWARE_BLUE,
3445 EL_SP_HARDWARE_YELLOW,
3446 EL_SP_HARDWARE_BASE_2,
3447 EL_SP_HARDWARE_BASE_3,
3448 EL_SP_HARDWARE_BASE_4,
3449 EL_SP_HARDWARE_BASE_5,
3450 EL_SP_HARDWARE_BASE_6,
3454 // additional elements that appeared in newer Supaplex levels
3457 // additional gravity port elements (not switching, but setting gravity)
3458 EL_SP_GRAVITY_ON_PORT_LEFT,
3459 EL_SP_GRAVITY_ON_PORT_RIGHT,
3460 EL_SP_GRAVITY_ON_PORT_UP,
3461 EL_SP_GRAVITY_ON_PORT_DOWN,
3462 EL_SP_GRAVITY_OFF_PORT_LEFT,
3463 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3464 EL_SP_GRAVITY_OFF_PORT_UP,
3465 EL_SP_GRAVITY_OFF_PORT_DOWN,
3467 // more than one Murphy in a level results in an inactive clone
3470 // runtime Supaplex elements
3471 EL_SP_DISK_RED_ACTIVE,
3472 EL_SP_TERMINAL_ACTIVE,
3473 EL_SP_BUGGY_BASE_ACTIVATING,
3474 EL_SP_BUGGY_BASE_ACTIVE,
3481 static int ep_sb_element[] =
3486 EL_SOKOBAN_FIELD_EMPTY,
3487 EL_SOKOBAN_FIELD_FULL,
3488 EL_SOKOBAN_FIELD_PLAYER,
3493 EL_INVISIBLE_STEELWALL,
3498 static int ep_gem[] =
3510 static int ep_food_dark_yamyam[] =
3538 static int ep_food_penguin[] =
3552 static int ep_food_pig[] =
3564 static int ep_historic_wall[] =
3575 EL_GATE_1_GRAY_ACTIVE,
3576 EL_GATE_2_GRAY_ACTIVE,
3577 EL_GATE_3_GRAY_ACTIVE,
3578 EL_GATE_4_GRAY_ACTIVE,
3587 EL_EM_GATE_1_GRAY_ACTIVE,
3588 EL_EM_GATE_2_GRAY_ACTIVE,
3589 EL_EM_GATE_3_GRAY_ACTIVE,
3590 EL_EM_GATE_4_GRAY_ACTIVE,
3597 EL_EXPANDABLE_WALL_HORIZONTAL,
3598 EL_EXPANDABLE_WALL_VERTICAL,
3599 EL_EXPANDABLE_WALL_ANY,
3600 EL_EXPANDABLE_WALL_GROWING,
3601 EL_BD_EXPANDABLE_WALL,
3608 EL_SP_HARDWARE_GRAY,
3609 EL_SP_HARDWARE_GREEN,
3610 EL_SP_HARDWARE_BLUE,
3612 EL_SP_HARDWARE_YELLOW,
3613 EL_SP_HARDWARE_BASE_1,
3614 EL_SP_HARDWARE_BASE_2,
3615 EL_SP_HARDWARE_BASE_3,
3616 EL_SP_HARDWARE_BASE_4,
3617 EL_SP_HARDWARE_BASE_5,
3618 EL_SP_HARDWARE_BASE_6,
3620 EL_SP_TERMINAL_ACTIVE,
3623 EL_INVISIBLE_STEELWALL,
3624 EL_INVISIBLE_STEELWALL_ACTIVE,
3626 EL_INVISIBLE_WALL_ACTIVE,
3627 EL_STEELWALL_SLIPPERY,
3644 static int ep_historic_solid[] =
3648 EL_EXPANDABLE_WALL_HORIZONTAL,
3649 EL_EXPANDABLE_WALL_VERTICAL,
3650 EL_EXPANDABLE_WALL_ANY,
3651 EL_BD_EXPANDABLE_WALL,
3664 EL_QUICKSAND_FILLING,
3665 EL_QUICKSAND_EMPTYING,
3667 EL_MAGIC_WALL_ACTIVE,
3668 EL_MAGIC_WALL_EMPTYING,
3669 EL_MAGIC_WALL_FILLING,
3673 EL_BD_MAGIC_WALL_ACTIVE,
3674 EL_BD_MAGIC_WALL_EMPTYING,
3675 EL_BD_MAGIC_WALL_FULL,
3676 EL_BD_MAGIC_WALL_FILLING,
3677 EL_BD_MAGIC_WALL_DEAD,
3686 EL_SP_TERMINAL_ACTIVE,
3690 EL_INVISIBLE_WALL_ACTIVE,
3691 EL_SWITCHGATE_SWITCH_UP,
3692 EL_SWITCHGATE_SWITCH_DOWN,
3694 EL_TIMEGATE_SWITCH_ACTIVE,
3706 // the following elements are a direct copy of "indestructible" elements,
3707 // except "EL_ACID", which is "indestructible", but not "solid"!
3712 EL_ACID_POOL_TOPLEFT,
3713 EL_ACID_POOL_TOPRIGHT,
3714 EL_ACID_POOL_BOTTOMLEFT,
3715 EL_ACID_POOL_BOTTOM,
3716 EL_ACID_POOL_BOTTOMRIGHT,
3717 EL_SP_HARDWARE_GRAY,
3718 EL_SP_HARDWARE_GREEN,
3719 EL_SP_HARDWARE_BLUE,
3721 EL_SP_HARDWARE_YELLOW,
3722 EL_SP_HARDWARE_BASE_1,
3723 EL_SP_HARDWARE_BASE_2,
3724 EL_SP_HARDWARE_BASE_3,
3725 EL_SP_HARDWARE_BASE_4,
3726 EL_SP_HARDWARE_BASE_5,
3727 EL_SP_HARDWARE_BASE_6,
3728 EL_INVISIBLE_STEELWALL,
3729 EL_INVISIBLE_STEELWALL_ACTIVE,
3730 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3731 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3732 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3733 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3734 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3735 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3736 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3737 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3738 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3739 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3740 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3741 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3743 EL_LIGHT_SWITCH_ACTIVE,
3744 EL_SIGN_EXCLAMATION,
3745 EL_SIGN_RADIOACTIVITY,
3752 EL_SIGN_ENTRY_FORBIDDEN,
3753 EL_SIGN_EMERGENCY_EXIT,
3761 EL_STEEL_EXIT_CLOSED,
3763 EL_STEEL_EXIT_OPENING,
3764 EL_STEEL_EXIT_CLOSING,
3765 EL_EM_STEEL_EXIT_CLOSED,
3766 EL_EM_STEEL_EXIT_OPEN,
3767 EL_EM_STEEL_EXIT_OPENING,
3768 EL_EM_STEEL_EXIT_CLOSING,
3769 EL_DC_STEELWALL_1_LEFT,
3770 EL_DC_STEELWALL_1_RIGHT,
3771 EL_DC_STEELWALL_1_TOP,
3772 EL_DC_STEELWALL_1_BOTTOM,
3773 EL_DC_STEELWALL_1_HORIZONTAL,
3774 EL_DC_STEELWALL_1_VERTICAL,
3775 EL_DC_STEELWALL_1_TOPLEFT,
3776 EL_DC_STEELWALL_1_TOPRIGHT,
3777 EL_DC_STEELWALL_1_BOTTOMLEFT,
3778 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3779 EL_DC_STEELWALL_1_TOPLEFT_2,
3780 EL_DC_STEELWALL_1_TOPRIGHT_2,
3781 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3782 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3783 EL_DC_STEELWALL_2_LEFT,
3784 EL_DC_STEELWALL_2_RIGHT,
3785 EL_DC_STEELWALL_2_TOP,
3786 EL_DC_STEELWALL_2_BOTTOM,
3787 EL_DC_STEELWALL_2_HORIZONTAL,
3788 EL_DC_STEELWALL_2_VERTICAL,
3789 EL_DC_STEELWALL_2_MIDDLE,
3790 EL_DC_STEELWALL_2_SINGLE,
3791 EL_STEELWALL_SLIPPERY,
3805 EL_GATE_1_GRAY_ACTIVE,
3806 EL_GATE_2_GRAY_ACTIVE,
3807 EL_GATE_3_GRAY_ACTIVE,
3808 EL_GATE_4_GRAY_ACTIVE,
3817 EL_EM_GATE_1_GRAY_ACTIVE,
3818 EL_EM_GATE_2_GRAY_ACTIVE,
3819 EL_EM_GATE_3_GRAY_ACTIVE,
3820 EL_EM_GATE_4_GRAY_ACTIVE,
3829 EL_EMC_GATE_5_GRAY_ACTIVE,
3830 EL_EMC_GATE_6_GRAY_ACTIVE,
3831 EL_EMC_GATE_7_GRAY_ACTIVE,
3832 EL_EMC_GATE_8_GRAY_ACTIVE,
3834 EL_DC_GATE_WHITE_GRAY,
3835 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3836 EL_DC_GATE_FAKE_GRAY,
3838 EL_SWITCHGATE_OPENING,
3839 EL_SWITCHGATE_CLOSED,
3840 EL_SWITCHGATE_CLOSING,
3841 EL_DC_SWITCHGATE_SWITCH_UP,
3842 EL_DC_SWITCHGATE_SWITCH_DOWN,
3844 EL_TIMEGATE_OPENING,
3846 EL_TIMEGATE_CLOSING,
3847 EL_DC_TIMEGATE_SWITCH,
3848 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3852 EL_TUBE_VERTICAL_LEFT,
3853 EL_TUBE_VERTICAL_RIGHT,
3854 EL_TUBE_HORIZONTAL_UP,
3855 EL_TUBE_HORIZONTAL_DOWN,
3860 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3861 EL_EXPANDABLE_STEELWALL_VERTICAL,
3862 EL_EXPANDABLE_STEELWALL_ANY,
3867 static int ep_classic_enemy[] =
3884 static int ep_belt[] =
3886 EL_CONVEYOR_BELT_1_LEFT,
3887 EL_CONVEYOR_BELT_1_MIDDLE,
3888 EL_CONVEYOR_BELT_1_RIGHT,
3889 EL_CONVEYOR_BELT_2_LEFT,
3890 EL_CONVEYOR_BELT_2_MIDDLE,
3891 EL_CONVEYOR_BELT_2_RIGHT,
3892 EL_CONVEYOR_BELT_3_LEFT,
3893 EL_CONVEYOR_BELT_3_MIDDLE,
3894 EL_CONVEYOR_BELT_3_RIGHT,
3895 EL_CONVEYOR_BELT_4_LEFT,
3896 EL_CONVEYOR_BELT_4_MIDDLE,
3897 EL_CONVEYOR_BELT_4_RIGHT,
3902 static int ep_belt_active[] =
3904 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3905 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3906 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3907 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3908 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3909 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3910 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3911 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3912 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3913 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3914 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3915 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3920 static int ep_belt_switch[] =
3922 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3923 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3924 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3925 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3926 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3927 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3928 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3929 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3930 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3931 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3932 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3933 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3938 static int ep_tube[] =
3945 EL_TUBE_HORIZONTAL_UP,
3946 EL_TUBE_HORIZONTAL_DOWN,
3948 EL_TUBE_VERTICAL_LEFT,
3949 EL_TUBE_VERTICAL_RIGHT,
3955 static int ep_acid_pool[] =
3957 EL_ACID_POOL_TOPLEFT,
3958 EL_ACID_POOL_TOPRIGHT,
3959 EL_ACID_POOL_BOTTOMLEFT,
3960 EL_ACID_POOL_BOTTOM,
3961 EL_ACID_POOL_BOTTOMRIGHT,
3966 static int ep_keygate[] =
3976 EL_GATE_1_GRAY_ACTIVE,
3977 EL_GATE_2_GRAY_ACTIVE,
3978 EL_GATE_3_GRAY_ACTIVE,
3979 EL_GATE_4_GRAY_ACTIVE,
3988 EL_EM_GATE_1_GRAY_ACTIVE,
3989 EL_EM_GATE_2_GRAY_ACTIVE,
3990 EL_EM_GATE_3_GRAY_ACTIVE,
3991 EL_EM_GATE_4_GRAY_ACTIVE,
4000 EL_EMC_GATE_5_GRAY_ACTIVE,
4001 EL_EMC_GATE_6_GRAY_ACTIVE,
4002 EL_EMC_GATE_7_GRAY_ACTIVE,
4003 EL_EMC_GATE_8_GRAY_ACTIVE,
4005 EL_DC_GATE_WHITE_GRAY,
4006 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4011 static int ep_amoeboid[] =
4023 static int ep_amoebalive[] =
4034 static int ep_has_editor_content[] =
4040 EL_SOKOBAN_FIELD_PLAYER,
4057 static int ep_can_turn_each_move[] =
4059 // !!! do something with this one !!!
4063 static int ep_can_grow[] =
4077 static int ep_active_bomb[] =
4080 EL_EM_DYNAMITE_ACTIVE,
4081 EL_DYNABOMB_PLAYER_1_ACTIVE,
4082 EL_DYNABOMB_PLAYER_2_ACTIVE,
4083 EL_DYNABOMB_PLAYER_3_ACTIVE,
4084 EL_DYNABOMB_PLAYER_4_ACTIVE,
4085 EL_SP_DISK_RED_ACTIVE,
4090 static int ep_inactive[] =
4100 EL_QUICKSAND_FAST_EMPTY,
4123 EL_GATE_1_GRAY_ACTIVE,
4124 EL_GATE_2_GRAY_ACTIVE,
4125 EL_GATE_3_GRAY_ACTIVE,
4126 EL_GATE_4_GRAY_ACTIVE,
4135 EL_EM_GATE_1_GRAY_ACTIVE,
4136 EL_EM_GATE_2_GRAY_ACTIVE,
4137 EL_EM_GATE_3_GRAY_ACTIVE,
4138 EL_EM_GATE_4_GRAY_ACTIVE,
4147 EL_EMC_GATE_5_GRAY_ACTIVE,
4148 EL_EMC_GATE_6_GRAY_ACTIVE,
4149 EL_EMC_GATE_7_GRAY_ACTIVE,
4150 EL_EMC_GATE_8_GRAY_ACTIVE,
4152 EL_DC_GATE_WHITE_GRAY,
4153 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4154 EL_DC_GATE_FAKE_GRAY,
4157 EL_INVISIBLE_STEELWALL,
4165 EL_WALL_EMERALD_YELLOW,
4166 EL_DYNABOMB_INCREASE_NUMBER,
4167 EL_DYNABOMB_INCREASE_SIZE,
4168 EL_DYNABOMB_INCREASE_POWER,
4172 EL_SOKOBAN_FIELD_EMPTY,
4173 EL_SOKOBAN_FIELD_FULL,
4174 EL_WALL_EMERALD_RED,
4175 EL_WALL_EMERALD_PURPLE,
4176 EL_ACID_POOL_TOPLEFT,
4177 EL_ACID_POOL_TOPRIGHT,
4178 EL_ACID_POOL_BOTTOMLEFT,
4179 EL_ACID_POOL_BOTTOM,
4180 EL_ACID_POOL_BOTTOMRIGHT,
4184 EL_BD_MAGIC_WALL_DEAD,
4186 EL_DC_MAGIC_WALL_DEAD,
4187 EL_AMOEBA_TO_DIAMOND,
4195 EL_SP_GRAVITY_PORT_RIGHT,
4196 EL_SP_GRAVITY_PORT_DOWN,
4197 EL_SP_GRAVITY_PORT_LEFT,
4198 EL_SP_GRAVITY_PORT_UP,
4199 EL_SP_PORT_HORIZONTAL,
4200 EL_SP_PORT_VERTICAL,
4211 EL_SP_HARDWARE_GRAY,
4212 EL_SP_HARDWARE_GREEN,
4213 EL_SP_HARDWARE_BLUE,
4215 EL_SP_HARDWARE_YELLOW,
4216 EL_SP_HARDWARE_BASE_1,
4217 EL_SP_HARDWARE_BASE_2,
4218 EL_SP_HARDWARE_BASE_3,
4219 EL_SP_HARDWARE_BASE_4,
4220 EL_SP_HARDWARE_BASE_5,
4221 EL_SP_HARDWARE_BASE_6,
4222 EL_SP_GRAVITY_ON_PORT_LEFT,
4223 EL_SP_GRAVITY_ON_PORT_RIGHT,
4224 EL_SP_GRAVITY_ON_PORT_UP,
4225 EL_SP_GRAVITY_ON_PORT_DOWN,
4226 EL_SP_GRAVITY_OFF_PORT_LEFT,
4227 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4228 EL_SP_GRAVITY_OFF_PORT_UP,
4229 EL_SP_GRAVITY_OFF_PORT_DOWN,
4230 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4231 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4232 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4233 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4234 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4235 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4236 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4237 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4238 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4239 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4240 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4241 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4242 EL_SIGN_EXCLAMATION,
4243 EL_SIGN_RADIOACTIVITY,
4250 EL_SIGN_ENTRY_FORBIDDEN,
4251 EL_SIGN_EMERGENCY_EXIT,
4259 EL_DC_STEELWALL_1_LEFT,
4260 EL_DC_STEELWALL_1_RIGHT,
4261 EL_DC_STEELWALL_1_TOP,
4262 EL_DC_STEELWALL_1_BOTTOM,
4263 EL_DC_STEELWALL_1_HORIZONTAL,
4264 EL_DC_STEELWALL_1_VERTICAL,
4265 EL_DC_STEELWALL_1_TOPLEFT,
4266 EL_DC_STEELWALL_1_TOPRIGHT,
4267 EL_DC_STEELWALL_1_BOTTOMLEFT,
4268 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4269 EL_DC_STEELWALL_1_TOPLEFT_2,
4270 EL_DC_STEELWALL_1_TOPRIGHT_2,
4271 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4272 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4273 EL_DC_STEELWALL_2_LEFT,
4274 EL_DC_STEELWALL_2_RIGHT,
4275 EL_DC_STEELWALL_2_TOP,
4276 EL_DC_STEELWALL_2_BOTTOM,
4277 EL_DC_STEELWALL_2_HORIZONTAL,
4278 EL_DC_STEELWALL_2_VERTICAL,
4279 EL_DC_STEELWALL_2_MIDDLE,
4280 EL_DC_STEELWALL_2_SINGLE,
4281 EL_STEELWALL_SLIPPERY,
4286 EL_EMC_WALL_SLIPPERY_1,
4287 EL_EMC_WALL_SLIPPERY_2,
4288 EL_EMC_WALL_SLIPPERY_3,
4289 EL_EMC_WALL_SLIPPERY_4,
4310 static int ep_em_slippery_wall[] =
4315 static int ep_gfx_crumbled[] =
4326 static int ep_editor_cascade_active[] =
4328 EL_INTERNAL_CASCADE_BD_ACTIVE,
4329 EL_INTERNAL_CASCADE_EM_ACTIVE,
4330 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4331 EL_INTERNAL_CASCADE_RND_ACTIVE,
4332 EL_INTERNAL_CASCADE_SB_ACTIVE,
4333 EL_INTERNAL_CASCADE_SP_ACTIVE,
4334 EL_INTERNAL_CASCADE_DC_ACTIVE,
4335 EL_INTERNAL_CASCADE_DX_ACTIVE,
4336 EL_INTERNAL_CASCADE_MM_ACTIVE,
4337 EL_INTERNAL_CASCADE_DF_ACTIVE,
4338 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4339 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4340 EL_INTERNAL_CASCADE_CE_ACTIVE,
4341 EL_INTERNAL_CASCADE_GE_ACTIVE,
4342 EL_INTERNAL_CASCADE_REF_ACTIVE,
4343 EL_INTERNAL_CASCADE_USER_ACTIVE,
4344 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4349 static int ep_editor_cascade_inactive[] =
4351 EL_INTERNAL_CASCADE_BD,
4352 EL_INTERNAL_CASCADE_EM,
4353 EL_INTERNAL_CASCADE_EMC,
4354 EL_INTERNAL_CASCADE_RND,
4355 EL_INTERNAL_CASCADE_SB,
4356 EL_INTERNAL_CASCADE_SP,
4357 EL_INTERNAL_CASCADE_DC,
4358 EL_INTERNAL_CASCADE_DX,
4359 EL_INTERNAL_CASCADE_MM,
4360 EL_INTERNAL_CASCADE_DF,
4361 EL_INTERNAL_CASCADE_CHARS,
4362 EL_INTERNAL_CASCADE_STEEL_CHARS,
4363 EL_INTERNAL_CASCADE_CE,
4364 EL_INTERNAL_CASCADE_GE,
4365 EL_INTERNAL_CASCADE_REF,
4366 EL_INTERNAL_CASCADE_USER,
4367 EL_INTERNAL_CASCADE_DYNAMIC,
4372 static int ep_obsolete[] =
4376 EL_EM_KEY_1_FILE_OBSOLETE,
4377 EL_EM_KEY_2_FILE_OBSOLETE,
4378 EL_EM_KEY_3_FILE_OBSOLETE,
4379 EL_EM_KEY_4_FILE_OBSOLETE,
4380 EL_ENVELOPE_OBSOLETE,
4389 } element_properties[] =
4391 { ep_diggable, EP_DIGGABLE },
4392 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4393 { ep_dont_run_into, EP_DONT_RUN_INTO },
4394 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4395 { ep_dont_touch, EP_DONT_TOUCH },
4396 { ep_indestructible, EP_INDESTRUCTIBLE },
4397 { ep_slippery, EP_SLIPPERY },
4398 { ep_can_change, EP_CAN_CHANGE },
4399 { ep_can_move, EP_CAN_MOVE },
4400 { ep_can_fall, EP_CAN_FALL },
4401 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4402 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4403 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4404 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4405 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4406 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4407 { ep_walkable_over, EP_WALKABLE_OVER },
4408 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4409 { ep_walkable_under, EP_WALKABLE_UNDER },
4410 { ep_passable_over, EP_PASSABLE_OVER },
4411 { ep_passable_inside, EP_PASSABLE_INSIDE },
4412 { ep_passable_under, EP_PASSABLE_UNDER },
4413 { ep_droppable, EP_DROPPABLE },
4414 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4415 { ep_pushable, EP_PUSHABLE },
4416 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4417 { ep_protected, EP_PROTECTED },
4418 { ep_throwable, EP_THROWABLE },
4419 { ep_can_explode, EP_CAN_EXPLODE },
4420 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4422 { ep_player, EP_PLAYER },
4423 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4424 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4425 { ep_switchable, EP_SWITCHABLE },
4426 { ep_bd_element, EP_BD_ELEMENT },
4427 { ep_sp_element, EP_SP_ELEMENT },
4428 { ep_sb_element, EP_SB_ELEMENT },
4430 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4431 { ep_food_penguin, EP_FOOD_PENGUIN },
4432 { ep_food_pig, EP_FOOD_PIG },
4433 { ep_historic_wall, EP_HISTORIC_WALL },
4434 { ep_historic_solid, EP_HISTORIC_SOLID },
4435 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4436 { ep_belt, EP_BELT },
4437 { ep_belt_active, EP_BELT_ACTIVE },
4438 { ep_belt_switch, EP_BELT_SWITCH },
4439 { ep_tube, EP_TUBE },
4440 { ep_acid_pool, EP_ACID_POOL },
4441 { ep_keygate, EP_KEYGATE },
4442 { ep_amoeboid, EP_AMOEBOID },
4443 { ep_amoebalive, EP_AMOEBALIVE },
4444 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4445 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4446 { ep_can_grow, EP_CAN_GROW },
4447 { ep_active_bomb, EP_ACTIVE_BOMB },
4448 { ep_inactive, EP_INACTIVE },
4450 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4452 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4454 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4455 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4457 { ep_obsolete, EP_OBSOLETE },
4464 // always start with reliable default values (element has no properties)
4465 // (but never initialize clipboard elements after the very first time)
4466 // (to be able to use clipboard elements between several levels)
4467 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4468 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4469 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4470 SET_PROPERTY(i, j, FALSE);
4472 // set all base element properties from above array definitions
4473 for (i = 0; element_properties[i].elements != NULL; i++)
4474 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4475 SET_PROPERTY((element_properties[i].elements)[j],
4476 element_properties[i].property, TRUE);
4478 // copy properties to some elements that are only stored in level file
4479 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4480 for (j = 0; copy_properties[j][0] != -1; j++)
4481 if (HAS_PROPERTY(copy_properties[j][0], i))
4482 for (k = 1; k <= 4; k++)
4483 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4485 // set static element properties that are not listed in array definitions
4486 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4487 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4489 clipboard_elements_initialized = TRUE;
4492 void InitElementPropertiesEngine(int engine_version)
4494 static int no_wall_properties[] =
4497 EP_COLLECTIBLE_ONLY,
4499 EP_DONT_COLLIDE_WITH,
4502 EP_CAN_SMASH_PLAYER,
4503 EP_CAN_SMASH_ENEMIES,
4504 EP_CAN_SMASH_EVERYTHING,
4509 EP_FOOD_DARK_YAMYAM,
4525 /* important: after initialization in InitElementPropertiesStatic(), the
4526 elements are not again initialized to a default value; therefore all
4527 changes have to make sure that they leave the element with a defined
4528 property (which means that conditional property changes must be set to
4529 a reliable default value before) */
4531 // resolve group elements
4532 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4533 ResolveGroupElement(EL_GROUP_START + i);
4535 // set all special, combined or engine dependent element properties
4536 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4538 // do not change (already initialized) clipboard elements here
4539 if (IS_CLIPBOARD_ELEMENT(i))
4542 // ---------- INACTIVE ----------------------------------------------------
4543 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4544 i <= EL_CHAR_END) ||
4545 (i >= EL_STEEL_CHAR_START &&
4546 i <= EL_STEEL_CHAR_END)));
4548 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4549 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4550 IS_WALKABLE_INSIDE(i) ||
4551 IS_WALKABLE_UNDER(i)));
4553 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4554 IS_PASSABLE_INSIDE(i) ||
4555 IS_PASSABLE_UNDER(i)));
4557 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4558 IS_PASSABLE_OVER(i)));
4560 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4561 IS_PASSABLE_INSIDE(i)));
4563 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4564 IS_PASSABLE_UNDER(i)));
4566 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4569 // ---------- COLLECTIBLE -------------------------------------------------
4570 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4574 // ---------- SNAPPABLE ---------------------------------------------------
4575 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4576 IS_COLLECTIBLE(i) ||
4580 // ---------- WALL --------------------------------------------------------
4581 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4583 for (j = 0; no_wall_properties[j] != -1; j++)
4584 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4585 i >= EL_FIRST_RUNTIME_UNREAL)
4586 SET_PROPERTY(i, EP_WALL, FALSE);
4588 if (IS_HISTORIC_WALL(i))
4589 SET_PROPERTY(i, EP_WALL, TRUE);
4591 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4592 if (engine_version < VERSION_IDENT(2,2,0,0))
4593 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4595 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4597 !IS_COLLECTIBLE(i)));
4599 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4600 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4601 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4603 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4606 // ---------- EXPLOSION_PROOF ---------------------------------------------
4608 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4609 else if (engine_version < VERSION_IDENT(2,2,0,0))
4610 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4612 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4616 if (IS_CUSTOM_ELEMENT(i))
4618 // these are additional properties which are initially false when set
4620 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4622 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4623 if (DONT_COLLIDE_WITH(i))
4624 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4626 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4627 if (CAN_SMASH_EVERYTHING(i))
4628 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4629 if (CAN_SMASH_ENEMIES(i))
4630 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4633 // ---------- CAN_SMASH ---------------------------------------------------
4634 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4635 CAN_SMASH_ENEMIES(i) ||
4636 CAN_SMASH_EVERYTHING(i)));
4638 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4639 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4640 EXPLODES_BY_FIRE(i)));
4642 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4643 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4644 EXPLODES_SMASHED(i)));
4646 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4647 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4648 EXPLODES_IMPACT(i)));
4650 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4651 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4653 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4654 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4655 i == EL_BLACK_ORB));
4657 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4658 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4660 IS_CUSTOM_ELEMENT(i)));
4662 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4663 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4664 i == EL_SP_ELECTRON));
4666 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4667 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4668 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4669 getMoveIntoAcidProperty(&level, i));
4671 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4672 if (MAYBE_DONT_COLLIDE_WITH(i))
4673 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4674 getDontCollideWithProperty(&level, i));
4676 // ---------- SP_PORT -----------------------------------------------------
4677 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4678 IS_PASSABLE_INSIDE(i)));
4680 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4681 for (j = 0; j < level.num_android_clone_elements; j++)
4682 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4684 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4686 // ---------- CAN_CHANGE --------------------------------------------------
4687 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4688 for (j = 0; j < element_info[i].num_change_pages; j++)
4689 if (element_info[i].change_page[j].can_change)
4690 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4692 // ---------- HAS_ACTION --------------------------------------------------
4693 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4694 for (j = 0; j < element_info[i].num_change_pages; j++)
4695 if (element_info[i].change_page[j].has_action)
4696 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4698 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4699 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4702 // ---------- GFX_CRUMBLED ------------------------------------------------
4703 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4704 element_info[i].crumbled[ACTION_DEFAULT] !=
4705 element_info[i].graphic[ACTION_DEFAULT]);
4707 // ---------- EDITOR_CASCADE ----------------------------------------------
4708 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4709 IS_EDITOR_CASCADE_INACTIVE(i)));
4712 // dynamically adjust element properties according to game engine version
4714 static int ep_em_slippery_wall[] =
4719 EL_EXPANDABLE_WALL_HORIZONTAL,
4720 EL_EXPANDABLE_WALL_VERTICAL,
4721 EL_EXPANDABLE_WALL_ANY,
4722 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4723 EL_EXPANDABLE_STEELWALL_VERTICAL,
4724 EL_EXPANDABLE_STEELWALL_ANY,
4725 EL_EXPANDABLE_STEELWALL_GROWING,
4729 static int ep_em_explodes_by_fire[] =
4732 EL_EM_DYNAMITE_ACTIVE,
4737 // special EM style gems behaviour
4738 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4739 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4740 level.em_slippery_gems);
4742 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4743 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4744 (level.em_slippery_gems &&
4745 engine_version > VERSION_IDENT(2,0,1,0)));
4747 // special EM style explosion behaviour regarding chain reactions
4748 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4749 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4750 level.em_explodes_by_fire);
4753 // this is needed because some graphics depend on element properties
4754 if (game_status == GAME_MODE_PLAYING)
4755 InitElementGraphicInfo();
4758 void InitElementPropertiesGfxElement(void)
4762 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4764 struct ElementInfo *ei = &element_info[i];
4766 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4770 static void InitGlobal(void)
4775 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4777 // check if element_name_info entry defined for each element in "main.h"
4778 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4779 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4781 element_info[i].token_name = element_name_info[i].token_name;
4782 element_info[i].class_name = element_name_info[i].class_name;
4783 element_info[i].editor_description= element_name_info[i].editor_description;
4786 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4788 // check if global_anim_name_info defined for each entry in "main.h"
4789 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4790 global_anim_name_info[i].token_name == NULL)
4791 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4793 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4796 // create hash from image config list
4797 image_config_hash = newSetupFileHash();
4798 for (i = 0; image_config[i].token != NULL; i++)
4799 setHashEntry(image_config_hash,
4800 image_config[i].token,
4801 image_config[i].value);
4803 // create hash from element token list
4804 element_token_hash = newSetupFileHash();
4805 for (i = 0; element_name_info[i].token_name != NULL; i++)
4806 setHashEntry(element_token_hash,
4807 element_name_info[i].token_name,
4810 // create hash from graphic token list
4811 graphic_token_hash = newSetupFileHash();
4812 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4813 if (strSuffix(image_config[i].value, ".png") ||
4814 strSuffix(image_config[i].value, ".pcx") ||
4815 strSuffix(image_config[i].value, ".wav") ||
4816 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4817 setHashEntry(graphic_token_hash,
4818 image_config[i].token,
4819 int2str(graphic++, 0));
4821 // create hash from font token list
4822 font_token_hash = newSetupFileHash();
4823 for (i = 0; font_info[i].token_name != NULL; i++)
4824 setHashEntry(font_token_hash,
4825 font_info[i].token_name,
4828 // set default filenames for all cloned graphics in static configuration
4829 for (i = 0; image_config[i].token != NULL; i++)
4831 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4833 char *token = image_config[i].token;
4834 char *token_clone_from = getStringCat2(token, ".clone_from");
4835 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4837 if (token_cloned != NULL)
4839 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4841 if (value_cloned != NULL)
4843 // set default filename in static configuration
4844 image_config[i].value = value_cloned;
4846 // set default filename in image config hash
4847 setHashEntry(image_config_hash, token, value_cloned);
4851 free(token_clone_from);
4855 // always start with reliable default values (all elements)
4856 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4857 ActiveElement[i] = i;
4859 // now add all entries that have an active state (active elements)
4860 for (i = 0; element_with_active_state[i].element != -1; i++)
4862 int element = element_with_active_state[i].element;
4863 int element_active = element_with_active_state[i].element_active;
4865 ActiveElement[element] = element_active;
4868 // always start with reliable default values (all buttons)
4869 for (i = 0; i < NUM_IMAGE_FILES; i++)
4870 ActiveButton[i] = i;
4872 // now add all entries that have an active state (active buttons)
4873 for (i = 0; button_with_active_state[i].button != -1; i++)
4875 int button = button_with_active_state[i].button;
4876 int button_active = button_with_active_state[i].button_active;
4878 ActiveButton[button] = button_active;
4881 // always start with reliable default values (all fonts)
4882 for (i = 0; i < NUM_FONTS; i++)
4885 // now add all entries that have an active state (active fonts)
4886 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4888 int font = font_with_active_state[i].font_nr;
4889 int font_active = font_with_active_state[i].font_nr_active;
4891 ActiveFont[font] = font_active;
4894 global.autoplay_leveldir = NULL;
4895 global.convert_leveldir = NULL;
4896 global.create_images_dir = NULL;
4898 global.frames_per_second = 0;
4899 global.show_frames_per_second = FALSE;
4901 global.border_status = GAME_MODE_LOADING;
4902 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4904 global.use_envelope_request = FALSE;
4907 static void Execute_Command(char *command)
4911 if (strEqual(command, "print graphicsinfo.conf"))
4913 Print("# You can configure additional/alternative image files here.\n");
4914 Print("# (The entries below are default and therefore commented out.)\n");
4916 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4918 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4921 for (i = 0; image_config[i].token != NULL; i++)
4922 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4923 image_config[i].value));
4927 else if (strEqual(command, "print soundsinfo.conf"))
4929 Print("# You can configure additional/alternative sound files here.\n");
4930 Print("# (The entries below are default and therefore commented out.)\n");
4932 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4934 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4937 for (i = 0; sound_config[i].token != NULL; i++)
4938 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4939 sound_config[i].value));
4943 else if (strEqual(command, "print musicinfo.conf"))
4945 Print("# You can configure additional/alternative music files here.\n");
4946 Print("# (The entries below are default and therefore commented out.)\n");
4948 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4950 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4953 for (i = 0; music_config[i].token != NULL; i++)
4954 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4955 music_config[i].value));
4959 else if (strEqual(command, "print editorsetup.conf"))
4961 Print("# You can configure your personal editor element list here.\n");
4962 Print("# (The entries below are default and therefore commented out.)\n");
4965 // this is needed to be able to check element list for cascade elements
4966 InitElementPropertiesStatic();
4967 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4969 PrintEditorElementList();
4973 else if (strEqual(command, "print helpanim.conf"))
4975 Print("# You can configure different element help animations here.\n");
4976 Print("# (The entries below are default and therefore commented out.)\n");
4979 for (i = 0; helpanim_config[i].token != NULL; i++)
4981 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4982 helpanim_config[i].value));
4984 if (strEqual(helpanim_config[i].token, "end"))
4990 else if (strEqual(command, "print helptext.conf"))
4992 Print("# You can configure different element help text here.\n");
4993 Print("# (The entries below are default and therefore commented out.)\n");
4996 for (i = 0; helptext_config[i].token != NULL; i++)
4997 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4998 helptext_config[i].value));
5002 else if (strPrefix(command, "dump level "))
5004 char *filename = &command[11];
5006 if (!fileExists(filename))
5007 Error(ERR_EXIT, "cannot open file '%s'", filename);
5009 LoadLevelFromFilename(&level, filename);
5014 else if (strPrefix(command, "dump tape "))
5016 char *filename = &command[10];
5018 if (!fileExists(filename))
5019 Error(ERR_EXIT, "cannot open file '%s'", filename);
5021 LoadTapeFromFilename(filename);
5026 else if (strPrefix(command, "autotest ") ||
5027 strPrefix(command, "autoplay ") ||
5028 strPrefix(command, "autoffwd ") ||
5029 strPrefix(command, "autowarp "))
5031 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5033 global.autoplay_mode =
5034 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5035 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5036 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5037 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5038 AUTOPLAY_MODE_NONE);
5040 while (*str_ptr != '\0') // continue parsing string
5042 // cut leading whitespace from string, replace it by string terminator
5043 while (*str_ptr == ' ' || *str_ptr == '\t')
5046 if (*str_ptr == '\0') // end of string reached
5049 if (global.autoplay_leveldir == NULL) // read level set string
5051 global.autoplay_leveldir = str_ptr;
5052 global.autoplay_all = TRUE; // default: play all tapes
5054 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5055 global.autoplay_level[i] = FALSE;
5057 else // read level number string
5059 int level_nr = atoi(str_ptr); // get level_nr value
5061 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5062 global.autoplay_level[level_nr] = TRUE;
5064 global.autoplay_all = FALSE;
5067 // advance string pointer to the next whitespace (or end of string)
5068 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5072 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5073 program.headless = TRUE;
5075 else if (strPrefix(command, "convert "))
5077 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5078 char *str_ptr = strchr(str_copy, ' ');
5080 global.convert_leveldir = str_copy;
5081 global.convert_level_nr = -1;
5083 if (str_ptr != NULL) // level number follows
5085 *str_ptr++ = '\0'; // terminate leveldir string
5086 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5089 program.headless = TRUE;
5091 else if (strPrefix(command, "create images "))
5093 global.create_images_dir = getStringCopy(&command[14]);
5095 if (access(global.create_images_dir, W_OK) != 0)
5096 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5097 global.create_images_dir);
5099 else if (strPrefix(command, "create CE image "))
5101 CreateCustomElementImages(&command[16]);
5107 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5110 // disable networking if any valid command was recognized
5111 options.network = setup.network_mode = FALSE;
5114 static void InitSetup(void)
5116 LoadSetup(); // global setup info
5117 LoadSetup_AutoSetup(); // global auto setup info
5119 // set some options from setup file
5121 if (setup.options.verbose)
5122 options.verbose = TRUE;
5124 if (setup.debug.show_frames_per_second)
5125 global.show_frames_per_second = TRUE;
5128 static void InitGameInfo(void)
5130 game.restart_level = FALSE;
5131 game.restart_game_message = NULL;
5132 game.request_active = FALSE;
5135 static void InitPlayerInfo(void)
5139 // choose default local player
5140 local_player = &stored_player[0];
5142 for (i = 0; i < MAX_PLAYERS; i++)
5144 stored_player[i].connected_locally = FALSE;
5145 stored_player[i].connected_network = FALSE;
5148 local_player->connected_locally = TRUE;
5151 static void InitArtworkInfo(void)
5156 static char *get_string_in_brackets(char *string)
5158 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5160 sprintf(string_in_brackets, "[%s]", string);
5162 return string_in_brackets;
5165 static char *get_level_id_suffix(int id_nr)
5167 char *id_suffix = checked_malloc(1 + 3 + 1);
5169 if (id_nr < 0 || id_nr > 999)
5172 sprintf(id_suffix, ".%03d", id_nr);
5177 static void InitArtworkConfig(void)
5179 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5181 NUM_GLOBAL_ANIM_TOKENS + 1];
5182 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5183 NUM_GLOBAL_ANIM_TOKENS + 1];
5184 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5185 NUM_GLOBAL_ANIM_TOKENS + 1];
5186 static char *action_id_suffix[NUM_ACTIONS + 1];
5187 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5188 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5189 static char *level_id_suffix[MAX_LEVELS + 1];
5190 static char *dummy[1] = { NULL };
5191 static char *ignore_generic_tokens[] =
5196 "program_copyright",
5201 static char **ignore_image_tokens;
5202 static char **ignore_sound_tokens;
5203 static char **ignore_music_tokens;
5204 int num_ignore_generic_tokens;
5205 int num_ignore_image_tokens;
5206 int num_ignore_sound_tokens;
5207 int num_ignore_music_tokens;
5210 // dynamically determine list of generic tokens to be ignored
5211 num_ignore_generic_tokens = 0;
5212 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5213 num_ignore_generic_tokens++;
5215 // dynamically determine list of image tokens to be ignored
5216 num_ignore_image_tokens = num_ignore_generic_tokens;
5217 for (i = 0; image_config_vars[i].token != NULL; i++)
5218 num_ignore_image_tokens++;
5219 ignore_image_tokens =
5220 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5221 for (i = 0; i < num_ignore_generic_tokens; i++)
5222 ignore_image_tokens[i] = ignore_generic_tokens[i];
5223 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5224 ignore_image_tokens[num_ignore_generic_tokens + i] =
5225 image_config_vars[i].token;
5226 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5228 // dynamically determine list of sound tokens to be ignored
5229 num_ignore_sound_tokens = num_ignore_generic_tokens;
5230 ignore_sound_tokens =
5231 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5232 for (i = 0; i < num_ignore_generic_tokens; i++)
5233 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5234 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5236 // dynamically determine list of music tokens to be ignored
5237 num_ignore_music_tokens = num_ignore_generic_tokens;
5238 ignore_music_tokens =
5239 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5240 for (i = 0; i < num_ignore_generic_tokens; i++)
5241 ignore_music_tokens[i] = ignore_generic_tokens[i];
5242 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5244 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5245 image_id_prefix[i] = element_info[i].token_name;
5246 for (i = 0; i < NUM_FONTS; i++)
5247 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5248 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5249 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5250 global_anim_info[i].token_name;
5251 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5253 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5254 sound_id_prefix[i] = element_info[i].token_name;
5255 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5256 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5257 get_string_in_brackets(element_info[i].class_name);
5258 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5259 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5260 global_anim_info[i].token_name;
5261 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5263 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5264 music_id_prefix[i] = music_prefix_info[i].prefix;
5265 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5266 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5267 global_anim_info[i].token_name;
5268 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5270 for (i = 0; i < NUM_ACTIONS; i++)
5271 action_id_suffix[i] = element_action_info[i].suffix;
5272 action_id_suffix[NUM_ACTIONS] = NULL;
5274 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5275 direction_id_suffix[i] = element_direction_info[i].suffix;
5276 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5278 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5279 special_id_suffix[i] = special_suffix_info[i].suffix;
5280 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5282 for (i = 0; i < MAX_LEVELS; i++)
5283 level_id_suffix[i] = get_level_id_suffix(i);
5284 level_id_suffix[MAX_LEVELS] = NULL;
5286 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5287 image_id_prefix, action_id_suffix, direction_id_suffix,
5288 special_id_suffix, ignore_image_tokens);
5289 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5290 sound_id_prefix, action_id_suffix, dummy,
5291 special_id_suffix, ignore_sound_tokens);
5292 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5293 music_id_prefix, action_id_suffix, special_id_suffix,
5294 level_id_suffix, ignore_music_tokens);
5297 static void InitMixer(void)
5304 static void InitVideoOverlay(void)
5306 // if virtual buttons are not loaded from setup file, repeat initializing
5307 // virtual buttons grid with default values now that video is initialized
5308 if (!setup.touch.grid_initialized)
5311 InitTileCursorInfo();
5315 void InitGfxBuffers(void)
5317 static int win_xsize_last = -1;
5318 static int win_ysize_last = -1;
5320 // create additional image buffers for double-buffering and cross-fading
5322 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5324 // used to temporarily store the backbuffer -- only re-create if changed
5325 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5326 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5328 win_xsize_last = WIN_XSIZE;
5329 win_ysize_last = WIN_YSIZE;
5332 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5333 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5334 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5335 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5337 // initialize screen properties
5338 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5339 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5341 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5342 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5343 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5344 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5345 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5346 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5348 // required if door size definitions have changed
5349 InitGraphicCompatibilityInfo_Doors();
5351 InitGfxBuffers_EM();
5352 InitGfxBuffers_SP();
5355 static void InitGfx(void)
5357 struct GraphicInfo *graphic_info_last = graphic_info;
5358 char *filename_font_initial = NULL;
5359 char *filename_anim_initial = NULL;
5360 Bitmap *bitmap_font_initial = NULL;
5363 // determine settings for initial font (for displaying startup messages)
5364 for (i = 0; image_config[i].token != NULL; i++)
5366 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5368 char font_token[128];
5371 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5372 len_font_token = strlen(font_token);
5374 if (strEqual(image_config[i].token, font_token))
5375 filename_font_initial = image_config[i].value;
5376 else if (strlen(image_config[i].token) > len_font_token &&
5377 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5379 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5380 font_initial[j].src_x = atoi(image_config[i].value);
5381 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5382 font_initial[j].src_y = atoi(image_config[i].value);
5383 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5384 font_initial[j].width = atoi(image_config[i].value);
5385 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5386 font_initial[j].height = atoi(image_config[i].value);
5391 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5393 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5394 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5397 if (filename_font_initial == NULL) // should not happen
5398 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5401 InitGfxCustomArtworkInfo();
5402 InitGfxOtherSettings();
5404 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5406 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5407 font_initial[j].bitmap = bitmap_font_initial;
5409 InitFontGraphicInfo();
5413 DrawInitText("Loading graphics", 120, FC_GREEN);
5415 // initialize settings for busy animation with default values
5416 int parameter[NUM_GFX_ARGS];
5417 for (i = 0; i < NUM_GFX_ARGS; i++)
5418 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5419 image_config_suffix[i].token,
5420 image_config_suffix[i].type);
5422 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5423 int len_anim_token = strlen(anim_token);
5425 // read settings for busy animation from default custom artwork config
5426 char *gfx_config_filename = getPath3(options.graphics_directory,
5428 GRAPHICSINFO_FILENAME);
5430 if (fileExists(gfx_config_filename))
5432 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5434 if (setup_file_hash)
5436 char *filename = getHashEntry(setup_file_hash, anim_token);
5440 filename_anim_initial = getStringCopy(filename);
5442 for (j = 0; image_config_suffix[j].token != NULL; j++)
5444 int type = image_config_suffix[j].type;
5445 char *suffix = image_config_suffix[j].token;
5446 char *token = getStringCat2(anim_token, suffix);
5447 char *value = getHashEntry(setup_file_hash, token);
5449 checked_free(token);
5452 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5456 freeSetupFileHash(setup_file_hash);
5460 if (filename_anim_initial == NULL)
5462 // read settings for busy animation from static default artwork config
5463 for (i = 0; image_config[i].token != NULL; i++)
5465 if (strEqual(image_config[i].token, anim_token))
5466 filename_anim_initial = getStringCopy(image_config[i].value);
5467 else if (strlen(image_config[i].token) > len_anim_token &&
5468 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5470 for (j = 0; image_config_suffix[j].token != NULL; j++)
5472 if (strEqual(&image_config[i].token[len_anim_token],
5473 image_config_suffix[j].token))
5475 get_graphic_parameter_value(image_config[i].value,
5476 image_config_suffix[j].token,
5477 image_config_suffix[j].type);
5483 if (filename_anim_initial == NULL) // should not happen
5484 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5486 anim_initial.bitmaps =
5487 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5489 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5490 LoadCustomImage(filename_anim_initial);
5492 checked_free(filename_anim_initial);
5494 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5496 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5498 graphic_info = graphic_info_last;
5500 init.busy.width = anim_initial.width;
5501 init.busy.height = anim_initial.height;
5503 InitMenuDesignSettings_Static();
5505 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5506 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5507 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5508 InitGfxDrawTileCursorFunction(DrawTileCursor);
5510 gfx.fade_border_source_status = global.border_status;
5511 gfx.fade_border_target_status = global.border_status;
5512 gfx.masked_border_bitmap_ptr = backbuffer;
5514 // use copy of busy animation to prevent change while reloading artwork
5518 static void InitGfxBackground(void)
5520 fieldbuffer = bitmap_db_field;
5521 SetDrawtoField(DRAW_TO_BACKBUFFER);
5523 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5525 redraw_mask = REDRAW_ALL;
5528 static void InitLevelInfo(void)
5530 LoadLevelInfo(); // global level info
5531 LoadLevelSetup_LastSeries(); // last played series info
5532 LoadLevelSetup_SeriesInfo(); // last played level info
5534 if (global.autoplay_leveldir &&
5535 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5537 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5538 global.autoplay_leveldir);
5539 if (leveldir_current == NULL)
5540 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5543 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5546 static void InitLevelArtworkInfo(void)
5548 LoadLevelArtworkInfo();
5551 static void InitImages(void)
5553 print_timestamp_init("InitImages");
5556 printf("::: leveldir_current->identifier == '%s'\n",
5557 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5558 printf("::: leveldir_current->graphics_path == '%s'\n",
5559 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5560 printf("::: leveldir_current->graphics_set == '%s'\n",
5561 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5562 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5563 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5566 setLevelArtworkDir(artwork.gfx_first);
5569 printf("::: leveldir_current->identifier == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5571 printf("::: leveldir_current->graphics_path == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5573 printf("::: leveldir_current->graphics_set == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5575 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5576 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5580 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5581 leveldir_current->identifier,
5582 artwork.gfx_current_identifier,
5583 artwork.gfx_current->identifier,
5584 leveldir_current->graphics_set,
5585 leveldir_current->graphics_path);
5588 UPDATE_BUSY_STATE();
5590 ReloadCustomImages();
5591 print_timestamp_time("ReloadCustomImages");
5593 UPDATE_BUSY_STATE();
5595 LoadCustomElementDescriptions();
5596 print_timestamp_time("LoadCustomElementDescriptions");
5598 UPDATE_BUSY_STATE();
5600 LoadMenuDesignSettings();
5601 print_timestamp_time("LoadMenuDesignSettings");
5603 UPDATE_BUSY_STATE();
5605 ReinitializeGraphics();
5606 print_timestamp_time("ReinitializeGraphics");
5608 LoadMenuDesignSettings_AfterGraphics();
5609 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5611 UPDATE_BUSY_STATE();
5613 print_timestamp_done("InitImages");
5616 static void InitSound(char *identifier)
5618 print_timestamp_init("InitSound");
5620 if (identifier == NULL)
5621 identifier = artwork.snd_current->identifier;
5623 // set artwork path to send it to the sound server process
5624 setLevelArtworkDir(artwork.snd_first);
5626 InitReloadCustomSounds(identifier);
5627 print_timestamp_time("InitReloadCustomSounds");
5629 ReinitializeSounds();
5630 print_timestamp_time("ReinitializeSounds");
5632 print_timestamp_done("InitSound");
5635 static void InitMusic(char *identifier)
5637 print_timestamp_init("InitMusic");
5639 if (identifier == NULL)
5640 identifier = artwork.mus_current->identifier;
5642 // set artwork path to send it to the sound server process
5643 setLevelArtworkDir(artwork.mus_first);
5645 InitReloadCustomMusic(identifier);
5646 print_timestamp_time("InitReloadCustomMusic");
5648 ReinitializeMusic();
5649 print_timestamp_time("ReinitializeMusic");
5651 print_timestamp_done("InitMusic");
5654 static void InitArtworkDone(void)
5656 if (program.headless)
5659 InitGlobalAnimations();
5662 static void InitNetworkSettings(void)
5664 boolean network_enabled = (options.network || setup.network_mode);
5665 char *network_server = (options.server_host != NULL ? options.server_host :
5666 setup.network_server_hostname);
5668 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5669 network_server = NULL;
5671 InitNetworkInfo(network_enabled,
5675 options.server_port);
5678 void InitNetworkServer(void)
5680 if (!network.enabled || network.connected)
5683 LimitScreenUpdates(FALSE);
5685 if (game_status == GAME_MODE_LOADING)
5688 if (!ConnectToServer(network.server_host, network.server_port))
5690 network.enabled = FALSE;
5692 setup.network_mode = FALSE;
5696 SendToServer_ProtocolVersion();
5697 SendToServer_PlayerName(setup.player_name);
5698 SendToServer_NrWanted(setup.network_player_nr + 1);
5700 network.connected = TRUE;
5703 // short time to recognize result of network initialization
5704 if (game_status == GAME_MODE_LOADING)
5705 Delay_WithScreenUpdates(1000);
5708 static boolean CheckArtworkConfigForCustomElements(char *filename)
5710 SetupFileHash *setup_file_hash;
5711 boolean redefined_ce_found = FALSE;
5713 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5715 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5717 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5719 char *token = HASH_ITERATION_TOKEN(itr);
5721 if (strPrefix(token, "custom_"))
5723 redefined_ce_found = TRUE;
5728 END_HASH_ITERATION(setup_file_hash, itr)
5730 freeSetupFileHash(setup_file_hash);
5733 return redefined_ce_found;
5736 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5738 char *filename_base, *filename_local;
5739 boolean redefined_ce_found = FALSE;
5741 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5744 printf("::: leveldir_current->identifier == '%s'\n",
5745 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5746 printf("::: leveldir_current->graphics_path == '%s'\n",
5747 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5748 printf("::: leveldir_current->graphics_set == '%s'\n",
5749 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5750 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5751 leveldir_current == NULL ? "[NULL]" :
5752 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5755 // first look for special artwork configured in level series config
5756 filename_base = getCustomArtworkLevelConfigFilename(type);
5759 printf("::: filename_base == '%s'\n", filename_base);
5762 if (fileExists(filename_base))
5763 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5765 filename_local = getCustomArtworkConfigFilename(type);
5768 printf("::: filename_local == '%s'\n", filename_local);
5771 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5772 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5775 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5778 return redefined_ce_found;
5781 static void InitOverrideArtwork(void)
5783 boolean redefined_ce_found = FALSE;
5785 // to check if this level set redefines any CEs, do not use overriding
5786 gfx.override_level_graphics = FALSE;
5787 gfx.override_level_sounds = FALSE;
5788 gfx.override_level_music = FALSE;
5790 // now check if this level set has definitions for custom elements
5791 if (setup.override_level_graphics == AUTO ||
5792 setup.override_level_sounds == AUTO ||
5793 setup.override_level_music == AUTO)
5794 redefined_ce_found =
5795 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5796 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5797 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5800 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5803 if (redefined_ce_found)
5805 // this level set has CE definitions: change "AUTO" to "FALSE"
5806 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5807 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5808 gfx.override_level_music = (setup.override_level_music == TRUE);
5812 // this level set has no CE definitions: change "AUTO" to "TRUE"
5813 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5814 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5815 gfx.override_level_music = (setup.override_level_music != FALSE);
5819 printf("::: => %d, %d, %d\n",
5820 gfx.override_level_graphics,
5821 gfx.override_level_sounds,
5822 gfx.override_level_music);
5826 static char *getNewArtworkIdentifier(int type)
5828 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5829 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5830 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5831 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5832 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5833 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5834 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5835 char *leveldir_identifier = leveldir_current->identifier;
5836 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5837 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5838 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5839 char *artwork_current_identifier;
5840 char *artwork_new_identifier = NULL; // default: nothing has changed
5842 // leveldir_current may be invalid (level group, parent link)
5843 if (!validLevelSeries(leveldir_current))
5846 /* 1st step: determine artwork set to be activated in descending order:
5847 --------------------------------------------------------------------
5848 1. setup artwork (when configured to override everything else)
5849 2. artwork set configured in "levelinfo.conf" of current level set
5850 (artwork in level directory will have priority when loading later)
5851 3. artwork in level directory (stored in artwork sub-directory)
5852 4. setup artwork (currently configured in setup menu) */
5854 if (setup_override_artwork)
5855 artwork_current_identifier = setup_artwork_set;
5856 else if (leveldir_artwork_set != NULL)
5857 artwork_current_identifier = leveldir_artwork_set;
5858 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5859 artwork_current_identifier = leveldir_identifier;
5861 artwork_current_identifier = setup_artwork_set;
5864 /* 2nd step: check if it is really needed to reload artwork set
5865 ------------------------------------------------------------ */
5867 // ---------- reload if level set and also artwork set has changed ----------
5868 if (leveldir_current_identifier[type] != leveldir_identifier &&
5869 (last_has_level_artwork_set[type] || has_level_artwork_set))
5870 artwork_new_identifier = artwork_current_identifier;
5872 leveldir_current_identifier[type] = leveldir_identifier;
5873 last_has_level_artwork_set[type] = has_level_artwork_set;
5875 // ---------- reload if "override artwork" setting has changed --------------
5876 if (last_override_level_artwork[type] != setup_override_artwork)
5877 artwork_new_identifier = artwork_current_identifier;
5879 last_override_level_artwork[type] = setup_override_artwork;
5881 // ---------- reload if current artwork identifier has changed --------------
5882 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5883 artwork_current_identifier))
5884 artwork_new_identifier = artwork_current_identifier;
5886 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5888 // ---------- do not reload directly after starting -------------------------
5889 if (!initialized[type])
5890 artwork_new_identifier = NULL;
5892 initialized[type] = TRUE;
5894 return artwork_new_identifier;
5897 void ReloadCustomArtwork(int force_reload)
5899 int last_game_status = game_status; // save current game status
5900 char *gfx_new_identifier;
5901 char *snd_new_identifier;
5902 char *mus_new_identifier;
5903 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5904 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5905 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5906 boolean reload_needed;
5908 InitOverrideArtwork();
5910 force_reload_gfx |= AdjustGraphicsForEMC();
5912 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5913 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5914 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5916 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5917 snd_new_identifier != NULL || force_reload_snd ||
5918 mus_new_identifier != NULL || force_reload_mus);
5923 print_timestamp_init("ReloadCustomArtwork");
5925 SetGameStatus(GAME_MODE_LOADING);
5927 FadeOut(REDRAW_ALL);
5929 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5930 print_timestamp_time("ClearRectangle");
5934 if (gfx_new_identifier != NULL || force_reload_gfx)
5937 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5938 artwork.gfx_current_identifier,
5940 artwork.gfx_current->identifier,
5941 leveldir_current->graphics_set);
5945 print_timestamp_time("InitImages");
5948 if (snd_new_identifier != NULL || force_reload_snd)
5950 InitSound(snd_new_identifier);
5951 print_timestamp_time("InitSound");
5954 if (mus_new_identifier != NULL || force_reload_mus)
5956 InitMusic(mus_new_identifier);
5957 print_timestamp_time("InitMusic");
5962 SetGameStatus(last_game_status); // restore current game status
5964 init_last = init; // switch to new busy animation
5966 FadeOut(REDRAW_ALL);
5968 RedrawGlobalBorder();
5970 // force redraw of (open or closed) door graphics
5971 SetDoorState(DOOR_OPEN_ALL);
5972 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5974 FadeSetEnterScreen();
5975 FadeSkipNextFadeOut();
5977 print_timestamp_done("ReloadCustomArtwork");
5979 LimitScreenUpdates(FALSE);
5982 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5984 if (global.autoplay_leveldir == NULL)
5985 KeyboardAutoRepeatOff();
5988 void DisplayExitMessage(char *format, va_list ap)
5990 // also check for initialized video (headless flag may be temporarily unset)
5991 if (program.headless || !video.initialized)
5994 // check if draw buffer and fonts for exit message are already available
5995 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5998 int font_1 = FC_RED;
5999 int font_2 = FC_YELLOW;
6000 int font_3 = FC_BLUE;
6001 int font_width = getFontWidth(font_2);
6002 int font_height = getFontHeight(font_2);
6005 int sxsize = WIN_XSIZE - 2 * sx;
6006 int sysize = WIN_YSIZE - 2 * sy;
6007 int line_length = sxsize / font_width;
6008 int max_lines = sysize / font_height;
6009 int num_lines_printed;
6013 gfx.sxsize = sxsize;
6014 gfx.sysize = sysize;
6018 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6020 DrawTextSCentered(sy, font_1, "Fatal error:");
6021 sy += 3 * font_height;;
6024 DrawTextBufferVA(sx, sy, format, ap, font_2,
6025 line_length, line_length, max_lines,
6026 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6027 sy += (num_lines_printed + 3) * font_height;
6029 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6030 sy += 3 * font_height;
6033 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6034 line_length, line_length, max_lines,
6035 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6037 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6039 redraw_mask = REDRAW_ALL;
6041 // force drawing exit message even if screen updates are currently limited
6042 LimitScreenUpdates(FALSE);
6046 // deactivate toons on error message screen
6047 setup.toons = FALSE;
6049 WaitForEventToContinue();
6053 // ============================================================================
6055 // ============================================================================
6059 print_timestamp_init("OpenAll");
6061 SetGameStatus(GAME_MODE_LOADING);
6065 InitGlobal(); // initialize some global variables
6067 print_timestamp_time("[init global stuff]");
6071 print_timestamp_time("[init setup/config stuff (1)]");
6075 if (options.execute_command)
6076 Execute_Command(options.execute_command);
6078 InitNetworkSettings();
6082 if (network.serveronly)
6084 #if defined(PLATFORM_UNIX)
6085 NetworkServer(network.server_port, TRUE);
6087 Error(ERR_WARN, "networking only supported in Unix version");
6090 exit(0); // never reached, server loops forever
6094 print_timestamp_time("[init setup/config stuff (2)]");
6096 print_timestamp_time("[init setup/config stuff (3)]");
6097 InitArtworkInfo(); // needed before loading gfx, sound & music
6098 print_timestamp_time("[init setup/config stuff (4)]");
6099 InitArtworkConfig(); // needed before forking sound child process
6100 print_timestamp_time("[init setup/config stuff (5)]");
6102 print_timestamp_time("[init setup/config stuff (6)]");
6104 InitRND(NEW_RANDOMIZE);
6105 InitSimpleRandom(NEW_RANDOMIZE);
6109 print_timestamp_time("[init setup/config stuff]");
6111 InitVideoDefaults();
6113 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6116 InitEventFilter(FilterMouseMotionEvents);
6118 print_timestamp_time("[init video stuff]");
6120 InitElementPropertiesStatic();
6121 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6122 InitElementPropertiesGfxElement();
6124 print_timestamp_time("[init element properties stuff]");
6128 print_timestamp_time("InitGfx");
6131 print_timestamp_time("InitLevelInfo");
6133 InitLevelArtworkInfo();
6134 print_timestamp_time("InitLevelArtworkInfo");
6136 InitOverrideArtwork(); // needs to know current level directory
6137 print_timestamp_time("InitOverrideArtwork");
6139 InitImages(); // needs to know current level directory
6140 print_timestamp_time("InitImages");
6142 InitSound(NULL); // needs to know current level directory
6143 print_timestamp_time("InitSound");
6145 InitMusic(NULL); // needs to know current level directory
6146 print_timestamp_time("InitMusic");
6150 InitGfxBackground();
6156 if (global.autoplay_leveldir)
6161 else if (global.convert_leveldir)
6166 else if (global.create_images_dir)
6168 CreateLevelSketchImages();
6172 InitNetworkServer();
6174 SetGameStatus(GAME_MODE_MAIN);
6176 FadeSetEnterScreen();
6177 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6178 FadeSkipNextFadeOut();
6180 print_timestamp_time("[post-artwork]");
6182 print_timestamp_done("OpenAll");
6187 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6189 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6190 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6191 #if defined(PLATFORM_ANDROID)
6192 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6193 SDL_AndroidGetInternalStoragePath());
6194 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6195 SDL_AndroidGetExternalStoragePath());
6196 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6197 (SDL_AndroidGetExternalStorageState() &
6198 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6199 SDL_AndroidGetExternalStorageState() &
6200 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6205 void CloseAllAndExit(int exit_value)
6210 CloseAudio(); // called after freeing sounds (needed for SDL)
6218 // set a flag to tell the network server thread to quit and wait for it
6219 // using SDL_WaitThread()
6221 // Code used with SDL 1.2:
6222 // if (network_server) // terminate network server
6223 // SDL_KillThread(server_thread);
6225 CloseVideoDisplay();
6226 ClosePlatformDependentStuff();
6228 if (exit_value != 0 && !options.execute_command)
6230 // fall back to default level set (current set may have caused an error)
6231 SaveLevelSetup_LastSeries_Deactivate();
6233 // tell user where to find error log file which may contain more details
6234 // (error notification now directly displayed on screen inside R'n'D
6235 // NotifyUserAboutErrorFile(); // currently only works for Windows