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)
280 FreeAllImageTextures();
282 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
283 CreateImageTextures(i);
285 for (i = 0; i < MAX_NUM_TOONS; i++)
286 CreateImageTextures(IMG_TOON_1 + i);
288 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
290 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
292 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
294 int graphic = global_anim_info[i].graphic[j][k];
296 if (graphic == IMG_UNDEFINED)
299 CreateImageTextures(graphic);
306 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
307 void SetBitmaps_EM(Bitmap **em_bitmap)
309 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
310 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
315 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
316 void SetBitmaps_SP(Bitmap **sp_bitmap)
318 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
322 static int getFontBitmapID(int font_nr)
326 // (special case: do not use special font for GAME_MODE_LOADING)
327 if (game_status >= GAME_MODE_TITLE_INITIAL &&
328 game_status <= GAME_MODE_PSEUDO_PREVIEW)
329 special = game_status;
330 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
331 special = GFX_SPECIAL_ARG_MAIN;
334 return font_info[font_nr].special_bitmap_id[special];
339 static int getFontFromToken(char *token)
341 char *value = getHashEntry(font_token_hash, token);
346 // if font not found, use reliable default value
347 return FONT_INITIAL_1;
350 static void InitFontGraphicInfo(void)
352 static struct FontBitmapInfo *font_bitmap_info = NULL;
353 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
354 int num_property_mappings = getImageListPropertyMappingSize();
355 int num_font_bitmaps = NUM_FONTS;
358 if (graphic_info == NULL) // still at startup phase
360 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
361 getFontBitmapID, getFontFromToken);
366 // ---------- initialize font graphic definitions ----------
368 // always start with reliable default values (normal font graphics)
369 for (i = 0; i < NUM_FONTS; i++)
370 font_info[i].graphic = IMG_FONT_INITIAL_1;
372 // initialize normal font/graphic mapping from static configuration
373 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
375 int font_nr = font_to_graphic[i].font_nr;
376 int special = font_to_graphic[i].special;
377 int graphic = font_to_graphic[i].graphic;
382 font_info[font_nr].graphic = graphic;
385 // always start with reliable default values (special font graphics)
386 for (i = 0; i < NUM_FONTS; i++)
388 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
390 font_info[i].special_graphic[j] = font_info[i].graphic;
391 font_info[i].special_bitmap_id[j] = i;
395 // initialize special font/graphic mapping from static configuration
396 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
398 int font_nr = font_to_graphic[i].font_nr;
399 int special = font_to_graphic[i].special;
400 int graphic = font_to_graphic[i].graphic;
401 int base_graphic = font2baseimg(font_nr);
403 if (IS_SPECIAL_GFX_ARG(special))
405 boolean base_redefined =
406 getImageListEntryFromImageID(base_graphic)->redefined;
407 boolean special_redefined =
408 getImageListEntryFromImageID(graphic)->redefined;
409 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
411 /* if the base font ("font.title_1", for example) has been redefined,
412 but not the special font ("font.title_1.LEVELS", for example), do not
413 use an existing (in this case considered obsolete) special font
414 anymore, but use the automatically determined default font */
415 /* special case: cloned special fonts must be explicitly redefined,
416 but are not automatically redefined by redefining base font */
417 if (base_redefined && !special_redefined && !special_cloned)
420 font_info[font_nr].special_graphic[special] = graphic;
421 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
426 // initialize special font/graphic mapping from dynamic configuration
427 for (i = 0; i < num_property_mappings; i++)
429 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
430 int special = property_mapping[i].ext3_index;
431 int graphic = property_mapping[i].artwork_index;
433 if (font_nr < 0 || font_nr >= NUM_FONTS)
436 if (IS_SPECIAL_GFX_ARG(special))
438 font_info[font_nr].special_graphic[special] = graphic;
439 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
444 /* correct special font/graphic mapping for cloned fonts for downwards
445 compatibility of PREVIEW fonts -- this is only needed for implicit
446 redefinition of special font by redefined base font, and only if other
447 fonts are cloned from this special font (like in the "Zelda" level set) */
448 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
450 int font_nr = font_to_graphic[i].font_nr;
451 int special = font_to_graphic[i].special;
452 int graphic = font_to_graphic[i].graphic;
454 if (IS_SPECIAL_GFX_ARG(special))
456 boolean special_redefined =
457 getImageListEntryFromImageID(graphic)->redefined;
458 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
460 if (special_cloned && !special_redefined)
464 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
466 int font_nr2 = font_to_graphic[j].font_nr;
467 int special2 = font_to_graphic[j].special;
468 int graphic2 = font_to_graphic[j].graphic;
470 if (IS_SPECIAL_GFX_ARG(special2) &&
471 graphic2 == graphic_info[graphic].clone_from)
473 font_info[font_nr].special_graphic[special] =
474 font_info[font_nr2].special_graphic[special2];
475 font_info[font_nr].special_bitmap_id[special] =
476 font_info[font_nr2].special_bitmap_id[special2];
483 // reset non-redefined ".active" font graphics if normal font is redefined
484 // (this different treatment is needed because normal and active fonts are
485 // independently defined ("active" is not a property of font definitions!)
486 for (i = 0; i < NUM_FONTS; i++)
488 int font_nr_base = i;
489 int font_nr_active = FONT_ACTIVE(font_nr_base);
491 // check only those fonts with exist as normal and ".active" variant
492 if (font_nr_base != font_nr_active)
494 int base_graphic = font_info[font_nr_base].graphic;
495 int active_graphic = font_info[font_nr_active].graphic;
496 boolean base_redefined =
497 getImageListEntryFromImageID(base_graphic)->redefined;
498 boolean active_redefined =
499 getImageListEntryFromImageID(active_graphic)->redefined;
501 /* if the base font ("font.menu_1", for example) has been redefined,
502 but not the active font ("font.menu_1.active", for example), do not
503 use an existing (in this case considered obsolete) active font
504 anymore, but use the automatically determined default font */
505 if (base_redefined && !active_redefined)
506 font_info[font_nr_active].graphic = base_graphic;
508 // now also check each "special" font (which may be the same as above)
509 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
511 int base_graphic = font_info[font_nr_base].special_graphic[j];
512 int active_graphic = font_info[font_nr_active].special_graphic[j];
513 boolean base_redefined =
514 getImageListEntryFromImageID(base_graphic)->redefined;
515 boolean active_redefined =
516 getImageListEntryFromImageID(active_graphic)->redefined;
518 // same as above, but check special graphic definitions, for example:
519 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
520 if (base_redefined && !active_redefined)
522 font_info[font_nr_active].special_graphic[j] =
523 font_info[font_nr_base].special_graphic[j];
524 font_info[font_nr_active].special_bitmap_id[j] =
525 font_info[font_nr_base].special_bitmap_id[j];
531 // ---------- initialize font bitmap array ----------
533 if (font_bitmap_info != NULL)
534 FreeFontInfo(font_bitmap_info);
537 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
539 // ---------- initialize font bitmap definitions ----------
541 for (i = 0; i < NUM_FONTS; i++)
543 if (i < NUM_INITIAL_FONTS)
545 font_bitmap_info[i] = font_initial[i];
549 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
551 int font_bitmap_id = font_info[i].special_bitmap_id[j];
552 int graphic = font_info[i].special_graphic[j];
554 // set 'graphic_info' for font entries, if uninitialized (guessed)
555 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
557 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
558 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
561 // copy font relevant information from graphics information
562 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
563 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
564 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
565 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
566 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
568 font_bitmap_info[font_bitmap_id].offset_x =
569 graphic_info[graphic].offset_x;
570 font_bitmap_info[font_bitmap_id].offset_y =
571 graphic_info[graphic].offset_y;
573 font_bitmap_info[font_bitmap_id].draw_xoffset =
574 graphic_info[graphic].draw_xoffset;
575 font_bitmap_info[font_bitmap_id].draw_yoffset =
576 graphic_info[graphic].draw_yoffset;
578 font_bitmap_info[font_bitmap_id].num_chars =
579 graphic_info[graphic].anim_frames;
580 font_bitmap_info[font_bitmap_id].num_chars_per_line =
581 graphic_info[graphic].anim_frames_per_line;
585 InitFontInfo(font_bitmap_info, num_font_bitmaps,
586 getFontBitmapID, getFontFromToken);
589 static void InitGlobalAnimGraphicInfo(void)
591 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
592 int num_property_mappings = getImageListPropertyMappingSize();
595 if (graphic_info == NULL) // still at startup phase
598 // always start with reliable default values (no global animations)
599 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
600 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
601 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
602 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
604 // initialize global animation definitions from static configuration
605 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
607 int j = GLOBAL_ANIM_ID_PART_BASE;
608 int k = GFX_SPECIAL_ARG_DEFAULT;
610 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
613 // initialize global animation definitions from dynamic configuration
614 for (i = 0; i < num_property_mappings; i++)
616 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
617 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
618 int special = property_mapping[i].ext3_index;
619 int graphic = property_mapping[i].artwork_index;
621 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
624 // set animation part to base part, if not specified
625 if (!IS_GLOBAL_ANIM_PART(part_nr))
626 part_nr = GLOBAL_ANIM_ID_PART_BASE;
628 // set animation screen to default, if not specified
629 if (!IS_SPECIAL_GFX_ARG(special))
630 special = GFX_SPECIAL_ARG_DEFAULT;
632 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
634 // fix default value for ".draw_masked" (for backward compatibility)
635 struct GraphicInfo *g = &graphic_info[graphic];
636 struct FileInfo *image = getImageListEntryFromImageID(graphic);
637 char **parameter_raw = image->parameter;
638 int p = GFX_ARG_DRAW_MASKED;
639 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
640 image_config_suffix[p].token,
641 image_config_suffix[p].type);
643 // if ".draw_masked" parameter is undefined, use default value "TRUE"
644 if (draw_masked == ARG_UNDEFINED_VALUE)
645 g->draw_masked = TRUE;
649 printf("::: InitGlobalAnimGraphicInfo\n");
651 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
652 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
653 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
654 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
655 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
656 printf("::: - anim %d, part %d, mode %d => %d\n",
657 i, j, k, global_anim_info[i].graphic[j][k]);
661 static void InitGlobalAnimSoundInfo(void)
663 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
664 int num_property_mappings = getSoundListPropertyMappingSize();
667 // always start with reliable default values (no global animation sounds)
668 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
669 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
670 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
671 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
673 // initialize global animation sound definitions from dynamic configuration
674 for (i = 0; i < num_property_mappings; i++)
676 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
677 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
678 int special = property_mapping[i].ext3_index;
679 int sound = property_mapping[i].artwork_index;
681 // sound uses control definition; map it to position of graphic (artwork)
682 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
684 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
687 // set animation part to base part, if not specified
688 if (!IS_GLOBAL_ANIM_PART(part_nr))
689 part_nr = GLOBAL_ANIM_ID_PART_BASE;
691 // set animation screen to default, if not specified
692 if (!IS_SPECIAL_GFX_ARG(special))
693 special = GFX_SPECIAL_ARG_DEFAULT;
695 global_anim_info[anim_nr].sound[part_nr][special] = sound;
699 printf("::: InitGlobalAnimSoundInfo\n");
701 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
702 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
703 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
704 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
705 printf("::: - anim %d, part %d, mode %d => %d\n",
706 i, j, k, global_anim_info[i].sound[j][k]);
710 static void InitGlobalAnimMusicInfo(void)
712 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
713 int num_property_mappings = getMusicListPropertyMappingSize();
716 // always start with reliable default values (no global animation music)
717 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
718 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
719 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
720 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
722 // initialize global animation music definitions from dynamic configuration
723 for (i = 0; i < num_property_mappings; i++)
725 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
726 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
727 int special = property_mapping[i].ext2_index;
728 int music = property_mapping[i].artwork_index;
730 // music uses control definition; map it to position of graphic (artwork)
731 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
733 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
736 // set animation part to base part, if not specified
737 if (!IS_GLOBAL_ANIM_PART(part_nr))
738 part_nr = GLOBAL_ANIM_ID_PART_BASE;
740 // set animation screen to default, if not specified
741 if (!IS_SPECIAL_GFX_ARG(special))
742 special = GFX_SPECIAL_ARG_DEFAULT;
744 global_anim_info[anim_nr].music[part_nr][special] = music;
748 printf("::: InitGlobalAnimMusicInfo\n");
750 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
754 printf("::: - anim %d, part %d, mode %d => %d\n",
755 i, j, k, global_anim_info[i].music[j][k]);
759 static void InitElementGraphicInfo(void)
761 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
762 int num_property_mappings = getImageListPropertyMappingSize();
765 if (graphic_info == NULL) // still at startup phase
768 // set values to -1 to identify later as "uninitialized" values
769 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
771 for (act = 0; act < NUM_ACTIONS; act++)
773 element_info[i].graphic[act] = -1;
774 element_info[i].crumbled[act] = -1;
776 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
778 element_info[i].direction_graphic[act][dir] = -1;
779 element_info[i].direction_crumbled[act][dir] = -1;
786 // initialize normal element/graphic mapping from static configuration
787 for (i = 0; element_to_graphic[i].element > -1; i++)
789 int element = element_to_graphic[i].element;
790 int action = element_to_graphic[i].action;
791 int direction = element_to_graphic[i].direction;
792 boolean crumbled = element_to_graphic[i].crumbled;
793 int graphic = element_to_graphic[i].graphic;
794 int base_graphic = el2baseimg(element);
796 if (graphic_info[graphic].bitmap == NULL)
799 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
802 boolean base_redefined =
803 getImageListEntryFromImageID(base_graphic)->redefined;
804 boolean act_dir_redefined =
805 getImageListEntryFromImageID(graphic)->redefined;
807 /* if the base graphic ("emerald", for example) has been redefined,
808 but not the action graphic ("emerald.falling", for example), do not
809 use an existing (in this case considered obsolete) action graphic
810 anymore, but use the automatically determined default graphic */
811 if (base_redefined && !act_dir_redefined)
816 action = ACTION_DEFAULT;
821 element_info[element].direction_crumbled[action][direction] = graphic;
823 element_info[element].crumbled[action] = graphic;
828 element_info[element].direction_graphic[action][direction] = graphic;
830 element_info[element].graphic[action] = graphic;
834 // initialize normal element/graphic mapping from dynamic configuration
835 for (i = 0; i < num_property_mappings; i++)
837 int element = property_mapping[i].base_index;
838 int action = property_mapping[i].ext1_index;
839 int direction = property_mapping[i].ext2_index;
840 int special = property_mapping[i].ext3_index;
841 int graphic = property_mapping[i].artwork_index;
842 boolean crumbled = FALSE;
844 if (special == GFX_SPECIAL_ARG_CRUMBLED)
850 if (graphic_info[graphic].bitmap == NULL)
853 if (element >= MAX_NUM_ELEMENTS || special != -1)
857 action = ACTION_DEFAULT;
862 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
863 element_info[element].direction_crumbled[action][dir] = -1;
866 element_info[element].direction_crumbled[action][direction] = graphic;
868 element_info[element].crumbled[action] = graphic;
873 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
874 element_info[element].direction_graphic[action][dir] = -1;
877 element_info[element].direction_graphic[action][direction] = graphic;
879 element_info[element].graphic[action] = graphic;
883 // now copy all graphics that are defined to be cloned from other graphics
884 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
886 int graphic = element_info[i].graphic[ACTION_DEFAULT];
887 int crumbled_like, diggable_like;
892 crumbled_like = graphic_info[graphic].crumbled_like;
893 diggable_like = graphic_info[graphic].diggable_like;
895 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
897 for (act = 0; act < NUM_ACTIONS; act++)
898 element_info[i].crumbled[act] =
899 element_info[crumbled_like].crumbled[act];
900 for (act = 0; act < NUM_ACTIONS; act++)
901 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
902 element_info[i].direction_crumbled[act][dir] =
903 element_info[crumbled_like].direction_crumbled[act][dir];
906 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
908 element_info[i].graphic[ACTION_DIGGING] =
909 element_info[diggable_like].graphic[ACTION_DIGGING];
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
912 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
916 // set hardcoded definitions for some runtime elements without graphic
917 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
919 // set hardcoded definitions for some internal elements without graphic
920 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
922 if (IS_EDITOR_CASCADE_INACTIVE(i))
923 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
924 else if (IS_EDITOR_CASCADE_ACTIVE(i))
925 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
928 // now set all undefined/invalid graphics to -1 to set to default after it
929 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
931 for (act = 0; act < NUM_ACTIONS; act++)
935 graphic = element_info[i].graphic[act];
936 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
937 element_info[i].graphic[act] = -1;
939 graphic = element_info[i].crumbled[act];
940 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
941 element_info[i].crumbled[act] = -1;
943 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
945 graphic = element_info[i].direction_graphic[act][dir];
946 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
947 element_info[i].direction_graphic[act][dir] = -1;
949 graphic = element_info[i].direction_crumbled[act][dir];
950 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
951 element_info[i].direction_crumbled[act][dir] = -1;
958 // adjust graphics with 2nd tile for movement according to direction
959 // (do this before correcting '-1' values to minimize calculations)
960 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
962 for (act = 0; act < NUM_ACTIONS; act++)
964 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
966 int graphic = element_info[i].direction_graphic[act][dir];
967 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
969 if (act == ACTION_FALLING) // special case
970 graphic = element_info[i].graphic[act];
973 graphic_info[graphic].double_movement &&
974 graphic_info[graphic].swap_double_tiles != 0)
976 struct GraphicInfo *g = &graphic_info[graphic];
977 int src_x_front = g->src_x;
978 int src_y_front = g->src_y;
979 int src_x_back = g->src_x + g->offset2_x;
980 int src_y_back = g->src_y + g->offset2_y;
981 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
983 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
984 src_y_front < src_y_back);
985 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
986 boolean swap_movement_tiles_autodetected =
987 (!frames_are_ordered_diagonally &&
988 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
989 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
990 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
991 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
993 // swap frontside and backside graphic tile coordinates, if needed
994 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
996 // get current (wrong) backside tile coordinates
997 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
999 // set frontside tile coordinates to backside tile coordinates
1000 g->src_x = src_x_back;
1001 g->src_y = src_y_back;
1003 // invert tile offset to point to new backside tile coordinates
1007 // do not swap front and backside tiles again after correction
1008 g->swap_double_tiles = 0;
1015 UPDATE_BUSY_STATE();
1017 // now set all '-1' values to element specific default values
1018 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1020 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1021 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1022 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1023 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1025 if (default_graphic == -1)
1026 default_graphic = IMG_UNKNOWN;
1028 if (default_crumbled == -1)
1029 default_crumbled = default_graphic;
1031 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1033 default_direction_graphic[dir] =
1034 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1035 default_direction_crumbled[dir] =
1036 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1038 if (default_direction_graphic[dir] == -1)
1039 default_direction_graphic[dir] = default_graphic;
1041 if (default_direction_crumbled[dir] == -1)
1042 default_direction_crumbled[dir] = default_direction_graphic[dir];
1045 for (act = 0; act < NUM_ACTIONS; act++)
1047 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1048 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1049 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1050 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1051 act == ACTION_TURNING_FROM_RIGHT ||
1052 act == ACTION_TURNING_FROM_UP ||
1053 act == ACTION_TURNING_FROM_DOWN);
1055 // generic default action graphic (defined by "[default]" directive)
1056 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1057 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1058 int default_remove_graphic = IMG_EMPTY;
1060 if (act_remove && default_action_graphic != -1)
1061 default_remove_graphic = default_action_graphic;
1063 // look for special default action graphic (classic game specific)
1064 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1065 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1066 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1067 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1068 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1069 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1070 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1071 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1073 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1074 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1075 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1076 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1077 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1078 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1079 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1080 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1082 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1083 // !!! make this better !!!
1084 if (i == EL_EMPTY_SPACE)
1086 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1087 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1090 if (default_action_graphic == -1)
1091 default_action_graphic = default_graphic;
1093 if (default_action_crumbled == -1)
1094 default_action_crumbled = default_action_graphic;
1096 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1098 // use action graphic as the default direction graphic, if undefined
1099 int default_action_direction_graphic = element_info[i].graphic[act];
1100 int default_action_direction_crumbled = element_info[i].crumbled[act];
1102 // no graphic for current action -- use default direction graphic
1103 if (default_action_direction_graphic == -1)
1104 default_action_direction_graphic =
1105 (act_remove ? default_remove_graphic :
1107 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1108 default_action_graphic != default_graphic ?
1109 default_action_graphic :
1110 default_direction_graphic[dir]);
1112 if (element_info[i].direction_graphic[act][dir] == -1)
1113 element_info[i].direction_graphic[act][dir] =
1114 default_action_direction_graphic;
1116 if (default_action_direction_crumbled == -1)
1117 default_action_direction_crumbled =
1118 element_info[i].direction_graphic[act][dir];
1120 if (element_info[i].direction_crumbled[act][dir] == -1)
1121 element_info[i].direction_crumbled[act][dir] =
1122 default_action_direction_crumbled;
1125 // no graphic for this specific action -- use default action graphic
1126 if (element_info[i].graphic[act] == -1)
1127 element_info[i].graphic[act] =
1128 (act_remove ? default_remove_graphic :
1129 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1130 default_action_graphic);
1132 if (element_info[i].crumbled[act] == -1)
1133 element_info[i].crumbled[act] = element_info[i].graphic[act];
1137 UPDATE_BUSY_STATE();
1140 static void InitElementSpecialGraphicInfo(void)
1142 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1143 int num_property_mappings = getImageListPropertyMappingSize();
1146 // always start with reliable default values
1147 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1148 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1149 element_info[i].special_graphic[j] =
1150 element_info[i].graphic[ACTION_DEFAULT];
1152 // initialize special element/graphic mapping from static configuration
1153 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1155 int element = element_to_special_graphic[i].element;
1156 int special = element_to_special_graphic[i].special;
1157 int graphic = element_to_special_graphic[i].graphic;
1158 int base_graphic = el2baseimg(element);
1159 boolean base_redefined =
1160 getImageListEntryFromImageID(base_graphic)->redefined;
1161 boolean special_redefined =
1162 getImageListEntryFromImageID(graphic)->redefined;
1164 /* if the base graphic ("emerald", for example) has been redefined,
1165 but not the special graphic ("emerald.EDITOR", for example), do not
1166 use an existing (in this case considered obsolete) special graphic
1167 anymore, but use the automatically created (down-scaled) graphic */
1168 if (base_redefined && !special_redefined)
1171 element_info[element].special_graphic[special] = graphic;
1174 // initialize special element/graphic mapping from dynamic configuration
1175 for (i = 0; i < num_property_mappings; i++)
1177 int element = property_mapping[i].base_index;
1178 int action = property_mapping[i].ext1_index;
1179 int direction = property_mapping[i].ext2_index;
1180 int special = property_mapping[i].ext3_index;
1181 int graphic = property_mapping[i].artwork_index;
1183 // for action ".active", replace element with active element, if exists
1184 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1186 element = ELEMENT_ACTIVE(element);
1190 if (element >= MAX_NUM_ELEMENTS)
1193 // do not change special graphic if action or direction was specified
1194 if (action != -1 || direction != -1)
1197 if (IS_SPECIAL_GFX_ARG(special))
1198 element_info[element].special_graphic[special] = graphic;
1201 // now set all undefined/invalid graphics to default
1202 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1203 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1204 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1205 element_info[i].special_graphic[j] =
1206 element_info[i].graphic[ACTION_DEFAULT];
1209 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1211 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1212 return get_parameter_value(value_raw, suffix, type);
1214 if (strEqual(value_raw, ARG_UNDEFINED))
1215 return ARG_UNDEFINED_VALUE;
1217 if (type == TYPE_ELEMENT)
1219 char *value = getHashEntry(element_token_hash, value_raw);
1223 Error(ERR_INFO_LINE, "-");
1224 Error(ERR_INFO, "warning: error found in config file:");
1225 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1226 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1227 Error(ERR_INFO, "custom graphic rejected for this element/action");
1228 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1229 Error(ERR_INFO_LINE, "-");
1232 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1234 else if (type == TYPE_GRAPHIC)
1236 char *value = getHashEntry(graphic_token_hash, value_raw);
1237 int fallback_graphic = IMG_CHAR_EXCLAM;
1241 Error(ERR_INFO_LINE, "-");
1242 Error(ERR_INFO, "warning: error found in config file:");
1243 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1244 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1245 Error(ERR_INFO, "custom graphic rejected for this element/action");
1246 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1247 Error(ERR_INFO_LINE, "-");
1250 return (value != NULL ? atoi(value) : fallback_graphic);
1256 static int get_scaled_graphic_width(int graphic)
1258 int original_width = getOriginalImageWidthFromImageID(graphic);
1259 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1261 return original_width * scale_up_factor;
1264 static int get_scaled_graphic_height(int graphic)
1266 int original_height = getOriginalImageHeightFromImageID(graphic);
1267 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1269 return original_height * scale_up_factor;
1272 static void set_graphic_parameters_ext(int graphic, int *parameter,
1273 Bitmap **src_bitmaps)
1275 struct GraphicInfo *g = &graphic_info[graphic];
1276 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1277 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1278 int anim_frames_per_line = 1;
1280 // always start with reliable default values
1281 g->src_image_width = 0;
1282 g->src_image_height = 0;
1285 g->width = TILEX; // default for element graphics
1286 g->height = TILEY; // default for element graphics
1287 g->offset_x = 0; // one or both of these values ...
1288 g->offset_y = 0; // ... will be corrected later
1289 g->offset2_x = 0; // one or both of these values ...
1290 g->offset2_y = 0; // ... will be corrected later
1291 g->swap_double_tiles = -1; // auto-detect tile swapping
1292 g->crumbled_like = -1; // do not use clone element
1293 g->diggable_like = -1; // do not use clone element
1294 g->border_size = TILEX / 8; // "CRUMBLED" border size
1295 g->scale_up_factor = 1; // default: no scaling up
1296 g->tile_size = TILESIZE; // default: standard tile size
1297 g->clone_from = -1; // do not use clone graphic
1298 g->init_delay_fixed = 0;
1299 g->init_delay_random = 0;
1300 g->anim_delay_fixed = 0;
1301 g->anim_delay_random = 0;
1302 g->post_delay_fixed = 0;
1303 g->post_delay_random = 0;
1304 g->init_event = ANIM_EVENT_UNDEFINED;
1305 g->anim_event = ANIM_EVENT_UNDEFINED;
1306 g->init_event_action = -1;
1307 g->anim_event_action = -1;
1308 g->draw_masked = FALSE;
1310 g->fade_mode = FADE_MODE_DEFAULT;
1314 g->align = ALIGN_CENTER; // default for title screens
1315 g->valign = VALIGN_MIDDLE; // default for title screens
1316 g->sort_priority = 0; // default for title screens
1318 g->style = STYLE_DEFAULT;
1320 g->bitmaps = src_bitmaps;
1321 g->bitmap = src_bitmap;
1323 // optional zoom factor for scaling up the image to a larger size
1324 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1325 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1326 if (g->scale_up_factor < 1)
1327 g->scale_up_factor = 1; // no scaling
1329 // optional tile size for using non-standard image size
1330 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1332 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1335 // CHECK: should tile sizes less than standard tile size be allowed?
1336 if (g->tile_size < TILESIZE)
1337 g->tile_size = TILESIZE; // standard tile size
1340 // when setting tile size, also set width and height accordingly
1341 g->width = g->tile_size;
1342 g->height = g->tile_size;
1345 if (g->use_image_size)
1347 // set new default bitmap size (with scaling, but without small images)
1348 g->width = get_scaled_graphic_width(graphic);
1349 g->height = get_scaled_graphic_height(graphic);
1352 // optional width and height of each animation frame
1353 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1354 g->width = parameter[GFX_ARG_WIDTH];
1355 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1356 g->height = parameter[GFX_ARG_HEIGHT];
1358 // optional x and y tile position of animation frame sequence
1359 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1360 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1361 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1362 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1364 // optional x and y pixel position of animation frame sequence
1365 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1366 g->src_x = parameter[GFX_ARG_X];
1367 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1368 g->src_y = parameter[GFX_ARG_Y];
1374 Error(ERR_INFO_LINE, "-");
1375 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1376 g->width, getTokenFromImageID(graphic), TILEX);
1377 Error(ERR_INFO_LINE, "-");
1379 g->width = TILEX; // will be checked to be inside bitmap later
1384 Error(ERR_INFO_LINE, "-");
1385 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1386 g->height, getTokenFromImageID(graphic), TILEY);
1387 Error(ERR_INFO_LINE, "-");
1389 g->height = TILEY; // will be checked to be inside bitmap later
1395 // get final bitmap size (with scaling, but without small images)
1396 int src_image_width = get_scaled_graphic_width(graphic);
1397 int src_image_height = get_scaled_graphic_height(graphic);
1399 if (src_image_width == 0 || src_image_height == 0)
1401 // only happens when loaded outside artwork system (like "global.busy")
1402 src_image_width = src_bitmap->width;
1403 src_image_height = src_bitmap->height;
1406 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1408 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1409 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1413 anim_frames_per_row = MAX(1, src_image_width / g->width);
1414 anim_frames_per_col = MAX(1, src_image_height / g->height);
1417 g->src_image_width = src_image_width;
1418 g->src_image_height = src_image_height;
1421 // correct x or y offset dependent of vertical or horizontal frame order
1422 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1424 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1425 parameter[GFX_ARG_OFFSET] : g->height);
1426 anim_frames_per_line = anim_frames_per_col;
1428 else // frames are ordered horizontally
1430 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1431 parameter[GFX_ARG_OFFSET] : g->width);
1432 anim_frames_per_line = anim_frames_per_row;
1435 // optionally, the x and y offset of frames can be specified directly
1436 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1437 g->offset_x = parameter[GFX_ARG_XOFFSET];
1438 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1439 g->offset_y = parameter[GFX_ARG_YOFFSET];
1441 // optionally, moving animations may have separate start and end graphics
1442 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1444 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1445 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1447 // correct x or y offset2 dependent of vertical or horizontal frame order
1448 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1449 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1450 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1451 else // frames are ordered horizontally
1452 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1453 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1455 // optionally, the x and y offset of 2nd graphic can be specified directly
1456 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1457 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1458 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1459 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1461 // optionally, the second movement tile can be specified as start tile
1462 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1463 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1465 // automatically determine correct number of frames, if not defined
1466 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1467 g->anim_frames = parameter[GFX_ARG_FRAMES];
1468 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1469 g->anim_frames = anim_frames_per_row;
1470 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1471 g->anim_frames = anim_frames_per_col;
1475 if (g->anim_frames == 0) // frames must be at least 1
1478 g->anim_frames_per_line =
1479 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1480 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1482 g->anim_delay = parameter[GFX_ARG_DELAY];
1483 if (g->anim_delay == 0) // delay must be at least 1
1486 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1488 // automatically determine correct start frame, if not defined
1489 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1490 g->anim_start_frame = 0;
1491 else if (g->anim_mode & ANIM_REVERSE)
1492 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1494 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1496 // animation synchronized with global frame counter, not move position
1497 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1499 // optional element for cloning crumble graphics
1500 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1501 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1503 // optional element for cloning digging graphics
1504 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1505 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1507 // optional border size for "crumbling" diggable graphics
1508 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1509 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1511 // used for global animations and player "boring" and "sleeping" actions
1512 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1513 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1514 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1515 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1516 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1517 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1518 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1519 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1520 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1521 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1522 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1523 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1525 // used for global animations
1526 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1527 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1528 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1529 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1530 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1531 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1532 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1533 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1535 // used for toon animations and global animations
1536 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1537 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1538 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1539 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1540 g->direction = parameter[GFX_ARG_DIRECTION];
1541 g->position = parameter[GFX_ARG_POSITION];
1542 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1543 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1545 // this is only used for drawing font characters
1546 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1547 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1549 // use a different default value for global animations and toons
1550 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1551 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1552 g->draw_masked = TRUE;
1554 // this is used for drawing envelopes, global animations and toons
1555 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1556 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1558 // used for toon animations and global animations
1559 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1560 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1562 // optional graphic for cloning all graphics settings
1563 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1564 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1566 // optional settings for drawing title screens and title messages
1567 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1568 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1569 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1570 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1571 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1572 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1573 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1574 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1575 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1576 g->align = parameter[GFX_ARG_ALIGN];
1577 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1578 g->valign = parameter[GFX_ARG_VALIGN];
1579 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1580 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1582 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1583 g->class = parameter[GFX_ARG_CLASS];
1584 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1585 g->style = parameter[GFX_ARG_STYLE];
1587 // this is only used for drawing menu buttons and text
1588 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1589 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1590 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1591 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1594 static void set_graphic_parameters(int graphic)
1596 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1597 char **parameter_raw = image->parameter;
1598 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1599 int parameter[NUM_GFX_ARGS];
1602 // if fallback to default artwork is done, also use the default parameters
1603 if (image->fallback_to_default)
1604 parameter_raw = image->default_parameter;
1606 // get integer values from string parameters
1607 for (i = 0; i < NUM_GFX_ARGS; i++)
1608 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1609 image_config_suffix[i].token,
1610 image_config_suffix[i].type);
1612 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1614 UPDATE_BUSY_STATE();
1617 static void set_cloned_graphic_parameters(int graphic)
1619 int fallback_graphic = IMG_CHAR_EXCLAM;
1620 int max_num_images = getImageListSize();
1621 int clone_graphic = graphic_info[graphic].clone_from;
1622 int num_references_followed = 1;
1624 while (graphic_info[clone_graphic].clone_from != -1 &&
1625 num_references_followed < max_num_images)
1627 clone_graphic = graphic_info[clone_graphic].clone_from;
1629 num_references_followed++;
1632 if (num_references_followed >= max_num_images)
1634 Error(ERR_INFO_LINE, "-");
1635 Error(ERR_INFO, "warning: error found in config file:");
1636 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1637 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1638 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1639 Error(ERR_INFO, "custom graphic rejected for this element/action");
1641 if (graphic == fallback_graphic)
1642 Error(ERR_EXIT, "no fallback graphic available");
1644 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1645 Error(ERR_INFO_LINE, "-");
1647 graphic_info[graphic] = graphic_info[fallback_graphic];
1651 graphic_info[graphic] = graphic_info[clone_graphic];
1652 graphic_info[graphic].clone_from = clone_graphic;
1656 static void InitGraphicInfo(void)
1658 int fallback_graphic = IMG_CHAR_EXCLAM;
1659 int num_images = getImageListSize();
1662 // use image size as default values for width and height for these images
1663 static int full_size_graphics[] =
1666 IMG_GLOBAL_BORDER_MAIN,
1667 IMG_GLOBAL_BORDER_SCORES,
1668 IMG_GLOBAL_BORDER_EDITOR,
1669 IMG_GLOBAL_BORDER_PLAYING,
1672 IMG_BACKGROUND_ENVELOPE_1,
1673 IMG_BACKGROUND_ENVELOPE_2,
1674 IMG_BACKGROUND_ENVELOPE_3,
1675 IMG_BACKGROUND_ENVELOPE_4,
1676 IMG_BACKGROUND_REQUEST,
1679 IMG_BACKGROUND_TITLE_INITIAL,
1680 IMG_BACKGROUND_TITLE,
1681 IMG_BACKGROUND_MAIN,
1682 IMG_BACKGROUND_LEVELS,
1683 IMG_BACKGROUND_LEVELNR,
1684 IMG_BACKGROUND_SCORES,
1685 IMG_BACKGROUND_EDITOR,
1686 IMG_BACKGROUND_INFO,
1687 IMG_BACKGROUND_INFO_ELEMENTS,
1688 IMG_BACKGROUND_INFO_MUSIC,
1689 IMG_BACKGROUND_INFO_CREDITS,
1690 IMG_BACKGROUND_INFO_PROGRAM,
1691 IMG_BACKGROUND_INFO_VERSION,
1692 IMG_BACKGROUND_INFO_LEVELSET,
1693 IMG_BACKGROUND_SETUP,
1694 IMG_BACKGROUND_PLAYING,
1695 IMG_BACKGROUND_DOOR,
1696 IMG_BACKGROUND_TAPE,
1697 IMG_BACKGROUND_PANEL,
1698 IMG_BACKGROUND_PALETTE,
1699 IMG_BACKGROUND_TOOLBOX,
1701 IMG_TITLESCREEN_INITIAL_1,
1702 IMG_TITLESCREEN_INITIAL_2,
1703 IMG_TITLESCREEN_INITIAL_3,
1704 IMG_TITLESCREEN_INITIAL_4,
1705 IMG_TITLESCREEN_INITIAL_5,
1712 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1713 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1714 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1715 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1716 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1717 IMG_BACKGROUND_TITLEMESSAGE_1,
1718 IMG_BACKGROUND_TITLEMESSAGE_2,
1719 IMG_BACKGROUND_TITLEMESSAGE_3,
1720 IMG_BACKGROUND_TITLEMESSAGE_4,
1721 IMG_BACKGROUND_TITLEMESSAGE_5,
1726 FreeGlobalAnimEventInfo();
1728 checked_free(graphic_info);
1730 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1732 // initialize "use_image_size" flag with default value
1733 for (i = 0; i < num_images; i++)
1734 graphic_info[i].use_image_size = FALSE;
1736 // initialize "use_image_size" flag from static configuration above
1737 for (i = 0; full_size_graphics[i] != -1; i++)
1738 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1740 // first set all graphic paramaters ...
1741 for (i = 0; i < num_images; i++)
1742 set_graphic_parameters(i);
1744 // ... then copy these parameters for cloned graphics
1745 for (i = 0; i < num_images; i++)
1746 if (graphic_info[i].clone_from != -1)
1747 set_cloned_graphic_parameters(i);
1749 for (i = 0; i < num_images; i++)
1751 Bitmap *src_bitmap = graphic_info[i].bitmap;
1755 int src_bitmap_width, src_bitmap_height;
1757 // now check if no animation frames are outside of the loaded image
1759 if (graphic_info[i].bitmap == NULL)
1760 continue; // skip check for optional images that are undefined
1762 // get image size (this can differ from the standard element tile size!)
1763 width = graphic_info[i].width;
1764 height = graphic_info[i].height;
1766 // get final bitmap size (with scaling, but without small images)
1767 src_bitmap_width = graphic_info[i].src_image_width;
1768 src_bitmap_height = graphic_info[i].src_image_height;
1770 // check if first animation frame is inside specified bitmap
1772 // do not use getGraphicSourceXY() here to get position of first frame;
1773 // this avoids calculating wrong start position for out-of-bounds frame
1774 src_x = graphic_info[i].src_x;
1775 src_y = graphic_info[i].src_y;
1777 if (program.headless)
1780 if (src_x < 0 || src_y < 0 ||
1781 src_x + width > src_bitmap_width ||
1782 src_y + height > src_bitmap_height)
1784 Error(ERR_INFO_LINE, "-");
1785 Error(ERR_INFO, "warning: error found in config file:");
1786 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1787 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1788 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1789 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1791 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1792 src_x, src_y, src_bitmap_width, src_bitmap_height);
1793 Error(ERR_INFO, "custom graphic rejected for this element/action");
1795 if (i == fallback_graphic)
1796 Error(ERR_EXIT, "no fallback graphic available");
1798 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1799 Error(ERR_INFO_LINE, "-");
1801 graphic_info[i] = graphic_info[fallback_graphic];
1803 // if first frame out of bounds, do not check last frame anymore
1807 // check if last animation frame is inside specified bitmap
1809 last_frame = graphic_info[i].anim_frames - 1;
1810 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1812 if (src_x < 0 || src_y < 0 ||
1813 src_x + width > src_bitmap_width ||
1814 src_y + height > src_bitmap_height)
1816 Error(ERR_INFO_LINE, "-");
1817 Error(ERR_INFO, "warning: error found in config file:");
1818 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1819 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1820 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1821 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1823 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1824 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1825 Error(ERR_INFO, "custom graphic rejected for this element/action");
1827 if (i == fallback_graphic)
1828 Error(ERR_EXIT, "no fallback graphic available");
1830 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1831 Error(ERR_INFO_LINE, "-");
1833 graphic_info[i] = graphic_info[fallback_graphic];
1838 static void InitGraphicCompatibilityInfo(void)
1840 struct FileInfo *fi_global_door =
1841 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1842 int num_images = getImageListSize();
1845 /* the following compatibility handling is needed for the following case:
1846 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1847 graphics mainly used for door and panel graphics, like editor, tape and
1848 in-game buttons with hard-coded bitmap positions and button sizes; as
1849 these graphics now have individual definitions, redefining "global.door"
1850 to change all these graphics at once like before does not work anymore
1851 (because all those individual definitions still have their default values);
1852 to solve this, remap all those individual definitions that are not
1853 redefined to the new bitmap of "global.door" if it was redefined */
1855 // special compatibility handling if image "global.door" was redefined
1856 if (fi_global_door->redefined)
1858 for (i = 0; i < num_images; i++)
1860 struct FileInfo *fi = getImageListEntryFromImageID(i);
1862 // process only those images that still use the default settings
1865 // process all images which default to same image as "global.door"
1866 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1868 // printf("::: special treatment needed for token '%s'\n", fi->token);
1870 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1871 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1877 InitGraphicCompatibilityInfo_Doors();
1880 static void InitElementSoundInfo(void)
1882 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1883 int num_property_mappings = getSoundListPropertyMappingSize();
1886 // set values to -1 to identify later as "uninitialized" values
1887 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1888 for (act = 0; act < NUM_ACTIONS; act++)
1889 element_info[i].sound[act] = -1;
1891 // initialize element/sound mapping from static configuration
1892 for (i = 0; element_to_sound[i].element > -1; i++)
1894 int element = element_to_sound[i].element;
1895 int action = element_to_sound[i].action;
1896 int sound = element_to_sound[i].sound;
1897 boolean is_class = element_to_sound[i].is_class;
1900 action = ACTION_DEFAULT;
1903 element_info[element].sound[action] = sound;
1905 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1906 if (strEqual(element_info[j].class_name,
1907 element_info[element].class_name))
1908 element_info[j].sound[action] = sound;
1911 // initialize element class/sound mapping from dynamic configuration
1912 for (i = 0; i < num_property_mappings; i++)
1914 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1915 int action = property_mapping[i].ext1_index;
1916 int sound = property_mapping[i].artwork_index;
1918 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1922 action = ACTION_DEFAULT;
1924 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1925 if (strEqual(element_info[j].class_name,
1926 element_info[element_class].class_name))
1927 element_info[j].sound[action] = sound;
1930 // initialize element/sound mapping from dynamic configuration
1931 for (i = 0; i < num_property_mappings; i++)
1933 int element = property_mapping[i].base_index;
1934 int action = property_mapping[i].ext1_index;
1935 int sound = property_mapping[i].artwork_index;
1937 if (element >= MAX_NUM_ELEMENTS)
1941 action = ACTION_DEFAULT;
1943 element_info[element].sound[action] = sound;
1946 // now set all '-1' values to element specific default values
1947 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1949 for (act = 0; act < NUM_ACTIONS; act++)
1951 // generic default action sound (defined by "[default]" directive)
1952 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1954 // look for special default action sound (classic game specific)
1955 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1956 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1957 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1958 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1959 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1960 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1961 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1962 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1964 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1965 // !!! make this better !!!
1966 if (i == EL_EMPTY_SPACE)
1967 default_action_sound = element_info[EL_DEFAULT].sound[act];
1969 // no sound for this specific action -- use default action sound
1970 if (element_info[i].sound[act] == -1)
1971 element_info[i].sound[act] = default_action_sound;
1975 // copy sound settings to some elements that are only stored in level file
1976 // in native R'n'D levels, but are used by game engine in native EM levels
1977 for (i = 0; copy_properties[i][0] != -1; i++)
1978 for (j = 1; j <= 4; j++)
1979 for (act = 0; act < NUM_ACTIONS; act++)
1980 element_info[copy_properties[i][j]].sound[act] =
1981 element_info[copy_properties[i][0]].sound[act];
1984 static void InitGameModeSoundInfo(void)
1988 // set values to -1 to identify later as "uninitialized" values
1989 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1992 // initialize gamemode/sound mapping from static configuration
1993 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1995 int gamemode = gamemode_to_sound[i].gamemode;
1996 int sound = gamemode_to_sound[i].sound;
1999 gamemode = GAME_MODE_DEFAULT;
2001 menu.sound[gamemode] = sound;
2004 // now set all '-1' values to levelset specific default values
2005 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2006 if (menu.sound[i] == -1)
2007 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2010 static void set_sound_parameters(int sound, char **parameter_raw)
2012 int parameter[NUM_SND_ARGS];
2015 // get integer values from string parameters
2016 for (i = 0; i < NUM_SND_ARGS; i++)
2018 get_parameter_value(parameter_raw[i],
2019 sound_config_suffix[i].token,
2020 sound_config_suffix[i].type);
2022 // explicit loop mode setting in configuration overrides default value
2023 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2024 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2026 // sound volume to change the original volume when loading the sound file
2027 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2029 // sound priority to give certain sounds a higher or lower priority
2030 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2033 static void InitSoundInfo(void)
2035 int *sound_effect_properties;
2036 int num_sounds = getSoundListSize();
2039 checked_free(sound_info);
2041 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2042 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2044 // initialize sound effect for all elements to "no sound"
2045 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2046 for (j = 0; j < NUM_ACTIONS; j++)
2047 element_info[i].sound[j] = SND_UNDEFINED;
2049 for (i = 0; i < num_sounds; i++)
2051 struct FileInfo *sound = getSoundListEntry(i);
2052 int len_effect_text = strlen(sound->token);
2054 sound_effect_properties[i] = ACTION_OTHER;
2055 sound_info[i].loop = FALSE; // default: play sound only once
2057 // determine all loop sounds and identify certain sound classes
2059 for (j = 0; element_action_info[j].suffix; j++)
2061 int len_action_text = strlen(element_action_info[j].suffix);
2063 if (len_action_text < len_effect_text &&
2064 strEqual(&sound->token[len_effect_text - len_action_text],
2065 element_action_info[j].suffix))
2067 sound_effect_properties[i] = element_action_info[j].value;
2068 sound_info[i].loop = element_action_info[j].is_loop_sound;
2074 // associate elements and some selected sound actions
2076 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2078 if (element_info[j].class_name)
2080 int len_class_text = strlen(element_info[j].class_name);
2082 if (len_class_text + 1 < len_effect_text &&
2083 strncmp(sound->token,
2084 element_info[j].class_name, len_class_text) == 0 &&
2085 sound->token[len_class_text] == '.')
2087 int sound_action_value = sound_effect_properties[i];
2089 element_info[j].sound[sound_action_value] = i;
2094 set_sound_parameters(i, sound->parameter);
2097 free(sound_effect_properties);
2100 static void InitGameModeMusicInfo(void)
2102 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2103 int num_property_mappings = getMusicListPropertyMappingSize();
2104 int default_levelset_music = -1;
2107 // set values to -1 to identify later as "uninitialized" values
2108 for (i = 0; i < MAX_LEVELS; i++)
2109 levelset.music[i] = -1;
2110 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2113 // initialize gamemode/music mapping from static configuration
2114 for (i = 0; gamemode_to_music[i].music > -1; i++)
2116 int gamemode = gamemode_to_music[i].gamemode;
2117 int music = gamemode_to_music[i].music;
2120 gamemode = GAME_MODE_DEFAULT;
2122 menu.music[gamemode] = music;
2125 // initialize gamemode/music mapping from dynamic configuration
2126 for (i = 0; i < num_property_mappings; i++)
2128 int prefix = property_mapping[i].base_index;
2129 int gamemode = property_mapping[i].ext2_index;
2130 int level = property_mapping[i].ext3_index;
2131 int music = property_mapping[i].artwork_index;
2133 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2137 gamemode = GAME_MODE_DEFAULT;
2139 // level specific music only allowed for in-game music
2140 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2141 gamemode = GAME_MODE_PLAYING;
2146 default_levelset_music = music;
2149 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2150 levelset.music[level] = music;
2151 if (gamemode != GAME_MODE_PLAYING)
2152 menu.music[gamemode] = music;
2155 // now set all '-1' values to menu specific default values
2156 // (undefined values of "levelset.music[]" might stay at "-1" to
2157 // allow dynamic selection of music files from music directory!)
2158 for (i = 0; i < MAX_LEVELS; i++)
2159 if (levelset.music[i] == -1)
2160 levelset.music[i] = default_levelset_music;
2161 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2162 if (menu.music[i] == -1)
2163 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2166 static void set_music_parameters(int music, char **parameter_raw)
2168 int parameter[NUM_MUS_ARGS];
2171 // get integer values from string parameters
2172 for (i = 0; i < NUM_MUS_ARGS; i++)
2174 get_parameter_value(parameter_raw[i],
2175 music_config_suffix[i].token,
2176 music_config_suffix[i].type);
2178 // explicit loop mode setting in configuration overrides default value
2179 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2180 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2183 static void InitMusicInfo(void)
2185 int num_music = getMusicListSize();
2188 checked_free(music_info);
2190 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2192 for (i = 0; i < num_music; i++)
2194 struct FileInfo *music = getMusicListEntry(i);
2195 int len_music_text = strlen(music->token);
2197 music_info[i].loop = TRUE; // default: play music in loop mode
2199 // determine all loop music
2201 for (j = 0; music_prefix_info[j].prefix; j++)
2203 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2205 if (len_prefix_text < len_music_text &&
2206 strncmp(music->token,
2207 music_prefix_info[j].prefix, len_prefix_text) == 0)
2209 music_info[i].loop = music_prefix_info[j].is_loop_music;
2215 set_music_parameters(i, music->parameter);
2219 static void ReinitializeGraphics(void)
2221 print_timestamp_init("ReinitializeGraphics");
2223 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2225 InitGraphicInfo(); // graphic properties mapping
2226 print_timestamp_time("InitGraphicInfo");
2227 InitElementGraphicInfo(); // element game graphic mapping
2228 print_timestamp_time("InitElementGraphicInfo");
2229 InitElementSpecialGraphicInfo(); // element special graphic mapping
2230 print_timestamp_time("InitElementSpecialGraphicInfo");
2232 InitElementSmallImages(); // scale elements to all needed sizes
2233 print_timestamp_time("InitElementSmallImages");
2234 InitScaledImages(); // scale all other images, if needed
2235 print_timestamp_time("InitScaledImages");
2236 InitBitmapPointers(); // set standard size bitmap pointers
2237 print_timestamp_time("InitBitmapPointers");
2238 InitFontGraphicInfo(); // initialize text drawing functions
2239 print_timestamp_time("InitFontGraphicInfo");
2240 InitGlobalAnimGraphicInfo(); // initialize global animation config
2241 print_timestamp_time("InitGlobalAnimGraphicInfo");
2243 InitImageTextures(); // create textures for certain images
2244 print_timestamp_time("InitImageTextures");
2246 InitGraphicInfo_EM(); // graphic mapping for EM engine
2247 print_timestamp_time("InitGraphicInfo_EM");
2249 InitGraphicCompatibilityInfo();
2250 print_timestamp_time("InitGraphicCompatibilityInfo");
2252 SetMainBackgroundImage(IMG_BACKGROUND);
2253 print_timestamp_time("SetMainBackgroundImage");
2254 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2255 print_timestamp_time("SetDoorBackgroundImage");
2258 print_timestamp_time("InitGadgets");
2260 print_timestamp_time("InitDoors");
2262 print_timestamp_done("ReinitializeGraphics");
2265 static void ReinitializeSounds(void)
2267 InitSoundInfo(); // sound properties mapping
2268 InitElementSoundInfo(); // element game sound mapping
2269 InitGameModeSoundInfo(); // game mode sound mapping
2270 InitGlobalAnimSoundInfo(); // global animation sound settings
2272 InitPlayLevelSound(); // internal game sound settings
2275 static void ReinitializeMusic(void)
2277 InitMusicInfo(); // music properties mapping
2278 InitGameModeMusicInfo(); // game mode music mapping
2279 InitGlobalAnimMusicInfo(); // global animation music settings
2282 static int get_special_property_bit(int element, int property_bit_nr)
2284 struct PropertyBitInfo
2290 static struct PropertyBitInfo pb_can_move_into_acid[] =
2292 // the player may be able fall into acid when gravity is activated
2297 { EL_SP_MURPHY, 0 },
2298 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2300 // all elements that can move may be able to also move into acid
2303 { EL_BUG_RIGHT, 1 },
2306 { EL_SPACESHIP, 2 },
2307 { EL_SPACESHIP_LEFT, 2 },
2308 { EL_SPACESHIP_RIGHT, 2 },
2309 { EL_SPACESHIP_UP, 2 },
2310 { EL_SPACESHIP_DOWN, 2 },
2311 { EL_BD_BUTTERFLY, 3 },
2312 { EL_BD_BUTTERFLY_LEFT, 3 },
2313 { EL_BD_BUTTERFLY_RIGHT, 3 },
2314 { EL_BD_BUTTERFLY_UP, 3 },
2315 { EL_BD_BUTTERFLY_DOWN, 3 },
2316 { EL_BD_FIREFLY, 4 },
2317 { EL_BD_FIREFLY_LEFT, 4 },
2318 { EL_BD_FIREFLY_RIGHT, 4 },
2319 { EL_BD_FIREFLY_UP, 4 },
2320 { EL_BD_FIREFLY_DOWN, 4 },
2322 { EL_YAMYAM_LEFT, 5 },
2323 { EL_YAMYAM_RIGHT, 5 },
2324 { EL_YAMYAM_UP, 5 },
2325 { EL_YAMYAM_DOWN, 5 },
2326 { EL_DARK_YAMYAM, 6 },
2329 { EL_PACMAN_LEFT, 8 },
2330 { EL_PACMAN_RIGHT, 8 },
2331 { EL_PACMAN_UP, 8 },
2332 { EL_PACMAN_DOWN, 8 },
2334 { EL_MOLE_LEFT, 9 },
2335 { EL_MOLE_RIGHT, 9 },
2337 { EL_MOLE_DOWN, 9 },
2341 { EL_SATELLITE, 13 },
2342 { EL_SP_SNIKSNAK, 14 },
2343 { EL_SP_ELECTRON, 15 },
2346 { EL_EMC_ANDROID, 18 },
2351 static struct PropertyBitInfo pb_dont_collide_with[] =
2353 { EL_SP_SNIKSNAK, 0 },
2354 { EL_SP_ELECTRON, 1 },
2362 struct PropertyBitInfo *pb_info;
2365 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2366 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2371 struct PropertyBitInfo *pb_info = NULL;
2374 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2375 if (pb_definition[i].bit_nr == property_bit_nr)
2376 pb_info = pb_definition[i].pb_info;
2378 if (pb_info == NULL)
2381 for (i = 0; pb_info[i].element != -1; i++)
2382 if (pb_info[i].element == element)
2383 return pb_info[i].bit_nr;
2388 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2389 boolean property_value)
2391 int bit_nr = get_special_property_bit(element, property_bit_nr);
2396 *bitfield |= (1 << bit_nr);
2398 *bitfield &= ~(1 << bit_nr);
2402 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2404 int bit_nr = get_special_property_bit(element, property_bit_nr);
2407 return ((*bitfield & (1 << bit_nr)) != 0);
2412 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2414 static int group_nr;
2415 static struct ElementGroupInfo *group;
2416 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2419 if (actual_group == NULL) // not yet initialized
2422 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2424 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2425 group_element - EL_GROUP_START + 1);
2427 // replace element which caused too deep recursion by question mark
2428 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2433 if (recursion_depth == 0) // initialization
2435 group = actual_group;
2436 group_nr = GROUP_NR(group_element);
2438 group->num_elements_resolved = 0;
2439 group->choice_pos = 0;
2441 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2442 element_info[i].in_group[group_nr] = FALSE;
2445 for (i = 0; i < actual_group->num_elements; i++)
2447 int element = actual_group->element[i];
2449 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2452 if (IS_GROUP_ELEMENT(element))
2453 ResolveGroupElementExt(element, recursion_depth + 1);
2456 group->element_resolved[group->num_elements_resolved++] = element;
2457 element_info[element].in_group[group_nr] = TRUE;
2462 void ResolveGroupElement(int group_element)
2464 ResolveGroupElementExt(group_element, 0);
2467 void InitElementPropertiesStatic(void)
2469 static boolean clipboard_elements_initialized = FALSE;
2471 static int ep_diggable[] =
2476 EL_SP_BUGGY_BASE_ACTIVATING,
2479 EL_INVISIBLE_SAND_ACTIVE,
2482 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2483 // (if amoeba can grow into anything diggable, maybe keep these out)
2488 EL_SP_BUGGY_BASE_ACTIVE,
2495 static int ep_collectible_only[] =
2517 EL_DYNABOMB_INCREASE_NUMBER,
2518 EL_DYNABOMB_INCREASE_SIZE,
2519 EL_DYNABOMB_INCREASE_POWER,
2537 // !!! handle separately !!!
2538 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2544 static int ep_dont_run_into[] =
2546 // same elements as in 'ep_dont_touch'
2552 // same elements as in 'ep_dont_collide_with'
2564 // !!! maybe this should better be handled by 'ep_diggable' !!!
2569 EL_SP_BUGGY_BASE_ACTIVE,
2576 static int ep_dont_collide_with[] =
2578 // same elements as in 'ep_dont_touch'
2595 static int ep_dont_touch[] =
2605 static int ep_indestructible[] =
2609 EL_ACID_POOL_TOPLEFT,
2610 EL_ACID_POOL_TOPRIGHT,
2611 EL_ACID_POOL_BOTTOMLEFT,
2612 EL_ACID_POOL_BOTTOM,
2613 EL_ACID_POOL_BOTTOMRIGHT,
2614 EL_SP_HARDWARE_GRAY,
2615 EL_SP_HARDWARE_GREEN,
2616 EL_SP_HARDWARE_BLUE,
2618 EL_SP_HARDWARE_YELLOW,
2619 EL_SP_HARDWARE_BASE_1,
2620 EL_SP_HARDWARE_BASE_2,
2621 EL_SP_HARDWARE_BASE_3,
2622 EL_SP_HARDWARE_BASE_4,
2623 EL_SP_HARDWARE_BASE_5,
2624 EL_SP_HARDWARE_BASE_6,
2625 EL_INVISIBLE_STEELWALL,
2626 EL_INVISIBLE_STEELWALL_ACTIVE,
2627 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2628 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2629 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2630 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2631 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2632 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2633 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2634 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2635 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2636 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2637 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2638 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2640 EL_LIGHT_SWITCH_ACTIVE,
2641 EL_SIGN_EXCLAMATION,
2642 EL_SIGN_RADIOACTIVITY,
2649 EL_SIGN_ENTRY_FORBIDDEN,
2650 EL_SIGN_EMERGENCY_EXIT,
2658 EL_STEEL_EXIT_CLOSED,
2660 EL_STEEL_EXIT_OPENING,
2661 EL_STEEL_EXIT_CLOSING,
2662 EL_EM_STEEL_EXIT_CLOSED,
2663 EL_EM_STEEL_EXIT_OPEN,
2664 EL_EM_STEEL_EXIT_OPENING,
2665 EL_EM_STEEL_EXIT_CLOSING,
2666 EL_DC_STEELWALL_1_LEFT,
2667 EL_DC_STEELWALL_1_RIGHT,
2668 EL_DC_STEELWALL_1_TOP,
2669 EL_DC_STEELWALL_1_BOTTOM,
2670 EL_DC_STEELWALL_1_HORIZONTAL,
2671 EL_DC_STEELWALL_1_VERTICAL,
2672 EL_DC_STEELWALL_1_TOPLEFT,
2673 EL_DC_STEELWALL_1_TOPRIGHT,
2674 EL_DC_STEELWALL_1_BOTTOMLEFT,
2675 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2676 EL_DC_STEELWALL_1_TOPLEFT_2,
2677 EL_DC_STEELWALL_1_TOPRIGHT_2,
2678 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2679 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2680 EL_DC_STEELWALL_2_LEFT,
2681 EL_DC_STEELWALL_2_RIGHT,
2682 EL_DC_STEELWALL_2_TOP,
2683 EL_DC_STEELWALL_2_BOTTOM,
2684 EL_DC_STEELWALL_2_HORIZONTAL,
2685 EL_DC_STEELWALL_2_VERTICAL,
2686 EL_DC_STEELWALL_2_MIDDLE,
2687 EL_DC_STEELWALL_2_SINGLE,
2688 EL_STEELWALL_SLIPPERY,
2702 EL_GATE_1_GRAY_ACTIVE,
2703 EL_GATE_2_GRAY_ACTIVE,
2704 EL_GATE_3_GRAY_ACTIVE,
2705 EL_GATE_4_GRAY_ACTIVE,
2714 EL_EM_GATE_1_GRAY_ACTIVE,
2715 EL_EM_GATE_2_GRAY_ACTIVE,
2716 EL_EM_GATE_3_GRAY_ACTIVE,
2717 EL_EM_GATE_4_GRAY_ACTIVE,
2726 EL_EMC_GATE_5_GRAY_ACTIVE,
2727 EL_EMC_GATE_6_GRAY_ACTIVE,
2728 EL_EMC_GATE_7_GRAY_ACTIVE,
2729 EL_EMC_GATE_8_GRAY_ACTIVE,
2731 EL_DC_GATE_WHITE_GRAY,
2732 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2733 EL_DC_GATE_FAKE_GRAY,
2735 EL_SWITCHGATE_OPENING,
2736 EL_SWITCHGATE_CLOSED,
2737 EL_SWITCHGATE_CLOSING,
2738 EL_DC_SWITCHGATE_SWITCH_UP,
2739 EL_DC_SWITCHGATE_SWITCH_DOWN,
2741 EL_TIMEGATE_OPENING,
2743 EL_TIMEGATE_CLOSING,
2744 EL_DC_TIMEGATE_SWITCH,
2745 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2749 EL_TUBE_VERTICAL_LEFT,
2750 EL_TUBE_VERTICAL_RIGHT,
2751 EL_TUBE_HORIZONTAL_UP,
2752 EL_TUBE_HORIZONTAL_DOWN,
2757 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2758 EL_EXPANDABLE_STEELWALL_VERTICAL,
2759 EL_EXPANDABLE_STEELWALL_ANY,
2764 static int ep_slippery[] =
2778 EL_ROBOT_WHEEL_ACTIVE,
2784 EL_ACID_POOL_TOPLEFT,
2785 EL_ACID_POOL_TOPRIGHT,
2795 EL_STEELWALL_SLIPPERY,
2798 EL_EMC_WALL_SLIPPERY_1,
2799 EL_EMC_WALL_SLIPPERY_2,
2800 EL_EMC_WALL_SLIPPERY_3,
2801 EL_EMC_WALL_SLIPPERY_4,
2803 EL_EMC_MAGIC_BALL_ACTIVE,
2808 static int ep_can_change[] =
2813 static int ep_can_move[] =
2815 // same elements as in 'pb_can_move_into_acid'
2838 static int ep_can_fall[] =
2852 EL_QUICKSAND_FAST_FULL,
2854 EL_BD_MAGIC_WALL_FULL,
2855 EL_DC_MAGIC_WALL_FULL,
2869 static int ep_can_smash_player[] =
2895 static int ep_can_smash_enemies[] =
2904 static int ep_can_smash_everything[] =
2913 static int ep_explodes_by_fire[] =
2915 // same elements as in 'ep_explodes_impact'
2920 // same elements as in 'ep_explodes_smashed'
2930 EL_EM_DYNAMITE_ACTIVE,
2931 EL_DYNABOMB_PLAYER_1_ACTIVE,
2932 EL_DYNABOMB_PLAYER_2_ACTIVE,
2933 EL_DYNABOMB_PLAYER_3_ACTIVE,
2934 EL_DYNABOMB_PLAYER_4_ACTIVE,
2935 EL_DYNABOMB_INCREASE_NUMBER,
2936 EL_DYNABOMB_INCREASE_SIZE,
2937 EL_DYNABOMB_INCREASE_POWER,
2938 EL_SP_DISK_RED_ACTIVE,
2952 static int ep_explodes_smashed[] =
2954 // same elements as in 'ep_explodes_impact'
2968 static int ep_explodes_impact[] =
2977 static int ep_walkable_over[] =
2981 EL_SOKOBAN_FIELD_EMPTY,
2988 EL_EM_STEEL_EXIT_OPEN,
2989 EL_EM_STEEL_EXIT_OPENING,
2998 EL_GATE_1_GRAY_ACTIVE,
2999 EL_GATE_2_GRAY_ACTIVE,
3000 EL_GATE_3_GRAY_ACTIVE,
3001 EL_GATE_4_GRAY_ACTIVE,
3009 static int ep_walkable_inside[] =
3014 EL_TUBE_VERTICAL_LEFT,
3015 EL_TUBE_VERTICAL_RIGHT,
3016 EL_TUBE_HORIZONTAL_UP,
3017 EL_TUBE_HORIZONTAL_DOWN,
3026 static int ep_walkable_under[] =
3031 static int ep_passable_over[] =
3041 EL_EM_GATE_1_GRAY_ACTIVE,
3042 EL_EM_GATE_2_GRAY_ACTIVE,
3043 EL_EM_GATE_3_GRAY_ACTIVE,
3044 EL_EM_GATE_4_GRAY_ACTIVE,
3053 EL_EMC_GATE_5_GRAY_ACTIVE,
3054 EL_EMC_GATE_6_GRAY_ACTIVE,
3055 EL_EMC_GATE_7_GRAY_ACTIVE,
3056 EL_EMC_GATE_8_GRAY_ACTIVE,
3058 EL_DC_GATE_WHITE_GRAY,
3059 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3066 static int ep_passable_inside[] =
3072 EL_SP_PORT_HORIZONTAL,
3073 EL_SP_PORT_VERTICAL,
3075 EL_SP_GRAVITY_PORT_LEFT,
3076 EL_SP_GRAVITY_PORT_RIGHT,
3077 EL_SP_GRAVITY_PORT_UP,
3078 EL_SP_GRAVITY_PORT_DOWN,
3079 EL_SP_GRAVITY_ON_PORT_LEFT,
3080 EL_SP_GRAVITY_ON_PORT_RIGHT,
3081 EL_SP_GRAVITY_ON_PORT_UP,
3082 EL_SP_GRAVITY_ON_PORT_DOWN,
3083 EL_SP_GRAVITY_OFF_PORT_LEFT,
3084 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3085 EL_SP_GRAVITY_OFF_PORT_UP,
3086 EL_SP_GRAVITY_OFF_PORT_DOWN,
3091 static int ep_passable_under[] =
3096 static int ep_droppable[] =
3101 static int ep_explodes_1x1_old[] =
3106 static int ep_pushable[] =
3118 EL_SOKOBAN_FIELD_FULL,
3127 static int ep_explodes_cross_old[] =
3132 static int ep_protected[] =
3134 // same elements as in 'ep_walkable_inside'
3138 EL_TUBE_VERTICAL_LEFT,
3139 EL_TUBE_VERTICAL_RIGHT,
3140 EL_TUBE_HORIZONTAL_UP,
3141 EL_TUBE_HORIZONTAL_DOWN,
3147 // same elements as in 'ep_passable_over'
3156 EL_EM_GATE_1_GRAY_ACTIVE,
3157 EL_EM_GATE_2_GRAY_ACTIVE,
3158 EL_EM_GATE_3_GRAY_ACTIVE,
3159 EL_EM_GATE_4_GRAY_ACTIVE,
3168 EL_EMC_GATE_5_GRAY_ACTIVE,
3169 EL_EMC_GATE_6_GRAY_ACTIVE,
3170 EL_EMC_GATE_7_GRAY_ACTIVE,
3171 EL_EMC_GATE_8_GRAY_ACTIVE,
3173 EL_DC_GATE_WHITE_GRAY,
3174 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3178 // same elements as in 'ep_passable_inside'
3183 EL_SP_PORT_HORIZONTAL,
3184 EL_SP_PORT_VERTICAL,
3186 EL_SP_GRAVITY_PORT_LEFT,
3187 EL_SP_GRAVITY_PORT_RIGHT,
3188 EL_SP_GRAVITY_PORT_UP,
3189 EL_SP_GRAVITY_PORT_DOWN,
3190 EL_SP_GRAVITY_ON_PORT_LEFT,
3191 EL_SP_GRAVITY_ON_PORT_RIGHT,
3192 EL_SP_GRAVITY_ON_PORT_UP,
3193 EL_SP_GRAVITY_ON_PORT_DOWN,
3194 EL_SP_GRAVITY_OFF_PORT_LEFT,
3195 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3196 EL_SP_GRAVITY_OFF_PORT_UP,
3197 EL_SP_GRAVITY_OFF_PORT_DOWN,
3202 static int ep_throwable[] =
3207 static int ep_can_explode[] =
3209 // same elements as in 'ep_explodes_impact'
3214 // same elements as in 'ep_explodes_smashed'
3220 // elements that can explode by explosion or by dragonfire
3224 EL_EM_DYNAMITE_ACTIVE,
3225 EL_DYNABOMB_PLAYER_1_ACTIVE,
3226 EL_DYNABOMB_PLAYER_2_ACTIVE,
3227 EL_DYNABOMB_PLAYER_3_ACTIVE,
3228 EL_DYNABOMB_PLAYER_4_ACTIVE,
3229 EL_DYNABOMB_INCREASE_NUMBER,
3230 EL_DYNABOMB_INCREASE_SIZE,
3231 EL_DYNABOMB_INCREASE_POWER,
3232 EL_SP_DISK_RED_ACTIVE,
3240 // elements that can explode only by explosion
3246 static int ep_gravity_reachable[] =
3252 EL_INVISIBLE_SAND_ACTIVE,
3257 EL_SP_PORT_HORIZONTAL,
3258 EL_SP_PORT_VERTICAL,
3260 EL_SP_GRAVITY_PORT_LEFT,
3261 EL_SP_GRAVITY_PORT_RIGHT,
3262 EL_SP_GRAVITY_PORT_UP,
3263 EL_SP_GRAVITY_PORT_DOWN,
3264 EL_SP_GRAVITY_ON_PORT_LEFT,
3265 EL_SP_GRAVITY_ON_PORT_RIGHT,
3266 EL_SP_GRAVITY_ON_PORT_UP,
3267 EL_SP_GRAVITY_ON_PORT_DOWN,
3268 EL_SP_GRAVITY_OFF_PORT_LEFT,
3269 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3270 EL_SP_GRAVITY_OFF_PORT_UP,
3271 EL_SP_GRAVITY_OFF_PORT_DOWN,
3277 static int ep_player[] =
3284 EL_SOKOBAN_FIELD_PLAYER,
3290 static int ep_can_pass_magic_wall[] =
3304 static int ep_can_pass_dc_magic_wall[] =
3320 static int ep_switchable[] =
3324 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3325 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3326 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3327 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3328 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3329 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3330 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3331 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3332 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3333 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3334 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3335 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3336 EL_SWITCHGATE_SWITCH_UP,
3337 EL_SWITCHGATE_SWITCH_DOWN,
3338 EL_DC_SWITCHGATE_SWITCH_UP,
3339 EL_DC_SWITCHGATE_SWITCH_DOWN,
3341 EL_LIGHT_SWITCH_ACTIVE,
3343 EL_DC_TIMEGATE_SWITCH,
3344 EL_BALLOON_SWITCH_LEFT,
3345 EL_BALLOON_SWITCH_RIGHT,
3346 EL_BALLOON_SWITCH_UP,
3347 EL_BALLOON_SWITCH_DOWN,
3348 EL_BALLOON_SWITCH_ANY,
3349 EL_BALLOON_SWITCH_NONE,
3352 EL_EMC_MAGIC_BALL_SWITCH,
3353 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3358 static int ep_bd_element[] =
3392 static int ep_sp_element[] =
3394 // should always be valid
3397 // standard classic Supaplex elements
3404 EL_SP_HARDWARE_GRAY,
3412 EL_SP_GRAVITY_PORT_RIGHT,
3413 EL_SP_GRAVITY_PORT_DOWN,
3414 EL_SP_GRAVITY_PORT_LEFT,
3415 EL_SP_GRAVITY_PORT_UP,
3420 EL_SP_PORT_VERTICAL,
3421 EL_SP_PORT_HORIZONTAL,
3427 EL_SP_HARDWARE_BASE_1,
3428 EL_SP_HARDWARE_GREEN,
3429 EL_SP_HARDWARE_BLUE,
3431 EL_SP_HARDWARE_YELLOW,
3432 EL_SP_HARDWARE_BASE_2,
3433 EL_SP_HARDWARE_BASE_3,
3434 EL_SP_HARDWARE_BASE_4,
3435 EL_SP_HARDWARE_BASE_5,
3436 EL_SP_HARDWARE_BASE_6,
3440 // additional elements that appeared in newer Supaplex levels
3443 // additional gravity port elements (not switching, but setting gravity)
3444 EL_SP_GRAVITY_ON_PORT_LEFT,
3445 EL_SP_GRAVITY_ON_PORT_RIGHT,
3446 EL_SP_GRAVITY_ON_PORT_UP,
3447 EL_SP_GRAVITY_ON_PORT_DOWN,
3448 EL_SP_GRAVITY_OFF_PORT_LEFT,
3449 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3450 EL_SP_GRAVITY_OFF_PORT_UP,
3451 EL_SP_GRAVITY_OFF_PORT_DOWN,
3453 // more than one Murphy in a level results in an inactive clone
3456 // runtime Supaplex elements
3457 EL_SP_DISK_RED_ACTIVE,
3458 EL_SP_TERMINAL_ACTIVE,
3459 EL_SP_BUGGY_BASE_ACTIVATING,
3460 EL_SP_BUGGY_BASE_ACTIVE,
3467 static int ep_sb_element[] =
3472 EL_SOKOBAN_FIELD_EMPTY,
3473 EL_SOKOBAN_FIELD_FULL,
3474 EL_SOKOBAN_FIELD_PLAYER,
3479 EL_INVISIBLE_STEELWALL,
3484 static int ep_gem[] =
3496 static int ep_food_dark_yamyam[] =
3524 static int ep_food_penguin[] =
3538 static int ep_food_pig[] =
3550 static int ep_historic_wall[] =
3561 EL_GATE_1_GRAY_ACTIVE,
3562 EL_GATE_2_GRAY_ACTIVE,
3563 EL_GATE_3_GRAY_ACTIVE,
3564 EL_GATE_4_GRAY_ACTIVE,
3573 EL_EM_GATE_1_GRAY_ACTIVE,
3574 EL_EM_GATE_2_GRAY_ACTIVE,
3575 EL_EM_GATE_3_GRAY_ACTIVE,
3576 EL_EM_GATE_4_GRAY_ACTIVE,
3583 EL_EXPANDABLE_WALL_HORIZONTAL,
3584 EL_EXPANDABLE_WALL_VERTICAL,
3585 EL_EXPANDABLE_WALL_ANY,
3586 EL_EXPANDABLE_WALL_GROWING,
3587 EL_BD_EXPANDABLE_WALL,
3594 EL_SP_HARDWARE_GRAY,
3595 EL_SP_HARDWARE_GREEN,
3596 EL_SP_HARDWARE_BLUE,
3598 EL_SP_HARDWARE_YELLOW,
3599 EL_SP_HARDWARE_BASE_1,
3600 EL_SP_HARDWARE_BASE_2,
3601 EL_SP_HARDWARE_BASE_3,
3602 EL_SP_HARDWARE_BASE_4,
3603 EL_SP_HARDWARE_BASE_5,
3604 EL_SP_HARDWARE_BASE_6,
3606 EL_SP_TERMINAL_ACTIVE,
3609 EL_INVISIBLE_STEELWALL,
3610 EL_INVISIBLE_STEELWALL_ACTIVE,
3612 EL_INVISIBLE_WALL_ACTIVE,
3613 EL_STEELWALL_SLIPPERY,
3630 static int ep_historic_solid[] =
3634 EL_EXPANDABLE_WALL_HORIZONTAL,
3635 EL_EXPANDABLE_WALL_VERTICAL,
3636 EL_EXPANDABLE_WALL_ANY,
3637 EL_BD_EXPANDABLE_WALL,
3650 EL_QUICKSAND_FILLING,
3651 EL_QUICKSAND_EMPTYING,
3653 EL_MAGIC_WALL_ACTIVE,
3654 EL_MAGIC_WALL_EMPTYING,
3655 EL_MAGIC_WALL_FILLING,
3659 EL_BD_MAGIC_WALL_ACTIVE,
3660 EL_BD_MAGIC_WALL_EMPTYING,
3661 EL_BD_MAGIC_WALL_FULL,
3662 EL_BD_MAGIC_WALL_FILLING,
3663 EL_BD_MAGIC_WALL_DEAD,
3672 EL_SP_TERMINAL_ACTIVE,
3676 EL_INVISIBLE_WALL_ACTIVE,
3677 EL_SWITCHGATE_SWITCH_UP,
3678 EL_SWITCHGATE_SWITCH_DOWN,
3680 EL_TIMEGATE_SWITCH_ACTIVE,
3692 // the following elements are a direct copy of "indestructible" elements,
3693 // except "EL_ACID", which is "indestructible", but not "solid"!
3698 EL_ACID_POOL_TOPLEFT,
3699 EL_ACID_POOL_TOPRIGHT,
3700 EL_ACID_POOL_BOTTOMLEFT,
3701 EL_ACID_POOL_BOTTOM,
3702 EL_ACID_POOL_BOTTOMRIGHT,
3703 EL_SP_HARDWARE_GRAY,
3704 EL_SP_HARDWARE_GREEN,
3705 EL_SP_HARDWARE_BLUE,
3707 EL_SP_HARDWARE_YELLOW,
3708 EL_SP_HARDWARE_BASE_1,
3709 EL_SP_HARDWARE_BASE_2,
3710 EL_SP_HARDWARE_BASE_3,
3711 EL_SP_HARDWARE_BASE_4,
3712 EL_SP_HARDWARE_BASE_5,
3713 EL_SP_HARDWARE_BASE_6,
3714 EL_INVISIBLE_STEELWALL,
3715 EL_INVISIBLE_STEELWALL_ACTIVE,
3716 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3717 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3718 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3719 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3720 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3721 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3722 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3723 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3724 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3725 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3726 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3727 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3729 EL_LIGHT_SWITCH_ACTIVE,
3730 EL_SIGN_EXCLAMATION,
3731 EL_SIGN_RADIOACTIVITY,
3738 EL_SIGN_ENTRY_FORBIDDEN,
3739 EL_SIGN_EMERGENCY_EXIT,
3747 EL_STEEL_EXIT_CLOSED,
3749 EL_STEEL_EXIT_OPENING,
3750 EL_STEEL_EXIT_CLOSING,
3751 EL_EM_STEEL_EXIT_CLOSED,
3752 EL_EM_STEEL_EXIT_OPEN,
3753 EL_EM_STEEL_EXIT_OPENING,
3754 EL_EM_STEEL_EXIT_CLOSING,
3755 EL_DC_STEELWALL_1_LEFT,
3756 EL_DC_STEELWALL_1_RIGHT,
3757 EL_DC_STEELWALL_1_TOP,
3758 EL_DC_STEELWALL_1_BOTTOM,
3759 EL_DC_STEELWALL_1_HORIZONTAL,
3760 EL_DC_STEELWALL_1_VERTICAL,
3761 EL_DC_STEELWALL_1_TOPLEFT,
3762 EL_DC_STEELWALL_1_TOPRIGHT,
3763 EL_DC_STEELWALL_1_BOTTOMLEFT,
3764 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3765 EL_DC_STEELWALL_1_TOPLEFT_2,
3766 EL_DC_STEELWALL_1_TOPRIGHT_2,
3767 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3768 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3769 EL_DC_STEELWALL_2_LEFT,
3770 EL_DC_STEELWALL_2_RIGHT,
3771 EL_DC_STEELWALL_2_TOP,
3772 EL_DC_STEELWALL_2_BOTTOM,
3773 EL_DC_STEELWALL_2_HORIZONTAL,
3774 EL_DC_STEELWALL_2_VERTICAL,
3775 EL_DC_STEELWALL_2_MIDDLE,
3776 EL_DC_STEELWALL_2_SINGLE,
3777 EL_STEELWALL_SLIPPERY,
3791 EL_GATE_1_GRAY_ACTIVE,
3792 EL_GATE_2_GRAY_ACTIVE,
3793 EL_GATE_3_GRAY_ACTIVE,
3794 EL_GATE_4_GRAY_ACTIVE,
3803 EL_EM_GATE_1_GRAY_ACTIVE,
3804 EL_EM_GATE_2_GRAY_ACTIVE,
3805 EL_EM_GATE_3_GRAY_ACTIVE,
3806 EL_EM_GATE_4_GRAY_ACTIVE,
3815 EL_EMC_GATE_5_GRAY_ACTIVE,
3816 EL_EMC_GATE_6_GRAY_ACTIVE,
3817 EL_EMC_GATE_7_GRAY_ACTIVE,
3818 EL_EMC_GATE_8_GRAY_ACTIVE,
3820 EL_DC_GATE_WHITE_GRAY,
3821 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3822 EL_DC_GATE_FAKE_GRAY,
3824 EL_SWITCHGATE_OPENING,
3825 EL_SWITCHGATE_CLOSED,
3826 EL_SWITCHGATE_CLOSING,
3827 EL_DC_SWITCHGATE_SWITCH_UP,
3828 EL_DC_SWITCHGATE_SWITCH_DOWN,
3830 EL_TIMEGATE_OPENING,
3832 EL_TIMEGATE_CLOSING,
3833 EL_DC_TIMEGATE_SWITCH,
3834 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3838 EL_TUBE_VERTICAL_LEFT,
3839 EL_TUBE_VERTICAL_RIGHT,
3840 EL_TUBE_HORIZONTAL_UP,
3841 EL_TUBE_HORIZONTAL_DOWN,
3846 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3847 EL_EXPANDABLE_STEELWALL_VERTICAL,
3848 EL_EXPANDABLE_STEELWALL_ANY,
3853 static int ep_classic_enemy[] =
3870 static int ep_belt[] =
3872 EL_CONVEYOR_BELT_1_LEFT,
3873 EL_CONVEYOR_BELT_1_MIDDLE,
3874 EL_CONVEYOR_BELT_1_RIGHT,
3875 EL_CONVEYOR_BELT_2_LEFT,
3876 EL_CONVEYOR_BELT_2_MIDDLE,
3877 EL_CONVEYOR_BELT_2_RIGHT,
3878 EL_CONVEYOR_BELT_3_LEFT,
3879 EL_CONVEYOR_BELT_3_MIDDLE,
3880 EL_CONVEYOR_BELT_3_RIGHT,
3881 EL_CONVEYOR_BELT_4_LEFT,
3882 EL_CONVEYOR_BELT_4_MIDDLE,
3883 EL_CONVEYOR_BELT_4_RIGHT,
3888 static int ep_belt_active[] =
3890 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3891 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3892 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3893 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3894 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3895 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3896 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3897 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3898 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3899 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3900 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3901 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3906 static int ep_belt_switch[] =
3908 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3909 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3910 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3911 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3912 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3913 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3914 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3915 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3916 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3917 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3918 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3919 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3924 static int ep_tube[] =
3931 EL_TUBE_HORIZONTAL_UP,
3932 EL_TUBE_HORIZONTAL_DOWN,
3934 EL_TUBE_VERTICAL_LEFT,
3935 EL_TUBE_VERTICAL_RIGHT,
3941 static int ep_acid_pool[] =
3943 EL_ACID_POOL_TOPLEFT,
3944 EL_ACID_POOL_TOPRIGHT,
3945 EL_ACID_POOL_BOTTOMLEFT,
3946 EL_ACID_POOL_BOTTOM,
3947 EL_ACID_POOL_BOTTOMRIGHT,
3952 static int ep_keygate[] =
3962 EL_GATE_1_GRAY_ACTIVE,
3963 EL_GATE_2_GRAY_ACTIVE,
3964 EL_GATE_3_GRAY_ACTIVE,
3965 EL_GATE_4_GRAY_ACTIVE,
3974 EL_EM_GATE_1_GRAY_ACTIVE,
3975 EL_EM_GATE_2_GRAY_ACTIVE,
3976 EL_EM_GATE_3_GRAY_ACTIVE,
3977 EL_EM_GATE_4_GRAY_ACTIVE,
3986 EL_EMC_GATE_5_GRAY_ACTIVE,
3987 EL_EMC_GATE_6_GRAY_ACTIVE,
3988 EL_EMC_GATE_7_GRAY_ACTIVE,
3989 EL_EMC_GATE_8_GRAY_ACTIVE,
3991 EL_DC_GATE_WHITE_GRAY,
3992 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3997 static int ep_amoeboid[] =
4009 static int ep_amoebalive[] =
4020 static int ep_has_editor_content[] =
4026 EL_SOKOBAN_FIELD_PLAYER,
4043 static int ep_can_turn_each_move[] =
4045 // !!! do something with this one !!!
4049 static int ep_can_grow[] =
4063 static int ep_active_bomb[] =
4066 EL_EM_DYNAMITE_ACTIVE,
4067 EL_DYNABOMB_PLAYER_1_ACTIVE,
4068 EL_DYNABOMB_PLAYER_2_ACTIVE,
4069 EL_DYNABOMB_PLAYER_3_ACTIVE,
4070 EL_DYNABOMB_PLAYER_4_ACTIVE,
4071 EL_SP_DISK_RED_ACTIVE,
4076 static int ep_inactive[] =
4086 EL_QUICKSAND_FAST_EMPTY,
4109 EL_GATE_1_GRAY_ACTIVE,
4110 EL_GATE_2_GRAY_ACTIVE,
4111 EL_GATE_3_GRAY_ACTIVE,
4112 EL_GATE_4_GRAY_ACTIVE,
4121 EL_EM_GATE_1_GRAY_ACTIVE,
4122 EL_EM_GATE_2_GRAY_ACTIVE,
4123 EL_EM_GATE_3_GRAY_ACTIVE,
4124 EL_EM_GATE_4_GRAY_ACTIVE,
4133 EL_EMC_GATE_5_GRAY_ACTIVE,
4134 EL_EMC_GATE_6_GRAY_ACTIVE,
4135 EL_EMC_GATE_7_GRAY_ACTIVE,
4136 EL_EMC_GATE_8_GRAY_ACTIVE,
4138 EL_DC_GATE_WHITE_GRAY,
4139 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4140 EL_DC_GATE_FAKE_GRAY,
4143 EL_INVISIBLE_STEELWALL,
4151 EL_WALL_EMERALD_YELLOW,
4152 EL_DYNABOMB_INCREASE_NUMBER,
4153 EL_DYNABOMB_INCREASE_SIZE,
4154 EL_DYNABOMB_INCREASE_POWER,
4158 EL_SOKOBAN_FIELD_EMPTY,
4159 EL_SOKOBAN_FIELD_FULL,
4160 EL_WALL_EMERALD_RED,
4161 EL_WALL_EMERALD_PURPLE,
4162 EL_ACID_POOL_TOPLEFT,
4163 EL_ACID_POOL_TOPRIGHT,
4164 EL_ACID_POOL_BOTTOMLEFT,
4165 EL_ACID_POOL_BOTTOM,
4166 EL_ACID_POOL_BOTTOMRIGHT,
4170 EL_BD_MAGIC_WALL_DEAD,
4172 EL_DC_MAGIC_WALL_DEAD,
4173 EL_AMOEBA_TO_DIAMOND,
4181 EL_SP_GRAVITY_PORT_RIGHT,
4182 EL_SP_GRAVITY_PORT_DOWN,
4183 EL_SP_GRAVITY_PORT_LEFT,
4184 EL_SP_GRAVITY_PORT_UP,
4185 EL_SP_PORT_HORIZONTAL,
4186 EL_SP_PORT_VERTICAL,
4197 EL_SP_HARDWARE_GRAY,
4198 EL_SP_HARDWARE_GREEN,
4199 EL_SP_HARDWARE_BLUE,
4201 EL_SP_HARDWARE_YELLOW,
4202 EL_SP_HARDWARE_BASE_1,
4203 EL_SP_HARDWARE_BASE_2,
4204 EL_SP_HARDWARE_BASE_3,
4205 EL_SP_HARDWARE_BASE_4,
4206 EL_SP_HARDWARE_BASE_5,
4207 EL_SP_HARDWARE_BASE_6,
4208 EL_SP_GRAVITY_ON_PORT_LEFT,
4209 EL_SP_GRAVITY_ON_PORT_RIGHT,
4210 EL_SP_GRAVITY_ON_PORT_UP,
4211 EL_SP_GRAVITY_ON_PORT_DOWN,
4212 EL_SP_GRAVITY_OFF_PORT_LEFT,
4213 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4214 EL_SP_GRAVITY_OFF_PORT_UP,
4215 EL_SP_GRAVITY_OFF_PORT_DOWN,
4216 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4217 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4218 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4219 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4220 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4221 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4222 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4223 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4224 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4225 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4226 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4227 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4228 EL_SIGN_EXCLAMATION,
4229 EL_SIGN_RADIOACTIVITY,
4236 EL_SIGN_ENTRY_FORBIDDEN,
4237 EL_SIGN_EMERGENCY_EXIT,
4245 EL_DC_STEELWALL_1_LEFT,
4246 EL_DC_STEELWALL_1_RIGHT,
4247 EL_DC_STEELWALL_1_TOP,
4248 EL_DC_STEELWALL_1_BOTTOM,
4249 EL_DC_STEELWALL_1_HORIZONTAL,
4250 EL_DC_STEELWALL_1_VERTICAL,
4251 EL_DC_STEELWALL_1_TOPLEFT,
4252 EL_DC_STEELWALL_1_TOPRIGHT,
4253 EL_DC_STEELWALL_1_BOTTOMLEFT,
4254 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4255 EL_DC_STEELWALL_1_TOPLEFT_2,
4256 EL_DC_STEELWALL_1_TOPRIGHT_2,
4257 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4258 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4259 EL_DC_STEELWALL_2_LEFT,
4260 EL_DC_STEELWALL_2_RIGHT,
4261 EL_DC_STEELWALL_2_TOP,
4262 EL_DC_STEELWALL_2_BOTTOM,
4263 EL_DC_STEELWALL_2_HORIZONTAL,
4264 EL_DC_STEELWALL_2_VERTICAL,
4265 EL_DC_STEELWALL_2_MIDDLE,
4266 EL_DC_STEELWALL_2_SINGLE,
4267 EL_STEELWALL_SLIPPERY,
4272 EL_EMC_WALL_SLIPPERY_1,
4273 EL_EMC_WALL_SLIPPERY_2,
4274 EL_EMC_WALL_SLIPPERY_3,
4275 EL_EMC_WALL_SLIPPERY_4,
4296 static int ep_em_slippery_wall[] =
4301 static int ep_gfx_crumbled[] =
4312 static int ep_editor_cascade_active[] =
4314 EL_INTERNAL_CASCADE_BD_ACTIVE,
4315 EL_INTERNAL_CASCADE_EM_ACTIVE,
4316 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4317 EL_INTERNAL_CASCADE_RND_ACTIVE,
4318 EL_INTERNAL_CASCADE_SB_ACTIVE,
4319 EL_INTERNAL_CASCADE_SP_ACTIVE,
4320 EL_INTERNAL_CASCADE_DC_ACTIVE,
4321 EL_INTERNAL_CASCADE_DX_ACTIVE,
4322 EL_INTERNAL_CASCADE_MM_ACTIVE,
4323 EL_INTERNAL_CASCADE_DF_ACTIVE,
4324 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4325 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4326 EL_INTERNAL_CASCADE_CE_ACTIVE,
4327 EL_INTERNAL_CASCADE_GE_ACTIVE,
4328 EL_INTERNAL_CASCADE_REF_ACTIVE,
4329 EL_INTERNAL_CASCADE_USER_ACTIVE,
4330 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4335 static int ep_editor_cascade_inactive[] =
4337 EL_INTERNAL_CASCADE_BD,
4338 EL_INTERNAL_CASCADE_EM,
4339 EL_INTERNAL_CASCADE_EMC,
4340 EL_INTERNAL_CASCADE_RND,
4341 EL_INTERNAL_CASCADE_SB,
4342 EL_INTERNAL_CASCADE_SP,
4343 EL_INTERNAL_CASCADE_DC,
4344 EL_INTERNAL_CASCADE_DX,
4345 EL_INTERNAL_CASCADE_MM,
4346 EL_INTERNAL_CASCADE_DF,
4347 EL_INTERNAL_CASCADE_CHARS,
4348 EL_INTERNAL_CASCADE_STEEL_CHARS,
4349 EL_INTERNAL_CASCADE_CE,
4350 EL_INTERNAL_CASCADE_GE,
4351 EL_INTERNAL_CASCADE_REF,
4352 EL_INTERNAL_CASCADE_USER,
4353 EL_INTERNAL_CASCADE_DYNAMIC,
4358 static int ep_obsolete[] =
4362 EL_EM_KEY_1_FILE_OBSOLETE,
4363 EL_EM_KEY_2_FILE_OBSOLETE,
4364 EL_EM_KEY_3_FILE_OBSOLETE,
4365 EL_EM_KEY_4_FILE_OBSOLETE,
4366 EL_ENVELOPE_OBSOLETE,
4375 } element_properties[] =
4377 { ep_diggable, EP_DIGGABLE },
4378 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4379 { ep_dont_run_into, EP_DONT_RUN_INTO },
4380 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4381 { ep_dont_touch, EP_DONT_TOUCH },
4382 { ep_indestructible, EP_INDESTRUCTIBLE },
4383 { ep_slippery, EP_SLIPPERY },
4384 { ep_can_change, EP_CAN_CHANGE },
4385 { ep_can_move, EP_CAN_MOVE },
4386 { ep_can_fall, EP_CAN_FALL },
4387 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4388 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4389 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4390 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4391 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4392 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4393 { ep_walkable_over, EP_WALKABLE_OVER },
4394 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4395 { ep_walkable_under, EP_WALKABLE_UNDER },
4396 { ep_passable_over, EP_PASSABLE_OVER },
4397 { ep_passable_inside, EP_PASSABLE_INSIDE },
4398 { ep_passable_under, EP_PASSABLE_UNDER },
4399 { ep_droppable, EP_DROPPABLE },
4400 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4401 { ep_pushable, EP_PUSHABLE },
4402 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4403 { ep_protected, EP_PROTECTED },
4404 { ep_throwable, EP_THROWABLE },
4405 { ep_can_explode, EP_CAN_EXPLODE },
4406 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4408 { ep_player, EP_PLAYER },
4409 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4410 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4411 { ep_switchable, EP_SWITCHABLE },
4412 { ep_bd_element, EP_BD_ELEMENT },
4413 { ep_sp_element, EP_SP_ELEMENT },
4414 { ep_sb_element, EP_SB_ELEMENT },
4416 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4417 { ep_food_penguin, EP_FOOD_PENGUIN },
4418 { ep_food_pig, EP_FOOD_PIG },
4419 { ep_historic_wall, EP_HISTORIC_WALL },
4420 { ep_historic_solid, EP_HISTORIC_SOLID },
4421 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4422 { ep_belt, EP_BELT },
4423 { ep_belt_active, EP_BELT_ACTIVE },
4424 { ep_belt_switch, EP_BELT_SWITCH },
4425 { ep_tube, EP_TUBE },
4426 { ep_acid_pool, EP_ACID_POOL },
4427 { ep_keygate, EP_KEYGATE },
4428 { ep_amoeboid, EP_AMOEBOID },
4429 { ep_amoebalive, EP_AMOEBALIVE },
4430 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4431 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4432 { ep_can_grow, EP_CAN_GROW },
4433 { ep_active_bomb, EP_ACTIVE_BOMB },
4434 { ep_inactive, EP_INACTIVE },
4436 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4438 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4440 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4441 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4443 { ep_obsolete, EP_OBSOLETE },
4450 // always start with reliable default values (element has no properties)
4451 // (but never initialize clipboard elements after the very first time)
4452 // (to be able to use clipboard elements between several levels)
4453 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4454 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4455 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4456 SET_PROPERTY(i, j, FALSE);
4458 // set all base element properties from above array definitions
4459 for (i = 0; element_properties[i].elements != NULL; i++)
4460 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4461 SET_PROPERTY((element_properties[i].elements)[j],
4462 element_properties[i].property, TRUE);
4464 // copy properties to some elements that are only stored in level file
4465 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4466 for (j = 0; copy_properties[j][0] != -1; j++)
4467 if (HAS_PROPERTY(copy_properties[j][0], i))
4468 for (k = 1; k <= 4; k++)
4469 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4471 // set static element properties that are not listed in array definitions
4472 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4473 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4475 clipboard_elements_initialized = TRUE;
4478 void InitElementPropertiesEngine(int engine_version)
4480 static int no_wall_properties[] =
4483 EP_COLLECTIBLE_ONLY,
4485 EP_DONT_COLLIDE_WITH,
4488 EP_CAN_SMASH_PLAYER,
4489 EP_CAN_SMASH_ENEMIES,
4490 EP_CAN_SMASH_EVERYTHING,
4495 EP_FOOD_DARK_YAMYAM,
4511 /* important: after initialization in InitElementPropertiesStatic(), the
4512 elements are not again initialized to a default value; therefore all
4513 changes have to make sure that they leave the element with a defined
4514 property (which means that conditional property changes must be set to
4515 a reliable default value before) */
4517 // resolve group elements
4518 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4519 ResolveGroupElement(EL_GROUP_START + i);
4521 // set all special, combined or engine dependent element properties
4522 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4524 // do not change (already initialized) clipboard elements here
4525 if (IS_CLIPBOARD_ELEMENT(i))
4528 // ---------- INACTIVE ----------------------------------------------------
4529 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4530 i <= EL_CHAR_END) ||
4531 (i >= EL_STEEL_CHAR_START &&
4532 i <= EL_STEEL_CHAR_END)));
4534 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4535 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4536 IS_WALKABLE_INSIDE(i) ||
4537 IS_WALKABLE_UNDER(i)));
4539 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4540 IS_PASSABLE_INSIDE(i) ||
4541 IS_PASSABLE_UNDER(i)));
4543 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4544 IS_PASSABLE_OVER(i)));
4546 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4547 IS_PASSABLE_INSIDE(i)));
4549 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4550 IS_PASSABLE_UNDER(i)));
4552 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4555 // ---------- COLLECTIBLE -------------------------------------------------
4556 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4560 // ---------- SNAPPABLE ---------------------------------------------------
4561 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4562 IS_COLLECTIBLE(i) ||
4566 // ---------- WALL --------------------------------------------------------
4567 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4569 for (j = 0; no_wall_properties[j] != -1; j++)
4570 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4571 i >= EL_FIRST_RUNTIME_UNREAL)
4572 SET_PROPERTY(i, EP_WALL, FALSE);
4574 if (IS_HISTORIC_WALL(i))
4575 SET_PROPERTY(i, EP_WALL, TRUE);
4577 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4578 if (engine_version < VERSION_IDENT(2,2,0,0))
4579 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4581 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4583 !IS_COLLECTIBLE(i)));
4585 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4586 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4587 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4589 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4592 // ---------- EXPLOSION_PROOF ---------------------------------------------
4594 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4595 else if (engine_version < VERSION_IDENT(2,2,0,0))
4596 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4598 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4602 if (IS_CUSTOM_ELEMENT(i))
4604 // these are additional properties which are initially false when set
4606 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4608 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4609 if (DONT_COLLIDE_WITH(i))
4610 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4612 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4613 if (CAN_SMASH_EVERYTHING(i))
4614 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4615 if (CAN_SMASH_ENEMIES(i))
4616 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4619 // ---------- CAN_SMASH ---------------------------------------------------
4620 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4621 CAN_SMASH_ENEMIES(i) ||
4622 CAN_SMASH_EVERYTHING(i)));
4624 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4625 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4626 EXPLODES_BY_FIRE(i)));
4628 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4629 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4630 EXPLODES_SMASHED(i)));
4632 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4633 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4634 EXPLODES_IMPACT(i)));
4636 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4637 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4639 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4640 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4641 i == EL_BLACK_ORB));
4643 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4644 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4646 IS_CUSTOM_ELEMENT(i)));
4648 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4649 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4650 i == EL_SP_ELECTRON));
4652 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4653 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4654 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4655 getMoveIntoAcidProperty(&level, i));
4657 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4658 if (MAYBE_DONT_COLLIDE_WITH(i))
4659 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4660 getDontCollideWithProperty(&level, i));
4662 // ---------- SP_PORT -----------------------------------------------------
4663 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4664 IS_PASSABLE_INSIDE(i)));
4666 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4667 for (j = 0; j < level.num_android_clone_elements; j++)
4668 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4670 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4672 // ---------- CAN_CHANGE --------------------------------------------------
4673 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4674 for (j = 0; j < element_info[i].num_change_pages; j++)
4675 if (element_info[i].change_page[j].can_change)
4676 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4678 // ---------- HAS_ACTION --------------------------------------------------
4679 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4680 for (j = 0; j < element_info[i].num_change_pages; j++)
4681 if (element_info[i].change_page[j].has_action)
4682 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4684 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4685 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4688 // ---------- GFX_CRUMBLED ------------------------------------------------
4689 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4690 element_info[i].crumbled[ACTION_DEFAULT] !=
4691 element_info[i].graphic[ACTION_DEFAULT]);
4693 // ---------- EDITOR_CASCADE ----------------------------------------------
4694 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4695 IS_EDITOR_CASCADE_INACTIVE(i)));
4698 // dynamically adjust element properties according to game engine version
4700 static int ep_em_slippery_wall[] =
4705 EL_EXPANDABLE_WALL_HORIZONTAL,
4706 EL_EXPANDABLE_WALL_VERTICAL,
4707 EL_EXPANDABLE_WALL_ANY,
4708 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4709 EL_EXPANDABLE_STEELWALL_VERTICAL,
4710 EL_EXPANDABLE_STEELWALL_ANY,
4711 EL_EXPANDABLE_STEELWALL_GROWING,
4715 static int ep_em_explodes_by_fire[] =
4718 EL_EM_DYNAMITE_ACTIVE,
4723 // special EM style gems behaviour
4724 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4725 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4726 level.em_slippery_gems);
4728 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4729 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4730 (level.em_slippery_gems &&
4731 engine_version > VERSION_IDENT(2,0,1,0)));
4733 // special EM style explosion behaviour regarding chain reactions
4734 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4735 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4736 level.em_explodes_by_fire);
4739 // this is needed because some graphics depend on element properties
4740 if (game_status == GAME_MODE_PLAYING)
4741 InitElementGraphicInfo();
4744 void InitElementPropertiesGfxElement(void)
4748 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4750 struct ElementInfo *ei = &element_info[i];
4752 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4756 static void InitGlobal(void)
4761 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4763 // check if element_name_info entry defined for each element in "main.h"
4764 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4765 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4767 element_info[i].token_name = element_name_info[i].token_name;
4768 element_info[i].class_name = element_name_info[i].class_name;
4769 element_info[i].editor_description= element_name_info[i].editor_description;
4772 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4774 // check if global_anim_name_info defined for each entry in "main.h"
4775 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4776 global_anim_name_info[i].token_name == NULL)
4777 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4779 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4782 // create hash from image config list
4783 image_config_hash = newSetupFileHash();
4784 for (i = 0; image_config[i].token != NULL; i++)
4785 setHashEntry(image_config_hash,
4786 image_config[i].token,
4787 image_config[i].value);
4789 // create hash from element token list
4790 element_token_hash = newSetupFileHash();
4791 for (i = 0; element_name_info[i].token_name != NULL; i++)
4792 setHashEntry(element_token_hash,
4793 element_name_info[i].token_name,
4796 // create hash from graphic token list
4797 graphic_token_hash = newSetupFileHash();
4798 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4799 if (strSuffix(image_config[i].value, ".png") ||
4800 strSuffix(image_config[i].value, ".pcx") ||
4801 strSuffix(image_config[i].value, ".wav") ||
4802 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4803 setHashEntry(graphic_token_hash,
4804 image_config[i].token,
4805 int2str(graphic++, 0));
4807 // create hash from font token list
4808 font_token_hash = newSetupFileHash();
4809 for (i = 0; font_info[i].token_name != NULL; i++)
4810 setHashEntry(font_token_hash,
4811 font_info[i].token_name,
4814 // set default filenames for all cloned graphics in static configuration
4815 for (i = 0; image_config[i].token != NULL; i++)
4817 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4819 char *token = image_config[i].token;
4820 char *token_clone_from = getStringCat2(token, ".clone_from");
4821 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4823 if (token_cloned != NULL)
4825 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4827 if (value_cloned != NULL)
4829 // set default filename in static configuration
4830 image_config[i].value = value_cloned;
4832 // set default filename in image config hash
4833 setHashEntry(image_config_hash, token, value_cloned);
4837 free(token_clone_from);
4841 // always start with reliable default values (all elements)
4842 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4843 ActiveElement[i] = i;
4845 // now add all entries that have an active state (active elements)
4846 for (i = 0; element_with_active_state[i].element != -1; i++)
4848 int element = element_with_active_state[i].element;
4849 int element_active = element_with_active_state[i].element_active;
4851 ActiveElement[element] = element_active;
4854 // always start with reliable default values (all buttons)
4855 for (i = 0; i < NUM_IMAGE_FILES; i++)
4856 ActiveButton[i] = i;
4858 // now add all entries that have an active state (active buttons)
4859 for (i = 0; button_with_active_state[i].button != -1; i++)
4861 int button = button_with_active_state[i].button;
4862 int button_active = button_with_active_state[i].button_active;
4864 ActiveButton[button] = button_active;
4867 // always start with reliable default values (all fonts)
4868 for (i = 0; i < NUM_FONTS; i++)
4871 // now add all entries that have an active state (active fonts)
4872 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4874 int font = font_with_active_state[i].font_nr;
4875 int font_active = font_with_active_state[i].font_nr_active;
4877 ActiveFont[font] = font_active;
4880 global.autoplay_leveldir = NULL;
4881 global.convert_leveldir = NULL;
4882 global.create_images_dir = NULL;
4884 global.frames_per_second = 0;
4885 global.show_frames_per_second = FALSE;
4887 global.border_status = GAME_MODE_LOADING;
4888 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4890 global.use_envelope_request = FALSE;
4893 static void Execute_Command(char *command)
4897 if (strEqual(command, "print graphicsinfo.conf"))
4899 Print("# You can configure additional/alternative image files here.\n");
4900 Print("# (The entries below are default and therefore commented out.)\n");
4902 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4904 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4907 for (i = 0; image_config[i].token != NULL; i++)
4908 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4909 image_config[i].value));
4913 else if (strEqual(command, "print soundsinfo.conf"))
4915 Print("# You can configure additional/alternative sound files here.\n");
4916 Print("# (The entries below are default and therefore commented out.)\n");
4918 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4920 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4923 for (i = 0; sound_config[i].token != NULL; i++)
4924 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4925 sound_config[i].value));
4929 else if (strEqual(command, "print musicinfo.conf"))
4931 Print("# You can configure additional/alternative music files here.\n");
4932 Print("# (The entries below are default and therefore commented out.)\n");
4934 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4936 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4939 for (i = 0; music_config[i].token != NULL; i++)
4940 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4941 music_config[i].value));
4945 else if (strEqual(command, "print editorsetup.conf"))
4947 Print("# You can configure your personal editor element list here.\n");
4948 Print("# (The entries below are default and therefore commented out.)\n");
4951 // this is needed to be able to check element list for cascade elements
4952 InitElementPropertiesStatic();
4953 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4955 PrintEditorElementList();
4959 else if (strEqual(command, "print helpanim.conf"))
4961 Print("# You can configure different element help animations here.\n");
4962 Print("# (The entries below are default and therefore commented out.)\n");
4965 for (i = 0; helpanim_config[i].token != NULL; i++)
4967 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4968 helpanim_config[i].value));
4970 if (strEqual(helpanim_config[i].token, "end"))
4976 else if (strEqual(command, "print helptext.conf"))
4978 Print("# You can configure different element help text here.\n");
4979 Print("# (The entries below are default and therefore commented out.)\n");
4982 for (i = 0; helptext_config[i].token != NULL; i++)
4983 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4984 helptext_config[i].value));
4988 else if (strPrefix(command, "dump level "))
4990 char *filename = &command[11];
4992 if (!fileExists(filename))
4993 Error(ERR_EXIT, "cannot open file '%s'", filename);
4995 LoadLevelFromFilename(&level, filename);
5000 else if (strPrefix(command, "dump tape "))
5002 char *filename = &command[10];
5004 if (!fileExists(filename))
5005 Error(ERR_EXIT, "cannot open file '%s'", filename);
5007 LoadTapeFromFilename(filename);
5012 else if (strPrefix(command, "autotest ") ||
5013 strPrefix(command, "autoplay ") ||
5014 strPrefix(command, "autoffwd ") ||
5015 strPrefix(command, "autowarp "))
5017 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5019 global.autoplay_mode =
5020 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5021 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5022 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5023 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5024 AUTOPLAY_MODE_NONE);
5026 while (*str_ptr != '\0') // continue parsing string
5028 // cut leading whitespace from string, replace it by string terminator
5029 while (*str_ptr == ' ' || *str_ptr == '\t')
5032 if (*str_ptr == '\0') // end of string reached
5035 if (global.autoplay_leveldir == NULL) // read level set string
5037 global.autoplay_leveldir = str_ptr;
5038 global.autoplay_all = TRUE; // default: play all tapes
5040 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5041 global.autoplay_level[i] = FALSE;
5043 else // read level number string
5045 int level_nr = atoi(str_ptr); // get level_nr value
5047 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5048 global.autoplay_level[level_nr] = TRUE;
5050 global.autoplay_all = FALSE;
5053 // advance string pointer to the next whitespace (or end of string)
5054 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5058 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5059 program.headless = TRUE;
5061 else if (strPrefix(command, "convert "))
5063 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5064 char *str_ptr = strchr(str_copy, ' ');
5066 global.convert_leveldir = str_copy;
5067 global.convert_level_nr = -1;
5069 if (str_ptr != NULL) // level number follows
5071 *str_ptr++ = '\0'; // terminate leveldir string
5072 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5075 program.headless = TRUE;
5077 else if (strPrefix(command, "create images "))
5079 global.create_images_dir = getStringCopy(&command[14]);
5081 if (access(global.create_images_dir, W_OK) != 0)
5082 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5083 global.create_images_dir);
5085 else if (strPrefix(command, "create CE image "))
5087 CreateCustomElementImages(&command[16]);
5093 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5096 // disable networking if any valid command was recognized
5097 options.network = setup.network_mode = FALSE;
5100 static void InitSetup(void)
5102 LoadSetup(); // global setup info
5103 LoadSetup_AutoSetup(); // global auto setup info
5105 // set some options from setup file
5107 if (setup.options.verbose)
5108 options.verbose = TRUE;
5110 if (setup.debug.show_frames_per_second)
5111 global.show_frames_per_second = TRUE;
5114 static void InitGameInfo(void)
5116 game.restart_level = FALSE;
5117 game.restart_game_message = NULL;
5118 game.request_active = FALSE;
5121 static void InitPlayerInfo(void)
5125 // choose default local player
5126 local_player = &stored_player[0];
5128 for (i = 0; i < MAX_PLAYERS; i++)
5130 stored_player[i].connected_locally = FALSE;
5131 stored_player[i].connected_network = FALSE;
5134 local_player->connected_locally = TRUE;
5137 static void InitArtworkInfo(void)
5142 static char *get_string_in_brackets(char *string)
5144 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5146 sprintf(string_in_brackets, "[%s]", string);
5148 return string_in_brackets;
5151 static char *get_level_id_suffix(int id_nr)
5153 char *id_suffix = checked_malloc(1 + 3 + 1);
5155 if (id_nr < 0 || id_nr > 999)
5158 sprintf(id_suffix, ".%03d", id_nr);
5163 static void InitArtworkConfig(void)
5165 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5167 NUM_GLOBAL_ANIM_TOKENS + 1];
5168 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5169 NUM_GLOBAL_ANIM_TOKENS + 1];
5170 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5171 NUM_GLOBAL_ANIM_TOKENS + 1];
5172 static char *action_id_suffix[NUM_ACTIONS + 1];
5173 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5174 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5175 static char *level_id_suffix[MAX_LEVELS + 1];
5176 static char *dummy[1] = { NULL };
5177 static char *ignore_generic_tokens[] =
5182 "program_copyright",
5187 static char **ignore_image_tokens;
5188 static char **ignore_sound_tokens;
5189 static char **ignore_music_tokens;
5190 int num_ignore_generic_tokens;
5191 int num_ignore_image_tokens;
5192 int num_ignore_sound_tokens;
5193 int num_ignore_music_tokens;
5196 // dynamically determine list of generic tokens to be ignored
5197 num_ignore_generic_tokens = 0;
5198 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5199 num_ignore_generic_tokens++;
5201 // dynamically determine list of image tokens to be ignored
5202 num_ignore_image_tokens = num_ignore_generic_tokens;
5203 for (i = 0; image_config_vars[i].token != NULL; i++)
5204 num_ignore_image_tokens++;
5205 ignore_image_tokens =
5206 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5207 for (i = 0; i < num_ignore_generic_tokens; i++)
5208 ignore_image_tokens[i] = ignore_generic_tokens[i];
5209 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5210 ignore_image_tokens[num_ignore_generic_tokens + i] =
5211 image_config_vars[i].token;
5212 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5214 // dynamically determine list of sound tokens to be ignored
5215 num_ignore_sound_tokens = num_ignore_generic_tokens;
5216 ignore_sound_tokens =
5217 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5218 for (i = 0; i < num_ignore_generic_tokens; i++)
5219 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5220 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5222 // dynamically determine list of music tokens to be ignored
5223 num_ignore_music_tokens = num_ignore_generic_tokens;
5224 ignore_music_tokens =
5225 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5226 for (i = 0; i < num_ignore_generic_tokens; i++)
5227 ignore_music_tokens[i] = ignore_generic_tokens[i];
5228 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5230 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5231 image_id_prefix[i] = element_info[i].token_name;
5232 for (i = 0; i < NUM_FONTS; i++)
5233 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5234 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5235 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5236 global_anim_info[i].token_name;
5237 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5239 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5240 sound_id_prefix[i] = element_info[i].token_name;
5241 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5242 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5243 get_string_in_brackets(element_info[i].class_name);
5244 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5245 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5246 global_anim_info[i].token_name;
5247 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5249 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5250 music_id_prefix[i] = music_prefix_info[i].prefix;
5251 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5252 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5253 global_anim_info[i].token_name;
5254 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5256 for (i = 0; i < NUM_ACTIONS; i++)
5257 action_id_suffix[i] = element_action_info[i].suffix;
5258 action_id_suffix[NUM_ACTIONS] = NULL;
5260 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5261 direction_id_suffix[i] = element_direction_info[i].suffix;
5262 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5264 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5265 special_id_suffix[i] = special_suffix_info[i].suffix;
5266 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5268 for (i = 0; i < MAX_LEVELS; i++)
5269 level_id_suffix[i] = get_level_id_suffix(i);
5270 level_id_suffix[MAX_LEVELS] = NULL;
5272 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5273 image_id_prefix, action_id_suffix, direction_id_suffix,
5274 special_id_suffix, ignore_image_tokens);
5275 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5276 sound_id_prefix, action_id_suffix, dummy,
5277 special_id_suffix, ignore_sound_tokens);
5278 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5279 music_id_prefix, action_id_suffix, special_id_suffix,
5280 level_id_suffix, ignore_music_tokens);
5283 static void InitMixer(void)
5290 static void InitVideoOverlay(void)
5292 // if virtual buttons are not loaded from setup file, repeat initializing
5293 // virtual buttons grid with default values now that video is initialized
5294 if (!setup.touch.grid_initialized)
5297 InitTileCursorInfo();
5301 void InitGfxBuffers(void)
5303 static int win_xsize_last = -1;
5304 static int win_ysize_last = -1;
5306 // create additional image buffers for double-buffering and cross-fading
5308 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5310 // used to temporarily store the backbuffer -- only re-create if changed
5311 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5312 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5314 win_xsize_last = WIN_XSIZE;
5315 win_ysize_last = WIN_YSIZE;
5318 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5319 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5320 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5321 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5323 // initialize screen properties
5324 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5325 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5327 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5328 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5329 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5330 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5331 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5332 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5334 // required if door size definitions have changed
5335 InitGraphicCompatibilityInfo_Doors();
5337 InitGfxBuffers_EM();
5338 InitGfxBuffers_SP();
5341 static void InitGfx(void)
5343 struct GraphicInfo *graphic_info_last = graphic_info;
5344 char *filename_font_initial = NULL;
5345 char *filename_anim_initial = NULL;
5346 Bitmap *bitmap_font_initial = NULL;
5349 // determine settings for initial font (for displaying startup messages)
5350 for (i = 0; image_config[i].token != NULL; i++)
5352 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5354 char font_token[128];
5357 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5358 len_font_token = strlen(font_token);
5360 if (strEqual(image_config[i].token, font_token))
5361 filename_font_initial = image_config[i].value;
5362 else if (strlen(image_config[i].token) > len_font_token &&
5363 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5365 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5366 font_initial[j].src_x = atoi(image_config[i].value);
5367 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5368 font_initial[j].src_y = atoi(image_config[i].value);
5369 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5370 font_initial[j].width = atoi(image_config[i].value);
5371 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5372 font_initial[j].height = atoi(image_config[i].value);
5377 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5379 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5380 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5383 if (filename_font_initial == NULL) // should not happen
5384 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5387 InitGfxCustomArtworkInfo();
5388 InitGfxOtherSettings();
5390 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5392 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5393 font_initial[j].bitmap = bitmap_font_initial;
5395 InitFontGraphicInfo();
5399 DrawInitText("Loading graphics", 120, FC_GREEN);
5401 // initialize settings for busy animation with default values
5402 int parameter[NUM_GFX_ARGS];
5403 for (i = 0; i < NUM_GFX_ARGS; i++)
5404 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5405 image_config_suffix[i].token,
5406 image_config_suffix[i].type);
5408 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5409 int len_anim_token = strlen(anim_token);
5411 // read settings for busy animation from default custom artwork config
5412 char *gfx_config_filename = getPath3(options.graphics_directory,
5414 GRAPHICSINFO_FILENAME);
5416 if (fileExists(gfx_config_filename))
5418 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5420 if (setup_file_hash)
5422 char *filename = getHashEntry(setup_file_hash, anim_token);
5426 filename_anim_initial = getStringCopy(filename);
5428 for (j = 0; image_config_suffix[j].token != NULL; j++)
5430 int type = image_config_suffix[j].type;
5431 char *suffix = image_config_suffix[j].token;
5432 char *token = getStringCat2(anim_token, suffix);
5433 char *value = getHashEntry(setup_file_hash, token);
5435 checked_free(token);
5438 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5442 freeSetupFileHash(setup_file_hash);
5446 if (filename_anim_initial == NULL)
5448 // read settings for busy animation from static default artwork config
5449 for (i = 0; image_config[i].token != NULL; i++)
5451 if (strEqual(image_config[i].token, anim_token))
5452 filename_anim_initial = getStringCopy(image_config[i].value);
5453 else if (strlen(image_config[i].token) > len_anim_token &&
5454 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5456 for (j = 0; image_config_suffix[j].token != NULL; j++)
5458 if (strEqual(&image_config[i].token[len_anim_token],
5459 image_config_suffix[j].token))
5461 get_graphic_parameter_value(image_config[i].value,
5462 image_config_suffix[j].token,
5463 image_config_suffix[j].type);
5469 if (filename_anim_initial == NULL) // should not happen
5470 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5472 anim_initial.bitmaps =
5473 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5475 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5476 LoadCustomImage(filename_anim_initial);
5478 checked_free(filename_anim_initial);
5480 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5482 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5484 graphic_info = graphic_info_last;
5486 init.busy.width = anim_initial.width;
5487 init.busy.height = anim_initial.height;
5489 InitMenuDesignSettings_Static();
5491 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5492 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5493 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5494 InitGfxDrawTileCursorFunction(DrawTileCursor);
5496 gfx.fade_border_source_status = global.border_status;
5497 gfx.fade_border_target_status = global.border_status;
5498 gfx.masked_border_bitmap_ptr = backbuffer;
5500 // use copy of busy animation to prevent change while reloading artwork
5504 static void InitGfxBackground(void)
5506 fieldbuffer = bitmap_db_field;
5507 SetDrawtoField(DRAW_TO_BACKBUFFER);
5509 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5511 redraw_mask = REDRAW_ALL;
5514 static void InitLevelInfo(void)
5516 LoadLevelInfo(); // global level info
5517 LoadLevelSetup_LastSeries(); // last played series info
5518 LoadLevelSetup_SeriesInfo(); // last played level info
5520 if (global.autoplay_leveldir &&
5521 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5523 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5524 global.autoplay_leveldir);
5525 if (leveldir_current == NULL)
5526 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5529 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5532 static void InitLevelArtworkInfo(void)
5534 LoadLevelArtworkInfo();
5537 static void InitImages(void)
5539 print_timestamp_init("InitImages");
5542 printf("::: leveldir_current->identifier == '%s'\n",
5543 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5544 printf("::: leveldir_current->graphics_path == '%s'\n",
5545 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5546 printf("::: leveldir_current->graphics_set == '%s'\n",
5547 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5548 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5549 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5552 setLevelArtworkDir(artwork.gfx_first);
5555 printf("::: leveldir_current->identifier == '%s'\n",
5556 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5557 printf("::: leveldir_current->graphics_path == '%s'\n",
5558 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5559 printf("::: leveldir_current->graphics_set == '%s'\n",
5560 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5561 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5562 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5566 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5567 leveldir_current->identifier,
5568 artwork.gfx_current_identifier,
5569 artwork.gfx_current->identifier,
5570 leveldir_current->graphics_set,
5571 leveldir_current->graphics_path);
5574 UPDATE_BUSY_STATE();
5576 ReloadCustomImages();
5577 print_timestamp_time("ReloadCustomImages");
5579 UPDATE_BUSY_STATE();
5581 LoadCustomElementDescriptions();
5582 print_timestamp_time("LoadCustomElementDescriptions");
5584 UPDATE_BUSY_STATE();
5586 LoadMenuDesignSettings();
5587 print_timestamp_time("LoadMenuDesignSettings");
5589 UPDATE_BUSY_STATE();
5591 ReinitializeGraphics();
5592 print_timestamp_time("ReinitializeGraphics");
5594 LoadMenuDesignSettings_AfterGraphics();
5595 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5597 UPDATE_BUSY_STATE();
5599 print_timestamp_done("InitImages");
5602 static void InitSound(char *identifier)
5604 print_timestamp_init("InitSound");
5606 if (identifier == NULL)
5607 identifier = artwork.snd_current->identifier;
5609 // set artwork path to send it to the sound server process
5610 setLevelArtworkDir(artwork.snd_first);
5612 InitReloadCustomSounds(identifier);
5613 print_timestamp_time("InitReloadCustomSounds");
5615 ReinitializeSounds();
5616 print_timestamp_time("ReinitializeSounds");
5618 print_timestamp_done("InitSound");
5621 static void InitMusic(char *identifier)
5623 print_timestamp_init("InitMusic");
5625 if (identifier == NULL)
5626 identifier = artwork.mus_current->identifier;
5628 // set artwork path to send it to the sound server process
5629 setLevelArtworkDir(artwork.mus_first);
5631 InitReloadCustomMusic(identifier);
5632 print_timestamp_time("InitReloadCustomMusic");
5634 ReinitializeMusic();
5635 print_timestamp_time("ReinitializeMusic");
5637 print_timestamp_done("InitMusic");
5640 static void InitArtworkDone(void)
5642 if (program.headless)
5645 InitGlobalAnimations();
5648 static void InitNetworkSettings(void)
5650 boolean network_enabled = (options.network || setup.network_mode);
5651 char *network_server = (options.server_host != NULL ? options.server_host :
5652 setup.network_server_hostname);
5654 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5655 network_server = NULL;
5657 InitNetworkInfo(network_enabled,
5661 options.server_port);
5664 void InitNetworkServer(void)
5666 if (!network.enabled || network.connected)
5669 LimitScreenUpdates(FALSE);
5671 if (game_status == GAME_MODE_LOADING)
5674 if (!ConnectToServer(network.server_host, network.server_port))
5676 network.enabled = FALSE;
5678 setup.network_mode = FALSE;
5682 SendToServer_ProtocolVersion();
5683 SendToServer_PlayerName(setup.player_name);
5684 SendToServer_NrWanted(setup.network_player_nr + 1);
5686 network.connected = TRUE;
5689 // short time to recognize result of network initialization
5690 if (game_status == GAME_MODE_LOADING)
5691 Delay_WithScreenUpdates(1000);
5694 static boolean CheckArtworkConfigForCustomElements(char *filename)
5696 SetupFileHash *setup_file_hash;
5697 boolean redefined_ce_found = FALSE;
5699 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5701 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5703 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5705 char *token = HASH_ITERATION_TOKEN(itr);
5707 if (strPrefix(token, "custom_"))
5709 redefined_ce_found = TRUE;
5714 END_HASH_ITERATION(setup_file_hash, itr)
5716 freeSetupFileHash(setup_file_hash);
5719 return redefined_ce_found;
5722 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5724 char *filename_base, *filename_local;
5725 boolean redefined_ce_found = FALSE;
5727 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5730 printf("::: leveldir_current->identifier == '%s'\n",
5731 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5732 printf("::: leveldir_current->graphics_path == '%s'\n",
5733 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5734 printf("::: leveldir_current->graphics_set == '%s'\n",
5735 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5736 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5737 leveldir_current == NULL ? "[NULL]" :
5738 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5741 // first look for special artwork configured in level series config
5742 filename_base = getCustomArtworkLevelConfigFilename(type);
5745 printf("::: filename_base == '%s'\n", filename_base);
5748 if (fileExists(filename_base))
5749 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5751 filename_local = getCustomArtworkConfigFilename(type);
5754 printf("::: filename_local == '%s'\n", filename_local);
5757 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5758 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5761 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5764 return redefined_ce_found;
5767 static void InitOverrideArtwork(void)
5769 boolean redefined_ce_found = FALSE;
5771 // to check if this level set redefines any CEs, do not use overriding
5772 gfx.override_level_graphics = FALSE;
5773 gfx.override_level_sounds = FALSE;
5774 gfx.override_level_music = FALSE;
5776 // now check if this level set has definitions for custom elements
5777 if (setup.override_level_graphics == AUTO ||
5778 setup.override_level_sounds == AUTO ||
5779 setup.override_level_music == AUTO)
5780 redefined_ce_found =
5781 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5782 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5783 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5786 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5789 if (redefined_ce_found)
5791 // this level set has CE definitions: change "AUTO" to "FALSE"
5792 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5793 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5794 gfx.override_level_music = (setup.override_level_music == TRUE);
5798 // this level set has no CE definitions: change "AUTO" to "TRUE"
5799 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5800 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5801 gfx.override_level_music = (setup.override_level_music != FALSE);
5805 printf("::: => %d, %d, %d\n",
5806 gfx.override_level_graphics,
5807 gfx.override_level_sounds,
5808 gfx.override_level_music);
5812 static char *getNewArtworkIdentifier(int type)
5814 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5815 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5816 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5817 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5818 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5819 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5820 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5821 char *leveldir_identifier = leveldir_current->identifier;
5822 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5823 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5824 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5825 char *artwork_current_identifier;
5826 char *artwork_new_identifier = NULL; // default: nothing has changed
5828 // leveldir_current may be invalid (level group, parent link)
5829 if (!validLevelSeries(leveldir_current))
5832 /* 1st step: determine artwork set to be activated in descending order:
5833 --------------------------------------------------------------------
5834 1. setup artwork (when configured to override everything else)
5835 2. artwork set configured in "levelinfo.conf" of current level set
5836 (artwork in level directory will have priority when loading later)
5837 3. artwork in level directory (stored in artwork sub-directory)
5838 4. setup artwork (currently configured in setup menu) */
5840 if (setup_override_artwork)
5841 artwork_current_identifier = setup_artwork_set;
5842 else if (leveldir_artwork_set != NULL)
5843 artwork_current_identifier = leveldir_artwork_set;
5844 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5845 artwork_current_identifier = leveldir_identifier;
5847 artwork_current_identifier = setup_artwork_set;
5850 /* 2nd step: check if it is really needed to reload artwork set
5851 ------------------------------------------------------------ */
5853 // ---------- reload if level set and also artwork set has changed ----------
5854 if (leveldir_current_identifier[type] != leveldir_identifier &&
5855 (last_has_level_artwork_set[type] || has_level_artwork_set))
5856 artwork_new_identifier = artwork_current_identifier;
5858 leveldir_current_identifier[type] = leveldir_identifier;
5859 last_has_level_artwork_set[type] = has_level_artwork_set;
5861 // ---------- reload if "override artwork" setting has changed --------------
5862 if (last_override_level_artwork[type] != setup_override_artwork)
5863 artwork_new_identifier = artwork_current_identifier;
5865 last_override_level_artwork[type] = setup_override_artwork;
5867 // ---------- reload if current artwork identifier has changed --------------
5868 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5869 artwork_current_identifier))
5870 artwork_new_identifier = artwork_current_identifier;
5872 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5874 // ---------- do not reload directly after starting -------------------------
5875 if (!initialized[type])
5876 artwork_new_identifier = NULL;
5878 initialized[type] = TRUE;
5880 return artwork_new_identifier;
5883 void ReloadCustomArtwork(int force_reload)
5885 int last_game_status = game_status; // save current game status
5886 char *gfx_new_identifier;
5887 char *snd_new_identifier;
5888 char *mus_new_identifier;
5889 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5890 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5891 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5892 boolean reload_needed;
5894 InitOverrideArtwork();
5896 force_reload_gfx |= AdjustGraphicsForEMC();
5898 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5899 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5900 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5902 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5903 snd_new_identifier != NULL || force_reload_snd ||
5904 mus_new_identifier != NULL || force_reload_mus);
5909 print_timestamp_init("ReloadCustomArtwork");
5911 SetGameStatus(GAME_MODE_LOADING);
5913 FadeOut(REDRAW_ALL);
5915 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5916 print_timestamp_time("ClearRectangle");
5920 if (gfx_new_identifier != NULL || force_reload_gfx)
5923 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5924 artwork.gfx_current_identifier,
5926 artwork.gfx_current->identifier,
5927 leveldir_current->graphics_set);
5931 print_timestamp_time("InitImages");
5934 if (snd_new_identifier != NULL || force_reload_snd)
5936 InitSound(snd_new_identifier);
5937 print_timestamp_time("InitSound");
5940 if (mus_new_identifier != NULL || force_reload_mus)
5942 InitMusic(mus_new_identifier);
5943 print_timestamp_time("InitMusic");
5948 SetGameStatus(last_game_status); // restore current game status
5950 init_last = init; // switch to new busy animation
5952 FadeOut(REDRAW_ALL);
5954 RedrawGlobalBorder();
5956 // force redraw of (open or closed) door graphics
5957 SetDoorState(DOOR_OPEN_ALL);
5958 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5960 FadeSetEnterScreen();
5961 FadeSkipNextFadeOut();
5963 print_timestamp_done("ReloadCustomArtwork");
5965 LimitScreenUpdates(FALSE);
5968 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5970 if (global.autoplay_leveldir == NULL)
5971 KeyboardAutoRepeatOff();
5974 void DisplayExitMessage(char *format, va_list ap)
5976 // also check for initialized video (headless flag may be temporarily unset)
5977 if (program.headless || !video.initialized)
5980 // check if draw buffer and fonts for exit message are already available
5981 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5984 int font_1 = FC_RED;
5985 int font_2 = FC_YELLOW;
5986 int font_3 = FC_BLUE;
5987 int font_width = getFontWidth(font_2);
5988 int font_height = getFontHeight(font_2);
5991 int sxsize = WIN_XSIZE - 2 * sx;
5992 int sysize = WIN_YSIZE - 2 * sy;
5993 int line_length = sxsize / font_width;
5994 int max_lines = sysize / font_height;
5995 int num_lines_printed;
5999 gfx.sxsize = sxsize;
6000 gfx.sysize = sysize;
6004 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6006 DrawTextSCentered(sy, font_1, "Fatal error:");
6007 sy += 3 * font_height;;
6010 DrawTextBufferVA(sx, sy, format, ap, font_2,
6011 line_length, line_length, max_lines,
6012 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6013 sy += (num_lines_printed + 3) * font_height;
6015 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6016 sy += 3 * font_height;
6019 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6020 line_length, line_length, max_lines,
6021 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6023 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6025 redraw_mask = REDRAW_ALL;
6027 // force drawing exit message even if screen updates are currently limited
6028 LimitScreenUpdates(FALSE);
6032 // deactivate toons on error message screen
6033 setup.toons = FALSE;
6035 WaitForEventToContinue();
6039 // ============================================================================
6041 // ============================================================================
6045 print_timestamp_init("OpenAll");
6047 SetGameStatus(GAME_MODE_LOADING);
6051 InitGlobal(); // initialize some global variables
6053 print_timestamp_time("[init global stuff]");
6057 print_timestamp_time("[init setup/config stuff (1)]");
6061 if (options.execute_command)
6062 Execute_Command(options.execute_command);
6064 InitNetworkSettings();
6068 if (network.serveronly)
6070 #if defined(PLATFORM_UNIX)
6071 NetworkServer(network.server_port, TRUE);
6073 Error(ERR_WARN, "networking only supported in Unix version");
6076 exit(0); // never reached, server loops forever
6080 print_timestamp_time("[init setup/config stuff (2)]");
6082 print_timestamp_time("[init setup/config stuff (3)]");
6083 InitArtworkInfo(); // needed before loading gfx, sound & music
6084 print_timestamp_time("[init setup/config stuff (4)]");
6085 InitArtworkConfig(); // needed before forking sound child process
6086 print_timestamp_time("[init setup/config stuff (5)]");
6088 print_timestamp_time("[init setup/config stuff (6)]");
6090 InitRND(NEW_RANDOMIZE);
6091 InitSimpleRandom(NEW_RANDOMIZE);
6095 print_timestamp_time("[init setup/config stuff]");
6097 InitVideoDefaults();
6099 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6102 print_timestamp_time("[init video stuff]");
6104 InitElementPropertiesStatic();
6105 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6106 InitElementPropertiesGfxElement();
6108 print_timestamp_time("[init element properties stuff]");
6112 print_timestamp_time("InitGfx");
6115 print_timestamp_time("InitLevelInfo");
6117 InitLevelArtworkInfo();
6118 print_timestamp_time("InitLevelArtworkInfo");
6120 InitOverrideArtwork(); // needs to know current level directory
6121 print_timestamp_time("InitOverrideArtwork");
6123 InitImages(); // needs to know current level directory
6124 print_timestamp_time("InitImages");
6126 InitSound(NULL); // needs to know current level directory
6127 print_timestamp_time("InitSound");
6129 InitMusic(NULL); // needs to know current level directory
6130 print_timestamp_time("InitMusic");
6134 InitGfxBackground();
6140 if (global.autoplay_leveldir)
6145 else if (global.convert_leveldir)
6150 else if (global.create_images_dir)
6152 CreateLevelSketchImages();
6156 InitNetworkServer();
6158 SetGameStatus(GAME_MODE_MAIN);
6160 FadeSetEnterScreen();
6161 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6162 FadeSkipNextFadeOut();
6164 print_timestamp_time("[post-artwork]");
6166 print_timestamp_done("OpenAll");
6171 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6173 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6174 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6175 #if defined(PLATFORM_ANDROID)
6176 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6177 SDL_AndroidGetInternalStoragePath());
6178 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6179 SDL_AndroidGetExternalStoragePath());
6180 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6181 (SDL_AndroidGetExternalStorageState() &
6182 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6183 SDL_AndroidGetExternalStorageState() &
6184 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6189 void CloseAllAndExit(int exit_value)
6194 CloseAudio(); // called after freeing sounds (needed for SDL)
6202 // set a flag to tell the network server thread to quit and wait for it
6203 // using SDL_WaitThread()
6205 // Code used with SDL 1.2:
6206 // if (network_server) // terminate network server
6207 // SDL_KillThread(server_thread);
6209 CloseVideoDisplay();
6210 ClosePlatformDependentStuff();
6212 if (exit_value != 0 && !options.execute_command)
6214 // fall back to default level set (current set may have caused an error)
6215 SaveLevelSetup_LastSeries_Deactivate();
6217 // tell user where to find error log file which may contain more details
6218 // (error notification now directly displayed on screen inside R'n'D
6219 // NotifyUserAboutErrorFile(); // currently only works for Windows